Honestly, the first few times I set up a web server I just threw Apache on and called it a day. It worked. But once I started running multiple sites on the same server, I kept running into the same problem: Apache felt heavy for what I was doing, and the config syntax made my eyes glaze over.
Someone in a forum told me to just try Nginx. I resisted for a while — yet another thing to learn — but eventually gave in on a Sunday afternoon when I had nothing else to do.
That was a couple of years ago, and now Nginx is the first thing I install on any server. Whether I'm running a single website or five apps behind a reverse proxy, it handles everything cleanly. Getting comfortable with Nginx genuinely changed how I think about self-hosting.
This guide covers everything from installation to production-ready config: serving a static site, virtual hosts for multiple domains, and HTTPS with Let's Encrypt.
I run this on Tencent Cloud Lighthouse with Ubuntu 22.04 LTS. A few things that matter specifically for Nginx setups: Lighthouse instances provision with a clean Ubuntu image (no pre-installed web server conflict to work around), the console-level firewall means you can open ports 80 and 443 from the control panel without touching UFW, and the bandwidth packages (starting at 200GB/month on basic plans) are predictable — no surprise bills if a post goes viral. If you haven't done initial server setup yet, start with the initial setup guide first.
Key Takeaways
- Nginx handles HTTPS termination, static file serving, and reverse proxying
- Always test config with
sudo nginx -tbefore reloading- Virtual hosts let one server run multiple websites on different domains
- Nginx's event-driven model uses less memory than Apache at comparable traffic
- Use
sudo nginx -s reloadfor zero-downtime config updates
Nginx is a high-performance web server and reverse proxy. On a cloud server, it typically plays one of two roles:
Running applications behind Nginx rather than exposing them directly gives you:
sudo apt update
sudo apt install -y nginx
# Start Nginx and enable it to start on boot
sudo systemctl start nginx
sudo systemctl enable nginx
# Verify it's running
sudo systemctl status nginx
Allow HTTP and HTTPS through the firewall:
sudo ufw allow 'Nginx Full'
# This is equivalent to: sudo ufw allow 80 && sudo ufw allow 443
Visit http://YOUR_SERVER_IP in a browser. You should see the Nginx welcome page.
Before touching any config files, here's where things live:
| Path | What it is |
|---|---|
/etc/nginx/nginx.conf |
Main config file — global settings |
/etc/nginx/sites-available/ |
Config files for individual sites (inactive until linked) |
/etc/nginx/sites-enabled/ |
Symlinks to active site configs |
/var/www/html/ |
Default web root |
/var/log/nginx/access.log |
Request logs |
/var/log/nginx/error.log |
Error logs |
The workflow for adding a site:
sites-available/sites-enabled/sudo nginx -tsudo systemctl reload nginx# Create a directory for your site
sudo mkdir -p /var/www/mysite
# Create a simple HTML file to test with
sudo nano /var/www/mysite/index.html
<!DOCTYPE html>
<html>
<head><title>My Site</title></head>
<body>
<h1>Nginx is working.</h1>
<p>Running on Tencent Cloud Lighthouse.</p>
</body>
</html>
# Set ownership
sudo chown -R www-data:www-data /var/www/mysite
sudo nano /etc/nginx/sites-available/mysite
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/mysite;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
# Logging
access_log /var/log/nginx/mysite_access.log;
error_log /var/log/nginx/mysite_error.log;
}
# Enable the site
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
# Remove the default site (optional but clean)
sudo rm /etc/nginx/sites-enabled/default
# Test and reload
sudo nginx -t
sudo systemctl reload nginx
Visit http://yourdomain.com — your page is live.
One server can host multiple websites, each with its own domain. Create a separate config file for each:
sudo nano /etc/nginx/sites-available/secondsite
server {
listen 80;
server_name secondsite.com www.secondsite.com;
root /var/www/secondsite;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
sudo mkdir -p /var/www/secondsite
# Add content to /var/www/secondsite/index.html
sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Nginx routes requests to the right site based on the Host header (which matches server_name).
Once your domain's DNS A record points to the server:
# Install Certbot
sudo apt install -y certbot python3-certbot-nginx
# Obtain and install certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot automatically:
Verify renewal works:
sudo certbot renew --dry-run
This is how I run most apps: the application (Node.js, Python, etc.) listens on a local port, and Nginx proxies public traffic to it.
sudo nano /etc/nginx/sites-available/myapp
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Required for WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
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;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400s;
}
}
After enabling and reloading, run certbot --nginx -d app.yourdomain.com to add HTTPS.
Add to /etc/nginx/nginx.conf inside the http {} block:
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/x-javascript
application/xml
application/json;
Add inside your server {} block:
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
In /etc/nginx/nginx.conf, set worker processes to match your CPU count:
worker_processes auto; # "auto" detects CPU count automatically
After any change to nginx.conf:
sudo nginx -t && sudo systemctl reload nginx
The most common Nginx mistake: editing a config file with a syntax error, reloading, and taking down all sites on the server.
Always run sudo nginx -t before sudo systemctl reload nginx. If the test fails, Nginx shows you exactly where the error is:
nginx: [emerg] unexpected "}" in /etc/nginx/sites-available/mysite:15
nginx: configuration file /etc/nginx/nginx.conf test failed
Fix the error, test again, then reload. Never skip the test step.
A second common issue: enabling a site config but forgetting to reload Nginx. The symlink exists in sites-enabled/ but Nginx is still serving the old config. Always reload after making changes.
sudo nginx -t # Test configuration syntax
sudo systemctl reload nginx # Apply config changes (no downtime)
sudo systemctl restart nginx # Full restart (brief downtime)
sudo systemctl status nginx # Check service status
sudo tail -f /var/log/nginx/error.log # Watch error log live
sudo tail -f /var/log/nginx/access.log # Watch access log live
# Enable a site
sudo ln -s /etc/nginx/sites-available/SITE /etc/nginx/sites-enabled/
# Disable a site
sudo rm /etc/nginx/sites-enabled/SITE
# Check which sites are active
ls -la /etc/nginx/sites-enabled/
| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
What is Nginx used for on a cloud server?
Nginx serves static files, reverse-proxies backend applications, and terminates SSL/TLS for HTTPS. Most setups use it as the public-facing entry point.
Where are Nginx config files located?
Main config: /etc/nginx/nginx.conf. Sites: create in /etc/nginx/sites-available/, symlink to /etc/nginx/sites-enabled/ to activate.
How do I reload Nginx after config changes?
Run sudo nginx -t to test, then sudo nginx -s reload for a graceful reload without downtime.
Can Nginx host multiple websites on one server?
Yes — virtual hosts (server blocks) route requests by server_name.
What is the difference between nginx -s reload and systemctl restart nginx?
nginx -s reload finishes in-flight requests gracefully. systemctl restart immediately terminates all connections. Use reload for production.
Set up your cloud server today:
👉 Tencent Cloud Lighthouse — Ubuntu VPS, ready in minutes
👉 View current pricing and promotions
👉 Explore all active deals and offers