主题
10 · 部署迷你 Node/Go 服务常驻运行
目标:在 Ubuntu 上跑通迷你 HTTP API,用 systemd 常驻、Nginx 反代,达到可勾验收清单。
主线:Go 标准库;Node 原生http作对照半页。
1. 环境前提
- 01~09 已走过:SSH、权限、apt、端口、日志、ufw、systemd、Nginx 反代
- 反代目标:
127.0.0.1:8080→ 公网80(见 09 的lab-proxy) - 刻意不做:Docker、Let’s Encrypt 全流程(文末一步带过)
2. 主线:Go 迷你 API
2.1 安装 Go(官方)
按 https://go.dev/dl/ 选 Linux,或:
bash
# 示例版本号请换成 go.dev/dl 当前稳定版
curl -fsSL -o /tmp/go.tgz https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf /tmp/go.tgz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
go version1
2
3
4
5
6
7
2
3
4
5
6
7
架构若是 arm64,下载文件名改为 linux-arm64。
2.2 写服务
bash
mkdir -p ~/lab/mini-api
cd ~/lab/mini-api
go mod init example.com/mini-api
cat > main.go <<'EOF'
package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
addr := "127.0.0.1:8080"
log.Println("listen", addr)
log.Fatal(http.ListenAndServe(addr, mux))
}
EOF
go build -o mini-api .
./mini-api &
curl -s http://127.0.0.1:8080/health
kill %1 2>/dev/null || true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
应返回类似:{"status":"ok"}。
2.3 systemd 常驻
bash
# YOUR_USER 换成 whoami 的输出
sudo tee /etc/systemd/system/mini-api.service > /dev/null <<EOF
[Unit]
Description=Mini API lab service
After=network.target
[Service]
Type=simple
User=YOUR_USER
WorkingDirectory=/home/YOUR_USER/lab/mini-api
ExecStart=/home/YOUR_USER/lab/mini-api/mini-api
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now mini-api
sudo systemctl status mini-api
curl -s http://127.0.0.1:8080/health1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.4 Nginx 反代验收
确保 09 的 lab-proxy 仍指向 8080:
bash
sudo nginx -t && sudo systemctl reload nginx
curl -s http://127.0.0.1/health
# 公网:
curl -s http://公网IP/health1
2
3
4
2
3
4
模拟崩溃恢复:
bash
PID=$(pgrep -n mini-api)
kill "$PID"
sleep 4
sudo systemctl status mini-api
curl -s http://127.0.0.1:8080/health1
2
3
4
5
2
3
4
5
Restart=on-failure / 视信号而定;若未自动拉起,用 kill -9 后再看,或执行 sudo systemctl restart mini-api 确认单元本身正常。
3. 对照:Node 原生 http(半页)
bash
# 安装 Node:可用 NodeSource / fnm / 官方包;练习机示例用 Node 20 官方二进制或:
sudo apt install -y nodejs npm # 版本可能偏旧,仅实验够用
mkdir -p ~/lab/mini-api-node
cat > ~/lab/mini-api-node/server.js <<'EOF'
const http = require('http')
const server = http.createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ status: 'ok' }))
return
}
res.writeHead(404)
res.end()
})
server.listen(8080, '127.0.0.1', () => console.log('listen 8080'))
EOF1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
unit 与 Go 版相同,只改:
text
WorkingDirectory=.../mini-api-node
ExecStart=/usr/bin/node /home/YOUR_USER/lab/mini-api-node/server.js1
2
2
同一时间只跑一个占 8080 的服务(先 stop Go 版再启 Node 版)。
4. 验收检查清单
- [ ]
curl -s http://127.0.0.1:8080/health返回 ok - [ ]
systemctl is-active mini-api为active - [ ]
enable已开;重启云机后服务仍在(可选但推荐) - [ ]
curl -s http://127.0.0.1/health经 Nginx 反代成功 - [ ] 公网 IP(或域名)
curl通(安全组 + ufw 已放行 80) - [ ]
journalctl -u mini-api -n 50能看到启动日志 - [ ]
sudo ss -tulpn | grep 8080显示听在127.0.0.1(而非必须0.0.0.0)
5. 下一步(本系列不做展开)
- HTTPS:Let’s Encrypt + certbot(先保证 80 通、域名解析到机)
- 多环境 / 多机:再学编排与 CI;不要一上来 Docker 全家桶
- 与 Journal 后端部署:把本篇清单迁到真实二进制与环境变量即可
6. 常见翻车
| 翻车 | 处理 |
|---|---|
| 8080 被占用 | ss 找 PID;停掉 python 演示或旧服务 |
| 502 | 后端没起;Nginx upstream 地址错;看 error.log |
| systemd 权限 | User= 对二进制无执行权;chmod +x |
只监听 0.0.0.0:8080 且 ufw 放了 8080 | 收敛为 127.0.0.1 + 反代,缩小暴露面 |
7. 官方入口
- How to Write Go Code · net/http
- Node.js HTTP
- 回看本系列:08 systemd · 09 Nginx · 07 ufw
8. 系列收束
你现在应能独立完成:
text
登录云机 → 装包 → 查端口与日志 → 收紧防火墙
→ 写 systemd 服务 → Nginx 反代 → curl 验收1
2
2
之后每次上线新服务,重复的是同一张清单,而不是「盲重启」。
续篇:要用脚本做探活、备份与定时,见 11 · 第一个 Bash 脚本 起的 Shell 阶段(至 15 · 备份与 cron)。
OS 深读:22 · 套接字、端口与网络栈直觉(反代背后的两个监听点)。
