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
Warning: Never open port 22 to 0.0.0.0/0. Restrict SSH to your own IP or use AWS Systems Manager Session Manager instead.

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:GetObject and s3:PutObject on 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
Tip: Use AWS IAM Access Analyzer to detect overly permissive policies and external access automatically.

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.

Share this article: