远程访问:登录与 IP 允许列表

本指南介绍怎样从另一台设备访问 Marinara Engine,比如手机、笔记本电脑或者 Docker 容器。主要办法是登录。此外还会讲到 IP 允许列表、登录代理、HTTPS、Admin Access 以及“保存被拦截”的 CSRF 提示。这里几乎所有设置都写在服务器的 .env 文件里,不在应用界面中。

先明确几个贯穿全文的说法:

用 Tailscale 从任何地方连接

Tailscale 是一个供你自己的设备使用的私有网络。用它就能在手机或笔记本电脑上打开 Marinara,在家在外都行,不用在路由器上开放端口,也不用把 Marinara 放到公网上。Marinara 信任直接通过 Tailscale 连接的设备,所以不需要设置登录。

  1. 在运行 Marinara 的电脑和你的另一台设备上都安装 Tailscale。从 tailscale.com/download 下载。
  2. 两台设备都用同一个账号登录 Tailscale。
  3. 用 start.sh、start.bat、start-termux.sh 或 Windows 安装程序启动 Marinara。这几种方式允许其他设备连接。如果改用 pnpm start,先在 .env 文件里加上 HOST=0.0.0.0(见.env 文件在哪里)。
  4. 找到运行 Marinara 的那台电脑的 Tailscale 地址。在那台电脑上打开 Tailscale 应用,或者运行 tailscale ip -4。地址以 100. 开头,例如 100.101.102.103。
  5. 在另一台设备上开启 Tailscale,然后在浏览器里打开 http://100.101.102.103:7860。地址换成你自己的;改过 PORT 的话,端口也换成你的。Marinara 会直接打开,不会出现登录页面。

如果页面打不开,检查两台设备是否都开着 Tailscale,以及服务器是否在 HOST=0.0.0.0 上监听。

注意: Docker 安装不适用这个办法。Tailscale 流量要经过 Docker 网关才能到达容器,所以 Marinara 看不出它来自 Tailscale。先设置登录(方案 1),再把端口发布到 127.0.0.1 之外。

从远程设备执行备份、导入、更新和其他有风险的操作时,仍然需要管理员密钥。见 Admin Access 与高权限操作。

Marinara 默认会拦截什么

为了保护数据,全新安装的 Marinara 在你设置访问控制之前会拒绝其他设备的连接。默认只信任三类客户端:

  1. 环回地址(127.0.0.1 或 ::1),也就是运行服务器的这台机器本身。同一台机器上的反向代理或隧道转发过来的访客不算在内,见同一台电脑上的反向代理和隧道。
  2. 你 tailnet 里的 Tailscale 设备。Tailscale 是一款私有网络工具,地址落在 100.64.0.0/10 段。
  3. 同一台主机上的 Docker 客户端。Marinara 认得常见的 172.16.0.0/12 网桥段,以及容器里检测到的具体默认网关,因此 Docker Desktop 和自定义地址池也都能覆盖。

其余一律拦截,包括连着同一个 Wi-Fi 的手机和公网客户端,直到你设置登录为止。被拦截的设备在浏览器里打开 Marinara 会看到一个深色的设置页面,标题写着 This Marinara Engine install needs a login before remote devices can connect.,页面上有一个填写服务器日志里一次性设置码的表单,这样你就能在那台设备上设置登录。

如果什么都不做、也从不设密码,Marinara 就一直只对上面三类来源开放。这是最安全的默认状态。

.env 文件在哪里

所有访问相关的设置都写在项目根目录的 .env 文件里,和 package.json 同级。还没有这个文件的话,复制一份示例:

cp .env.example .env

用任意文本编辑器打开 .env。多数访问设置几秒内就会生效,不用重启,包括 Basic Auth、IP 允许列表、管理员密钥和 CSRF 来源。少数底层设置仍然需要重启,比如 PORT、HOST 和 HTTPS 证书路径。

有时其他设备根本连不上服务器,表现为超时而不是 403。这种情况多半是服务器只在本机监听。让服务器在所有网络接口上监听:

HOST=0.0.0.0

启动脚本(start.bat、start.sh)会自动设置 HOST=0.0.0.0,直接运行 pnpm start 则不会。

不同启动方式下的默认绑定地址:

启动方式HOST 默认值
pnpm start、start-local.bat127.0.0.1
start.sh、start.bat、Windows 安装程序、start-termux.sh0.0.0.0
Docker 镜像容器内为 0.0.0.0
docker-compose.yml只在 127.0.0.1 上发布端口

该选哪个方案

