跳到主要内容

在 DigitalOcean 上托管 n8n

本指南介绍如何在 DigitalOcean Droplet 上自托管 n8n,使用真实域名和自动 HTTPS,采用以下组件:

  • Caddy,反向代理,让 Droplet 可以从互联网访问,也会为 n8n 实例自动创建和管理 SSL/TLS 证书。
  • Docker Compose,创建并定义应用组件及其协作方式。

n8n 启动运行后,最后的可选章节介绍如何添加 n8n Assistant。

信息

自托管的知识要求

自行托管 n8n 需要具备以下技术知识:

  • 设置和配置服务器与容器
  • 管理应用资源和扩展容量
  • 保护服务器和应用的安全
  • 配置 n8n

n8n 建议有经验的用户选择自托管。操作失误可能导致数据丢失、安全问题和停机。如果不熟悉服务器管理,n8n 建议使用 n8n Cloud。

信息

Stable 与 Beta 版本

n8n 通常每周发布一个新的次版本。stable 版本用于生产环境;beta 是最近发布的版本;beta 版本可能不稳定。如需报告问题,请使用论坛。

当前 stable:2.45.5 当前 beta:2.46.1

创建 Droplet ​

  1. 登录 DigitalOcean。
  2. 选择托管 Droplet 的项目,或创建新项目。
  3. 在项目的 Manage(管理)菜单中选择 Droplets。
  4. 使用 Marketplace(市场)选项卡提供的 Docker 镜像,创建新 Droplet。
信息

Droplet 资源

创建 Droplet 时,DigitalOcean 会要求选择套餐。对于大多数使用量,基础共享 CPU 套餐就足够。

信息

SSH 密钥或密码

DigitalOcean 支持选择 SSH 密钥或密码身份验证,SSH 密钥被认为更安全。

登录 Droplet 并创建新用户 ​

后续步骤需要通过终端使用 SSH 登录 Droplet。更多信息请参阅如何通过 SSH 连接 Droplet。

应创建新用户,避免使用 root 用户操作:

  1. 以 root 身份登录。

  2. 创建新用户:

    adduser <username>
  3. 按照 CLI 提示完成用户创建。

  4. 授予新用户管理权限:

    usermod -aG sudo <username>

    现在可以在命令前添加 sudo,以超级用户权限运行。

  5. 按照添加公钥身份验证的步骤,为新用户设置 SSH。

  6. 退出 Droplet。

  7. 通过 SSH 以新用户身份登录。

克隆配置仓库 ​

Docker Compose、n8n 和 Caddy 需要一系列文件夹和配置文件。可以从此仓库克隆到 Droplet 当前登录用户的主目录。以下步骤说明要更改哪些文件,以及具体修改内容。

使用以下命令克隆仓库:

git clone https://github.com/n8n-io/n8n-docker-caddy.git

然后切换到所克隆仓库的根目录:

cd n8n-docker-caddy

默认文件夹和文件 ​

主机操作系统,即 DigitalOcean Droplet,将创建的两个文件夹复制到 Docker 容器中,供 Docker 使用。这两个文件夹是:

  • caddy_config:保存 Caddy 配置文件。
  • local_files:保存通过 n8n 上传或添加的文件。

创建 Docker 卷 ​

要在重启间保留 Caddy 缓存并加快启动,请创建一个可在重启后复用的 Docker 卷:

sudo docker volume create caddy_data

为 n8n 数据创建 Docker 卷:

sudo docker volume create n8n_data

设置 DNS ​

n8n 通常运行在子域名上。请在 DNS 提供商处为子域名创建记录,指向 Droplet 的 IP 地址。具体步骤取决于 DNS 提供商,通常需要为 n8n 子域名创建 A 记录。DigitalOcean 提供了 DNS 术语、组件和概念介绍。

开放端口 ​

n8n 作为 Web 应用运行,因此 Droplet 需要允许端口 80 的非加密入站流量,以及端口 443 的加密入站流量。

运行以下两条命令,在 Droplet 防火墙中开放端口:

sudo ufw allow 80
sudo ufw allow 443

配置 n8n ​

需要为 n8n 设置一些环境变量,并传递给 Docker 容器中的应用。示例 .env 文件包含占位符,请替换为你自己的值。

使用以下命令打开文件:

nano .env

文件内包含行内注释,说明需要更改哪些内容。

n8n 环境变量详情请参阅环境变量。

Docker Compose 文件 ​

Docker Compose 文件(docker-compose.yml)定义应用所需的服务,此处为 Caddy 和 n8n。没有独立数据库服务,n8n 默认使用内置 SQLite 数据库。

  • Caddy 服务定义使用的端口,以及要复制到容器中的本地卷。
  • n8n 服务定义使用的端口、运行所需的环境变量,其中部分在 .env 文件中定义,以及要复制到容器中的卷。

