You’ve chosen to self-host n8n for privacy, cost savings, local access, persistent data, and reachable webhooks.

This guide explains running n8n in a cross-platform Docker container with persistent storage, basic authentication, and webhook access without certificate complexity.

If you’re new to n8n, read What Is N8n? first to understand what it does.

Prerequisites

Before starting, ensure you have:

  • Docker installed: Download Docker Desktop for Windows, Mac, or Linux.
  • Docker Compose: Included with Docker Desktop. On Linux, install it separately if needed.
  • Basic terminal knowledge: You’ll run commands in a terminal or command prompt.

Step 1: Create a Project Directory

Create a directory for your n8n setup to stay organized and easily find your configuration.

mkdir n8n-self-host
cd n8n-self-host

This directory stores your Docker Compose file and n8n data.

Step 2: Create Docker Compose Configuration

Create a docker-compose.yml in your project to define your n8n container with all settings.

services:
  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=changeme
      - TZ=America/Los_Angeles
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Configuration explanation:

  • Ports: Maps port 5678 from the container to your host machine.
  • Authentication: Sets basic auth with username admin and password changeme. Change these immediately.
  • Volumes: Creates a Docker volume that persists your workflows and settings.

Optional: Add TZ=America/Los_Angeles (replace with your timezone) to the environment section if you need scheduled workflows to run in your local timezone. Without it, n8n defaults to UTC.

Important: Replace changeme with a strong password before starting the container.

Step 3: Start N8n

Start n8n using Docker Compose. This command reads your docker-compose.yml file and starts the container.

On Windows (PowerShell or Command Prompt):

docker compose up -d

On Mac or Linux:

docker compose up -d

The -d flag runs the container in detached mode, so it continues running in the background.

Wait about 30 seconds for n8n to start, then open your browser and go to http://localhost:5678.

Step 4: Log In and Verify

You should see the n8n login page. Enter your credentials:

  • Username: admin
  • Password: changeme (or whatever you set in the Docker Compose file)

After logging in, you’ll see the n8n workflow editor. Your n8n instance is running locally.

Step 5: Configure Email (Optional)

To send emails from your n8n workflows (notifications, alerts, or workflow triggers), configure SMTP settings. If you’re running n8n on a Unix/Linux system, you can use your local mail setup configured with Gmail SMTP.

Option 1: Configure SMTP in n8n

Configure SMTP directly in n8n’s settings:

  1. In n8n, go to SettingsCommunity Nodes (or use the Email node directly in workflows)
  2. When using the Email Send node, configure these SMTP settings:
    • SMTP Host: smtp.gmail.com
    • SMTP Port: 465 (SSL) or 587 (TLS)
    • SMTP User: Your Gmail address
    • SMTP Password: Your Gmail App Password (not your regular password)
    • Enable SSL/TLS: Yes

Important: You’ll need a Gmail App Password. Enable 2FA on your Gmail account, then generate an App Password at Google Account Settings.

Option 2: Use Local Mail System

If you’ve configured your host system to send emails through Gmail SMTP (see How to Send System Emails from Unix/Linux to Gmail), you can use the system’s mail command from within n8n workflows using the Execute Command node. This approach uses your system’s mail configuration that you’ve already set up.

Note: For the Execute Command node to work, you may need to run the n8n container with access to the host’s mail system, or install mail utilities inside the container.

Step 6: Enable Webhook Access (Optional)

Use Cloudflare Tunnel to send webhooks to your local n8n without exposing your machine directly to the internet. It’s free and open-source.

Quick Tunnel (Temporary URL)

For testing, use a quick tunnel that generates a temporary URL:

cloudflared tunnel --url http://localhost:5678

This provides a temporary URL like https://random-words.trycloudflare.com that changes each time you restart the tunnel.

For production use, create a named tunnel with a persistent URL:

  • Authenticate: Run cloudflared tunnel login and follow the prompts to authenticate with Cloudflare (free account required).

  • Create a named tunnel:

cloudflared tunnel create n8n
  • Create a config file (config.yml):
tunnel: 
credentials-file: ~/.cloudflared/.json
ingress:
  - hostname: n8n.yourdomain.com
    service: http://localhost:5678
  - service: http_status:404