按顺序往下读,读到第一条符合自己情况的就停下。

  1. 只通过 Tailscale 直接连接,或者只从同一台主机上的 Docker 容器连接。用 pnpm start 时,直连的 Tailscale 客户端会跳过登录;请设置 HOST=0.0.0.0,它们才能连上服务器。默认的 Compose 文件只发布到 127.0.0.1。如果你把端口发布到环回地址之外,好让 Tailscale 设备能连上,请先设置登录。这样 Docker 会向每台设备索要登录,包括 Tailscale 设备,因为 Docker 在网关地址上看到它们。参见 Tailscale 与 Docker 放行。
  2. 想在家里 Wi-Fi 下用手机、平板或笔记本电脑访问 Marinara。设置登录(下面的方案 1)。
  3. 要把 Marinara 暴露到公网。设置登录,并使用 HTTPS。
  4. 你的网络上有登录代理,比如 tinyauth、Authelia 或 Authentik,它已经要求每位访客先登录。读登录代理(转发认证)。

登录是最灵活的选择:任何 IP 都能用,每台设备都不用单独配置,浏览器也会一直保持登录。

方案 1:登录(推荐)

登录就是每台远程设备都要输入的一个用户名和密码。有三种设置方式:

BASIC_AUTH_USER=alice
BASIC_AUTH_PASS=correct-horse-battery-staple

.env 里的登录优先于应用里设置的登录,要修改它只能改 .env。保存 .env。改动几秒内生效,不用重启。

密码要够强、也别和别处重复。应用要求至少 10 个字符。可以生成一个随机密码:

openssl rand -base64 24

然后在远程设备上按下面几步操作。

  1. 在浏览器里用服务器的地址打开 Marinara,例如 http://192.168.1.50:7860。
  2. 在登录页输入你的用户名和密码。
  3. 应用应该正常加载。浏览器最多会保持登录一年,直到你退出登录。脚本和 API 客户端每次请求都要带上用户名和密码(Basic Auth)。

不输密码也能在另一台设备上登录,用配对码。在已登录的设备上,打开 Settings → Advanced → Access,选择 Add a device。然后在新设备的登录页输入这个码。每个码只能用一次,有效几分钟。过期的码会收到自己的提示;重新生成一个就行。在 Signed-in devices 下,可以看到每台设备的登录方式和首次登录的日期。可以让任何设备退出登录,包括你正在用的这台。也可以修改或移除密码。这时 Marinara 会要求输入当前密码,除非你在运行 Marinara 的那台电脑上操作,或者设置了 ADMIN_SECRET。

如果忘了密码,在运行 Marinara 的电脑上,到 Marinara 文件夹里运行 node scripts/reset-login.mjs。在 Docker 里,运行 docker exec <container> node scripts/reset-login.mjs。它会删除应用里设置的登录,并让每个浏览器退出登录。如果服务器监听范围超出环回地址,它随后会打印一个新的设置码。只有这条命令用不了时,才改为从数据文件夹里删除 .remote-login.json 和 .remote-sessions.json。用默认的 /app/data 时,运行 docker exec <container> rm -f /app/data/.remote-login.json /app/data/.remote-sessions.json;如果你改过 DATA_DIR,就用那个文件夹。你在 .env 里设置的登录要在 .env 里修改。

没有浏览器的无头服务器?无头服务器上的原生安装只在环回地址上监听,也不会打印设置码。在你自己的电脑上,运行 ssh -L 7860:127.0.0.1:7860 user@server。然后在那里打开 http://localhost:7860 并使用 Settings。

如果 15 分钟内输错了 10 个不同的密码或设置码,Marinara 会以 429 Too Many Requests 拒绝来自该地址的登录,直到这 15 分钟过去。在此之前输对一次密码就会清零计数。主机上的反向代理或隧道转发过来的访客共用一个计数,其中一人登录成功也不会清零。重启服务器同样会清零。之前登录过的浏览器只要输对密码仍然能进,所以别人输错密码不会把你挡在自己常用的设备之外。登录页会告诉你还要等几分钟。如果忘了密码,登录页有 Forgot the password? 提示。

浏览器在 /login 页面登录。BASIC_AUTH_REALM 改的是面向脚本和 API 客户端的 Basic Auth 质询里的 realm,不会改登录页面。

即使开着 Basic Auth,仍有几类客户端不需要输密码:

重要提醒:Basic Auth 只是把密码编码,并没有加密。任何人只要能监听未加密的连接就能读到它。如果要把 Marinara 暴露到公网,一定要给 Basic Auth 配上 HTTPS(见下文)。

方案 2:IP 允许列表