Docker Compose 文件使用 .env 文件中设置的环境变量,因此通常无需修改。要查看其内容,请运行:

nano docker-compose.yml

配置 Caddy ​

Caddy 需要知道应提供服务的域名,以及向外暴露的端口。请编辑 Caddyfile 文件,它位于 caddy_config 文件夹中。

nano caddy_config/Caddyfile

将占位域名改为你的域名。如果按照上述步骤将子域名命名为 n8n,完整域名会类似 n8n.example.com。n8n 位于 reverse_proxy 设置中,指示 Caddy 使用 docker-compose.yml 文件中定义的服务:

n8n.<domain>.<suffix> {
reverse_proxy n8n:5678 {
flush_interval -1
}
}

如果使用 automate.example.com,Caddyfile 可能如下所示:

automate.example.com {
reverse_proxy n8n:5678 {
flush_interval -1
}
}

启动 Docker Compose ​

使用以下命令启动 n8n 和 Caddy:

sudo docker compose up -d

这可能需要几分钟。

测试配置 ​

在浏览器中打开前面定义的子域名和域名组成的 URL。首次访问时,n8n 会提示创建所有者账号。

停止 n8n 和 Caddy ​

使用以下命令停止 n8n 和 Caddy:

sudo docker compose stop

可选:添加 n8n Assistant ​

