Setup Nginx server with custom domain
Here's a complete, step-by-step tutorial to set up an Nginx server with a custom domain and free HTTPS using Let's Encrypt (Certbot). This guide works best on Ubuntu 22.04 / 24.04 / 26.04 (most common for servers in 2026). It assumes you're using a VPS or dedicated server with root access.
Prerequisites
- A Ubuntu server (fresh or existing)
- A registered domain name (e.g.,
example.com) - Point your domain to the server's public IP:
- Create an A record for
@(example.com) → your server IP - Create an A record for
www(www.example.com) → same IP - Wait 5–30 minutes for DNS propagation (check with
ping example.com)
- Create an A record for
- Firewall open for ports 80 and 443 (we'll handle this)
Step 1: Update System and Install Nginx
sudo apt update && sudo apt upgrade -y
sudo apt install nginx -y
Start and enable Nginx:
sudo systemctl start nginx
sudo systemctl enable nginx
Check status:
sudo systemctl status nginx
Test in browser: Visit your server's IP address. You should see the default "Welcome to nginx!" page.
Step 2: Configure Firewall (UFW)
If using UFW (recommended):
sudo apt install ufw -y
sudo ufw allow 'Nginx Full' # Allows both HTTP (80) and HTTPS (443)
sudo ufw enable
sudo ufw status
Step 3: Create a Dedicated Server Block for Your Domain
It's best to use a separate config file instead of editing the default.
sudo mkdir -p /var/www/example.com/html # Replace example.com with your domain
sudo chown -R $USER:$USER /var/www/example.com/html
sudo chmod -R 755 /var/www/example.com
Create a sample index page:
echo "<h1>Welcome to example.com!</h1>" | sudo tee /var/www/example.com/html/index.html
Now create the server block:
sudo nano /etc/nginx/sites-available/example.com
Paste the following basic configuration (HTTP only for now):
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm index.nginx-debian.html;
location / {
try_files $uri $uri/ =404;
}
}
Save and exit (Ctrl+O → Enter → Ctrl+X).
Enable the site and disable default:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
Test configuration and reload:
sudo nginx -t
sudo systemctl reload nginx
Now visit http://example.com in your browser — you should see your welcome page.
Step 4: Install Certbot and Get Free HTTPS Certificate
Recommended method (Snap — most reliable in 2026):
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Install the Nginx plugin (if using apt method, but Snap is preferred):
# Optional: sudo apt install python3-certbot-nginx -y
Obtain and install the certificate (Certbot will automatically modify your config):
sudo certbot --nginx -d example.com -d www.example.com
During the process:
- Enter your email address (for renewal notices)
- Agree to terms
- Choose whether to redirect HTTP to HTTPS (recommended: select 2 — it adds automatic redirect)
Certbot will:
- Verify domain ownership via HTTP-01 challenge
- Install the certificate
- Update your Nginx config to use HTTPS
Step 5: Verify HTTPS Configuration
After Certbot finishes, check your config:
sudo nano /etc/nginx/sites-available/example.com
It should now look similar to this (Certbot adds SSL parts):
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Certbot added redirect
return 301 https://$host$request_uri;
}
server {
listen 443 ssl; # HTTPS
listen [::]:443 ssl;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Additional strong SSL settings (recommended)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers off;
location / {
try_files $uri $uri/ =404;
}
}
Test and reload:
sudo nginx -t
sudo systemctl reload nginx
Visit https://example.com — you should see a secure padlock in the browser.
Step 6: Automatic Renewal
Certbot sets up auto-renewal by default (via systemd timer or cron).
Test renewal (dry run):
sudo certbot renew --dry-run
Bonus: Recommended Security Hardening
Add these inside your HTTPS server { } block for better security:
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Optional: Stronger SSL
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
Common Troubleshooting
- 502 Bad Gateway (if using as reverse proxy): Check your
proxy_passsettings. - Certificate not found: Run
sudo certbot certificatesto list them. - DNS not propagated: Use
dig example.comor https://dnschecker.org - Port issues: Ensure ports 80/443 are open in your VPS firewall (AWS, DigitalOcean, etc.).
- Permission denied: Make sure web files are readable by www-data.
Next Steps (Common Use Cases)
- Reverse Proxy → Add
proxy_pass http://127.0.0.1:3000;insidelocation / { } - Multiple domains → Create separate server blocks
- Wildcard certificate → Use DNS challenge:
sudo certbot certonly --manual --preferred-challenges dns -d *.example.com