IP 允许列表让指定地址免密码进入,适合设备 IP 地址固定的情况。用逗号分隔写出地址或地址段:

IP_ALLOWLIST=192.168.1.0/24,203.0.113.42

例子里的 /24 是 CIDR 写法。CIDR 是用一条记录表示一整段地址的简写方式,比如 192.168.1.0/24 覆盖从 192.168.1.0 到 192.168.1.255 的全部地址。不带斜杠的单个地址,比如 203.0.113.42,只匹配那一台设备。

0.0.0.0/0 这样的大范围公网地址,可能让公网客户端不用登录就进来。只列出你信任的地址。

IP 允许列表的行为如下:

允许列表做不到“列表内免密码、其他人输密码登录”这种混合模式。想让其他设备用密码登录,就别设 IP_ALLOWLIST,只用 Basic Auth。

不删列表也可以临时停用它,从新 IP 排查问题时很方便。把启用开关设成 false:

IP_ALLOWLIST_ENABLED=false

私有网络放行(参考)

有几个开关可以为可信的私有网络解除封锁。它们适用于特殊场景。登录是更好的选择。这些开关及其风险见访问控制。

Tailscale 与 Docker 放行

默认情况下,Marinara 信任直连这台电脑的 Tailscale 网络的设备。它也信任 Docker 容器自己的主机。登录、IP 允许列表或 TRUSTED_AUTH_PROXY 会让自动的 Docker 信任失效,这样每台设备都需要自己的登录或在允许列表里的位置。想了解改变这一点的开关,见访问控制。

Docker Desktop、OrbStack 和 rootless Docker 会让每台使用已发布端口的设备都显示为 Docker 网关地址。如果你把端口发布在所有接口上(-p 7860:7860)又没有设置登录,你网络里的任何人都能进来。请让端口只监听 127.0.0.1,或者先设置登录。服务器日志在启动时会就此给出警告。

同一台电脑上的反向代理和隧道

运行 Marinara 的那台机器上的反向代理或隧道,例如 nginx、Caddy、Traefik、Cloudflare Tunnel、Tailscale Serve 或 Funnel、ngrok,是从环回地址连接 Marinara 的。Marinara 会根据代理添加的转发请求头识别出这种情况:Forwarded、X-Forwarded-For、X-Real-IP、X-Forwarded-Host、X-Forwarded-Proto、CF-Connecting-IP、True-Client-IP、Tailscale 的身份请求头,或者 Via。Marinara 也会识别以 HTTP/1.0 到达的请求,因为浏览器从不使用它,而 nginx 的默认 proxy_pass 会使用。即使代理没有添加任何请求头,Marinara 也会识别 Host 指向另一台计算机(例如域名或局域网地址)的请求。之后它会把每个请求当作真正的远程访客对待:

你自己在这台机器上用 http://127.0.0.1:7860 或 http://localhost:7860 打开的浏览器,仍然不需要密码。

Caddy、Traefik、Cloudflare Tunnel、Tailscale 和 ngrok 默认会添加转发请求头。nginx 仍然建议在 location 块里加上这一行:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

转发原始连接的工具,例如 socat 或 ssh -R,不会添加任何请求头,所以它们的流量看起来就像本地流量。不要用它们来公开 Marinara。

如果你的代理在转发之前已经要求每位访客登录,见登录代理(转发认证)。

登录代理(转发认证)

转发认证代理,例如 tinyauth、Authelia、Authentik 或 oauth2-proxy,会在转发请求之前要求每位访客登录。如果这样的代理是访问 Marinara 的唯一途径,你可以跳过第二道 Marinara 登录。没有这样的代理时不要设置它。

把代理的地址写进 .env:

TRUSTED_AUTH_PROXY=192.168.1.5

这样,Marinara 会让每个连接来自该地址的请求直接进入。Marinara 不会再要求它自己的登录,也不会打印设置码。Marinara 只检查连接本身的地址。做这个判断时,它会忽略 X-Forwarded-For 之类的转发请求头。来自代理的请求也会跳过 IP_ALLOWLIST,因为由代理决定谁能进来。它们不算本地,所以高权限操作仍然需要管理员密钥。Settings → Advanced → Access 在设置生效期间会显示 Trusted login proxy: Set。

设置之前:

设置了 TRUSTED_AUTH_PROXY 时,Marinara 也会让自动的 Docker 信任失效。不是代理的直连访客需要 Marinara 登录或 IP 允许列表。Marinara 随后也不会再显示“尚无登录”横幅。