n8n Assistant 需要沙箱来运行代码。可以向此部署添加 Docker Compose 指南使用的相同沙箱组件栈。开始前请了解:

  • 此沙箱适合本地开发和测试。以下组件栈使用 n8n 自带的沙箱(n8n-sandbox)。具有公开域名的 DigitalOcean Droplet 通常是真实部署,如果要用于生产,请考虑改用 Daytona。
  • **按需调整规格。**沙箱运行器使用 Docker-in-Docker,需要比单独运行 n8n 更多的资源余量。请至少提供 4 GB RAM 和 2 vCPU。
  • **无需更改网络。**Caddy 仅代理 n8n 本身,沙箱服务保留在 Compose 内部网络,无需更改 DNS、防火墙或 Caddyfile。
  1. 将沙箱密钥添加到 .env,与现有变量放在一起:

    # Sandbox service secrets — pick your own values
    SANDBOX_API_KEYS=change-me-api-key
    SANDBOX_API_RUNNER_REGISTRATION_TOKEN=change-me-registration-token
    SANDBOX_API_RUNNER_API_KEY=change-me-runner-key

    # Web search: secret for the bundled SearXNG instance — pick your own value
    SEARXNG_SECRET=change-me-searxng-secret
  2. 在其他配置文件旁创建 searxng-settings.yml 文件。默认 SearXNG 镜像仅提供 HTML,此配置启用 n8n 网页搜索需要的 JSON API:

    use_default_settings: true
    search:
    formats:
    - html
    - json
  3. 打开 docker-compose.yml,在现有 caddy 和 n8n 服务旁添加沙箱和搜索服务:

    volumes:
    sandbox-tls:

    services:
    sandbox-certs:
    image: ghcr.io/n8n-io/n8n-sandbox-service-api:latest
    user: '0:0'
    entrypoint: ['sh', '-c']
    command:
    - >
    bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api
    --control-san-prefix sandbox-runner &&
    chown -R sandbox-api:sandbox-api /tls/api
    environment:
    NUM_RUNNERS: '1'
    volumes:
    - sandbox-tls:/tls

    sandbox-api:
    image: ghcr.io/n8n-io/n8n-sandbox-service-api:latest
    depends_on:
    sandbox-certs:
    condition: service_completed_successfully
    environment:
    SANDBOX_API_KEYS: ${SANDBOX_API_KEYS}
    SANDBOX_API_RUNNER_REGISTRATION_TOKEN: ${SANDBOX_API_RUNNER_REGISTRATION_TOKEN}
    SANDBOX_API_RUNNER_API_KEY: ${SANDBOX_API_RUNNER_API_KEY}
    SANDBOX_API_GRPC_TLS_CERT_FILE: /tls/api/grpc-server.crt
    SANDBOX_API_GRPC_TLS_KEY_FILE: /tls/api/grpc-server.key
    SANDBOX_API_GRPC_TLS_CLIENT_CA_FILE: /tls/api/ca.crt
    SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_CA_FILE: /tls/api/ca.crt
    SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_CERT_FILE: /tls/api/control-grpc-api-client.crt
    SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_KEY_FILE: /tls/api/control-grpc-api-client.key
    SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_SERVER_NAME: sandbox-runner-1
    volumes:
    - sandbox-tls:/tls:ro
    healthcheck:
    test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
    interval: 5s
    timeout: 3s
    retries: 5
    start_period: 10s
    # Never publish 8080/9090 — Caddy never routes to this service, and it shouldn't.

    sandbox-runner-1:
    image: ghcr.io/n8n-io/n8n-sandbox-service-runner-dind:latest
    privileged: true
    depends_on:
    sandbox-api:
    condition: service_healthy
    environment:
    SANDBOX_RUNNER_API_KEYS: ${SANDBOX_API_RUNNER_API_KEY}
    SANDBOX_RUNNER_REGISTRATION_TOKEN: ${SANDBOX_API_RUNNER_REGISTRATION_TOKEN}
    SANDBOX_RUNNER_API_GRPC_ADDR: sandbox-api:9090
    SANDBOX_RUNNER_HTTP_BASE_URL: http://sandbox-runner-1:8080
    SANDBOX_RUNNER_CONTROL_GRPC_LISTEN_ADDR: ':9091'
    SANDBOX_RUNNER_CONTROL_GRPC_ADVERTISE_ADDR: sandbox-runner-1:9091
    SANDBOX_RUNNER_ID: runner-1
    SANDBOX_RUNNER_DOCKER_SANDBOX_IMAGE: ghcr.io/n8n-io/n8n-sandbox-service-sandbox:latest
    SANDBOX_RUNNER_REGISTRATION_GRPC_CA_FILE: /tls/runner/ca.crt
    SANDBOX_RUNNER_REGISTRATION_GRPC_CERT_FILE: /tls/runner/grpc-client.crt
    SANDBOX_RUNNER_REGISTRATION_GRPC_KEY_FILE: /tls/runner/grpc-client.key
    SANDBOX_RUNNER_REGISTRATION_GRPC_SERVER_NAME: sandbox-api
    SANDBOX_RUNNER_CONTROL_GRPC_TLS_CERT_FILE: /tls/runner/control-grpc-server.crt
    SANDBOX_RUNNER_CONTROL_GRPC_TLS_KEY_FILE: /tls/runner/control-grpc-server.key
    SANDBOX_RUNNER_CONTROL_GRPC_TLS_CLIENT_CA_FILE: /tls/runner/ca.crt
    volumes:
    - sandbox-tls:/tls:ro
    # Never expose this container's ports publicly — it runs privileged Docker-in-Docker.

    searxng:
    image: ghcr.io/searxng/searxng:latest
    environment:
    SEARXNG_SECRET: ${SEARXNG_SECRET}
    volumes:
    - ./searxng-settings.yml:/etc/searxng/settings.yml:ro
    # Internal-only: n8n reaches it by service name. Never publish its port, and don't route Caddy to it.
  4. 在现有 n8n 服务的 environment 块中添加匹配的沙箱变量:

    environment:
    # ...your existing N8N_HOST, N8N_PORT, etc. stay as they are
    - N8N_ENABLED_MODULES=instance-ai
    - N8N_INSTANCE_AI_SANDBOX_ENABLED=true
    - N8N_INSTANCE_AI_SANDBOX_PROVIDER=n8n-sandbox
    - N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080
    - N8N_SANDBOX_SERVICE_API_KEY=${SANDBOX_API_KEYS}
    - N8N_INSTANCE_AI_SEARXNG_URL=http://searxng:8080
    depends_on:
    sandbox-api:
    condition: service_healthy
  5. 重启全部服务,让新服务加载更改:

    sudo docker compose up -d
  6. 添加模型 API 密钥。完整参考及模型提供商选择,请参阅设置 n8n Assistant。网页搜索可直接使用上方内置的 SearXNG 服务;如果更喜欢 Brave Search,可改为添加其密钥。

注意

将 Droplet 暴露到互联网之前,请将 change-me-... 占位符替换为你自己的唯一密钥,占位符位于 .env 中。sandbox-runner-1 以特权模式运行 Docker-in-Docker。不要公开其端口,也不要让 Caddy 路由到它。

更新 ​

如果通过 Docker Compose 文件运行 n8n,请按照以下步骤更新:

# Navigate to the directory containing your docker compose file <a href="#navigate-to-the-directory-containing-your-docker-compose-file" id="navigate-to-the-directory-containing-your-docker-compose-file"></a>
cd </path/to/your/compose/file/directory>

# Pull latest version <a href="#pull-latest-version" id="pull-latest-version"></a>
docker compose pull

# Stop and remove older version <a href="#stop-and-remove-older-version" id="stop-and-remove-older-version"></a>
docker compose down

# Start the container <a href="#start-the-container" id="start-the-container"></a>
docker compose up -d

后续步骤 ​

相关资源 ​

本文为社区中文翻译。查看对应英文原文