标签 Docker 下的文章

绿联 NAS Docker 部署 · 扔掉 CF Tunnel · 一行命令公网访问 · 支持自定义域名 · 免费 HTTPS

背景

我之前用绿联 NAS 的 Docker 部署了 Cloudflare Tunnel,把家里的服务通过自己的域名暴露到公网。但 CF Tunnel 在国内环境下频繁掉线——QUIC 协议被运营商掐、NAT 超时回收、Docker 容器动不动就断连。日志里全是:

WRN Failed to dial a quic connection error="timeout: no recent network activity"
ERR Connection terminated

折腾了好几轮 --protocol http2restart: always、健康检查……治标不治本。

后来发现 Tailscale Funnel 才是正解。它直接复用你已经跑通的 Tailscale 网络底座,一行命令把服务暴露到公网,自带 HTTPS 和自定义域名绑定,彻底甩掉 CF Tunnel 这个不稳定因素。

这篇教程完整记录从迁移到上线的每一步。


前置条件

  • 绿联 NAS 已部署 Tailscale(Docker 或套件版均可)
  • Tailscale 已登录,设备在线
  • 有一个自己的域名,DNS 托管在任意服务商
  • NAS 上的服务正常运行(假设跑在 8080 端口)

第一步:确认 Tailscale 正常工作

SSH 登录 NAS,检查 Tailscale 状态:

tailscale status

应该能看到你的 NAS 设备在线,记住它的 Tailscale IP(形如 100.x.x.x)。

如果是 Docker 部署的 Tailscale:

docker exec tailscale tailscale status

第二步:启用 HTTPS 证书

Funnel 需要 TLS 证书。Tailscale 可以自动签发 Let's Encrypt 证书:

tailscale cert --cert-file /tmp/ts-cert.pem --key-file /tmp/ts-key.pem

如果是 Docker 部署:

docker exec tailscale tailscale cert \
  --cert-file /tmp/ts-cert.pem \
  --key-file /tmp/ts-key.pem

这一步 Tailscale 会自动完成域名验证,无需手动操作 DNS。


第三步:开启 Tailscale Funnel

假设你的服务跑在 NAS 的 8080 端口,一行命令暴露:

# 先开启 serve(HTTPS 反向代理)
tailscale serve --bg --https=443 8080

# 再开启 funnel(公网访问)
tailscale funnel 8080 on

Docker 环境:

docker exec tailscale tailscale serve --bg --https=443 8080
docker exec tailscale tailscale funnel 8080 on

现在已经可以通过 https://你的NAS主机名.tailnet名称.ts.net 从公网访问了。


第四步:绑定自定义域名

Funnel 默认用的是 Tailscale 的 ts.net 域名,但你可以绑定自己的域名(例如 sub.example.com):

4.1 在 Tailscale Admin Console 添加域名

  1. 打开 https://login.tailscale.com/admin/dns
  2. 点击 HTTPS Certificates 标签
  3. 点击 Add a custom domain
  4. 输入你的域名,例如 sub.example.com
  5. 页面会显示一组 TXT 验证记录

4.2 在域名 DNS 服务商添加 TXT 记录

去你的域名 DNS 管理后台(如 Cloudflare、阿里云 DNS、DNSPod),添加两条记录:

类型主机记录记录值
TXT_acme-challenge.subTailscale 提供的验证值
TXT_acme-challenge.sub第二条验证值(如果有)

4.3 等待验证

回到 Tailscale Admin Console,点击 Verify。通常几分钟内生效。验证通过后,证书会自动签发。

4.4 配置 Funnel 使用自定义域名

验证通过后,指定域名重新启用 Funnel:

# 先关闭之前的 funnel
tailscale funnel 8080 off

# 用自定义域名重新开启
tailscale serve --bg --https=443 --set-path / 8080
tailscale funnel --bg --set-path / 8080 on

Docker 环境:

docker exec tailscale tailscale funnel 8080 off
docker exec tailscale tailscale serve --bg --https=443 --set-path / 8080
docker exec tailscale tailscale funnel --bg --set-path / 8080 on

第五步:DNS 解析到 Tailscale IP(关键)

到你的域名 DNS 管理后台,添加一条 A 记录:

类型主机记录记录值
Asub你的 NAS 的 Tailscale IP(100.x.x.x)
⚠️ 注意:这一步是把域名指向 Tailscale IP,不是指向公网 IP。只有加入你 Tailnet 的设备能通过域名访问。如果需要完全公网访问,直接用 Funnel 自带的 ts.net 域名即可,不需要这一步。

第六步:验证

# 在任意设备上测试
curl -I https://sub.example.com

# 或用浏览器直接打开
# https://sub.example.com

看到 HTTP/2 200 就是成功了。


停掉旧的 Cloudflare Tunnel

既然 Tailscale Funnel 已经跑通了,可以停掉 CF Tunnel 容器:

docker stop cloudflared
docker rm cloudflared

不再需要维护这个不稳定的隧道了。


Docker Compose 长期运行配置

如果你想让 Funnel 在 Docker 里持久化运行,在当前运行 Tailscale 的容器里,servefunnel 命令加了 --bg 就会后台常驻。Tailscale 容器本身已经设了 restart: always,重启 NAS 后 Funnel 也会自动恢复。

不需要额外容器。


常见问题

Q: Funnel 跑起来后,从外网访问很慢?

Funnel 走 Tailscale 的 DERP 中继节点,速度取决于中继节点的位置。国内访问一般可以接受,但如果你的服务是流媒体/大文件传输,Funnel 不适合(Tailscale ToS 也禁止)。

Q: 自定义域名只能 Tailnet 内访问?

对。如果你把域名 A 记录指向 Tailscale IP(100.x.x.x),只有加入你 Tailnet 的设备能解析和访问。如果需要完全公网访问,直接用 Funnel 分配的 ts.net 域名,自动对全网开放。

Q: 和 Cloudflare Tunnel 比,少了什么?

Funnel 没有 CDN 缓存、没有 WAF、没有 DDoS 防护。但换来的是稳定不掉线。对于个人 NAS 服务来说,稳定比这些附加功能重要得多。

Q: 免费版有流量限制吗?

Tailscale 免费版 Funnel 没有明确的流量硬限制,但 ToS 禁止跑流媒体和大量文件传输。个人 Web 服务、Dashboard、API 完全够用。


总结

对比Cloudflare TunnelTailscale Funnel
稳定性国内频繁掉线极其稳定
配置量Docker + Token + 配置一行命令
HTTPS自动自动
自定义域名
费用免费免费
额外依赖依赖 CF 网络复用 Tailscale

CF Tunnel 在国内就是一个大坑,Tailscale Funnel 才是 NAS 玩家正确的公网暴露方式。


本文基于绿联 NAS + Docker + Tailscale v1.80+ 撰写,功能以官方最新版本为准。

记一次 Emlog Docker 部署后全站 404 的排查与解决

分类:建站运维 · 标签:Emlog、Docker、1Panel、伪静态、Apache

最近用 Docker 在服务器上部署了一个 Emlog 博客,配合 1Panel 面板和 OpenResty 反向代理。容器跑起来之后,访问首页直接返回一个 Apache 的 404 页面:

Not Found
The requested URL was not found on this server.
Apache/2.4.54 (Debian) Server at www.你的域名 Port 80

奇怪的是,容器明明是运行状态,数据库也连上了,但就是打不开。折腾了一番才找到根因,这里把完整的排查思路和解决方法记录下来,给遇到同样问题的朋友一个参考。

一、我的部署环境

先交代一下环境,方便对照:

  • 博客程序:Emlog Pro(Docker 容器部署)
  • 镜像:emlog/emlog:pro-latest-php7.4-apache
  • 面板:1Panel
  • Web 服务:OpenResty(反向代理到容器)
  • 数据库:MySQL 容器
  • 端口映射:宿主机 8080 → 容器 80
  • 数据挂载:宿主机数据目录 → 容器 /app

请求链路是这样的:用户 → CDN → OpenResty → Docker Emlog 容器(Apache + PHP)→ MySQL。

二、排查过程

1. 先确认容器在不在

容器名可能因为重建而变化,所以第一步先看实际容器名:

docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

确认容器确实在运行,名字也记下来(下文用 emlog容器 代指)。

2. 检查伪静态模块

Emlog 的伪静态依赖 Apache 的 mod_rewrite,先确认它启用了:

docker exec emlog容器 apache2ctl -M | grep rewrite

输出 rewrite_module (shared),说明模块没问题。

3. 关键发现:DocumentRoot 指向了空目录

接着看 Apache 的站点配置:

docker exec emlog容器 apache2ctl -S 2>&1 | head -20

输出里有一行:

Main DocumentRoot: "/var/www/html"

再去看这个目录里有什么:

docker exec emlog容器 ls /var/www/html/

结果是空的,什么都没有。

那 Emlog 的文件到底在哪?全局搜一下 index.php:

docker exec emlog容器 find / -name "index.php" -not -path "*/usr/share/*" 2>/dev/null

输出里能看到 Emlog 的程序文件其实在 /app 目录下:

/app/index.php
/app/admin/index.php
/app/content/...

到这里问题就清楚了。

三、问题根因

这个 Emlog Docker 镜像有一个设计上的坑:

Apache 默认的站点配置 000-default.conf 里,DocumentRoot 指向的是 /var/www/html,但 Emlog 的实际程序文件放在了 /app 目录。/var/www/html 是一个空目录,所以无论访问什么路径,Apache 都找不到文件,统统返回 404。

雪上加霜的是,Apache 默认配置里所有 Directory 块的 AllowOverride 都是 None。这意味着即使你放了 .htaccess 伪静态文件,Apache 也根本不会去读它。

所以要让站点正常访问、伪静态生效,必须同时解决两个问题:

  1. 把 DocumentRoot 指向正确的 /app 目录
  2. 开启 AllowOverride All,让 .htaccess 生效

四、解决方案

第一步:准备 .htaccess 文件

Emlog 的数据目录是挂载到容器 /app 的,所以直接在宿主机的数据目录里创建 .htaccess 即可:

cat > /你的数据目录/.htaccess << "EOF"
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
EOF

第二步:准备自定义站点配置

在宿主机上写一个 Apache 站点配置文件,把 DocumentRoot 指向 /app 并开启 AllowOverride:

mkdir -p /opt/emlog/conf

cat > /opt/emlog/conf/emlog-site.conf << "EOF"
<VirtualHost *:80>
    DocumentRoot /app
    <Directory /app>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
EOF

第三步:用 docker run 重建容器

这里要特别注意:不要用 1Panel 的图形界面去改挂载,它会报一个莫名其妙的错误:

includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed

这是 1Panel 把挂载路径当成了 Docker 的命名卷(named volume)而不是 bind mount。直接用 docker run 手动建容器最稳妥:

docker run -d \
  --name emlog容器 \
  --restart always \
  -p 8080:80 \
  -v /你的数据目录:/app \
  -v /opt/emlog/conf/emlog-site.conf:/etc/apache2/sites-enabled/000-default.conf \
  emlog/emlog:pro-latest-php7.4-apache

注意:.htaccess 要放在 /app 目录下(也就是宿主机的数据目录里),不要挂载到 /var/www/html/.htaccess,那个目录是空的,挂了也没用。

第四步:配置 OpenResty 伪静态

在 1Panel 里找到对应站点 → 站点设置 → 伪静态,填入:

if (!-e $request_filename) {
    rewrite ^/(.*)$ /index.php last;
}

如果面板的伪静态入口对反向代理站点不生效,就手动编辑 OpenResty 配置,在 location / 之前加入 rewrite 规则:

server {
    listen 80;
    server_name 你的域名 www.你的域名;

    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php last;
    }

    location / {
        proxy_pass http://你的服务器IP:8080;
        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;
    }
}

改完重载 OpenResty:

docker exec openresty容器 nginx -s reload