Replace <TUNNEL_ID> with the ID shown when you created the tunnel, and n8n.yourdomain.com with your subdomain. The credentials file path uses ~ which works on Mac and Linux. On Windows, use the full path like C:\Users\YOUR_USERNAME\.cloudflared\<TUNNEL_ID>.json.

  • Configure DNS (if using your own domain):

You can try the automated DNS route command:

cloudflared tunnel route dns n8n n8n.yourdomain.com

If this fails with an authentication error, manually create the DNS record in Cloudflare:

  1. Go to Cloudflare Dashboard
  2. Select your domain
  3. Go to DNSRecords
  4. Click Add record:
    • Type: CNAME
    • Name: n8n (or your desired subdomain)
    • Target: <TUNNEL_ID>.cfargotunnel.com (replace <TUNNEL_ID> with your actual tunnel ID)
    • Proxy status: Proxied (orange cloud icon)
    • Click Save
  • Run the tunnel:

Start the tunnel with:

cloudflared tunnel --config config.yml run

This runs the tunnel in the foreground. To run it in the background, add & at the end (Mac/Linux) or use a process manager. The tunnel must be running for your n8n instance to be accessible from the internet.

Important: The tunnel process must stay running. If you close your terminal, the tunnel stops. To keep it running permanently:

  • Mac/Linux: Use screen or tmux to run it in a detached session
  • Windows: Run it in a separate PowerShell window or use a process manager
  • All platforms: Set it up as a system service (systemd on Linux, launchd on macOS, Task Scheduler on Windows)

This creates a persistent URL that doesn’t change when you restart the tunnel.

Step 7: Stop and Start N8n

When you’re done working with n8n, stop the container:

docker compose stop

To start it again:

docker compose up -d

Your workflows and data persist because they’re stored in the Docker volume.

Step 8: View Logs (Troubleshooting)

If something isn’t working, check the container logs:

docker compose logs -f n8n

The -f flag follows the logs in real time. Press Ctrl+C to stop following.

Common Issues and Solutions

Port 5678 is already in use:

Another application is using port 5678. Change the port mapping in docker-compose.yml:

ports:
  - "8080:5678"  # Use port 8080 instead

Then access n8n at http://localhost:8080.

Can’t access n8n after starting:

Wait a few more seconds for n8n to start fully. Check the logs with docker compose logs n8n to see if there are errors.

Forgot your password:

Stop the container, remove the volume, and start over:

docker compose down -v
docker compose up -d

Warning: This deletes all workflows and data.

Webhooks not working:

Ensure Cloudflare Tunnel is running and pointing to the correct port. Check that n8n’s webhook URL matches your tunnel URL.

Cloudflare Tunnel error (Error 1033):

This means the tunnel isn’t running or isn’t connected. Verify:

  1. The tunnel process is running: cloudflared tunnel info n8n should show active connections
  2. n8n is running: docker compose ps should show the container as “Up”
  3. DNS is configured: Check that the CNAME record exists in Cloudflare DNS
  4. The tunnel can reach n8n: Test curl http://localhost:5678 locally

If the tunnel shows “no active connections”, restart it: cloudflared tunnel --config config.yml run

Managing Your N8n Instance

Backup your data:

Your workflows are stored in the Docker volume. First, find your volume name:

docker volume ls | grep n8n

Then back up the volume (replace VOLUME_NAME with the actual volume name):

docker run --rm -v VOLUME_NAME:/data -v $(pwd):/backup alpine tar czf /backup/n8n-backup.tar.gz -C /data .

Restore from backup:

Replace VOLUME_NAME with the actual volume name to restore your backup:

docker run --rm -v VOLUME_NAME:/data -v $(pwd):/backup alpine tar xzf /backup/n8n-backup.tar.gz -C /data

Update n8n:

Pull the latest image and start the container again:

docker compose pull
docker compose up -d

Next Steps

Your n8n instance is running locally with persistent storage. You can:

  • Create workflows using the visual editor.
  • Connect to external services using n8n’s 400+ integrations.
  • Use webhooks with Cloudflare Tunnel for external access.
  • Customize settings through the n8n interface.

For workflow ideas and examples, see What Is N8n?.

References