Knowledgebase

How to Use a Custom Domain and HTTPS with n8n

To use a custom domain with HTTPS for n8n, create a DNS A record such as n8n.example.com that points to your server's IP. Then put a TLS-terminating reverse proxy in front of the n8n container. That can be Nginx with a free Let's Encrypt certificate from certbot, or the Traefik/Caddy proxy if your stack already includes one. Finally, set N8N_HOST, N8N_PROTOCOL=https, WEBHOOK_URL and N8N_EDITOR_BASE_URL to the new domain and recreate the container with docker compose up -d.

This guide applies to Cloudesta n8n hosting and to any Ubuntu 22.04/24.04 VPS running n8n in Docker. Follow it when you first move off the raw IP address, or whenever you change n8n's domain.

Prerequisites

  • Root or sudo SSH access to the server running n8n.
  • Access to the DNS zone of your domain, wherever the domain's DNS is hosted.
  • The server's public IPv4 address (for example 203.0.113.10).
  • Ports 80 and 443 reachable from the internet. Let's Encrypt needs port 80 to validate the domain.
  • A working email address for certificate expiry notices.

1. How do I point my domain to the n8n server?

In your DNS provider, add this record:

Type: A
Name: n8n          (becomes n8n.example.com)
Value: 203.0.113.10
TTL: 300

If an AAAA record exists for the same name, remove it unless it points to this server's IPv6 address. Let's Encrypt prefers IPv6, and a wrong AAAA record will make validation fail. Check that the record resolves before continuing:

dig +short n8n.example.com A
dig +short n8n.example.com AAAA

2. Does my n8n server already have Traefik or Caddy?

Check which containers are running and which ports they publish before you install anything:

sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
sudo ss -tlnp | grep -E ':(80|443)\s'
  • If a traefik or caddy container holds ports 80/443, use Option B (section 4).
  • If only n8n is running, or nothing listens on 80/443, use Option A (section 3).

Next, find the folder that holds the n8n docker-compose.yml and .env. Replace n8n below with the container name from the previous output:

sudo docker inspect -f '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}' n8n

3. Option A: How do I set up Nginx and Let's Encrypt in front of n8n?

Install Nginx and certbot

sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
sudo ufw allow 'Nginx Full'

The ufw rule matters only if UFW is active. Check with sudo ufw status.

Create the reverse proxy site

Create /etc/nginx/sites-available/n8n with sudo nano /etc/nginx/sites-available/n8n and paste the block below. The Upgrade and Connection headers are required. Without them the editor's WebSocket push connection fails and you see "Connection lost".

server {
    listen 80;
    listen [::]:80;
    server_name n8n.example.com;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        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_buffering off;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        client_max_body_size 50m;
    }
}

Enable the site and reload Nginx:

sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/n8n
sudo nginx -t
sudo systemctl reload nginx

Request the certificate

sudo certbot --nginx -d n8n.example.com -m you@example.com --agree-tos --redirect

Certbot adds the HTTPS server block and an HTTP-to-HTTPS redirect. It also installs a systemd timer that renews the certificate automatically.

Bind n8n to localhost only

In docker-compose.yml, change the n8n port mapping. This makes n8n reachable only through Nginx, not on http://203.0.113.10:5678:

    ports:
      - "127.0.0.1:5678:5678"

4. Option B: How do I change the domain when Traefik or Caddy is already installed?

Do not install Nginx in this case. Port 80/443 is already taken, and the existing proxy obtains certificates itself. Open the .env file in the compose folder:

cd /path/from/step/2
sudo nano .env

Variable names depend on how the stack was built. n8n's official Traefik example uses the variables below. Edit whatever your file actually contains rather than adding new names that nothing reads:

DOMAIN_NAME=example.com
SUBDOMAIN=n8n
SSL_EMAIL=you@example.com

For Caddy, the hostname is often written directly in a Caddyfile. If so, replace the old hostname with n8n.example.com there too. Also check the Traefik labels in docker-compose.yml for a hard-coded Host(`...`) rule.