第五步:Emlog 后台设置

  1. 登录 Emlog 后台
  2. 进入「设置 → 链接结构」
  3. 选择「文件格式」(形如 /post-1.html),SEO 友好
  4. 确认「站点地址」填的是你的正式域名(https://你的域名),而不是 http://服务器IP:8080,否则生成的链接会带 IP 和端口
  5. 保存

五、一个容易遇到的小插曲:.htaccess 不可写

后台保存链接结构时,可能会提示「根目录下的.htaccess不可写」。

原因是 .htaccess 是用 root 创建的,而容器里 Apache 的运行用户是 www-data(UID 33),没有写权限。改一下文件归属就行:

chown 33:33 /你的数据目录/.htaccess

还不行就直接放开写权限:

chmod 666 /你的数据目录/.htaccess

其实我们手动放的规则已经是通用的了,Emlog 保存时只是用自带规则覆盖一遍,效果一样。这一步主要是让后台保存不报错,同时把链接结构写进数据库。

六、让配置持久化

上面这套配置都是放在宿主机、通过挂载进容器的,所以容器重建也不会丢。需要持久化的就两个文件:

宿主机路径容器路径说明
/你的数据目录//appEmlog 全部数据(含 .htaccess)
/opt/emlog/conf/emlog-site.conf/etc/apache2/sites-enabled/000-default.confApache 站点配置

以后无论容器怎么重建,只要这两条挂载在,伪静态就一直是好的。

七、踩坑总结

把这次踩的坑集中列一下,方便快速对照:

  1. DocumentRoot 陷阱:Emlog 镜像的 Apache 默认指向空的 /var/www/html,真实文件在 /app,必须用自定义站点配置覆盖。
  2. AllowOverride 默认 None:即使放了 .htaccess 也不生效,必须显式开启 AllowOverride All
  3. 别用 1Panel UI 改挂载:会报 "invalid characters for a local volume name",直接用 docker run
  4. proxy_pass 别用 127.0.0.1:容器内的 127.0.0.1 指向容器自己,要用宿主机内网 IP。
  5. 站点地址要填正式域名:填 IP:端口会导致生成的链接全是 IP。
  6. .htaccess 写权限:root 创建的文件 www-data 写不了,记得 chown 33:33
  7. 改完 OpenResty 要重载:否则配置不生效。

八、常用排查命令备忘

最后留一份排查命令清单,下次遇到问题可以按顺序敲:

# 确认容器名
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

# 检查 mod_rewrite
docker exec emlog容器 apache2ctl -M | grep rewrite

# 查看 DocumentRoot 指向
docker exec emlog容器 apache2ctl -S 2>&1 | head -20

# 检查 .htaccess(注意是 /app 不是 /var/www/html)
docker exec emlog容器 cat /app/.htaccess

# 检查站点配置
docker exec emlog容器 cat /etc/apache2/sites-enabled/000-default.conf

# 确认 Emlog 文件存在
docker exec emlog容器 ls /app/index.php

# 查看挂载情况
docker inspect emlog容器 --format '{{json .Mounts}}' | python3 -m json.tool

# 看 Apache 错误日志
docker exec emlog容器 tail -20 /var/log/apache2/error.log

结语

这次问题的核心,就是 Emlog Docker 镜像的 DocumentRoot 指向和实际文件位置不一致。看似一个 404,背后其实是「DocumentRoot 指错 + AllowOverride 没开」两个问题叠加。把这个坑记下来,希望能帮到同样在用 Docker 部署 Emlog 的朋友。

如果你也遇到了类似的 404,不妨先 apache2ctl -S 看看 DocumentRoot 到底指向哪里,多半问题就出在那。

Emlog Docker 部署实战:从 0 到上线的完整记录(1Panel + OpenResty)

分类:建站运维 · 标签:Emlog、Docker、1Panel、OpenResty、伪静态

这篇文章记录我用 Docker + 1Panel + OpenResty 从零部署一个 Emlog 博客的完整过程,包括踩过的坑和最终的稳定方案。如果你也打算用容器化方式跑 Emlog,这篇应该能帮你少走不少弯路。

一、写在前面

传统方式部署 Emlog 需要在服务器上装 PHP、Apache/Nginx、MySQL,环境配起来繁琐,迁移也麻烦。用 Docker 之后,整个博客就是一个容器,迁移、备份、重建都很方便。

但 Docker 部署也不是「一键起飞」,我这次就踩了几个不小的坑,最典型的一个是容器跑起来后全站 404。下面把完整流程和这些坑一次性讲清楚。

最终效果:一个带伪静态、邮件通知、CDN 加速的 Emlog 博客,所有配置持久化,容器重建不丢。

二、最终架构

先看一下整体架构,心里有个数:

用户 → CDN → OpenResty(反向代理)→ Emlog 容器(Apache + PHP)→ MySQL 容器

各组件分工:

  • OpenResty:由 1Panel 管理,负责接收请求、伪静态 rewrite、反向代理到 Emlog 容器
  • Emlog 容器:内置 Apache + PHP,运行博客程序
  • MySQL 容器:独立数据库容器,存储博客数据

为什么用 OpenResty 反代而不是直接暴露 Emlog 容器?因为这样可以在前面统一处理伪静态、SSL、缓存,Emlog 容器只管跑程序,职责清晰,也方便后续加 CDN。

三、环境准备

我的环境如下,供对照:

  • 服务器:一台 Linux VPS(Debian)
  • 面板:1Panel
  • 博客程序:Emlog Pro
  • 镜像:emlog/emlog:pro-latest-php7.4-apache
  • 数据库:MySQL 8.x 容器

需要准备的参数(下文用占位符表示,替换成你自己的):

占位符含义
你的域名博客正式域名
你的服务器IP服务器内网 IP
你的数据目录Emlog 数据在宿主机的存放路径
你的数据库密码MySQL 密码

四、第一步:部署 MySQL 容器

Emlog 需要数据库。我用独立的 MySQL 容器,方便管理和备份。

在 1Panel 的应用商店里安装 MySQL,或者直接用命令:

docker run -d \
  --name mysql \
  --restart always \
  -e MYSQL_ROOT_PASSWORD=你的数据库密码 \
  -v /opt/mysql/data:/var/lib/mysql \
  mysql:8.4

装好后进入容器创建 Emlog 专用数据库:

docker exec -it mysql mysql -u root -p
CREATE DATABASE emlog CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

注意:数据库端口不用对外开放,容器之间通过内部网络通信即可,更安全。

五、第二步:部署 Emlog 容器

在 1Panel 应用商店找到 Emlog 安装,或者用命令部署。这里先按默认方式跑起来:

docker run -d \
  --name emlog容器 \
  --restart always \
  -p 8080:80 \
  -v 你的数据目录:/app \
  -e EMLOG_DB_HOST=mysql \
  -e EMLOG_DB_NAME=emlog \
  -e EMLOG_DB_USER=root \
  -e EMLOG_DB_PASSWORD=你的数据库密码 \
  emlog/emlog:pro-latest-php7.4-apache

关键参数说明:

  • -p 8080:80:把容器 80 端口映射到宿主机 8080,后面 OpenResty 反代这个端口
  • -v 你的数据目录:/app:Emlog 程序和数据都在容器的 /app,挂载到宿主机实现持久化

容器跑起来后,先别急着访问,因为大概率会遇到下面这个坑。

六、第三步:那个绕不开的 404 坑

容器跑起来后访问首页,返回的是这样一个 Apache 404:

Not Found
The requested URL was not found on this server.
Apache/2.4.54 (Debian) Server at www.你的域名 Port 80

排查方法:先看 Apache 的 DocumentRoot 指向哪里。

docker exec emlog容器 apache2ctl -S 2>&1 | head -20

输出里会看到:

Main DocumentRoot: "/var/www/html"

再看这个目录:

docker exec emlog容器 ls /var/www/html/

空的。而 Emlog 的真实文件其实在 /app

docker exec emlog容器 ls /app/index.php

根因:这个 Emlog 镜像的 Apache 默认配置 000-default.conf 把 DocumentRoot 指向了空的 /var/www/html,而程序文件实际在 /app。所以所有请求都 404。

同时,Apache 默认的 AllowOverride 全是 None,就算放了 .htaccess 也不会被读取。

所以必须同时修两个地方:把 DocumentRoot 指向 /app,并开启 AllowOverride All

七、第四步:配置伪静态(含 404 修复)

1. 准备 .htaccess

数据目录挂载到容器 /app,所以直接在宿主机数据目录里建 .htaccess

cat > 你的数据目录/.htaccess << "EOF"
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
EOF

2. 准备自定义站点配置

写一个 Apache 站点配置,把 DocumentRoot 改到 /app 并开启 AllowOverride:

mkdir -p /opt/emlog/conf

cat > /opt/emlog/conf/emlog-site.conf << "EOF"
<VirtualHost *:80>
    DocumentRoot /app
    <Directory /app>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
EOF

3. 用 docker run 重建容器(关键)

这里要特别提醒:不要用 1Panel 图形界面改挂载,会报错:

includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed

这是 1Panel 把路径当成了命名卷。直接用 docker run 重建,把站点配置挂载进去覆盖默认的 000-default.conf

docker run -d \
  --name emlog容器 \
  --restart always \
  -p 8080:80 \
  -v 你的数据目录:/app \
  -v /opt/emlog/conf/emlog-site.conf:/etc/apache2/sites-enabled/000-default.conf \
  -e EMLOG_DB_HOST=mysql \
  -e EMLOG_DB_NAME=emlog \
  -e EMLOG_DB_USER=root \
  -e EMLOG_DB_PASSWORD=你的数据库密码 \
  emlog/emlog:pro-latest-php7.4-apache

这样 DocumentRoot 和 AllowOverride 两个问题一次性解决,而且配置在宿主机上,容器重建也不会丢。

4. 配置 OpenResty 反代和伪静态

在 1Panel 里创建网站,添加反向代理指向 你的服务器IP:8080,然后在「站点设置 → 伪静态」填入:

if (!-e $request_filename) {
    rewrite ^/(.*)$ /index.php last;
}

如果面板的伪静态入口对反代站点不生效,就手动编辑 OpenResty 配置:

server {
    listen 80;
    server_name 你的域名 www.你的域名;

    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php last;
    }

    location / {
        proxy_pass http://你的服务器IP:8080;
        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;
    }
}

改完重载:

docker exec openresty容器 nginx -s reload

八、第五步:Emlog 后台初始化

站点能访问后,登录后台做几项基础设置:

  1. 链接结构:设置 → 链接结构,选「文件格式」(/post-1.html),SEO 友好
  2. 站点地址:设置 → 基本设置,站点地址填 https://你的域名,千万别填 http://服务器IP:8080,否则生成的链接全带 IP 端口
  3. 保存报错处理:如果保存链接结构时提示「.htaccess不可写」,是因为文件归属问题,执行:
chown 33:33 你的数据目录/.htaccess

还不行就 chmod 666。容器里 Apache 运行用户是 www-data(UID 33),root 创建的文件它写不了。

九、第六步:美化邮件通知(可选)

Emlog 自带邮件通知功能(比如评论回复提醒),默认模板比较朴素。可以在后台「设置 → 邮件通知」里替换成自定义 HTML 模板。

模板里有两个变量,发信时自动替换,不用改:

  • {{mail_site_title}} → 站点名称
  • {{mail_content}} → 邮件正文

一个简洁美观的模板结构参考:顶部品牌区(站点名 + 标语)、中间白色正文卡片、底部信息区(站点链接 + 联系方式 + 版权)。具体样式可以根据自己网站的配色调整,核心是保留那两个变量。

十、持久化清单

这套方案所有配置都在宿主机上,容器重建不丢。需要保管好的就这些:

宿主机路径容器路径说明
你的数据目录//appEmlog 全部数据(含 .htaccess)
/opt/emlog/conf/emlog-site.conf/etc/apache2/sites-enabled/000-default.confApache 站点配置
/opt/mysql/data//var/lib/mysql数据库数据

备份时把这几个目录打包即可,迁移到新服务器原样恢复就能跑。

十一、故障排查速查

留一份命令清单,遇到问题按顺序敲:

# 确认容器名(重建后可能变)
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

# 检查 mod_rewrite 是否启用
docker exec emlog容器 apache2ctl -M | grep rewrite

# 查看 DocumentRoot 指向(404 时第一个要看)
docker exec emlog容器 apache2ctl -S 2>&1 | head -20

# 检查 .htaccess(注意是 /app 不是 /var/www/html)
docker exec emlog容器 cat /app/.htaccess

# 检查站点配置是否挂载成功
docker exec emlog容器 cat /etc/apache2/sites-enabled/000-default.conf

# 确认 Emlog 文件存在
docker exec emlog容器 ls /app/index.php

# 查看挂载情况
docker inspect emlog容器 --format '{{json .Mounts}}' | python3 -m json.tool

# 看 Apache 错误日志
docker exec emlog容器 tail -20 /var/log/apache2/error.log

常见问题对照:

症状原因解决
全站 404(Apache 返回)DocumentRoot 指向空的 /var/www/html挂载 emlog-site.conf 覆盖默认配置
首页正常内页 404.htaccess 未生效检查 /app/.htaccess 和 AllowOverride All
链接带 IP:端口站点地址填错后台改成正式域名
502 Bad Gateway反代地址错误proxy_pass 用宿主机内网 IP,不用 127.0.0.1
改配置没效果没重载 OpenRestynginx -s reload
1Panel 改挂载报错UI 把路径当命名卷改用 docker run
.htaccess 不可写文件归属是 rootchown 33:33

十二、踩坑总结

把这次的坑集中列一下:

  1. DocumentRoot 陷阱:Emlog 镜像的 Apache 默认指向空的 /var/www/html,真实文件在 /app,必须用自定义站点配置覆盖。
  2. AllowOverride 默认 None:放了 .htaccess 也不生效,必须显式开启 AllowOverride All
  3. 别用 1Panel UI 改挂载:会报命名卷错误,直接 docker run
  4. proxy_pass 别用 127.0.0.1:容器内 127.0.0.1 指向自己,要用宿主机内网 IP。
  5. 站点地址填正式域名:填 IP:端口会导致链接全带 IP。
  6. .htaccess 写权限:root 建的文件 www-data 写不了,记得 chown 33:33
  7. 改完 OpenResty 要重载:否则不生效。

十三、结语

整体下来,Docker 部署 Emlog 的思路很清晰:MySQL 容器 + Emlog 容器 + OpenResty 反代,三层各司其职,数据全部挂载持久化。唯一的「惊喜」是镜像的 DocumentRoot 指向问题,只要知道真实文件在 /app,用自定义站点配置覆盖一下就能解决。

这套方案跑下来很稳定,迁移和备份也方便——打包几个数据目录就能整体搬走。如果你也在用容器跑 Emlog,希望这篇能帮你少踩点坑。

NAS 自建图床完整实操手册:Lsky Pro + Docker


你为什么需要自建图床?

别人的服务器说关就关,你的 NAS 永远在线。图片数据 100% 自己掌控,零跑路风险,而且 0 月费

一、硬件与环境要求

条件最低要求推荐配置
NAS / 小主机任何能跑 Docker 的设备群晖 / 威联通 / Unraid / 绿联 / 树莓派 4B+
内存1 GB 空闲2 GB+
存储10 GB 空闲50 GB+(看你图片量)
Docker 环境Docker 20.x + Compose v2最新版
外网访问(可选)公网 IPv4 或 IPv6公网 IP + 自有域名

二、Docker 环境准备

如果你已经装了 Docker,直接跳到第三节。

2.1 群晖 NAS(DSM 7.x)

  1. 打开 套件中心
  2. 搜索 Container Manager(DSM 7.2+)或 Docker(DSM 7.1 及以下)
  3. 点击安装,等待完成

2.2 威联通 NAS(QNAP)

  1. 打开 App Center
  2. 搜索 Container Station
  3. 安装即可

2.3 绿联 NAS(UGOS)

  1. 打开 应用中心
  2. 搜索 Docker
  3. 安装

2.4 Linux 小主机 / 树莓派(通用)

# 安装 Docker
curl -fsSL https://get.docker.com | bash

# 安装 Docker Compose
sudo apt install docker-compose-plugin -y   # Debian/Ubuntu
# 或
sudo yum install docker-compose-plugin -y   # CentOS/RHEL

# 验证
docker --version
docker compose version

# 设置非 root 用户也能用 Docker(推荐)
sudo usermod -aG docker $USER
# 然后重新登录

2.5 Windows(WSL2 + Docker Desktop)

  1. 安装 WSL2:管理员 PowerShell 执行 wsl --install
  2. 下载 Docker Desktop:https://www.docker.com/products/docker-desktop
  3. 安装后启动

三、部署 Lsky Pro(推荐 Docker Compose 方式)

我们使用 MySQL + Redis + Lsky Pro 三容器架构,这是生产环境推荐方案。

3.1 创建项目目录

# SSH 登录 NAS 或小主机,创建目录
mkdir -p /volume1/docker/lsky-pro
cd /volume1/docker/lsky-pro
📌 路径替换:群晖一般是 /volume2/docker/.../volume1/docker/...,请改成你自己的路径。

