这篇文章记录的是我从零开始搭一个 sub2api 自建中转站的完整过程。 目标很明确:
- 白嫖一台云服务器和一个域名。
- 用 VS Code 远程连接服务器,尽量减少纯命令行操作的痛苦。
- 用 Docker 部署
sub2api。 - 用域名和 HTTPS 对外提供访问。
- 顺手把几个最容易卡住的坑一次性讲清楚。
如果你和我一样,之前对 Linux、Nginx、SSL 证书都不算熟,这篇文章应该能帮你少走很多弯路。
一、准备工作
这次用到的核心资源有两个:
- 一台 Ubuntu 云服务器
- 一个自己的域名
这两个资源我这次主要是通过 GitHub Education Pack 官方入口 领取到的。
我这次用的是 GitHub Education Pack 里提供的优惠和额度。 学生认证通过之后,通常能拿到一些云厂商和域名服务商的试用权益,足够把这一套先跑起来。
下图中间是服务器相关权益,右边是域名相关权益:

如果你只是想先把整套链路跑通,不追求长期稳定商用,那么学生包确实是一个很划算的起点。
Name.com 的学生权益入口 也可以直接从这里进。

服务器购买这一步我参考的是 SkYFly2233/NEU-ipv6-proxy 里的流程,至少先把服务器买好并确认能 ping 通。
二、先把域名和服务器准备好
当你手里已经有了一个域名和一台服务器,第一件事不是立刻装程序,而是先把域名解析链路打通。
2.1 修改域名的 Nameserver
域名需要先把 Nameserver 指向你的云服务商,这样后续就能直接在云服务商的控制台里配置 DNS 记录。
我这里的做法是把域名托管到服务器提供商对应的 DNS 平台,方便后续统一管理。
操作过程大概如下:



不同平台的界面不一样,但思路是一样的: 找到域名服务商后台,把原有的 Nameserver 替换为云服务商给你的那几条记录。
以 DigitalOcean 为例,默认一般是这三条:
ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com
如果你不确定具体应该填什么,可以直接去你购买服务器的平台文档里查:

2.2 配置 A 记录
Nameserver 切过去之后,就可以在云服务商的 DNS 面板里配置域名解析了。
最关键的是两条:
@指向你的服务器公网 IPwww指向同一台服务器公网 IP
配置示意如下:


配置完成后,不要急着继续。 先确认解析有没有真正生效。
Windows PowerShell 可以直接这样测:
Resolve-DnsName liutan.codes -Type A -Server 8.8.8.8 | Format-List *
如果正常,结果里应该能看到你服务器的公网 IP。比如:
Address : 64.23.155.30
IPAddress : 64.23.155.30
QueryType : A
IP4Address : 64.23.155.30
Name : liutan.codes
Type : A
TTL : 3600
这一步成功后,说明你的域名已经正确指向服务器了。
三、为什么我强烈建议用 VS Code 远程连接服务器
很多服务器厂商后台都会提供在线终端,紧急情况下确实能救命:


后面部署 sub2api 的过程,本质上就是一堆 Linux 运维操作。 如果你一直用网页终端硬敲,体验其实比较差,尤其是:
- 容易复制错命令
- heredoc 和多行命令非常容易翻车
- 查日志、改配置文件都不方便
所以我最后的选择是:
- 本地用 Windows
- 编辑器用 VS Code
- 通过
Remote-SSH远程连到服务器
这样体验会好很多,基本可以把云服务器当成本地文件夹来操作。
3.1 生成 SSH 密钥
本地 PowerShell 执行:
ssh-keygen -t ed25519 -C "your_name@windows"
执行后会依次提示你输入几个东西:
Enter file in which to save the key:直接回车,使用默认路径即可。Enter passphrase:可选。如果只是自己用、图省事,也可以留空直接回车。Enter same passphrase again:如果前面设置了口令,这里再输一遍。
完成后,会生成两份文件:
- 私钥:
C:\Users\你的用户名\.ssh\id_ed25519 - 公钥:
C:\Users\你的用户名\.ssh\id_ed25519.pub
查看公钥:
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub
3.2 把公钥放到服务器
这一步建议先在服务器的网页终端里完成,因为此时你本地 SSH 还不一定已经打通。
先在服务器上准备好 .ssh 目录和授权文件:
install -d -m 700 /root/.ssh
touch /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
chown -R root:root /root/.ssh
然后打开这个文件:
nano /root/.ssh/authorized_keys
把刚才在本地 Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub 输出的整行公钥完整粘贴进去。 注意这里一定要满足两个条件:
- 公钥必须完整,不要截断。
- 公钥必须单独占一整行,前后不要和别的内容粘在一起。
保存退出后,可以再执行一次:
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
grep -n 'your_name@windows' /root/.ssh/authorized_keys
如果 grep 能搜到你刚才那行公钥,说明这一步基本没问题了。
这一步如果出错,我自己踩到的典型原因有:
- 公钥没有单独占一整行
authorized_keys被错误覆盖成空文件- 权限不对
如果你想先不写别名,直接测试原始连接,也可以在本地 PowerShell 里这样连:
ssh -i $env:USERPROFILE\.ssh\id_ed25519 -p 2222 root@64.23.155.30
如果你的服务器还是默认 SSH 端口,就把 -p 2222 改成 -p 22,或者干脆删掉这段端口参数。
3.3 配置本地 SSH 别名
我最后在本地的 C:\Users\ly\.ssh\config 里用了这样的配置:
Host do-server
HostName 64.23.155.30
User root
Port 2222
IdentityFile C:\Users\ly\.ssh\id_ed25519
这里的 2222 是我后面实际使用的 SSH 端口。 如果你没有改过端口,那一般还是默认的 22。 如果你前面测试直连时已经确认端口没问题,那这里一定要和实际端口保持一致。
配置完成后,直接测试:
ssh do-server
如果能正常进入服务器,说明 SSH 这一关就算打通了。
3.4 VS Code 远程连接
安装 Remote - SSH 插件之后,在 VS Code 里连接这个 do-server。 连上之后,左下角会显示:
SSH: do-server

这时候你打开的就不是本地目录,而是服务器上的远程目录了。 后面的 Docker 配置、Nginx 配置、查看日志,都可以在这个窗口里完成。
这里建议顺手再做两个确认:
- VS Code 左下角确实显示
SSH: do-server - 远程终端里执行
pwd时,看到的是 Linux 路径,比如/root或/opt/sub2api-deploy
只要这两个都对了,说明你现在操作的就是真正的远程服务器,不是本地窗口。
做到这一步之后,后面很多调试工作其实都可以直接交给 AI agent 来辅助完成了。 比如 Codex、Claude Code 之类的工具,都可以通过你本地已经配置好的 SSH 环境,直接在远程服务器上读文件、改配置、看日志和执行命令。
但这一点一定要谨慎:如果使用不当,AI agent 同样可能对云服务器环境造成不可逆的破坏。 尤其是涉及删除、覆盖、重置、批量改配置这类操作时,最好先确认命令再执行。
codex中使用

给他一个task