如果代理和 Marinara 运行在同一台电脑上,请使用 TRUSTED_AUTH_PROXY=127.0.0.1,并让代理指向 127.0.0.1:7860,而不是 localhost:7860。拨号 localhost 的代理可能从 ::1 连接,它和 127.0.0.1 不匹配。这样,这台电脑上的其他每个代理或隧道也都被信任,所以只有当登录代理是唯一的代理时才用它。这不会让被代理的访客获得本机的访问权限。

Caddy 示例,Marinara 在 192.168.1.20:7860:

marinara.example.com {
  forward_auth tinyauth:3000 {
    uri /api/auth/caddy
  }
  reverse_proxy 192.168.1.20:7860
}

对于 Authelia,用 forward_auth authelia:9091,加上 uri /api/authz/forward-auth。Authentik 还会通过代理提供它自己的登录页面。把这些放进 route 块里,这样 Caddy 会保持它们的顺序,而且 outpost 路径不会再经过转发认证:

marinara.example.com {
  route {
    reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
    forward_auth authentik-server:9000 {
      uri /outpost.goauthentik.io/auth/caddy
    }
    reverse_proxy 192.168.1.20:7860
  }
}

对于 Traefik,请遵循你的代理的转发认证指南。Marinara 需要的不只是代理的地址。

通过 HTTPS 提供服务

HTTPS 用 TLS 加密连接。TLS 就是把普通 http 地址变成安全的 https 地址的那层加密。如果这套安装在完全可信的私有网络之外也能访问到,就一定要用 HTTPS,配合 Basic Auth 时尤其如此。

有两种加上 HTTPS 的办法。

  1. 内置 TLS。给服务器指定证书文件和私钥文件:
SSL_CERT=/path/to/cert.pem
SSL_KEY=/path/to/key.pem
  1. 反向代理。把 Marinara 放在 nginx、Caddy、Traefik 或 Cloudflare Tunnel 后面,由代理负责 HTTPS,再在同一台机器上用普通 HTTP 转发给 Marinara。请先阅读同一台电脑上的反向代理和隧道。

设置 SSL_CERT 和 SSL_KEY 之前得先有证书和私钥。本地使用可以用 mkcert 之类的工具生成,公网域名则可以用 certbot。文件缺失或者读不到时,服务器会在启动时停下,并把尝试过的确切路径打印出来。

Admin Access 与高权限操作

有些操作格外敏感:清除数据、创建或下载备份、导入和导出档案、安装主题和智能体、安装本地模型运行时。除了上面选定的访问方案之外,这些操作还需要一个单独的共享密钥,叫管理员密钥。

在环回机器上,这些操作通常不用管理员密钥也能完成。从远程设备操作时就得先把密钥配好。可以在应用里生成,也可以在 .env 里设置。

已安装的智能体,比如主页上的那些,不需要管理员密钥。用登录信息登录过的设备就能使用它们。安装、更新和移除智能体仍然需要它。

在应用里生成管理员密钥

  1. 在运行 Marinara 的那台电脑上,打开 Settings(设置),切到 Advanced(高级) 选项卡,找到 Admin Access(管理员访问) 一节。
  2. 点击 Make admin secret(生成管理员密钥)。Marinara 会把新密钥显示一次,并保存在这个浏览器里。
  3. 在每台远程设备上,打开 Settings → Advanced → Admin Access,把密钥输进输入框,然后点击 Save(保存)。大小写、空格和短横线都不影响。

已经有密钥的设备也可以生成密钥。只用登录信息登录的设备不行。这样即使登录被盗,对方也没法接管这些高风险操作。

用 Docker 时,浏览器是通过 Docker 网络访问 Marinara 的,所以 Marinara 不会把它当成同一台电脑。改为在 .env 里设置第一个密钥(见下文)。

要更换密钥,点击 Replace admin secret(更换管理员密钥)。旧密钥会在所有设备上失效。要关闭它,点击 Remove admin secret(移除管理员密钥)。Marinara 只保存密钥的指纹,放在数据文件夹里的 .admin-secret.json 中。删除这个文件也会移除密钥。

在 .env 里设置管理员密钥

  1. 在 .env 里设一个足够强的随机值并保存。几秒内生效,不用重启。
ADMIN_SECRET=some-long-random-string
  1. 在远程设备上打开 Settings → Advanced → Admin Access。
  2. 把同一个值粘进输入框(占位文字是 ADMIN_SECRET),然后点击 Save。
  3. 应该会看到提示 Admin secret saved for this browser。

.env 里的 ADMIN_SECRET 优先于在应用里生成的密钥。设置了它时,Admin Access 会注明这一点,这时只能在 .env 里更改密钥。

