Marinara Engine 的官方介绍里把它称为一个本地 AI 聊天、角色扮演和游戏引擎。听起来很容易让人以为:既然是“本地”,是不是服务器上还要准备 GPU、下载模型、跑 llama.cpp 或者 embedding 服务?
如果只是想把 Marinara 当成一个 Web 应用来用,答案是不需要。我的阿里云 ECS 现在跑的就是这种最小化部署:Docker 里只跑 Marinara Engine 本体,模型能力走外部 API,容器端口只绑定到 127.0.0.1,再由反向代理对外提供访问。
本文记录的是这个部署方式。版本核对时间是 2026-06-29:官方最新稳定版是 v2.0.6,我当前服务器上实际运行的是 ghcr.nju.edu.cn/pasta-devs/marinara-engine:2.0.5-lite。新部署可以优先用最新稳定版的 *-lite tag;如果你想完全复刻本文环境,就固定到 2.0.5-lite。
先理解这个“最小化”是什么意思
最小化不是功能阉割到不能用,而是把不适合小云服务器承担的部分拿掉。
Marinara Engine 官方提供 lite 镜像。根据官方容器安装文档,lite 镜像去掉了三类较重的离线能力:
- 本地 sidecar 模型,也就是容器内直接跑本地 LLM 的那部分。
- 本地 embedding 模型。
- 依赖本地 embedding 的语义记忆检索。
保留下来的能力仍然包括聊天、角色、游戏模式、agent、lorebook、角色卡、远程 LLM API 连接等。也就是说,只要你本来就打算用 OpenAI、OpenRouter、Gemini、Anthropic 或者其他远程 OpenAI-compatible API,这种部署方式就够了。
我这里的结构是:
浏览器
-> 阿里云安全组开放 80/443
-> Pingap / Nginx / Caddy 这类反向代理
-> 127.0.0.1:7860
-> Docker 容器内的 Marinara Engine
-> 远程 LLM / 图片 / TTS API
看到这里,问题就变成了:服务器上到底需要跑什么?答案很少:Docker、一个 compose 文件、一个 .env 文件、一个反向代理入口。
准备服务器
下面假设你已经能 SSH 到 ECS,并且服务器上已经安装 Docker 和 Docker Compose 插件。
可以先确认一下:
docker version
docker compose version
然后创建部署目录:
mkdir -p /opt/marinara
cd /opt/marinara
我建议这个目录只给 root 读写,因为 .env 里会有 Basic Auth 密码、ADMIN_SECRET 和 ENCRYPTION_KEY:
chmod 700 /opt/marinara
docker-compose.yml
这是我当前服务器上的 compose 文件整理版:
services:
marinara:
image: ghcr.nju.edu.cn/pasta-devs/marinara-engine:2.0.5-lite
container_name: marinara
restart: unless-stopped
init: true
env_file:
- .env
ports:
- "127.0.0.1:7860:7860"
volumes:
- marinara-data:/app/data
environment:
NODE_ENV: production
DATA_DIR: /app/data
FILE_STORAGE_DIR: /app/data/storage
MARINARA_DOCKER: "true"
volumes:
marinara-data:
这里有几个关键点。
第一,镜像用的是 *-lite。如果你的服务器可以正常访问 GitHub Container Registry,可以把镜像地址换成官方地址:
image: ghcr.io/pasta-devs/marinara-engine:2.0.6-lite
如果在国内服务器上拉 GHCR 不稳定,也可以像我一样用镜像地址。版本最好固定,不要在生产环境里长期写 latest,否则升级时很难判断数据结构和配置行为发生了什么变化。
第二,端口绑定是 127.0.0.1:7860:7860,不是 0.0.0.0:7860:7860。这表示 Marinara 只在服务器本机可访问,公网用户必须经过反向代理。这样即使阿里云安全组不小心开放了别的端口,7860 也不会直接暴露到公网。
第三,数据放在 Docker named volume marinara-data 里。官方镜像会把运行时配置和文件存储放到 /app/data,所以容器删除重建不等于数据丢失。
.env
最小化部署的重点其实在 .env。下面是一个可以直接照着改的模板:
PORT=7860
HOST=0.0.0.0
AUTO_OPEN_BROWSER=false
AUTO_CREATE_DEFAULT_CONNECTION=false
LOG_LEVEL=warn
BASIC_AUTH_USER=replace-with-your-user
BASIC_AUTH_PASS=replace-with-a-long-password
ADMIN_SECRET=replace-with-a-long-random-secret
ENCRYPTION_KEY=replace-with-64-hex-chars
CSRF_TRUSTED_ORIGINS=https://marinara.example.com
CORS_ORIGINS=https://marinara.example.com
BYPASS_AUTH_TAILSCALE=false
BYPASS_AUTH_DOCKER=false
REQUIRE_AUTH_FOR_DOCKER_PROXY=true
ALLOW_UNAUTHENTICATED_PRIVATE_NETWORK=false
ALLOW_UNAUTHENTICATED_REMOTE=false
PROVIDER_LOCAL_URLS_ENABLED=false
IMAGE_LOCAL_URLS_ENABLED=false
TTS_LOCAL_URLS_ENABLED=false
DEEPLX_LOCAL_URLS_ENABLED=false
WEBHOOK_LOCAL_URLS_ENABLED=false
CUSTOM_TOOL_SCRIPT_ENABLED=false
SIDECAR_RUNTIME_INSTALL_ENABLED=false
BACKGROUNDREMOVER_AUTO_INSTALL=false
SPRITE_BACKGROUND_REMOVAL_ENGINE=builtin
ENCRYPTION_KEY 可以这样生成:
openssl rand -hex 32
这里分三组理解就够了。
第一组是访问控制。BASIC_AUTH_USER 和 BASIC_AUTH_PASS 会让浏览器进入 Marinara 前先弹出 HTTP Basic Auth。只要你把它放到公网,就应该配上;如果走 HTTPS 反代,Basic Auth 的账号密码才不会在明文 HTTP 里裸奔。
ADMIN_SECRET 用于高权限 API,比如备份、批量导入、更新、sidecar 安装、删除模型、自定义工具修改等。官方文档里也强调这些高风险操作需要这个 secret。它和登录密码不是一回事,建议单独生成一个长随机值。
第二组是反向代理来源。CSRF_TRUSTED_ORIGINS 和 CORS_ORIGINS 要填浏览器实际访问的 origin。比如你用域名和 HTTPS:
CSRF_TRUSTED_ORIGINS=https://marinara.example.com
CORS_ORIGINS=https://marinara.example.com
如果只是临时用公网 IP 的 HTTP 验证,就写实际 origin,例如:
CSRF_TRUSTED_ORIGINS=http://120.26.71.189
CORS_ORIGINS=http://120.26.71.189
有些浏览器请求或反代日志里会带上显式端口,比如 http://120.26.71.189:80。如果 Marinara 日志提示 not in CORS_ORIGINS,就把日志里出现的完整 origin 加进去,多个值用英文逗号分隔。
第三组是“不要在这台服务器上跑本地东西”。这些开关全部关掉以后,Marinara 不会为了 provider、图片、TTS、DeepLX、webhook 或脚本工具去访问内网地址,也不会自动安装 sidecar runtime。这样更适合公开服务器:它只是一个 UI 和编排服务,真正的模型调用走你配置的外部 API。
因为这里的 .env 是通过 Docker Compose 的 env_file 注入容器的,修改后建议重启一次容器:
docker compose up -d
启动和检查
在 /opt/marinara 目录执行:
docker compose up -d
查看容器:
docker compose ps
我当前服务器上的状态大概是这样:
NAME IMAGE STATUS PORTS
marinara ghcr.nju.edu.cn/pasta-devs/marinara-engine:2.0.5-lite Up 4 days 127.0.0.1:7860->7860/tcp
再从服务器本机请求一下:
curl -I http://127.0.0.1:7860/
如果你已经配置了 Basic Auth,看到 401 Unauthorized 不是坏事,反而说明访问控制生效了。响应头里会有类似:
www-authenticate: Basic realm="Marinara Engine"
这一步能说明两件事:容器活着,端口也只在本机监听。
反向代理
我的服务器入口用的是 Pingap。核心配置只有两段。
upstreams.toml:
[upstreams.marinara]
addrs = ["127.0.0.1:7860"]
read_timeout = "86400s"
write_timeout = "86400s"
idle_timeout = "86400s"
locations.toml:
[locations.marinaraIpHttp]
host = "120.26.71.189"
upstream = "marinara"
client_max_body_size = "100mb"
enable_reverse_proxy_headers = true
如果你用域名和 HTTPS,host 换成自己的域名即可。enable_reverse_proxy_headers = true 很重要,它会把原始客户端和协议相关信息传给后端,后端才能更正确地判断外部访问来源。
如果你不用 Pingap,Nginx 写法也很直接:
server {
listen 80;
server_name marinara.example.com;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:7860;
proxy_http_version 1.1;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
正式使用建议上 HTTPS。Basic Auth 只是编码,不是加密;真正让它安全传输的是 TLS。你可以用 Caddy 自动签证书,也可以继续用现有的 Nginx、Pingap 或其他网关统一处理证书。
阿里云安全组怎么放
安全组只需要开放入口代理用的端口:
- 使用 HTTP 验证时开放
80。 - 使用 HTTPS 时开放
443。 - SSH 端口按你自己的运维习惯限制来源。
- 不要开放
7860。
容器端口本身已经绑定到 127.0.0.1,安全组再不开放 7860,就形成了两层限制。外部用户只能经过反向代理访问,后端容器不会被直接扫到。
进入 Marinara 后怎么接模型
部署完成后,Marinara 只是一个可访问的 Web 应用。你还需要在界面里配置连接,也就是远程模型 provider。
如果目标是“不在本机跑任何模型”,就优先选外部 API:
- OpenAI
- OpenRouter
- Google Gemini
- Anthropic
- Mistral
- 其他 OpenAI-compatible endpoint
lite 镜像不会在容器里给你起本地模型。你也不要在同一台小 ECS 上额外跑 Ollama、llama.cpp 或 Stable Diffusion。小服务器适合做入口、存配置、存角色卡和聊天数据;模型推理交给专门的 API 或另一台有资源的机器。
我这台 2GB 左右内存的 ECS 上,Marinara 容器空闲时大约占 200MB 内存。这个量级对小云服务器比较友好,和动辄几个 GB 起步的本地模型不是一类负担。
更新和备份
容器部署没有自动原地更新,升级就是拉镜像再重建容器:
cd /opt/marinara
docker compose pull
docker compose up -d
如果 compose 里固定了版本号,先把 image 的 tag 改到目标版本,例如从 2.0.5-lite 改到 2.0.6-lite,再执行上面的命令。
但 Marinara 目前仍然是 alpha 软件,版本升级可能带来数据结构或行为变化。我更建议每次升级前先备份 named volume:
docker run --rm \
-v marinara_marinara-data:/data \
-v "$PWD":/backup \
busybox \
tar czf /backup/marinara-data-backup.tgz -C /data .
如果你把 compose project 名改了,volume 名也会变。可以先查一下:
docker volume ls
我当前这台服务器上的 volume 名是:
marinara_marinara-data
常见问题
访问公网地址打不开,先不要急着改 Marinara。按顺序查:
docker compose -f /opt/marinara/docker-compose.yml ps
curl -I http://127.0.0.1:7860/
systemctl status nginx
systemctl status pingap
如果本机 curl 通,问题通常在反向代理或安全组;如果本机都不通,再看容器日志:
docker logs --tail 100 marinara
如果浏览器页面能开,但接口报 CORS 或 CSRF 错误,看日志里提示的 origin,然后补到 .env:
CSRF_TRUSTED_ORIGINS=https://marinara.example.com
CORS_ORIGINS=https://marinara.example.com
补完以后重启容器:
docker compose -f /opt/marinara/docker-compose.yml up -d
如果 curl -I http://127.0.0.1:7860/ 返回 401 Unauthorized,这是 Basic Auth 生效,不是服务挂了。
如果日志里出现外部服务连接超时,例如访问翻译、图片或某个模型 API 超时,那通常不是容器部署问题,而是服务器到目标服务的网络不可达、DNS 问题、代理问题,或者目标服务本身限流。最小化部署只保证 Marinara 本体跑起来,不保证所有外部 provider 都能从你的 ECS 网络里顺畅访问。
最后
这套部署的核心思路很简单:把 Marinara Engine 当成一个 Web 应用和数据入口,而不是把它当成推理服务器。
小 ECS 负责:
- 跑 Marinara 的 Web 服务。
- 保存配置、角色、聊天和上传文件。
- 通过反向代理提供统一入口。
- 用 Basic Auth、
ADMIN_SECRET、CORS/CSRF origin 和安全组把边界收住。
模型服务负责:
- LLM 推理。
- 图片生成。
- TTS 或其他重计算能力。
这样部署的好处是很直接的:服务器成本低,维护面小,升级回滚也清楚。等以后真的需要本地模型、私有 embedding 或语义记忆,再换 full 镜像或者单独加推理机器也不迟。
参考资料: