cover.webp

前言

Oracle 免费 VM.Standard.A1.Flex 实例最多提供 4 个 ARM Ampere CPU、24GB RAM 以及 200GB SSD,尽管 CPU 性能不算顶尖,但对于一些小型 LLM 模型处理轻型任务基本够用。

今天通过 Docker 部署 n8n 服务,顺便尝试了下在里面通过 Ollama 调用本地模型,这下终于可以不让小鸡吃灰了。本文使用以下服务:

  • n8n 是一个开源的自动化工作流平台,对各家 AI 的支持都非常好。我没有这些 AI 平台的 API,就先试试本地 LLM 模型吧,由俭入奢嘛~

  • Ollama 是一款运行本地大语言模型的开源框架,部署起来很简单,可以让各家开源模型快速跑起来。

部署

参考 Docker 官方最新文档安装好 Docker 和 Doker Compose 插件,应该还需要一个反向代理服务器,文中以 Nginx 为例。

n8n

n8n 支持多种数据库(默认 SQLite),这里使用的是 PostgreSQL,提前创建数据卷并设置权限

# n8n data dir
cd ~/container/n8n

mkdir -p n8n_data postgres_data
# node user
sudo chown -R 1000:1000 ./n8n_data

# postgres user
sudo chown -R 999:999 ./postgres_data

chmod -R 700 ./postgres_data
chmod -R 755 ./n8n_data

创建 docker-compose.yml 模板

services:
  postgres:
    image: postgres:17.6-alpine
    container_name: n8n-postgres
    restart: unless-stopped
    user: "999:999"
    environment:
      POSTGRES_USER: n8n  # 数据库用户名
      POSTGRES_PASSWORD: n8npass  # 数据库密码
      POSTGRES_DB: n8n  # 数据库名称
      LANG: en_US.UTF-8
      LC_ALL: en_US.UTF-8
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n -d n8n || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    user: "1000:1000"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n  # 数据库名称
      - DB_POSTGRESDB_USER=n8n  # 数据库用户名
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - N8N_HOST=n8n.dejavu.moe
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.dejavu.moe/  # 替换你的域名
      - N8N_EDITOR_BASE_URL=https://n8n.dejavu.moe/  # 替换你的域名
      - N8N_PROXY_HOPS=1
      - GENERIC_TIMEZONE=Asia/Shanghai
      - TZ=Asia/Shanghai
    ports:
      - "127.0.0.1:5678:5678"
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - ./n8n_data:/home/node/.n8n

这时候我们只部署了 n8n 服务,启动容器

sudo docker compose up -d

反向代理

添加一个用于 n8n Web 服务的 Nginx 反向代理配置,示例如下:

server {
    listen 80;
    listen [::]:80;
    server_name n8n.dejavu.moe;  # 替换你的域名

    # HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name n8n.dejavu.moe;  # 替换你的域名

    ssl_certificate /etc/nginx/cert/wild.dejavu.moe.pem;  # SSL
    ssl_certificate_key /etc/nginx/cert/wild.dejavu.moe.key;  # SSL

    # Cloudflare Origin SSL cipher suites
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ecdh_curve X25519:P-256:P-384;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # logs
    access_log /var/log/nginx/n8n.dejavu.moe.access.log;
    error_log /var/log/nginx/n8n.dejavu.moe.error.log;
    location / {
        proxy_pass http://127.0.0.1:15678;
        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_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_buffering off;
        chunked_transfer_encoding off;
        proxy_read_timeout 3600;
        proxy_send_timeout 3600;
    }

    location ~ ^/(webhook|webhook-test)/ {
        proxy_pass http://127.0.0.1:15678;
        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;
    }
}

此时应该可以通过自己的域名访问 n8n 了,创建管理员账号输入邮箱,会收到一个用于解锁社区版特性的激活码。假如你有 ChatGPT、Gemini……这些平台的 API Key,现在就可以愉快的玩耍了,毕竟现在 n8n 宣称是原生 AI 集成的全自动工作流,在这里找模板:

和我一样的「穷鬼」们,去下一步吧,我们将在 Ollama 中体验各种免费的模型。

Ollama

假如用 Docker 部署 Ollama,我又不想再给它添加一个反向代理了,那么 n8n 怎么访问 Ollama 呢?那就直接编排到同一个 docker-compose.yml 模板里吧,它们会共享容器的网络,端口绑定本地环回地址即可确保安全,这样 Ollama 的 HTTP API 就仅限本机 n8n 使用了。

在上面的 n8n 服务中添加 Ollama 的服务,现在看起来应该这样:

services:
  ollama:
    container_name: ollama
    image: ollama/ollama:latest
    restart: unless-stopped
    environment:
      - OLLAMA_HOST=0.0.0.0
      - OLLAMA_KEEP_ALIVE=1h
    volumes:
      - ./ollama:/root/.ollama

  postgres:
    image: postgres:17.6-alpine
    container_name: n8n-postgres
    restart: unless-stopped
    user: "999:999"
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: n8npassword
      POSTGRES_DB: n8n
      LANG: en_US.UTF-8
      LC_ALL: en_US.UTF-8
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n -d n8n || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    user: "1000:1000"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - N8N_HOST=n8n.dejavu.moe
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.dejavu.moe/
      - N8N_EDITOR_BASE_URL=https://n8n.dejavu.moe/
      - N8N_PROXY_HOPS=1
      - GENERIC_TIMEZONE=Asia/Shanghai
      - TZ=Asia/Shanghai
    ports:
      - "127.0.0.1:15678:5678"
    extra_hosts:  # <添加这个>
      - "host.docker.internal:host-gateway"  # <以及这个>
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - ./n8n_data:/home/node/.n8n

启动 Ollama 服务

sudo docker compose up -d

下载 LLM 模型,比如 llama3.1:8b,也可以使用一些 Tool Calling 类模型,比如 deepseek-r1-tool-calling:1.5b

sudo docker exec -it ollama bash

ollama pull llama3.1:8b

完成后重启相关容器

sudo docker compose down && sudo docker compose up -d

测试

登录我们部署的 n8n 控制台,添加一个 Ollama 服务凭据,Base URL 填 http://ollama:11434 即可

connect-ollama.webp

这是一个获取 RSS 摘要并将总结发送到 Telegram 频道/群组/对话中的工作流(来自公开模板)

workflow.webp

纯 CPU 进行这种 LLM 推理压力还是挺大的,后续可以选择更小一点的模型

load.webp

考虑当前硬件性能对本地 LLM 的瓶颈,我们大概最多可以选择 7b/8b 以下的模型(甚至更低),虽然吐 Token 的速度还是有点慢,不过反正以后是 n8n 在跑,我们又不用等,让它跑吧!

time.webp

最终,这个简单的任务用时 11 分钟 24.635 秒,可以接受哈哈。