需要知道的事

远程设备上高权限操作失败时,Marinara 会给出一条错误提示,里面写着两种解决办法:一是改从 localhost 打开应用,二是按上面说的方法设置管理员密钥。

保存为什么被拦截(CSRF)

CSRF 指跨站请求伪造,是一种防护机制,用来阻止你同时开着的其他网站在你不知情的情况下悄悄改动 Marinara。它自动运行,没有开启它的设置项。

有时 CSRF 会把你自己的保存操作也拦下来。多半是因为访问 Marinara 用的是公网域名,或者是服务器还不信任的非常规端口。有两处地方会提示这种情况。

解决办法是把地址加进 .env 的受信任列表:

CSRF_TRUSTED_ORIGINS=https://chat.example.com,http://203.0.113.10:7831

用公网域名或反向代理域名时,还要把主机名也放行:

TRUSTED_HOSTS=chat.example.com

直连的局域网、Tailscale、IPv4 和 IPv6 地址不需要 TRUSTED_HOSTS。本地的 .local/.home.arpa 名称和单段机器名会自动放行。已经写在 CSRF_TRUSTED_ORIGINS 里的完整主机名同样有效。

环回地址、普通局域网地址、Tailscale(100.64.0.0/10) 和 Docker 网桥(172.16.0.0/12)来源都自动受信任,只需要把公网 IP 地址和域名列出来。改动几秒内生效,不用重启。

关于本地服务商被拦截

假设把 Marinara 连到本地的 AI 服务商,比如跑在自己机器上的那种。请求可能被拒绝,提示里提到“private, loopback, metadata, or reserved IP range”。这是另一套安全检查,叫 SSRF 防护。SSRF 指服务器端请求伪造,作用是阻止服务器在未获许可的情况下访问私有地址。错误提示会写明该设置哪个 .env 变量,比如 PROVIDER_LOCAL_URLS_ENABLED。完整清单见服务器配置参考。

从手机或平板访问

要在同一网络下用手机或平板打开 Marinara:

  1. 确认 .env 里设了 HOST=0.0.0.0,让服务器在所有接口上监听。
  2. 设置登录(上面的方案 1)。在手机上,可以用服务器日志里的设置码,在拦下手机的页面上设置。
  3. 找到服务器所在机器的局域网 IP 地址(例如 192.168.1.50)。
  4. 在手机浏览器里打开 http://192.168.1.50:7860。默认端口是 7860。
  5. 用你的用户名和密码登录。

页面完全打不开,说明多半连不上服务器,检查 HOST=0.0.0.0 和 PORT 的值。如果收到的是 403,那说明设备能连上,只是还没被放行,回头再看一遍选定的方案。

更新后被锁在外面

较新的版本在访问经由反向代理、隧道、Tailscale Serve 或 Tailscale Funnel 到达时,会要求登录。旧版本会不要密码就放行这些访问。如果你现在看到登录页、设置页或 403,原因就在这里。

升级说明:如果你用 Tailscale Serve,或者同一台电脑上的其他代理,而且从没设置过密码,那么更新之后你的其他设备就被锁在外面了。同一台电脑上的代理通常是连接一个只在环回地址上监听的服务器,所以服务器不会打印设置码。请改在运行 Marinara 的那台电脑上设置登录。

重新进入的方法:

  1. 在运行 Marinara 的那台电脑上,打开 http://localhost:7860(或你自己的 PORT)。本机使用不需要密码。在无头服务器上,先在你自己的电脑上运行 ssh -L 7860:127.0.0.1:7860 user@server,然后在那里打开 http://localhost:7860。在 Docker 中,只有在没有设置登录也没有设置 IP_ALLOWLIST 时才是这样。否则,在拦下你的页面上或 Settings → Advanced → Access 里输入服务器日志里的设置码(docker logs <container> 2>&1 | grep "setup code"),或者使用仍处于登录状态的浏览器。
  2. 到 Settings → Advanced → Access,在 Remote login 下设置用户名和密码。或者在那台电脑上打开 .env 文件,设置 BASIC_AUTH_USER 和 BASIC_AUTH_PASS。如果设置了 IP_ALLOWLIST,请把你另一台设备的地址加进去,或者删掉该设置,因为不在列表里的设备即使登录也会收到 403。
  3. 在你的另一台设备上用该用户名和密码登录。

搜索引擎

Marinara 会请求搜索引擎不要索引其页面(X-Robots-Tag: noindex, nofollow)。这不能保护你的安装,也不会移除已经被索引的页面。请使用上面的访问控制来保持你的安装私密。

相关指南