5. Which n8n environment variables must match the domain?

Set these in the n8n service's environment: section, or in .env if the compose file references them there:

    environment:
      - N8N_HOST=n8n.example.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.example.com/
      - N8N_EDITOR_BASE_URL=https://n8n.example.com/
      - N8N_PROXY_HOPS=1
Important: N8N_PORT is the port n8n listens on inside the container, so keep it at 5678. Do not set it to 443, because the proxy handles 443. N8N_PROXY_HOPS=1 tells n8n to trust the proxy's X-Forwarded-* headers.

6. How do I restart n8n so the changes apply?

cd /path/to/compose/folder
sudo docker compose up -d
sudo docker compose logs -f --tail=50
Use docker compose up -d, not docker compose restart. A restart reuses the old container and its old environment, so new variables are ignored. up -d recreates the container. Your workflows are safe as long as the n8n data volume is defined in the compose file, as it is on standard installs.

Verify it works

curl -I http://n8n.example.com     # expect 301/308 redirect to https
curl -I https://n8n.example.com    # expect HTTP/2 200 or HTTP/1.1 200
sudo docker exec n8n printenv | grep -E 'N8N_HOST|WEBHOOK_URL|N8N_PROTOCOL'
sudo certbot renew --dry-run       # Option A only
  • Open https://n8n.example.com in a browser. The padlock should show a valid certificate, and the editor should not display "Connection lost".
  • Open any Webhook node. Both the Test URL and the Production URL should start with https://n8n.example.com/.
  • Run a test webhook from outside, for example curl https://n8n.example.com/webhook-test/your-path while listening for a test event.

Common problems

Webhook URLs still show the IP, port 5678 or the old domain

Either WEBHOOK_URL is missing, or the container was not recreated. Fix the variable, run docker compose up -d, then confirm with printenv. Some trigger nodes register their URL with an external service, such as Telegram, Stripe or GitHub triggers. Deactivate and reactivate each of those workflows so they re-register the new URL.

Certbot or Traefik fails the certificate challenge

Check that dig returns your server IP, and that there is no stray AAAA record. Port 80 must be open in UFW and in any external firewall. If the domain uses a CDN proxy such as Cloudflare's orange cloud, set it to DNS-only while issuing the certificate. Let's Encrypt rate-limits repeated failures, so test with --dry-run first.

Nginx returns 502 Bad Gateway

Nginx cannot reach n8n. Run sudo docker compose ps to confirm n8n is running, and curl -I http://127.0.0.1:5678 to test it from the host. Then read sudo tail /var/log/nginx/error.log. Usually the port mapping is missing or the container is crash-looping, which docker compose logs will show.

OAuth sign-in fails with "redirect_uri_mismatch"

OAuth apps in Google, Microsoft, Slack and similar services still list the old callback URL. Open the credential in n8n and copy the new OAuth Redirect URL, which should start with https://n8n.example.com/rest/oauth2-credential/callback. Add it to the provider's app settings, then reconnect the credential.

Nginx will not start: "Address already in use"

Another proxy, usually Traefik or Caddy, already holds port 80/443. Use Option B instead, or remove the other proxy before continuing with Option A.

Frequently asked questions

Can I run n8n on the main domain instead of a subdomain?

Yes. Point the root A record to the server and use example.com in all the steps above. A subdomain is usually easier because your website can stay on separate hosting.

Do I need to renew the Let's Encrypt certificate manually?

No. Certbot's systemd timer and Traefik/Caddy both renew automatically before the 90-day expiry. Run sudo certbot renew --dry-run once to confirm renewal works.

Will changing the domain delete my workflows or credentials?

No. Workflows and credentials live in the n8n data volume and database, which recreating the container does not touch. Only external webhook registrations and OAuth callback URLs need updating.

Need help? If you get stuck, open a support ticket at https://cloudesta.com/submitticket.php. Include your domain and the output of docker compose logs --tail=50. More guides are in the Cloudesta knowledgebase.

Was this answer helpful?

0 Users Found This Useful

Powered by WHMCompleteSolution