One of the most rewarding things I've done this year was building my very own private cloud on AWS from scratch. Not using some simplified wizard — I mean actually configuring every layer: the EC2 instance, the Linux environment, Nginx as a reverse proxy, security groups, IAM roles, and finally Nextcloud as the application layer. Here's how it went.
Why Build a Private Cloud?
I wanted to stop relying on commercial cloud storage for my personal files and project datasets. The privacy, the learning experience, and the control you get from self-hosting are unmatched. Plus, deploying on AWS gave me hands-on exposure to real cloud engineering workflows.
"The best way to understand the cloud is to actually build something on it — not just read about it."
Step 1: Spinning Up the EC2 Instance
I chose a t3.small Ubuntu 22.04 instance in ap-south-1 (Mumbai
region) for low latency. The key decisions early on were:
- Using an Elastic IP so the server's address doesn't change on restart
- Attaching a separate 20GB EBS volume for Nextcloud data (separate from OS)
- Configuring a Security Group that only allows ports 22 (SSH, restricted to my IP), 80, and 443
Step 2: Configuring the Linux Environment
After SSH-ing in, I ran a full system update and installed the required stack:
sudo apt update && sudo apt upgrade -y
sudo apt install nginx php php-fpm php-gd php-curl \
php-mbstring php-xml php-zip mariadb-server -y
I also set up UFW firewall to add a second layer of protection alongside the AWS
Security Group, and configured automatic security updates with unattended-upgrades.
Step 3: Nginx Reverse Proxy Configuration
Nginx acts as the front door, handling SSL termination (via Let's Encrypt / Certbot) and proxying requests to the PHP-FPM backend running Nextcloud.
server {
listen 443 ssl;
server_name cloud.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/cloud.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cloud.yourdomain.com/privkey.pem;
root /var/www/nextcloud;
index index.php;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Step 4: IAM Hardening
I created a dedicated IAM role for the EC2 instance following the principle of least privilege:
- A custom policy allowing only
s3:GetObjectands3:PutObjecton the specific backup bucket - No programmatic access keys — only instance role-based access
- MFA enforced on the root account and all IAM users
- CloudTrail enabled for audit logging
Step 5: Deploying Nextcloud
After configuring the database (MariaDB) and ensuring all PHP extensions were active, I
downloaded and extracted Nextcloud into /var/www/nextcloud, set proper ownership to
www-data, and ran the web-based installation wizard. Post-install steps included:
- Moving the data directory to the separate EBS volume mount point
- Setting up a cron job for background tasks
- Configuring S3 as an external storage for large backups
- Enabling two-factor authentication for all users
What I Learned
This project taught me more practical cloud engineering in two weeks than months of theory. The most important lessons: always separate data from OS volumes, lock down every port, and automate backups before anything else. The cloud makes you think about resilience and security from day one.