3.2 编写 docker-compose.yml

nano docker-compose.yml

粘贴以下完整配置(⚠️ 务必修改密码):

version: '3.8'

services:
  # ========== MySQL 8.0 数据库 ==========
  mysql:
    image: mysql:8.0
    container_name: lsky-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: LskyRoot2025!    # ⚠️ 改成你自己的强密码
      MYSQL_DATABASE: lsky
      MYSQL_USER: lsky
      MYSQL_PASSWORD: LskyUser2025!         # ⚠️ 改成你自己的强密码
    volumes:
      - ./mysql-data:/var/lib/mysql
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    networks:
      - lsky-net

  # ========== Redis 缓存 ==========
  redis:
    image: redis:7-alpine
    container_name: lsky-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass "LskyRedis2025!"  # ⚠️ 改成你自己的密码
    volumes:
      - ./redis-data:/data
    networks:
      - lsky-net

  # ========== Lsky Pro 图床主程序 ==========
  lsky-pro:
    image: 0xxb/lsky-pro:latest
    container_name: lsky-pro
    restart: unless-stopped
    ports:
      - "8000:8000"    # 主机端口 : 容器端口
    volumes:
      - ./storage:/app/storage/app        # 上传的图片存这里
      - ./themes:/app/themes               # 主题文件
    environment:
      DB_CONNECTION: mysql
      DB_HOST: mysql
      DB_PORT: 3306
      DB_DATABASE: lsky
      DB_USERNAME: lsky
      DB_PASSWORD: LskyUser2025!           # ⚠️ 跟上面 MYSQL_PASSWORD 保持一致
      REDIS_HOST: redis
      REDIS_PASSWORD: LskyRedis2025!       # ⚠️ 跟上面 Redis 密码保持一致
      REDIS_PORT: 6379
    depends_on:
      mysql:
        condition: service_started
      redis:
        condition: service_started
    networks:
      - lsky-net

networks:
  lsky-net:
    driver: bridge

3.3 启动服务

docker compose up -d
# 查看是否全部启动成功(3 个容器都是 Up 状态)
docker compose ps
# 输出应该类似:
# NAME          STATUS
# lsky-mysql    Up (healthy)
# lsky-redis    Up
# lsky-pro      Up

四、初始化安装向导

4.1 访问安装页面

浏览器打开:http://你的NAS_IP:8000

例如:http://192.168.1.100:8000

4.2 填写数据库信息

Lsky Pro 安装向导会要求填入:

配置项说明
数据库地址mysql(容器名,不要填 localhost)
数据库端口3306MySQL 默认端口
数据库名称lsky和 docker-compose.yml 一致
数据库用户名lsky和 docker-compose.yml 一致
数据库密码LskyUser2025!和 docker-compose.yml 一致

4.3 设置管理员

配置项说明
管理员邮箱用于登录 + Token 获取
管理员密码⚠️ 用强密码,这是图床的总钥匙
站点名称随便填,比如"我的图床"

4.4 点击安装

等待几秒 → 显示安装成功 → 自动跳转登录页。

用刚刚设置的管理员邮箱和密码登录。


五、配置存储策略(核心步骤)

登录后,左侧菜单 → 「储存」「储存策略」「新建储存策略」

5.1 本地存储(最简方案,图片直接存 NAS 硬盘)

配置项
角色组勾选管理员组(后面再给普通用户组)
名称本地存储
存储驱动本地(Local)
文件命名规则{Y}/{m}/{d}/{md5}.{ext}
访问域名填你当前的访问地址(后续配了域名再改)
文件路径/app/storage/app/uploads
💡 文件命名建议:{Y}/{m}/{d}/{md5}.{ext} → 按年月日分文件夹,MD5 避免重名。

5.2 接入外部云存储(进阶,双重保险)

Lsky Pro 支持把图片直接存到云存储上,即使 NAS 挂了也能访问。

5.2.1 阿里云 OSS

配置项
AccessKeyId阿里云 RAM 账号的 AccessKey
AccessKeySecret对应的 Secret
Bucket你的 OSS 桶名
地域节点(Endpoint)oss-cn-hangzhou.aliyuncs.com(改成你的区域)
自定义 CDN 域名CDN 加速域名(可选)

5.2.2 腾讯云 COS

配置项
SecretId腾讯云 API 密钥 SecretId
SecretKey对应的 SecretKey
BucketCOS 桶名 + APPID(如 mybucket-1250000000
所属地域ap-guangzhou(改成你的区域)

5.2.3 AWS S3 / Cloudflare R2 / MinIO

配置项
AccessKeyIdS3 兼容密钥
AccessKeySecret对应的 Secret
Bucket存储桶名
地域节点auto(R2 填 auto,真实 S3 填区域)

六、PicGo 客户端配置(自动化上传)

6.1 获取 Lsky Pro 的 API Token

⚠️ 这是最关键的一步,Token 是 PicGo 连接图床的钥匙。

方法一:在 Lsky 后台直接获取(推荐)

  1. 登录 Lsky Pro 后台
  2. 「系统」「接口」 → 查看接口地址
  3. 记录 API 基础 URL:http://你的IP:8000/api/v1
  4. 用下面的工具生成 Token:

方法二:用 curl 命令获取(一条命令搞定)

curl -X POST "http://你的NAS_IP:8000/api/v1/tokens" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"你设置的管理员邮箱","password":"你设置的管理员密码"}'

返回示例:

{
  "status": true,
  "message": "success",
  "data": {
    "token": "1|aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890"
  }
}

方法三:用 Postman(图形界面)

配置
MethodPOST
URLhttp://你的NAS_IP:8000/api/v1/tokens
HeadersAccept: application/json
Content-Type: application/json
Body (raw JSON){"email":"admin@example.com","password":"your_password"}

从响应中复制 token 的值(那一段长字符串)。

6.2 配置 PicGo

6.2.1 安装 Lsky 插件

  1. 打开 PicGo
  2. 左侧 → 「插件设置」
  3. 搜索框输入 lankonglsky
  4. 找到 lankong(或 lsky-pro)插件 → 点击「安装」

6.2.2 配置 Lsky 连接

PicGo → 「图床设置」 → 找到 「lankong」「兰空图床」

配置项示例
Server你的 Lsky 地址http://192.168.1.100:8000
Auth Token上面获取的 token`1aBcDeFgHiJkLmNoPqRsTuVwXyZ1234`
策略 ID存储策略的 ID去 Lsky 后台 → 储存策略 → 看策略 ID 号
💡 策略 ID 可选填,不填则使用默认存储策略。

6.2.3 测试上传

  1. 拖一张图片到 PicGo 上传区
  2. 上传成功 → 链接自动复制
  3. 浏览器打开链接验证

七、Typora / Obsidian 自动上传集成

