E2E Domain Setup at node (not in Container)
This is a reusable guide to add any subdomain pointing to a Frappe/ERPNext container on your server with HTTP ➞ HTTPS and Certbot SSL.
1. DNS Setup
For each subdomain:
Hostname | Type | Value |
|---|---|---|
| A |
|
Example:
karam-dev.extensionerp.com ➞ 216.48.180.225
poc.extensionerp.com ➞ 216.48.180.225
prod.extensionerp.com ➞ 216.48.180.225
Test DNS propagation:
ping <domain>
2. Container Information
Item | Description |
|---|---|
Container Name |
|
Internal HTTP Port |
|
Container HTTPS | ❌ Do NOT enable inside container |
Container Redirects | ❌ Do NOT enable inside container |
Only host Nginx handles HTTPS and redirects.
3. Host Nginx Configuration
3.1 Create Site Config
sudo nano /etc/nginx/sites-available/<domain>
Paste this, replacing <domain> and <container_port>:
# =====================================
# <domain>
# Host Nginx ➞ Frappe container
# =====================================
# -------------------------
# HTTP ➞ HTTPS Redirect
# -------------------------
server {
listen 80;
listen [::]:80;
server_name <domain>;
return 301 https://$host$request_uri;
}
# -------------------------
# HTTPS Server
# -------------------------
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <domain>;
# SSL (managed by certbot)
ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Increase limits for Frappe
client_max_body_size 100M;
proxy_read_timeout 1200s;
proxy_send_timeout 1200s;
location / {
proxy_pass http://127.0.0.1:<container_port>;
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 https;
proxy_redirect off;
}
}
3.2 Enable Site
sudo ln -s /etc/nginx/sites-available/<domain> /etc/nginx/sites-enabled/
3.3 Test & Reload Nginx
sudo nginx -t
sudo systemctl reload nginx
4. SSL Certificate with Certbot
Install Certbot (if not installed):
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
Issue SSL:
sudo certbot --nginx -d <domain>
Choose Redirect HTTP ➞ HTTPS ✅
5. Test Domain
5.1 HTTP ➞ HTTPS Redirect
curl -I http://<domain>
Expected:
HTTP/1.1 301 Moved Permanently
Location: https://<domain>/
5.2 HTTPS Access
curl -I https://<domain>
Expected:
HTTP/2 200
6. ERPNext Site Configuration (Inside Container)
docker exec -it <container_name> bash
bench --site <domain> set-config host_name <domain>
bench --site <domain> set-config force_https 1
bench clear-cache
bench restart
Ensures ERPNext generates correct links
Force HTTPS inside app (optional, nginx handles main redirect)
7. Notes / Best Practices
Container nginx: HTTP only, no SSL, no redirects
Host nginx: Handles all SSL and HTTP ➞ HTTPS
Each subdomain → unique container port
Avoid duplicate redirects in container + host → prevents ERR_TOO_MANY_REDIRECTS
8. Testing Checklist
Test | Command | Expected Result |
|---|---|---|
HTTP redirect |
| 301 → https |
HTTPS access |
| 200 OK |
ERPNext links correct | Open site in browser | All URLs use HTTPS |
SSL certificate status |
| Active, valid |
✅ Done
<domain> is now live, fully SSL-enabled, and properly redirected without loops.
Repeat this guide for each new subdomain by replacing
<domain>and<container_port>.