Automated NGINX reverse proxy creator with Let's Encrypt SSL — Set up production-ready reverse proxies in seconds, not hours.
nginx-auto-proxy is a single Bash script that automates the entire process of setting up an NGINX reverse proxy with free SSL certificates from Let's Encrypt. Perfect for deploying web applications, APIs, and microservices behind a secure HTTPS endpoint.
Whether you're deploying a Node.js app, Python API, or any service running on a local port, this script handles all the heavy lifting:
┌─────────────────────────────────────────────────────────────────┐
│ INTERNET │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ NGINX │ │
│ │ (Port 80/443) │ │
│ │ + SSL │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Your App │ │
│ │ (Port 8000) │ │
│ └───────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- 🔧 Automatic NGINX Installation — Installs NGINX if not present
- 🔐 Free SSL Certificates — Automatic Let's Encrypt SSL via Certbot
- 🔄 Reverse Proxy Setup — Routes traffic from domain to local port
- ✅ Safe Configuration — Tests NGINX config before applying
- 🧹 Undo Mode — Completely removes config and SSL certificates
- 📦 Dependency Management — Auto-installs missing dependencies
- 🛡️ Production Ready — Idempotent and safe to run multiple times
- ❌ Clear Error Messages — Detailed feedback on failures
- 🧼 Clean Failure Handling — Cleans up on Certbot failures
- Operating System: Ubuntu/Debian-based Linux
- Privileges: Root access (sudo)
- Network:
- Ports 80 and 443 available
- Domain DNS already pointing to your server's IP
- Internet: Required for package installation and SSL verification
curl -O https://raw.githubusercontent.com/Gurwinder7735/nginx-auto-proxy/main/nginx-auto-proxy.sh
chmod +x nginx-auto-proxy.shgit clone https://github.com/Gurwinder7735/nginx-auto-proxy.git
cd nginx-auto-proxy
chmod +x nginx-auto-proxy.shsudo bash nginx-auto-proxy.sh install <domain> <port>Example:
sudo bash nginx-auto-proxy.sh install example.com 8000What this command does:
| Step | Action | Description |
|---|---|---|
| 1 | Dependency Check | Checks if NGINX and Certbot are installed |
| 2 | Auto-Install NGINX | Installs via apt-get install nginx if missing |
| 3 | Auto-Install Certbot | Installs certbot and python3-certbot-nginx if missing |
| 4 | Create Config | Generates /etc/nginx/sites-available/<domain> |
| 5 | Enable Site | Creates symlink in /etc/nginx/sites-enabled/ |
| 6 | Test Config | Runs nginx -t to validate syntax |
| 7 | Reload NGINX | Applies changes via systemctl restart nginx |
| 8 | Obtain SSL | Runs Certbot to get Let's Encrypt certificate |
| 9 | Done! | Your site is live at https://<domain>/ |
sudo bash nginx-auto-proxy.sh undo <domain>Example:
sudo bash nginx-auto-proxy.sh undo example.comWhat this command does:
| Step | Action | Description |
|---|---|---|
| 1 | Remove Symlink | Deletes /etc/nginx/sites-enabled/<domain> |
| 2 | Remove Config | Deletes /etc/nginx/sites-available/<domain> |
| 3 | Restart NGINX | Applies changes via systemctl restart nginx |
| 4 | Delete SSL Cert | Runs certbot delete --cert-name <domain> |
The script automatically installs these packages if they're missing:
| Package | Purpose |
|---|---|
nginx |
Web server and reverse proxy |
certbot |
Let's Encrypt client for SSL certificates |
python3-certbot-nginx |
Certbot plugin for NGINX integration |
# Check NGINX service status
sudo systemctl status nginx
# Test NGINX configuration
sudo nginx -t
# Check if NGINX is listening on ports
sudo ss -tlnp | grep nginxExpected output for healthy NGINX:
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: active (running)
# NGINX access log
sudo tail -f /var/log/nginx/access.log
# NGINX error log
sudo tail -f /var/log/nginx/error.log
# Domain-specific logs (if configured)
sudo tail -f /var/log/nginx/<domain>.access.log
sudo tail -f /var/log/nginx/<domain>.error.log
# Certbot logs
sudo tail -f /var/log/letsencrypt/letsencrypt.log
# Check SSL certificate status
sudo certbot certificates# Your Node.js app running on port 3000
sudo bash nginx-auto-proxy.sh install api.myapp.com 3000# Your FastAPI/Uvicorn app running on port 8000
sudo bash nginx-auto-proxy.sh install backend.myapp.com 8000# Main website on port 3000
sudo bash nginx-auto-proxy.sh install myapp.com 3000
# API on port 8000
sudo bash nginx-auto-proxy.sh install api.myapp.com 8000
# Admin panel on port 9000
sudo bash nginx-auto-proxy.sh install admin.myapp.com 9000sudo bash nginx-auto-proxy.sh undo api.myapp.comWhen you run the install command, the script creates:
/etc/nginx/sites-available/example.com # NGINX configuration
/etc/nginx/sites-enabled/example.com # Symlink to enable site
/etc/letsencrypt/live/example.com/ # SSL certificates
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
}After Certbot runs, it automatically modifies this to include SSL configuration.
Symptoms:
Challenge failed for domain example.com
The Certificate Authority failed to verify the challenge
unauthorized :: The client lacks sufficient authorization
Causes & Solutions:
| Cause | Solution |
|---|---|
| DNS not pointing to server | Update your A record to point to server IP |
| DNS not propagated yet | Wait 5-30 minutes after DNS changes |
| Wrong IP in DNS | Verify with dig +short example.com |
| Using a hostname, not a domain | Use a real domain with valid DNS |
Verify DNS is correct:
# Get your server's public IP
curl -s ifconfig.me
# Check where domain points
dig +short example.com
# These two IPs must match!Symptoms:
- Certbot fails even though DNS looks correct
- SSL certificate conflicts
- "Too many redirects" error
Cause: Cloudflare's orange cloud (proxy) intercepts traffic before it reaches your server.
Solution:
-
Temporarily disable Cloudflare proxy:
- Go to Cloudflare Dashboard → DNS
- Click the orange cloud icon → turns grey (DNS only)
- Wait 2-5 minutes
- Run the script
- Re-enable proxy after SSL is installed (optional)
-
Or use Cloudflare's SSL:
- Set SSL/TLS mode to "Full (strict)" in Cloudflare
- Let Cloudflare handle SSL instead of Let's Encrypt
┌─────────────────────────────────────────────────────────┐
│ Cloudflare DNS Settings │
├─────────────────────────────────────────────────────────┤
│ Type Name Content Proxy Status │
│ A example.com 203.0.113.50 🔘 DNS only │ ← Grey cloud
│ (for Certbot) │
└─────────────────────────────────────────────────────────┘
Symptoms:
Connection refused
Could not connect to port 80
HTTP challenge failed
Causes & Solutions:
| Cause | Solution |
|---|---|
| UFW firewall blocking | sudo ufw allow 80 && sudo ufw allow 443 |
| Cloud provider firewall | Open ports in AWS/GCP/Azure security groups |
| Another service using port 80 | Stop Apache: sudo systemctl stop apache2 |
| ISP blocking port 80 | Contact ISP or use DNS challenge instead |
Check if ports are open:
# Check UFW status
sudo ufw status
# Open required ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
# Check what's using port 80
sudo lsof -i :80
sudo ss -tlnp | grep ':80'Test from external network:
# From another machine or use online port checker
nc -zv your-server-ip 80
nc -zv your-server-ip 443Symptoms:
nginx: [emerg] unknown directive or syntax error
nginx -t failed
Causes & Solutions:
| Cause | Solution |
|---|---|
| Syntax error in config | Check generated config file |
| Duplicate server_name | Remove conflicting configs |
| Missing semicolon | Edit config and add missing ; |
| Invalid characters in domain | Use valid domain format |
Debug steps:
# Test NGINX configuration
sudo nginx -t
# View the generated config
sudo cat /etc/nginx/sites-available/example.com
# Check for conflicting configs
ls -la /etc/nginx/sites-enabled/
# Remove conflicting config if needed
sudo rm /etc/nginx/sites-enabled/conflicting-siteSymptoms:
Certificate not yet due for renewal
Solution:
# Force renewal
sudo certbot renew --force-renewal -d example.com
# Or delete and re-obtain
sudo certbot delete --cert-name example.com
sudo bash nginx-auto-proxy.sh install example.com 8000Cause: Let's Encrypt rate limit (50 certificates per domain per week)
Solution:
- Wait for rate limit to reset (1 week)
- Use staging environment for testing:
certbot --staging --nginx -d example.com
Before running the script, verify:
# 1. DNS is pointing to your server
dig +short example.com
curl -s ifconfig.me
# ↑ These must match!
# 2. Ports are open
sudo ufw allow 80
sudo ufw allow 443
# 3. No other web server is running
sudo systemctl stop apache2 # if installed
# 4. You have root access
sudo whoami # should output: root# Check DNS from multiple DNS servers
nslookup example.com 8.8.8.8 # Google DNS
nslookup example.com 1.1.1.1 # Cloudflare DNS
nslookup example.com 208.67.222.222 # OpenDNS
# Online tools:
# - https://dnschecker.org
# - https://www.whatsmydns.netnginx-auto-proxy/
├── nginx-auto-proxy.sh # Main script
├── README.md # Documentation
├── LICENSE # MIT License
└── .gitignore # Git ignore file
┌──────────────────────────────────────────────────────────────┐
│ nginx-auto-proxy │
├──────────────────────────────────────────────────────────────┤
│ 1. Check & Install Dependencies │
│ └── NGINX, Certbot, python3-certbot-nginx │
│ │
│ 2. Create NGINX Configuration │
│ └── /etc/nginx/sites-available/{domain} │
│ │
│ 3. Enable Site │
│ └── Symlink to sites-enabled │
│ │
│ 4. Test Configuration │
│ └── nginx -t (validates syntax) │
│ │
│ 5. Reload NGINX │
│ └── systemctl restart nginx │
│ │
│ 6. Obtain SSL Certificate │
│ └── certbot --nginx -d {domain} │
│ │
│ 7. Done! 🎉 │
│ └── https://{domain}/ is live │
└──────────────────────────────────────────────────────────────┘
Future features planned:
- Multi-domain support — Single command for multiple domains
- Custom NGINX templates — User-defined configuration templates
- Wildcard SSL — Support for
*.example.comcertificates - Load balancing — Multiple backend servers
- Rate limiting — Built-in rate limiting configuration
- WebSocket support — Automatic WebSocket proxy headers
- Dry-run mode — Preview changes without applying
- Backup & restore — Save and restore configurations
- Interactive mode — Guided setup with prompts
- Support for CentOS/RHEL — yum/dnf package manager support
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch
git checkout -b feature/amazing-feature
- Make your changes
- Test thoroughly on a fresh server
- Commit your changes
git commit -m "Add amazing feature" - Push to your branch
git push origin feature/amazing-feature
- Open a Pull Request
- Keep the script simple and readable
- Add comments for complex logic
- Test on Ubuntu 20.04+ and Debian 10+
- Update README for new features
- Follow existing code style
Found a bug? Please open an issue with:
- Your OS version
- Complete error message
- Steps to reproduce
This project is licensed under the MIT License - see the LICENSE file for details.
- NGINX — High-performance web server and reverse proxy
- Let's Encrypt — Free, automated SSL certificates
- Certbot — EFF's tool for obtaining Let's Encrypt certificates
If this project helped you, please consider giving it a ⭐ on GitHub!
- Repository: github.com/Gurwinder7735/nginx-auto-proxy
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ for the open-source community