7.1 Typora 配置

  1. Typora → 文件偏好设置图像
  2. 插入图片时 → 选择 「上传图片」
  3. 上传服务 → 选择 「PicGo (app)」
  4. PicGo 路径 → 选 PicGo 安装目录(Windows 如 C:\Program Files\PicGo\PicGo.exe

✅ 之后在 Typora 粘贴截图,会自动调用 PicGo → Lsky → 返回链接!

7.2 Obsidian 配置

  1. 社区插件搜 Image Auto Upload
  2. 安装后在设置中选 PicGo
  3. 粘贴图片自动上传

7.3 VS Code 配置

安装 Paste ImageMarkdown Image 插件,配置 PicGo 路径。


八、外网访问完整方案

图床建好了,但在公司想用?有三种方式让外面能访问到你的 NAS 图床。

8.1 方案 A:群晖 DDNS + 反向代理(有公网 IPv4,最推荐)

前提:确认你有公网 IPv4

# SSH 登录 NAS,查看你的公网 IP
curl ifconfig.me

然后登录路由器管理页,查看 WAN 口 IP。两个一致 = 有公网 IP。

步骤 1:配置群晖 DDNS

  1. 群晖 DSM → 控制面板外部访问DDNS
  2. 点击「新增」
配置项
服务供应商Synology(免费送 xxx.synology.me 域名)
或选 阿里云 / 腾讯云 / Cloudflare(需自有域名)
主机名称mypic.synology.me
用户名/密码按提示填写
外部地址保持 WAN 自动获取
  1. 点击「测试联机」→ 正常后点「确定」

步骤 2:申请 SSL 证书(HTTPS 必备)

  1. DSM → 控制面板安全性证书
  2. 点击「新增」→ 「从 Let's Encrypt 获取证书」
  3. 域名填 mypic.synology.me
  4. 申请成功后,点「配置」→ 把对应服务绑上证书

步骤 3:配置反向代理

  1. DSM → 控制面板登录门户高级反向代理服务器
  2. 点击「新增」:
来源配置
协议HTTPS
主机名mypic.synology.me
端口443
HSTS勾选
目的地配置
协议HTTP
主机名localhost
端口8000
  1. 保存

步骤 4:路由器端口转发

登录路由器后台 → 端口转发 / 虚拟服务器 → 添加:

配置项
外部端口443(HTTPS)
内部 IP群晖的内网 IP(如 192.168.1.100
内部端口443
协议TCP

✅ 现在浏览器访问 https://mypic.synology.me 就能到你的图床了!

⚠️ 安全提示

  • 别开 8000 端口! 外网一律走 443(HTTPS)
  • 把 PicGo 和 Typora 里的 Server 地址改成 https://mypic.synology.me

8.2 方案 B:公网 IPv6 + DDNS(没有 IPv4 时)

如果你的宽带只有 IPv6(移动宽带常见),也能用。

步骤 1:确认 IPv6

ip -6 addr show | grep global
# 有 240e:xxx 或 2409:xxx 开头的地址就是公网 IPv6

步骤 2:用 DDNS-GO 做动态解析

# Docker 部署 DDNS-GO
docker run -d \
  --name ddns-go \
  --restart=always \
  --net=host \
  -v /volume1/docker/ddns-go:/root \
  jeessy/ddns-go
  1. 浏览器打开 http://你的NAS_IP:9876
  2. DNS 服务商选 阿里云腾讯云Cloudflare
  3. 填写 AccessKey → 输入你的域名
  4. IPv6 选择「通过接口获取」
  5. 保存

步骤 3:群晖反向代理(同方案A)

步骤 4:⚠️ 关键——客户端也需要 IPv6

只有访问你的设备也有 IPv6 时才能访问。手机用 4G/5G 一般都有 IPv6。


8.3 方案 C:内网穿透(啥公网都没有)

如果你没有公网 IP,只能用内网穿透。推荐三个:

服务免费额度速度稳定性
Cloudflare Tunnel免费无限一般(海外中转)⭐⭐⭐⭐⭐
frp(自建)免费(需一台云服务器)⭐⭐⭐⭐
ZeroTier免费 25 设备直连飞快⭐⭐⭐

Cloudflare Tunnel 配置(推荐,完全免费)

  1. 登录 Cloudflare → Zero Trust → Tunnels
  2. 创建 Tunnel → 选 Docker 部署
  3. 运行命令(在你的 NAS 上):
docker run -d \
  --name cloudflared \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run \
  --token 你的Tunnel_Token
  1. 在 Cloudflare Dashboard 配置 Public Hostname:

    • 域名:img.yourdomain.com
    • 服务:http://lsky-pro:8000

✅ 现在 https://img.yourdomain.com 就能访问图床了!(Cloudflare 自动签发 SSL)


九、日常维护与安全

9.1 数据备份(一定要做!)

# 每天凌晨 3 点自动备份(加入 crontab)
# 备份数据库
docker exec lsky-mysql mysqldump -u lsky -p'LskyUser2025!' lsky \
  > /volume1/backup/lsky/lsky_db_$(date +%Y%m%d).sql

# 备份图片文件
tar -czf /volume1/backup/lsky/lsky_images_$(date +%Y%m%d).tar.gz \
  /volume1/docker/lsky-pro/storage/uploads/

# 只保留最近 30 天的备份
find /volume1/backup/lsky/ -name "*.tar.gz" -mtime +30 -delete
find /volume1/backup/lsky/ -name "*.sql" -mtime +30 -delete

9.2 版本更新

cd /volume1/docker/lsky-pro
docker compose down
docker compose pull     # 拉取最新镜像
docker compose up -d    # 重新启动

9.3 安全清单

事项操作
✅ 管理员密码12 位以上,包含大小写字母 + 数字 + 符号
✅ MySQL 密码和 docker-compose.yml 里一样长就行
✅ 外网只开 443路由器别暴露 8000/3306 端口
✅ SSL 证书Let's Encrypt 自动续期
✅ Token 管理定期更换,泄露立刻删除重新生成
✅ 登录失败限制Lsky 后台 → 系统 → 安全设置 → 开启

9.4 容量管理

Lsky Pro 后台 → 用户 → 编辑用户 → 总容量,建议设置:

  • 每个用户:2GB ~ 10GB(够用很久)
  • 上传单文件限制:10MB(大部分图片 <10MB)

十、常见踩坑

问题原因解决
容器启动失败端口冲突`netstat -tlnp \grep 8000` 检查
数据库连接失败密码不一致检查 docker-compose.yml 三处密码
安装时连不上数据库地址填了 localhost改填 mysql(容器名)
图片上传 404存储路径权限chmod -R 755 ./storage
PicGo 上传超时插件 URL 不对Server 后面不要带 /api/v1
反向代理 502容器名解析不到确保反向代理目的填 localhost:8000
外网访问不了运营商封了 80/443换个非标端口(如 8443),端口转发
Token 获取失败邮箱密码不对用管理员邮箱 + 密码(不是 MySQL 密码)

十一、方案总结

┌─────────────────────────────────────────────────────┐
│                    Typora / Obsidian                 │
│                   粘贴图片,自动上传                   │
└───────────────────────┬─────────────────────────────┘
                        │
                        ▼
                ┌───────────────┐
                │     PicGo     │  ← lankong 插件 + Token
                └───────┬───────┘
                        │ HTTP API
                        ▼
┌─────────────────────────────────────────────────────┐
│                    你的 NAS                           │
│  ┌─────────────────────────────────────────────────┐│
│  │  Docker Compose                                 ││
│  │  ┌─────────┐  ┌────────┐  ┌──────────────────┐ ││
│  │  │  MySQL  │◄─┤ Lsky   ├─►│     Redis        │ ││
│  │  │  8.0    │  │  Pro   │  │       7          │ ││
│  │  └─────────┘  └───┬────┘  └──────────────────┘ ││
│  │                   │ 图片文件                      ││
│  │            ┌──────▼──────┐                       ││
│  │            │  本地硬盘    │  ← /volume1/...       ││
│  │            └─────────────┘                       ││
│  └─────────────────────────────────────────────────┘│
└───────────────────────┬─────────────────────────────┘
                        │ 反向代理 + SSL
                        ▼
              ┌─────────────────┐
              │  https://域名   │  ← 外网访问
              └─────────────────┘
                        │ (可选)
          ┌─────────────┼─────────────┐
          ▼             ▼             ▼
    阿里云 OSS    Cloudflare R2   腾讯云 COS
    (远程备份)     (远程备份)      (远程备份)
图片存在你自己的硬盘上,域名是你的,SSL 是你的,一切都在你手里。没有月费,没有数据审查,不会跑路。

手把手教你用 1Panel 在 NAS 上部署 Hermes

全程图形化操作,小白也能搞定。从注册 DeepSeek 到微信聊天,一步一步来。

前言:为什么用 1Panel?

玩 NAS 的朋友都碰到过这样的困境:想装个 Docker 应用,要去网上搜命令、改配置、写 docker-compose……一搞就是半天,还容易报错。

<strong>1Panel</strong> 就是来解决这个的——它是一款<strong>国产开源</strong>的服务器管理面板,类似宝塔,但:

  • 对 Docker 的支持更原生
  • 界面更现代
  • 完全免费
  • 支持应用商店一键部署
  • 有了它,部署 Hermes 就是填几个表格的事。

    一、准备物料清单

    序号物料说明

    1飞牛NAS 或 绿联NAS系统正常、能联网、内存 ≥ 4GB

    2FinalShellWindows 上好用的 SSH 工具,官网:<a href="https://www.hostbuf.com/t/988.html">hostbuf.com</a>

    3DeepSeek 开发者账号调用大模型需要 API Key

    二、先注册 DeepSeek API

    Hermes 的核心是"大模型驱动",它自己不跑 AI,而是调用云端 API。先准备好 API Key。

    (一)为什么选 DeepSeek?

    DeepSeek 是目前最便宜的大模型 API 之一,效果很好:

    410 块钱DeepSeek 充值,够你用几个月

    模型输入价格(每百万 token)输出价格(每百万 token)

    DeepSeek-V3¥1¥4

    deepseek-chat 始终指向最新模型,注册后直接用就行。

    (二)注册步骤

    1. 浏览器访问 <a href="https://platform.deepseek.com">platform.deepseek.com</a>

    2. 点右上角「登录 / 注册」

    3. 手机号注册或微信扫码登录

    4. 注册完自动进入开发者后台

    (三)创建 API Key

    1. 左侧菜单 →「API Keys」

    2. 点「创建新的 API Key」

    3. 起个名字,比如 <code>hermes-nas</code>

    4. ⚠️ <strong>立刻复制保存!</strong> 这串 Key 只显示一次

    5. Key 格式类似:<code>sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code>

    <strong>把 Key 粘贴到记事本里存好</strong>,后面配置要用。

    (四)充值

    1. 左侧菜单 →「充值」

    2. 选金额:最低 10 元

    3. 微信/支付宝扫码支付

    ✅ DeepSeek 这边就搞定了。

    三、NAS 开启 SSH

    1Panel 需要通过 SSH 远程安装。

    (一)飞牛 NAS

    1. 浏览器打开飞牛 Web 管理页

    2. 左侧菜单 →「设置」→「终端」

    3. 勾选「开启 SSH」

    4. 默认端口 22

    (二)绿联 NAS

    1. 浏览器打开绿联 UGOS 管理页

    2. 「控制面板」→「终端机与SNMP」

    3. 勾选「启用 SSH 服务」

    4. 默认端口 22

    两种 NAS 操作差不多,找到 "SSH" 关键字打开就行。

    四、SSH 连接 NAS

    (一)Windows CMD(自带,无需安装)

    Windows 10/11 自带 SSH,按 <code>Win+R</code> 输入 <code>cmd</code> 回车,直接输入:

    
    ssh root@你的NAS_IP
    
    如果端口不是默认 22,加 <code>-p 端口号</code>,例如:<code>ssh root@192.168.1.100 -p 2222</code>

    第一次连接会提示确认,输入 <code>yes</code> 回车,然后输入 NAS 密码即可。

    (二)FinalShell(推荐新手)

    FinalShell 是 Windows 上好用的 SSH 客户端,界面友好、有中文、带文件管理,比 CMD 更好上手。

    官网:<a href="https://www.hostbuf.com/t/988.html">hostbuf.com</a>,下载 Windows 版,一路默认安装。

    (三)创建连接

    1. 打开 FinalShell → 左上角文件夹图标(新建连接)

    2. 选择「SSH 连接 (Linux)」

    3. 填写信息:

    DeepSeek-R1(推理增强)¥4¥16

    字段填什么

    名称随便写,比如「我的飞牛NAS」

    主机NAS 的 IP 地址(去路由器后台看,一般是 192.168.x.x)

    端口22

    用户名root

    4. 点「确定」→ 双击连接

    看到 <code>root@FNOS:~#</code> 就表示连上了!

    五、安装 1Panel 面板

    (一)获取安装命令

    浏览器打开 <a href="https://1panel.cn">1panel.cn</a>,首页就能看到大大的安装按钮,复制命令:

    
    curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && bash quick_start.sh
    

    (二)粘贴执行

    回到 SSH 终端(CMD 或 FinalShell),粘贴命令回车。

    安装程序会自动执行以下操作:

  • 检测你的 NAS 系统架构(x86/ARM64)
  • 自动安装 Docker(如果还没装)
  • 下载 1Panel 安装包
  • 配置面板服务
  • 整个过程 3-5 分钟,全程无需手动干预,等着就行。

    (三)设置面板账号

    安装到后半段,会弹出交互式配置,逐项输入:

    1. <strong>「请设置 1Panel 面板端口」</strong> → 直接回车,用默认 <code>10086</code>

    2. <strong>「请设置 1Panel 面板安全入口」</strong> → 设置一个后缀,比如 <code>/mypanel</code>。这是面板地址的路径部分,增加安全性。不设也行但建议设

    3. <strong>「请设置 1Panel 面板用户名」</strong> → 填 <code>admin</code>(或自定义)

    4. <strong>「请设置 1Panel 面板密码」</strong> → <strong>重点!</strong> 设复杂密码——大小写字母 + 数字 + 特殊符号,这是面板的唯一防线

    (四)保存登录信息

    安装完成后屏幕打印:

    
    ================================================
    面板地址: http://192.168.x.x:10086/mypanel
    用户名: admin
    密码: 你设的密码
    ================================================
    

    📸 <strong>截图或拍照保存!</strong> 马上要用。

    (五)访问面板验证

    浏览器打开面板地址 → 输入账号密码 → 看到蓝白仪表盘 → 安装成功!

    左侧「容器」菜单能看到 Docker 状态,说明 1Panel 已经把 Docker 也管理起来了。

    六、登录 1Panel

    1. 浏览器打开面板地址

    2. 输入用户名 <code>admin</code> 和密码

    3. 登录成功,看到蓝白配色的管理面板

    左侧菜单 →「容器」→ 能看到 Docker 运行状态,说明一切正常。

    (可选)配镜像加速

    国内访问 Docker Hub 有时很慢:

    1. 「容器」→「配置」→「镜像加速」

    2. 填入:

    
    https://docker.1panel.live
    

    3. 点「重启 Docker」

    七、部署 Hermes(三种方式任选)

    <strong>这就是装 1Panel 的目的!</strong> 1Panel 让 Hermes 部署变成了填表——不需要懂 Docker 命令,不需要写 docker-compose,甚至配置 DeepSeek API 都可以在面板里完成。对新手极其友好。

    下面提供三种方式,推荐新手用方式一。

    方式一:1Panel 应用商店一键安装(最推荐!⭐)

    这才是 1Panel 的核心优势——像手机装 App 一样部署 Hermes。

    1. 左侧菜单 →「应用商店」

    2. 搜索框输入 <code>hermes</code>

    3. 找到 <strong>Hermes Agent</strong>,点「安装」

    4. 填写配置:

    密码NAS 的管理员密码

    字段

    名称hermes

    端口8020

    5. 点「确认」→ 等 1-2 分钟 → 完成!

    这就是全部。不需要手动配端口映射、不需要配卷挂载、不需要写环境变量——1Panel 全部帮你处理好了。

    甚至配置 AI 模型都可以在应用商店的安装界面里直接填 DeepSeek API Key,不用进容器终端敲命令。

    方式二:Web 端手动创建(适合想了解参数的同学)

    1. 创建容器

    左侧菜单 →「容器」→「创建容器」,填写:

    数据目录/opt/hermes

    字段

    名称hermes

    ⚠️ 如果镜像拉不下来,换:<code>dockerpull.com/nousresearch/hermes-agent:latest</code>

    2. 端口映射

    「端口」栏 →「添加端口映射」:

    镜像ghcr.io/nousresearch/hermes-agent:latest

    主机端口容器端口

    3. 目录挂载

    「卷挂载」→「添加卷挂载」:

    80208020

    主机路径容器路径

    4. 环境变量

    「环境变量」→「添加环境变量」:

    /opt/hermes/opt/data

    变量名

    5. 启动

    点右下角「确认」,等待 1-2 分钟,容器状态变绿色「运行中」即可。

    方式三:一键 SSH 命令

    如果你更喜欢命令行,直接在 SSH 终端粘贴以下一整段:

    
    docker run -d \\
      --name hermes \\
      --restart=unless-stopped \\
      -p 8020:8020 \\
      -v /opt/hermes:/opt/data \\
      -e TZ=Asia/Shanghai \\
      ghcr.io/nousresearch/hermes-agent:latest
    
    如果镜像拉不下来,把最后一行换成 <code>dockerpull.com/nousresearch/hermes-agent:latest</code>

    执行后等 1-2 分钟,<code>docker ps | grep hermes</code> 看到状态 <code>Up</code> 就行。

    两种方式效果完全一样,选你喜欢的就好。

    八、配置 Hermes

    部署完成后需要配置 AI 模型,让 Hermes 接上 DeepSeek。同样两种方式任选。

    方式一:Hermes Web 管理界面配置(推荐!🌟)

    不用进终端,在浏览器里鼠标点击就能配好:

    1. 浏览器打开 <code>http://你的NAS_IP:8020</code>

    2. 左侧菜单 →「设置」→「模型配置」

    3. 1Panel / Hermes 提供了专门的模型配置页面,直接填表:

    TZAsia/Shanghai

    字段

    模型提供商自定义 (Custom)

    API 地址https://api.deepseek.com/v1

    默认模型deepseek-chat

    4. 点「保存」→ 立即生效!

    一行命令都不用敲,跟填注册表一样简单。这就是 1Panel 对新手最友好的地方。

    方式二:容器终端命令

    如果你想了解底层,也可以用命令行:

    1. 左侧「容器」→ 找到 <code>hermes</code>

    2. 点右边「终端」按钮 →「连接」

    3. 一行一行粘贴执行(<strong>把 Key 换成你自己的</strong>):

    
    hermes config set model.provider custom
    hermes config set model.base_url https://api.deepseek.com/v1
    hermes config set model.default deepseek-chat
    hermes config set model.api_key sk-你的APIKey粘贴到这里
    

    <strong>各参数含义:</strong>

  • <code>provider custom</code>:使用自定义 API
  • <code>base_url</code>:DeepSeek 的 API 地址
  • <code>default</code>:默认模型(deepseek-chat,始终使用最新版本)
  • <code>api_key</code>:你之前注册充值的那个 Key
  • 两种方式效果完全一样,推荐新手用方式一,填几个框就完事。

    (三)接入微信

    在同一个终端执行:

    
    hermes gateway setup
    

    终端会出现一个二维码。用<strong>微信扫这个码</strong>,按提示操作:

    1. 微信提示"发现一个新设备"

    2. 选择绑定到哪个聊天

    3. 确认授权

    绑定成功后执行:

    
    hermes gateway restart
    

    🎉 现在在微信里 @Hermes 就能跟它聊天了!

    九、验证一切正常

  • 🌐 浏览器打开下面这个地址,看到 Hermes Web 界面就成功了:
  • 
    http://你的NAS_IP:8020
    
  • 💬 微信里发一条消息 → 它应该会回复
  • 十、常见问题

  • <strong>镜像一直拉不下来?</strong> 换以下镜像之一:
  • 
    docker.1panel.live/nousresearch/hermes-agent:latest
    dockerpull.com/nousresearch/hermes-agent:latest
    
  • <strong>容器启动后马上退出?</strong> 点容器 →「日志」看错误信息,通常是网络不通或 API Key 没配对
  • <strong>FinalShell 连接提示 Connection refused?</strong> 检查 NAS 的 SSH 有没有开启,飞牛和绿联默认都是关闭的
  • <strong>微信扫码后没反应?</strong> 执行以下命令重启网关:
  • 
    hermes gateway restart
    
  • <strong>怎么升级到最新版?</strong> 1Panel → 容器 → hermes → 更多 → 重建 → 勾选「拉取最新镜像」
  • <strong>群晖/威联通/Unraid/OMV 能用吗?</strong> 完全可以!只要系统支持 Docker + 能开 SSH 就行
  • 十一、成本核算

    API Keysk-你的APIKey粘贴到这里

    项目费用

    NAS 硬件已有

    1Panel 面板免费

    Hermes 软件免费开源

    DeepSeek API≈ 10 元/2-3个月

    比腾讯云 VPS 一个月 50-100 元省太多了,而且数据全在自己手里!

    总结

    回顾整个过程:

    1. 注册 DeepSeek,拿到 API Key

    2. NAS 开 SSH → CMD/FinalShell 连接

    3. 一条命令装好 1Panel

    4. 应用商店一键安装 Hermes

    5. 配好 API Key + 绑微信

    6. 完成!

    全程不需要懂 Docker 命令,不需要写 docker-compose,不需要 vi 编辑器。<strong>1Panel 让部署 Hermes 变成了手机装 App 一样简单。</strong>

    这就是推荐 1Panel 的原因——对 NAS 玩家来说,简单就是王道。装 1Panel 就是为了用 1Panel 应用商店部署 Hermes,从注册 DeepSeek 到微信聊天,一条龙全搞定。

    <strong>排版:追梦学习库 文字:追梦学习库</strong>

    <strong>总计月均</strong><strong>≈ 3-5 元</strong>