为什么要单独记录后端部署
后端服务和 Risuki 博客的部署方式不一样。
博客是 Astro 构建出来的静态站点,最终只需要把 dist/ 目录交给 Nginx 返回即可;后端则是一个长期运行的 API 服务,需要考虑进程管理、端口监听、反向代理、HTTPS、日志和重启恢复。
这篇文章先记录当前的部署规划和检查清单。后续真正上服务器操作时,可以继续补充实际命令输出、报错和修复过程。
目标结构
公网发布前,文章里不直接写真实 API 子域名和服务器目录。下面统一使用占位符:
SITE_DOMAIN -> 博客主域名WWW_DOMAIN -> 博客 www 域名API_DOMAIN -> 后端 API 域名BACKEND_APP_DIR -> 后端服务目录BLOG_SOURCE_DIR -> 博客源码目录PUBLIC_WEB_ROOT -> Nginx 静态文件目录BACKEND_SERVICE -> systemd 服务名BACKEND_HOST -> 后端监听地址BACKEND_PORT -> 后端监听端口服务器目录先按职责分开:
BACKEND_APP_DIR # 后端源码和运行目录BLOG_SOURCE_DIR # 博客源码目录PUBLIC_WEB_ROOT # Nginx 对外访问的博客静态文件这样做的好处是:博客和后端互不混放,后续排查问题时可以很快判断是静态站点问题、API 服务问题,还是 Nginx 转发问题。
后端服务运行方式
后端服务建议只监听本机地址:
BACKEND_HOST:BACKEND_PORT实际部署时,BACKEND_HOST 通常使用本机回环地址,让服务只允许服务器本机访问,公网用户不能直接访问这个端口。外部请求统一先进 Nginx,再由 Nginx 转发给后端服务。
这种结构更清晰:
浏览器 -> https://API_DOMAIN -> Nginx -> BACKEND_HOST:BACKEND_PORT -> 后端服务如果后端直接监听所有网卡,就意味着服务端口可能被公网或内网其它机器访问。第一版没有必要这么做,除非后面有明确的内网访问或容器网络需求。
Systemd 管理后端进程
后端服务不应该靠手动开一个终端运行。终端一关,进程就可能退出;服务器重启后,也不会自动恢复。
更稳的方式是用 systemd 管理服务。示例服务文件可以放在:
/etc/systemd/system/BACKEND_SERVICE.service示例内容如下,实际的启动命令要根据后端项目的入口文件再调整:
[Unit]Description=Backend application serviceAfter=network.target
[Service]WorkingDirectory=BACKEND_APP_DIRExecStart=BACKEND_APP_DIR/.venv/bin/uvicorn APP_MODULE:APP_OBJECT --host BACKEND_HOST --port BACKEND_PORTRestart=alwaysRestartSec=3
[Install]WantedBy=multi-user.target几个关键字段的意思:
WorkingDirectory:服务启动前进入哪个目录。后端读取配置文件、相对路径资源时会用到它。ExecStart:真正启动后端的命令。这里假设后端使用 Python 虚拟环境和 Uvicorn。APP_MODULE:APP_OBJECT:后端入口对象,占位符不要直接照抄。--host BACKEND_HOST:建议只监听本机,避免后端端口直接暴露到公网。--port BACKEND_PORT:后端监听端口。Restart=always:进程异常退出后自动重启。WantedBy=multi-user.target:允许服务开机自启。
修改完服务文件后,需要执行:
sudo systemctl daemon-reload这条命令的意思是让 systemd 重新读取服务配置文件。否则你改了 .service 文件,systemd 可能还在使用旧配置。
启动服务:
sudo systemctl start BACKEND_SERVICE设置开机自启:
sudo systemctl enable BACKEND_SERVICE查看服务状态:
sudo systemctl status BACKEND_SERVICE如果状态不是 active (running),就要继续看日志:
journalctl -u BACKEND_SERVICE -n 100 --no-pager这条命令会查看 BACKEND_SERVICE 最近 100 行日志。--no-pager 表示直接输出,不进入翻页界面,适合快速复制和排查。
Nginx 反向代理
API 域名的 Nginx 配置可以先按下面这个结构写:
server { listen 80; server_name API_DOMAIN;
location / { proxy_pass http://BACKEND_HOST:BACKEND_PORT; 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; }}这里最重要的是 proxy_pass http://BACKEND_HOST:BACKEND_PORT;。
它的意思是:当用户访问 API_DOMAIN 时,Nginx 不直接找静态文件,而是把请求转发给本机后端服务。
几个请求头的作用:
Host:保留用户原始访问的域名。X-Real-IP:把真实客户端 IP 传给后端。X-Forwarded-For:记录代理链路上的 IP。X-Forwarded-Proto:告诉后端原始请求是http还是https。
配置改完后,先检查 Nginx 语法:
sudo nginx -t如果输出里有 syntax is ok 和 test is successful,说明配置文件语法没问题。
然后重载 Nginx:
sudo systemctl reload nginxreload 的意思是重新加载配置,但尽量不中断正在处理的连接。它比直接 restart 更适合线上服务。
HTTPS 证书
API 子域名也应该启用 HTTPS。博客主站和 API 可以分别申请证书。
如果只给 API 申请证书,可以执行:
sudo certbot --nginx -d API_DOMAIN这条命令会让 Certbot 自动读取 Nginx 配置,向 Let’s Encrypt 申请证书,并把 HTTPS 配置写回 Nginx。
如果主站还没申请,也可以一起处理:
sudo certbot --nginx -d SITE_DOMAIN -d WWW_DOMAIN -d API_DOMAIN证书申请前要先确认三件事:
- 域名 DNS 已经解析到阿里云服务器公网 IP。
- 服务器安全组放行了
80和443端口。 - Nginx 能正常响应对应域名的 HTTP 请求。
排查顺序
后端部署出问题时,不要一上来就反复改 Nginx。建议按链路一层一层查。
1. 后端进程是否启动
sudo systemctl status BACKEND_SERVICE如果服务没启动,先看 journalctl 日志,重点检查 Python 环境、依赖、入口文件、环境变量和端口占用。
2. 本机端口是否能访问
curl http://BACKEND_HOST:BACKEND_PORT这一步是在服务器本机访问后端。如果这里都不通,说明问题还在后端服务本身,暂时不要查 Nginx。
3. Nginx 配置是否正确
sudo nginx -tNginx 语法不通过时,先修配置文件。不要强行 reload。
4. 域名是否解析正确
ping API_DOMAIN这里主要看解析出来的 IP 是不是服务器公网 IP。ping 不通不一定代表网站不通,因为有些服务器会禁 ICMP,但 IP 解析结果仍然有参考价值。
5. 公网访问是否正常
curl -I https://API_DOMAIN-I 表示只请求响应头。它适合快速确认状态码、HTTPS 和反向代理是否正常。
当前结论
后端部署的核心不是“把服务跑起来”这么简单,而是要把运行边界整理清楚:
- 后端只监听
BACKEND_HOST:BACKEND_PORT。 - 公网入口只暴露 Nginx 的
80和443。 - 进程交给 systemd 管理,避免手动终端运行。
- HTTPS 交给 Certbot 和 Nginx 配合处理。
- 排查时按“后端进程 -> 本机端口 -> Nginx -> DNS -> 公网访问”的顺序来。
后续真正部署时,这篇文章会继续补充实际服务文件、Nginx 配置文件路径、日志截图和遇到的问题。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时






