Nginx Server Setup Tutorial Docker Edition

Introduction
Yo, server warriors! đ Ever felt like smashing your laptop just because setting up Nginx for your Docker project is a pain in the neck? Especially when SSL comes into playâsupposed to be easy, but suddenly your brainâs overheating. Youâve hustled hard to get your app running in Docker, but when itâs time to go public, boom, stuck at Nginx. Annoying as hell, right?
Chill, bro! In this note, Iâll show you step-by-step how to make Nginx your Docker appâs personal bouncer, so the whole world can access your masterpiece. And of course, weâll slap on SSL so your site doesnât look like itâs from the stone age (seriously, no padlock? Come on, man!). Real case study: your appâs running on Docker port 3000, Nginx stands guard in front. Easy, no drama, and guaranteed not to make you cry!
So, grab your coffee, brace yourself, and letâs roll!
Prerequisites
- A Linux server (iâm using ubuntu, but any distro will Do)
- Docker installed
- Docker Compose installed
- Basic knowledge of Docker and Nginx
- Domain name (optional, but recommended for SSL)
- A Docker container running yout app (e.g., Node.js, Python, etc.)
- About 30 minutes of your time (and maybe a coffe or two or three â)
Step 1: Install Nginx
first things first - letâs get Nginx installed on our server.
sudo apt update
sudo apt install -y nginx
Once installed, make sure Nginx is running:
sudo systemctl status nginx
Your should see something like âactive (running)â. If not, start it with:
sudo systemctl start nginx
Step 2: Create Nginx Configuration file
Now, letâs create a configuration file for Nginx. Weâll set it up a new config file for our fomain:
sudo nano /etc/nginx/sites-avaliable/yourdomain.com
Replace yourdomain.com
with your actual domain name. If you donât have a domain, you can use your serverâs IP address. Hereâs a basic configuration to get you started:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
access_log /var/log/nginx/yourdomain_access.log;
error_log /var/log/nginx/yourdomain_error.log;
location / {
proxy_pass http://localhost:3000; # Change this to your appp's port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# Cloudflare headers (useful even if you're not using Cloudflare)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Optional: Set a timeout for the proxy connection
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
Let me break down what this config does:
- listen 80;: This tells Nginx to listen on port 80 (HTTP).
- server_name yourdomain.com www.yourdomain.com;: This specifies the domain names that this server block will respond to.
- access_log and error_log: These lines specify where to log access and error messages.
- location /: This block defines how to handle requests to the root URL.
- proxy_pass http://localhost:3000;: This line tells Nginx to forward requests to your app running on port 3000.
- proxy_set_header: These lines set various headers to pass along to your app. This is important for things like WebSocket connections and getting the real IP address of the client.
- proxy_connect_timeout, proxy_send_timeout, and proxy_read_timeout: These lines set timeouts for the proxy connection. You can adjust these values based on your appâs needs.
- Cloudflare headers: These headers are useful if youâre using Cloudflare as a CDN, but even if youâre not, they can help with things like getting the real IP address of the client.
Step 3: Enable the Site
Now that we have our configuration file, we need to enable it. Create a symbolic link to the sites-enabled
directory:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
Now test if our Nginx config has any syntax errors:
sudo nginx -t
If everything looks good, restart Nginx to apply the changes:
sudo systemctl restart nginx
At this point, your site should be accessible via HTTP (port 80). Give it a quick check before we move to SSL!
Step 4: SSL Setup with Certbot
Now letâs get that sweet, sweet padlock icon by setting up SSL. Weâll use Certbot because itâs free and super easy:
# Install Certbot and the Nginx plugin
sudo apt install -y certbot python3-certbot-nginx
# Get SSL certificates and auto-configure Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts (usually just providing your email and agreeing to terms). When asked if you want to redirect HTTP to HTTPS, I recommend selecting option 2 for redirect - security first, folks!
After running Certbot, it will:
- Obtain the SSL certificate from Letâs Encrypt.
- Automatically configure Nginx to use the SSL certificate.
- Set up renewal hooks so your cert stays fresh.
Your config file should now look something like this (Certbot adds the SSL stuff):
server {
server_name yourdomain.com www.yourdomain.com;
# Original config stuff...
access_log /var/log/nginx/yourdomain.access.log;
error_log /var/log/nginx/yourdomain.error.log;
location / {
proxy_pass http://localhost:3000;
# All the proxy settings from before...
}
# SSL settings added by Certbot
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
# HTTP to HTTPS redirect
server {
if ($host = www.yourdomain.com) {
return 301 https://$host$request_uri;
}
if ($host = yourdomain.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 404;
}
Test things again to make sure no syntax errors slipped in:
sudo nginx -t
sudo systemctl reload nginx
Alternative: SSL with Cloudflare
Not feeling the Certbot vibes? No worries - Cloudflare is another awesome option. Instead of managing SSL certs yourself, you can use Cloudflare as a proxy with their SSL:
- Sign up for a Cloudflare account and add your domain.
- Add Your domain and update your nameservers to point to Cloudflare.
- In the Cloudflare dashboard, go to the SSL/TLS tab and set the SSL mode to âFullâ or âFull (strict)â.
For âFull (Strict)â mode, youâll still need a cert on your server. But the âFlexibleâ mode is super easy - it handles SSL between users and Cloudflare, while the connection between Cloudflare and your server can stay on HTTP.
Your Nginx config already has the needed Cloudflare headers:
# These headers are already in your config
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
These headers are absolutely crucial when using Cloudflare because:
- They make sure your app knows the real visitor IP (not just Cloudflareâs)
- They properly pass protocol info so your app can build URLs correctly
- They maintain compatibility with security frameworks that check request origins
Troubleshooting
it a snag? Here are some common issues and fixes:
502 Bad Gateway
This usually means Nginx canât reach your Docker container. Check:
- Is your container running?
docker ps
- Is it exposing port 3000?
docker port your-container-name
- Is your app listening on the right port? Check your appâs config.
- Can you reach it directly?
curl http://localhost:3000
SSL Certificate Not Working
- Check if Certbot created the certs:
ls -l /etc/letsencrypt/live/yourdomain.com/
- Verify Nginx is reading the right files (check paths in the config)
- Restart Nginx:
sudo systemctl restart nginx
Connection Refused
- Check if Nginx is running:
sudo systemctl status nginx
- Check if your firewall is blocking port 80/443:
sudo ufw status
- If using a cloud provider, check their security groups/firewall rules
Conclusion
Boom! đ Youâve just set up a rock-solid Nginx server with Docker and SSL! Your app is now:
- Running behind a proper reverse proxy
- Secured with SSL (either via Certbot or Cloudflare)
- Properly logging all access for troubleshooting
- Configured with correct headers for IP forwarding
- Ready to handle WebSocket connections
This setup has served me well across dozens of projects, from small personal sites to production apps handling thousands of users. The best part is that once youâve done this a few times, you can set up new projects in about 5 minutes flat!
Remember that the web server is your appâs bouncer - itâs the first line of defense and critical to performance. A well-configured Nginx setup like this one will keep your Docker apps running smoothly and securely.
Got questions or hit a snag? Feel free to drop them in the comments below! Happy coding! âď¸