OpenVPN + TLJH + isso 从 Debian 迁移到 Ubuntu
2026-03-26 完成了从 Debian (jhub.dtype.info) 到 Ubuntu (mail) 的服务迁移记录。
一、OpenVPN 迁移
1.1 备份与传输
在源服务器上备份配置:
1
| sudo tar -czvf openvpn-backup.tar.gz /etc/openvpn/
|
1.2 恢复时的问题与解决
| 问题 |
原因 |
解决方案 |
/etc/openvpn/server.conf 不存在 |
配置文件实际在 /etc/openvpn/server/server.conf |
创建符号链接 |
Cannot pre-load keyfile (tc.key) |
相对路径解析错误 |
改用绝对路径 /etc/openvpn/server/tc.key |
Cannot assign requested address |
local 10.146.0.3 是旧服务器 IP |
改为新服务器 IP 160.251.141.121 |
1.3 修复后的配置
1 2 3 4 5 6 7 8 9 10
| sudo ln -s /etc/openvpn/server/server.conf /etc/openvpn/server.conf
ca /etc/openvpn/server/ca.crt cert /etc/openvpn/server/server.crt key /etc/openvpn/server/server.key dh /etc/openvpn/server/dh.pem tls-crypt /etc/openvpn/server/tc.key crl-verify /etc/openvpn/server/crl.pem
|
1.4 NAT 转发配置
OpenVPN 客户端连接后无法上网,需要添加 NAT 规则:
1 2 3 4 5 6
| sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo apt install iptables-persistent sudo iptables-save > /etc/iptables/rules.v4
|
1.5 防火墙放行
1 2 3
| sudo ufw allow 1194/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp
|
二、TLJH (The Littlest JupyterHub) 迁移
2.1 安装 TLJH
Ubuntu 上使用官方安装脚本:
1 2
| curl -sL https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/main/bootstrap/bootstrap.py -o /tmp/bootstrap.py python3 /tmp/bootstrap.py
|
2.2 复制配置与状态
1 2
| ssh jhub "sudo tar -C /opt/tljh -czvf - config state" | ssh mail "sudo tar -xzvf - -C /opt/tljh/"
|
2.3 Traefik 配置问题
问题 1:端口 443 被 Tailscale Funnel 占用
1 2 3 4 5 6
| [entryPoints.http] address = "160.251.141.121:80"
[entryPoints.https] address = "160.251.141.121:443"
|
问题 2:traefik v3 不支持 toPort 参数(HTTP 重定向)
删除 traefik.toml 中的 toPort = 443 配置。
问题 3:缺少 HTTP 路由器定义
rules.toml 中需要显式定义路由器:
1 2 3 4
| [http.routers.router__2F] service = "service__2F" rule = "PathPrefix(`/`)" entryPoints = [ "https",]
|
2.4 防火墙放行
1 2
| sudo ufw allow 80/tcp sudo ufw allow 443/tcp
|
三、isso 评论系统迁移
3.1 安装 isso
1
| sudo pip3 install --break-system-packages isso gunicorn
|
3.2 创建 systemd 服务
1 2 3 4 5 6 7 8 9 10 11 12
| [Unit] Description=lightweight Disqus alternative
[Service] User=root Restart=always Environment="ISSO_SETTINGS=/etc/isso.conf" ExecStart=/usr/local/bin/gunicorn --bind 127.0.0.1:8000 --log-file /var/log/isso.log --preload isso.run
[Install] WantedBy=multi-user.target
|
3.3 配置文件与数据
1 2 3 4 5 6
| scp jhub:/etc/isso.conf mail:/tmp/ && ssh mail "sudo mv /tmp/isso.conf /etc/isso.conf"
scp jhub:/var/lib/isso/comments.db mail:/tmp/comments.db ssh mail "sudo mv /tmp/comments.db /var/lib/isso/comments.db"
|
3.4 Traefik 路由规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| [http.routers.isso] service = "isso" rule = "Host(`jhub.dtype.info`) && PathPrefix(`/isso/`)" entryPoints = [ "https",] middlewares = ["isso"]
[http.middlewares] [http.middlewares.isso.stripPrefix] prefixes = ["/isso"]
[http.services.isso.loadBalancer] passHostHeader = true [[http.services.isso.loadBalancer.servers]] url = "http://127.0.0.1:8000"
|
四、其他 Traefik 路由
4.1 LINE Webhook 转发
1 2 3 4 5 6 7 8 9 10
| [http.routers.line-webhook] service = "line-webhook" rule = "Host(`jhub.dtype.info`) && PathPrefix(`/line/`)" entryPoints = [ "https",]
[http.services.line-webhook.loadBalancer] passHostHeader = true [[http.services.line-webhook.loadBalancer.servers]] url = "http://100.94.198.8:18790"
|
五、服务状态
| 服务 |
端口 |
状态 |
| OpenVPN |
TCP 1194 |
✅ 运行中 |
| Traefik |
80/443 |
✅ 运行中 |
| JupyterHub |
15001 |
✅ 运行中 |
| isso |
8000 |
✅ 运行中 |
六、注意事项
- SSL 证书:acme.json 从旧服务器复制,Let’s Encrypt 证书可继续使用
- 客户端配置:OpenVPN 和 JupyterHub 客户端的
remote 地址需要更新为新服务器 IP
- DNS:确保
jhub.dtype.info 和 registry.dtype.info 指向新服务器 IP
- 二进制文件传输:使用
scp 而不是管道 cat,避免数据损坏
- iptables-persistent:替代 UFW 使用,更可靠地保存防火墙规则
Ubuntu Server + BCM4360 Wi-Fi + SSH + Tailscale + Claude Code + 免密 sudo
下面按这次针对我的 MacBook Pro (Retina, 13-inch, Late 2013 / A1502) 实际操作的顺序,整理成一份完整的关键命令清单。
1. 在 macOS 上确认机器和 USB
1 2 3
| system_profiler SPHardwareDataType diskutil list diskutil info /dev/disk4
|
我的机器确认是:
1 2 3
| MacBookPro11,1 MacBook Pro (Retina, 13-inch, Late 2013) Model A1502
|
2. Ubuntu 安装后确认网络接口
1 2
| ip link ls /sys/class/net
|
最初只有:
连接手机 USB 网络共享后出现:
3. 用手机 USB 网络临时联网
1 2
| sudo ip link set enxXXXXXXXXXXXX up sudo dhcpcd enxXXXXXXXXXXXX
|
确认 IPv4:
1
| ip -4 addr show enxXXXXXXXXXXXX
|
确认路由:
测试 Internet:
4. 安装 BCM4360 驱动
确认内核:
这次是:
确认驱动版本:
1
| apt policy bcmwl-kernel-source | grep Candidate
|
安装:
1 2
| sudo apt update sudo apt install bcmwl-kernel-source
|
5. 让 wl 接管 BCM4360
这台 Mac 的 BCM4360 最初被 b43/bcma 路径占用。
卸载 b43:
加载 Broadcom 专有驱动:
确认:
最终出现:
并且内核日志出现:
1 2
| wlan0: Broadcom BCM43a0 B02.11 Hybrid Wireless Controller 6.30.223.271 wl 0000:03:00.0 wlp3s0: renamed from wlan0
|
说明成功。
6. 启用 Wi-Fi
1
| sudo ip link set wlp3s0 up
|
确认:
7. 扫描 Wi-Fi
如果没有 iw:
扫描:
1
| sudo iw dev wlp3s0 scan | grep SSID
|
8. 配置 NetworkManager
1 2
| sudo apt install network-manager sudo systemctl enable --now NetworkManager
|
查看:
连接 Wi-Fi:
1
| nmcli device wifi connect "我的SSID" password "我的WiFi密码"
|
确认:
以及:
此时就可以拔掉手机 USB 网络共享。
9. 安装并启动 SSH
1
| sudo systemctl enable --now ssh
|
确认:
应该得到:
查看 Wi-Fi/LAN IP:
从另一台电脑:
如果因为重装系统出现:
1
| WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
|
执行:
1
| ssh-keygen -R 192.168.1.8
|
然后重新:
10. 安装 Tailscale
1
| curl -fsSL https://tailscale.com/install.sh | sh
|
登录:
查看:
1 2
| tailscale status tailscale ip
|
11. 安装 Claude Code
1
| curl -fsSL https://claude.ai/install.sh | bash
|
确认:
启动:
12. 设置 seii 免密 sudo
1
| sudo visudo -f /etc/sudoers.d/seii
|
加入:
1
| seii ALL=(ALL) NOPASSWD: ALL
|
保存时如果看到:
1
| File Name to Write: /etc/sudoers.d/seii.tmp
|
直接按:
然后:
检查:
测试:
应该直接输出:
现在这台 A1502 的状态已经是:Ubuntu Server + BCM4360 Wi-Fi + SSH + Tailscale + Claude Code + 免密 sudo。后续就可以基本脱离 HDMI 外接显示器,通过 SSH/Tailscale 管理这台 MacBook。