# How to Change the Base URL in n8n

- Tool: n8n
- Difficulty: Beginner
- Time required: 10-15 minutes
- Compatibility: n8n 1.0+ (self-hosted only)
- Last updated: March 2026

## TL;DR

To change the base URL in n8n, set the WEBHOOK_URL environment variable to your public-facing domain (e.g., https://n8n.example.com/) and optionally set N8N_EDITOR_BASE_URL if the editor is served from a subpath. These settings ensure webhook URLs, OAuth callbacks, and the editor UI use the correct host and path instead of defaulting to localhost.

## Configuring WEBHOOK_URL and N8N_EDITOR_BASE_URL for Custom Domains in n8n

When n8n runs behind a reverse proxy or on a custom domain, it does not automatically detect the public URL. Webhook URLs default to http://localhost:5678, OAuth redirect URLs point to the wrong host, and the editor may fail to load assets. Setting WEBHOOK_URL and N8N_EDITOR_BASE_URL tells n8n exactly how the outside world reaches it, fixing all URL generation across the application.

## Before you start

- A self-hosted n8n instance
- A domain name or public IP address pointing to your n8n server
- Access to environment variables or docker-compose.yml
- A reverse proxy (Nginx, Caddy, or Traefik) if using HTTPS

## Step-by-step guide

### 1. Set the WEBHOOK_URL environment variable

The WEBHOOK_URL tells n8n what base URL to use when generating webhook URLs for trigger nodes. Without it, webhook URLs default to http://localhost:5678/webhook/..., which is unreachable from external services. Set WEBHOOK_URL to your public-facing domain including the protocol and a trailing slash. This value is used for all production webhook URLs shown in the Webhook node. Do not include a path unless n8n runs on a subpath.

```
# docker-compose.yml
environment:
  - WEBHOOK_URL=https://n8n.example.com/

# .env file
WEBHOOK_URL=https://n8n.example.com/

# Docker run command
docker run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -e WEBHOOK_URL=https://n8n.example.com/ \
  -v n8n_data:/home/node/.n8n \
  docker.n8n.io/n8nio/n8n
```

**Expected result:** After restarting n8n, Webhook nodes display URLs starting with https://n8n.example.com/webhook/ instead of localhost.

### 2. Set N8N_EDITOR_BASE_URL for subpath deployments

If you serve n8n from a subpath like https://example.com/n8n/ (instead of the root of a domain), you also need to set N8N_EDITOR_BASE_URL. This tells the n8n editor where to load its frontend assets from. Without this, the editor tries to load JavaScript and CSS files from the domain root, which fails. Set it to the full URL including the subpath and a trailing slash. If n8n is served from the root of a domain, you do not need this variable.

```
# Subpath deployment: n8n at https://example.com/n8n/
environment:
  - WEBHOOK_URL=https://example.com/n8n/
  - N8N_EDITOR_BASE_URL=https://example.com/n8n/
  - N8N_PATH=/n8n/

# Root domain deployment: n8n at https://n8n.example.com/
# Only WEBHOOK_URL is needed
environment:
  - WEBHOOK_URL=https://n8n.example.com/
```

**Expected result:** The n8n editor loads correctly at the subpath URL with all assets, and webhook URLs include the subpath.

### 3. Configure your reverse proxy to forward requests correctly

Your reverse proxy must forward all requests to n8n, including WebSocket connections for the editor's real-time updates. Configure it to pass the Host header, upgrade WebSocket connections, and proxy to n8n's internal port (5678 by default). If using HTTPS, the reverse proxy handles SSL termination while n8n runs on plain HTTP internally. Below is an example Nginx configuration for a root domain deployment.

```
# Nginx configuration for n8n
server {
    listen 443 ssl;
    server_name n8n.example.com;

    ssl_certificate /etc/ssl/certs/n8n.example.com.pem;
    ssl_certificate_key /etc/ssl/private/n8n.example.com.key;

    location / {
        proxy_pass http://localhost: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;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
    }
}
```

**Expected result:** n8n is accessible at your custom domain via HTTPS, the editor loads correctly, and WebSocket connections work for real-time updates.

### 4. Verify the configuration

After setting the environment variables and restarting n8n, verify that URLs are generated correctly. Open a workflow with a Webhook trigger node and check that the displayed webhook URLs use your custom domain. Create a test OAuth credential and verify the redirect URL uses the correct domain. Open the browser developer console and check that no assets fail to load from the wrong domain. Finally, send a test webhook request to the production URL to confirm end-to-end connectivity.

```
# Restart n8n to apply changes
docker compose down && docker compose up -d

# Test webhook URL is accessible
curl -s -o /dev/null -w "%{http_code}" \
  https://n8n.example.com/webhook/test-path

# Should return 404 (no active workflow) not connection refused
```

**Expected result:** Webhook URLs display your custom domain, OAuth redirect URLs are correct, the editor loads all assets, and test requests reach n8n.

## Complete code example

File: `docker-compose.yml`

```yaml
version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - '5678:5678'
    environment:
      # URL configuration
      - WEBHOOK_URL=https://n8n.example.com/
      # Only needed for subpath deployments:
      # - N8N_EDITOR_BASE_URL=https://example.com/n8n/
      # - N8N_PATH=/n8n/

      # Database
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}

      # Security
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}

      # Protocol (set to https if n8n handles SSL directly)
      - N8N_PROTOCOL=http
      - N8N_PORT=5678
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  n8n_data:
  postgres_data:
```

## Common mistakes

- **Forgetting to include the trailing slash in WEBHOOK_URL** — undefined Fix: Always include the trailing slash: WEBHOOK_URL=https://n8n.example.com/ — not WEBHOOK_URL=https://n8n.example.com
- **Setting WEBHOOK_URL but not configuring the reverse proxy, so requests never reach n8n** — undefined Fix: WEBHOOK_URL only affects URL generation in the UI. You still need a reverse proxy or DNS pointing the domain to your n8n server.
- **Using http:// in WEBHOOK_URL when the site is served over HTTPS** — undefined Fix: Match the protocol to what your users and external services see. If your reverse proxy serves HTTPS, use https:// in WEBHOOK_URL.
- **Not updating OAuth redirect URLs in external services after changing the domain** — undefined Fix: After changing WEBHOOK_URL, update the redirect/callback URLs in every OAuth app configuration (Google, Slack, etc.) to match the new domain.

## Best practices

- Always set WEBHOOK_URL when deploying n8n with a public domain or behind a reverse proxy
- Include the trailing slash in WEBHOOK_URL and N8N_EDITOR_BASE_URL to prevent path concatenation issues
- Use HTTPS in production — let your reverse proxy handle SSL termination
- Configure WebSocket upgrade headers in your reverse proxy for editor real-time updates
- Set N8N_EDITOR_BASE_URL and N8N_PATH together when deploying on a subpath
- Test both webhook URLs and editor functionality after changing URL settings
- Update OAuth redirect URLs in external services when you change the n8n domain

## Frequently asked questions

### What is the difference between WEBHOOK_URL and N8N_EDITOR_BASE_URL?

WEBHOOK_URL sets the base URL for webhook endpoints (both test and production). N8N_EDITOR_BASE_URL sets the base URL for the editor frontend assets. For root domain deployments, only WEBHOOK_URL is needed. For subpath deployments, set both.

### Do I need to set WEBHOOK_URL on n8n Cloud?

No, n8n Cloud automatically configures webhook URLs. WEBHOOK_URL is only needed for self-hosted installations.

### Why do my webhook URLs still show localhost after setting WEBHOOK_URL?

You need to restart n8n after changing environment variables. Run docker compose down && docker compose up -d or restart the n8n process. Also verify the variable name is spelled correctly — it is WEBHOOK_URL, not WEBHOOK_BASE_URL.

### Can I use a subpath like /n8n/ instead of a subdomain?

Yes, set WEBHOOK_URL=https://example.com/n8n/, N8N_EDITOR_BASE_URL=https://example.com/n8n/, and N8N_PATH=/n8n/. Configure your reverse proxy to forward /n8n/ to n8n's port.

### Does changing WEBHOOK_URL break existing active workflows?

No, existing workflows continue to work at the old URL until the external service updates its configuration. However, new webhook URLs displayed in the editor will use the new domain. Update your integrations to point to the new URL.

### What port should I use in WEBHOOK_URL?

If your reverse proxy handles port mapping (standard ports 80/443), do not include a port in WEBHOOK_URL. Only include a port if n8n is directly accessible on a non-standard port, e.g., https://n8n.example.com:8443/.

### Can RapidDev help configure n8n with a custom domain and reverse proxy?

Yes, RapidDev can set up n8n with custom domain configuration, SSL certificates, reverse proxy tuning, and verify that all URLs — webhooks, OAuth, and editor — work correctly in your production environment.

---

Source: https://www.rapidevelopers.com/n8n-tutorial/how-to-change-the-base-url-in-n8n
© RapidDev — https://www.rapidevelopers.com/n8n-tutorial/how-to-change-the-base-url-in-n8n