四、在 Ubuntu 服务器上安装 Docker
sub2api 官方已经提供了 Docker 部署方式,所以不需要手动装 Go 环境,直接走容器会省心很多。
先更新系统:
apt update
apt install -y ca-certificates curl
然后按 Docker 官方仓库方式安装:
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
写入 Docker 源:
cat >/etc/apt/sources.list.d/docker.sources <<'EOF'
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: noble
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
安装 Docker:
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
检查是否安装成功:
docker --version
docker compose version
systemctl status docker --no-pager
五、部署 sub2api
接下来正式开始部署 sub2api:
项目地址:Wei-Shaw/sub2api
我这次把部署目录放在:
/opt/sub2api-deploy
这样目录干净,也符合 Linux 里“服务类程序放在 /opt”的习惯。
5.1 初始化部署目录
mkdir -p /opt/sub2api-deploy
cd /opt/sub2api-deploy
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/docker-deploy.sh | bash
这个脚本会自动生成:
docker-compose.yml.env.env.exampledata/postgres_data/redis_data/
同时还会帮你生成一些安全密钥,比如:
POSTGRES_PASSWORDJWT_SECRETTOTP_ENCRYPTION_KEY
5.2 启动容器
cd /opt/sub2api-deploy
docker compose up -d
查看状态:
docker compose ps
docker ps
如果一切正常,你会看到三个核心容器:
sub2apisub2api-postgressub2api-redis
并且状态一般会显示为:
Up (healthy)
5.3 初始访问
如果你还没做反向代理,可以直接先访问:
http://服务器公网IP:8080
能打开说明 sub2api 本体已经跑起来了。
如果你第一次启动后忘了管理员密码,也可以直接在服务器上查启动日志:
docker logs sub2api 2>&1 | grep -i "admin password"
正常会看到类似输出:
Generated admin password (one-time): 6d60f341ba924a7a6042c8621b9d0d75
这就是首次自动生成的管理员密码。 登录后台之后,这个密码也可以在面板设置里再修改成你自己更容易记住的版本。
六、给 sub2api 绑定域名
直接用 :8080 虽然能用,但不太像一个正经服务。 更常见的做法是:
- 外部访问
https://你的域名 - Nginx 转发到本机的
127.0.0.1:8080
这样你最终只对外暴露 80 和 443 端口。
6.1 安装 Nginx
apt install -y nginx
systemctl enable --now nginx
6.2 配置反向代理
我最终使用的思路是:
- 域名入口:
https://liutan.codes - 后端服务:
http://127.0.0.1:8080
一个最小可用的 Nginx 配置大概是这样:
server {
listen 80;
server_name liutan.codes www.liutan.codes;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
写完之后检查并重载:
nginx -t
systemctl reload nginx
这时访问:
http://liutan.codes
理论上就应该能看到 sub2api 页面了。
七、配置 HTTPS 证书
证书这一步我一开始也觉得复杂,后来发现真正走下来并不难。 最省事的组合就是:
NginxCertbotLet's Encrypt
7.1 安装 Certbot
apt install -y certbot python3-certbot-nginx
7.2 申请证书
certbot --nginx -d liutan.codes -d www.liutan.codes
按提示输入邮箱、同意协议之后,它会自动:
- 申请证书
- 改写 Nginx 配置
- 配置 80 跳转到 443
成功后会看到类似输出:
Successfully received certificate.
Congratulations! You have successfully enabled HTTPS on https://liutan.codes and https://www.liutan.codes
证书是免费的。 使用的是 Let's Encrypt,默认有效期 90 天,但 Certbot 会自动续期。
检查自动续期:
systemctl status certbot.timer
只要它是 active (waiting),一般就不用太操心。
八、我踩过的几个坑
这一部分我觉得比教程本身还重要,因为真正折腾人的往往不是“标准步骤”,而是那些看起来很小但会把你卡半天的问题。
8.1 VS Code Remote-SSH 一直连接失败
我一开始遇到的情况是:
- 本地
ssh命令连不上 - VS Code Remote-SSH 一直报错
- 远程连接日志里不断出现
Connection closed
后来排查下来,核心问题主要有三个:
authorized_keys内容写坏了,公钥没有独立成行。- SSH 端口被我改过,VS Code 还在按旧端口连接。
- 自己反复点了 “Uninstall VS Code Server”,把远程组件清掉了。
真正稳定下来之后,反而很简单:
- 本地
ssh do-server先能成功 ~/.ssh/config写正确- VS Code 连接同一个 Host 别名
只要命令行 SSH 能通,VS Code 大概率也能通。
8.2 SMTP 发信一直失败
sub2api 的邮箱配置我也踩了一个大坑。 刚开始以为是 Gmail 或 QQ 邮箱配置错了,后来才发现不是账号问题,而是云服务器网络出口的问题。
我这台 DigitalOcean Droplet 上的情况是:
smtp.gmail.com:465超时smtp.gmail.com:587超时smtp.qq.com:465/587同样不稳定
但 2525 这类替代端口能通。
这意味着: 很多云厂商会默认限制传统 SMTP 端口,防止新号被拿去发垃圾邮件。
如果你也遇到类似问题,建议直接考虑这两条路:
- 用支持
2525端口的服务商,例如 SendGrid、Mailgun。 - 如果只是自用测试,先关闭邮箱验证相关功能。
8.3 本地开了 TUN,到底走的是谁的流量
这也是我后来专门确认过的问题。
如果你本地浏览器访问的是:
https://www.liutan.codes
那么这段流量是否走代理,取决于你本地代理软件的规则。 如果规则命中了代理节点,比如日志里出现:
[TCP] 127.0.0.1:50099 --> www.liutan.codes:443 match using 某节点
那说明:
- 你本地到自己服务器域名这一段,走的是你本地代理流量
- 会消耗你本地代理套餐
但服务器上的 sub2api 自己再去访问上游接口时,走的是服务器网络,不是你本地 TUN。
所以这其实是两段流量:
- 你本地访问自己域名:可能走本地代理
- 服务器访问外部服务:走服务器出口
如果你不想让访问自己服务器也消耗代理流量,最简单的办法是把自己的域名加到 DIRECT 规则里。
九、部署完成后,怎么判断服务是不是正常常驻
sub2api 是跑在 Docker 里的,所以后面排查状态时,我最常用的是这几条命令:
查看容器状态:
docker ps
查看项目状态:
cd /opt/sub2api-deploy
docker compose ps
看日志:
cd /opt/sub2api-deploy
docker compose logs -f sub2api
重启:
cd /opt/sub2api-deploy
docker compose restart sub2api
只要容器状态显示:
Up (healthy)
基本就说明服务是正常常驻的。
十、我最后得到的是什么
做到这里,你最终会得到一套完整的可用方案:
- 一台自己的 Ubuntu 云服务器
- 一个已经正确解析的域名
- 一套能稳定连接的 SSH / VS Code 远程开发环境
- 一个通过 Docker 跑起来的
sub2api - 一个通过
Nginx + Certbot暴露出来的 HTTPS 入口
也就是说,你后续访问时,不再需要记:
http://ip:8080
而是直接:
https://你的域名
体验和维护成本都会好很多。
十一、写在最后
这次折腾下来,我最大的感受是:
自建服务真正难的,往往不是把程序跑起来,而是把整条链路打通:
- 域名解析
- SSH 登录
- VS Code 远程连接
- Docker 部署
- 反向代理
- HTTPS
- 邮件和网络限制
只要这几件事理顺了,后面继续在同一台服务器上加别的服务,其实就会轻松很多。 比如我后面又把别的 Python 小工具挂到了同一个域名的子路径下,本质上还是同样的思路。
如果你只是想先跑通一版,建议顺序一定按下面来:
- 先确认域名解析正常。
- 再确认 SSH 能稳定连上。
- 然后再装 Docker 和部署
sub2api。 - 最后再折腾 Nginx 和 HTTPS。
不要一上来就一股脑全部同时改,不然一旦出错,很难判断到底是哪一层出了问题。
如果后面我把这套流程继续整理得更系统一点,我会再单独写:
sub2api的配置项说明- SMTP 发信的替代方案
- 如何在同一台服务器上挂多个 Web 工具
- 如何把运维过程尽量迁移到 VS Code 里完成
至少到这里,这台“自建中转站”已经算是一个能长期用下去的版本了。