DEV Community

AJAYA SHRESTHA
AJAYA SHRESTHA

Posted on

Optimize Static Delivery: Host Static Assets on AWS EC2 with Nginx & Cloudflare

In modern web architecture, speed and scalability are non-negotiable. A CDN (Content Delivery Network) plays a critical role in improving site performance by delivering static assets closer to the end users. Delivering static assets (CSS, JavaScript, images) from a standalone CDN server can dramatically improve your site’s performance and reliability.
In this post, we’ll walk through setting up an AWS EC2 instance, hosting static files, serving them using Nginx, and dramatically improving their delivery speed using Cloudflare as a CDN.

Why a Separate CDN Server?

  • Isolation of concerns: Your web and app servers handle dynamic traffic, while your CDN server exclusively serves static content.
  • Scalability: You can scale or snapshot your CDN layer independently.
  • Cache-control: Nginx and Cloudflare provide fine-grained caching without requiring changes to Django.

1. SSH into Your Server

Use your SSH key and the EC2 public IP to connect:

ssh -i path/to/your-key.pem ubuntu@YOUR_EC2_PUBLIC_IP
Enter fullscreen mode Exit fullscreen mode

2. Installing Nginx & Preparing ~/static

Update your package list and install Nginx:

sudo apt update
sudo apt install -y nginx
Enter fullscreen mode Exit fullscreen mode

Create the static files directory in your home folder:

mkdir -p ~/static
chown -R $USER:www-data ~/static
chmod -R 755 ~/static
Enter fullscreen mode Exit fullscreen mode

Now /home/ubuntu/static is ready to receive your collected assets.

3. Nginx Configuration

# In your home directory, create a conf folder
mkdir -p ~/conf
cd ~/conf

# Edit your nginx.conf
vim nginx.conf
Enter fullscreen mode Exit fullscreen mode

Inside ~/conf/nginx.conf, add:

server {
    listen 80;
    server_name cdn.example.com;

    # Get real visitor IP from Cloudflare
    real_ip_header CF-Connecting-IP;
    set_real_ip_from 0.0.0.0/0;

    # Serve static files from ~/static
    ___location / {
        root /home/ubuntu;
        try_files /static$uri =404;

        # Cache for 7 days
        expires 7d;
        add_header Cache-Control "public, max-age=604800";

        # No access logs for static files
        access_log off;
    }

    # Let's Encrypt support
    ___location /.well-known/acme-challenge/ {
        root /home/ubuntu;
    }

    # Health check
    ___location /health {
        return 200 "OK";
        access_log off;
    }
}
Enter fullscreen mode Exit fullscreen mode

Then activate it by symlinking into Nginx’s conf.d:

sudo ln -sf /home/ubuntu/conf/nginx.conf /etc/nginx/conf.d/cdn_nginx.conf
sudo nginx -t
sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

4. Pointing cdn.example.com to Your EC2 + Cloudflare

  1. In your DNS provider or Cloudflare, create an A record:
  • Name: cdn
  • Type: A
  • Value: YOUR_EC2_PUBLIC_IP
  1. In Cloudflare’s dashboard, set Proxy status to Proxied. Requests to cdn.example.com will now route through Cloudflare’s edge network.

5. Syncing Your Static Files

rsync -av --delete path/to/local/static/ ubuntu@YOUR_EC2_PUBLIC_IP:/home/ubuntu/static/
Enter fullscreen mode Exit fullscreen mode

-a preserves permissions
--delete removes files no longer present locally
Automate this step so every deployment populates your CDN.

6. Enabling HTTPS on the CDN Server

For Cloudflare’s Full (strict) SSL mode, install a Let’s Encrypt certificate:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cdn.example.com
Enter fullscreen mode Exit fullscreen mode

Certbot will:

  • Configure Nginx to listen on port 443
  • Set up auto-renewal
  • Redirect HTTP to HTTPS

7. Django Configuration

In your production settings (settings.py), set:

STATIC_URL = "https://cdn.example.com/"
Enter fullscreen mode Exit fullscreen mode

No other Django changes are required. All {% static %} tags will now reference your CDN host.

8. Verifying Cache & Performance

  • Open Developer Tools - Network - reload a page with static assets.
  • Inspect headers for CSS/JS files
cf-cache-status: HIT
cache-control: max-age=2592000
Enter fullscreen mode Exit fullscreen mode
  • In Cloudflare’s dashboard, review Cache Analytics. Aim for a high Hit Ratio.

9. Advanced Tips

  • Cache Purge: Use Cloudflare’s API or dashboard to purge specific URLs after critical updates.
  • Security: Lock down SSH via Cloudflare Firewall, and allow only trusted IPs.

Top comments (0)