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

<domain>

A

<server_ip>

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

<container_name>

Internal HTTP Port

<container_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

curl -I http://<domain>

301 → https

HTTPS access

curl -I https://<domain>

200 OK

ERPNext links correct

Open site in browser

All URLs use HTTPS

SSL certificate status

sudo certbot certificates

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>.

On this page