一台 2C2G 云主机跑 4 个服务:Caddy 自签反代 + systemd user 托管

举报
yd_282927746 发表于 2026/10/31 08:22:46 2026/10/31
【摘要】 没有备案域名、只有 2G 内存,怎么同时跑管理面板、MQTT、记账和 Agent 四个服务?Caddy 内置 CA 给高端口签证书做反代,systemd --user 加 linger 托管保活,再配合 swap、journald 限容和两层防火墙的放通顺序。

为什么不用 80/443,也不装 Nginx 面板

我有一台最低配的云主机:2 核 2G、Ubuntu 24.04、没有备案域名。上面要同时跑四个自建服务:

端口 服务 说明
8443 管理面板(Go 单文件) 需要 HTTPS,否则 Cookie 带 Secure 标记不生效
8444 MQTT broker(EMQX) 控制台要 HTTPS,1883 端口只给设备用
8445 记账服务(Python) 手机浏览器访问,必须有 HTTPS 才能加到主屏
8446 自建 Agent(Web) 内部使用,但要求 WebSocket 走 wss

不用 80/443 是因为没备案域名,也不想去申请证书;不装 Nginx 面板是因为 2G 内存经不起额外的 PHP/Nginx/MySQL 三件套。最后的选择是 Caddy + 自签证书 + 四个高端口,配置文件不到 40 行。

一、Caddy 做自签 HTTPS 反代

Caddy 装完就自带一个内部 CA,给 IP 或任意域名签发证书,不需要 ACME、不需要域名:

{
    # 用 Caddy 内置 CA 给本机地址签证书
    local_certs
    auto_https disable_redirects
}

# 面板
https://:8443 {
    reverse_proxy 127.0.0.1:8317
    encode gzip
    log {
        output file /var/log/caddy/panel.log
        roll_size 10mb
        roll_keep 3
    }
}

# MQTT 控制台(含 WebSocket)
https://:8444 {
    reverse_proxy 127.0.0.1:18083
}

# 记账服务
https://:8445 {
    reverse_proxy 127.0.0.1:5000
}

# Agent Web(SSE/WS 都要,关掉缓冲)
https://:8446 {
    reverse_proxy 127.0.0.1:9119 {
        flush_interval -1
    }
}

几个容易踩的点:

  • local_certs 必须写在全局块里,写在站点块里不生效;
  • 端口用 https://:8443 这种写法,Caddy 才会在这个端口上做 TLS 监听;写成 http://:8443 就变成明文了;
  • flush_interval -1 是给 SSE / 长连接用的,不加的话流式响应会被缓冲到结束才吐出来;
  • 日志按大小轮转写在 Caddyfile 里,别指望系统 logrotate 帮你管容器外的文件。

浏览器第一次访问一定报「不安全」,因为自签证书不在信任链里。个人用可以选择把 Caddy 的根证书(/var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt)导进系统或手机,就不再有告警:

# 在服务器上找到根证书
sudo find /var/lib/caddy -name 'root.crt'

# 拉到本地后,Linux 导入
sudo cp root.crt /usr/local/share/ca-certificates/caddy-local.crt
sudo update-ca-certificates

二、用 systemd --user 托管,而不是 systemd 系统级

四个服务都不需要 root,用 systemd --user 更干净:每个 unit 文件放在 ~/.config/systemd/user/,服务以当前用户身份跑,权限最小。

# ~/.config/systemd/user/bee.crt.service
[Unit]
Description=BeeCount
After=network-online.target

[Service]
Type=simple
WorkingDirectory=%h/apps/bee
ExecStart=%h/apps/bee/venv/bin/python app.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
Environment=PORT=5000

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now bee.service
systemctl --user status bee.service

关键的一步是 enable-linger:

sudo loginctl enable-linger $USER

不开这个,用户退出 SSH 之后 user 级 systemd 会被回收,所有服务在注销瞬间全挂——表现是「我明明 start 了,一关终端就 502」。开了之后 user manager 常驻,还能跟着系统启动。

两个常见的坑:

  1. PATH 不一样。user unit 里没有登录 shell 的 PATH,ExecStart 里调 node、uv 这类命令会报 No such file or directory。要么写绝对路径,要么在 unit 里显式 Environment=PATH=...。
  2. XDG_RUNTIME_DIR 缺失。root 直接 systemctl --user 会报 Failed to connect to bus,得 su - <user> 或者在 crontab/脚本里手动设 XDG_RUNTIME_DIR=/run/user/$(id -u)。

三、两处网络都要放通,少一处就是打不开

云主机的「打不开」九成卡在两层防火墙上:

# 第一层:云控制台的安全组 —— 入方向放通 8443-8446/TCP
# 第二层:系统防火墙
sudo ufw allow 8443,8444,8445,8446/tcp
sudo ufw status verbose

# 本机监听是否真的在
sudo ss -lntp | grep -E '8443|8444|8445|8446'

顺序建议:先 ss -lntp 确认进程在监听,再 ufw,最后才是安全组。反过来的话你会花很多时间去怀疑 Caddy 配置,而问题其实在外面。

四、2G 内存怎么活下来

四个服务 + Docker + systemd 常驻,2G 内存是硬约束。几个实际有效的动作:

# 1) 加 2G swap(云主机默认常常没开)
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 2) 把 swappiness 调高一点,宁可换页也别 OOM Kill
echo 'vm.swappiness=60' | sudo tee /etc/sysctl.d/99-swap.conf
sudo sysctl --system

# 3) journald 限容,不然 /var/log 会吃掉几个 G
sudo sed -i 's/^#\?SystemMaxUse=.*/SystemMaxUse=200M/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald

再加两条习惯:

  • 镜像瘦身:能用 -alpine、-slim 就用,别装完整发行版镜像;docker image prune -f 挂个每周定时;
  • 别在 2G 机器上跑 Elasticsearch、Kibana、Jenkins 这类常驻大户,一个能吃掉 1.5G。真要跑,先看 docker stats 再决定。

内存紧张时的排查顺序:free -h → ps aux --sort=-%mem | head → journalctl -k | grep -i 'killed process'。如果看到 Out of memory: Killed process,说明是 OOM Killer 干的,不是服务自己崩的,加 swap 或者砍进程,别急着改代码。

五、最后的目录结构

~/apps/
  panel/         # 8443
  emqx/          # 8444(docker compose)
  bee/           # 8445(venv)
  agent/         # 8446
~/.config/systemd/user/
  bee.service  agent.service  panel.service
/etc/caddy/Caddyfile

四个服务、一个 Caddyfile、三个 user unit,重启机器后全部自动回来(前提是打开了 linger)。整套方案的资源占用常驻在 600MB 左右,剩下的留给 Docker 和临时构建——2C2G 的小机器上,这已经是能兼顾「多服务」和「可维护」的平衡点。

如果哪天有了备案域名,改 Caddyfile 两行就能让 Caddy 自动申请证书,反代结构完全不用动。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。