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?]({{< ref "/blog/what-x/what-is-n8n/index.md" >}}) first to understand what it does.

## Prerequisites

Before starting, ensure you have:

* **Docker installed**: Download Docker Desktop for [Windows](https://www.docker.com/products/docker-desktop/), [Mac](https://www.docker.com/products/docker-desktop/), or [Linux](https://docs.docker.com/engine/install/).
* **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.

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

```yaml
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):**

```powershell
docker compose up -d
```

**On Mac or Linux:**

```bash
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 **Settings** → **Community 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](https://myaccount.google.com/apppasswords).

### 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](https://jeffbailey.us/blog/2022/04/16/how-do-i-send-emails-with-unix-and-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:

* **Install cloudflared**: Download from [Cloudflare Zero Trust](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/).
* **Create a tunnel**: Run this command:

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

### Persistent URL (Recommended)

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**:

```bash
cloudflared tunnel create n8n
```

* **Create a config file** (`config.yml`):

```yaml
tunnel: <TUNNEL_ID>
credentials-file: ~/.cloudflared/<TUNNEL_ID>.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:

```bash
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](https://dash.cloudflare.com)
2. Select your domain
3. Go to **DNS** → **Records**
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:

```bash
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:

```bash
docker compose stop
```

To start it again:

```bash
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:

```bash
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`:

```yaml
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:

```bash
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:

```bash
docker volume ls | grep n8n
```

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

```bash
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:

```bash
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:

```bash
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?]({{< ref "/blog/what-x/what-is-n8n/index.md" >}}).

## References

* [n8n Docker Documentation](https://docs.n8n.io/hosting/installation/docker/) - Official Docker installation guide
* [n8n Docker Compose Examples](https://github.com/n8n-io/n8n-hosting/tree/main/docker-compose) - Official Docker Compose configurations
* [Docker Desktop Documentation](https://docs.docker.com/desktop/) - Docker Desktop installation and usage
* [Cloudflare Tunnel Documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/) - Guide to Cloudflare Tunnel setup
* [n8n API Reference](https://docs.n8n.io/api/api-reference) - Official API documentation
* [How to Send System Emails from Unix/Linux to Gmail](https://jeffbailey.us/blog/2022/04/16/how-do-i-send-emails-with-unix-and-gmail/) - Guide to configuring Gmail SMTP for system emails