基于GitHub Action部署.Net MVC+Postgres应用到DigitalOcean Droplet
现有部署流程的明显安全漏洞
- 防火墙规则不完整:当前UFW配置未设置默认拒绝入站规则,一旦Postgres、Kestrel等服务监听公网端口,会直接暴露在公网被扫描攻击;SSH端口全网放通无IP限制,极易遭遇暴力破解。
- 证书工具存在供应链风险:使用的
ppa:certbot/certbot源早已废弃,安装未维护的旧包可能引入恶意代码,且未配置证书自动续期,证书过期会直接导致站点不可用。 - Nginx配置存在多处缺陷:
- 启用了TLS1.0、TLS1.1等已被淘汰的不安全协议,存在POODLE、BEAST等已知漏洞
- 未关闭
server_tokens,响应头会暴露Nginx版本号,给攻击者提供版本信息 proxy.conf首行拼写错误,proxy_redirect被写为roxy_redirect,反向代理重定向规则完全失效,易引发域名跳转劫持、后端地址泄露问题- 保留了默认80端口站点配置,未做HTTP强制跳转HTTPS,用户访问HTTP或直接访问服务器IP时不会进入业务应用,还可能暴露默认目录下的敏感文件
- 未配置慢速攻击、异常请求拦截规则,易被CC攻击打垮服务
- 数据库权限过度开放:给应用账号授予了整个数据库的全部权限,未遵循最小权限原则,一旦应用被入侵,攻击者可直接删库、提权控制整个Postgres实例;同时未限制Postgres的访问来源,存在公网被爆破的风险。
- 服务运行权限过大:直接用普通登录用户运行.NET应用,该用户若持有SSH私钥、sudo权限,应用出现RCE漏洞时攻击者可直接控制整台服务器;systemd服务中硬编码环境配置,敏感信息易被泄露。
- 生产环境构建风险:直接在生产服务器安装.NET SDK执行构建、包还原操作,既增加了服务器攻击面,也存在NuGet包被篡改的供应链风险;Kestrel未配置仅监听本地回环地址或Unix Socket,配置错误时可被公网绕过Nginx直接访问。
- 服务配置不规范:systemd服务的
SyslogIdentifier写为dotnet-example,与实际服务名不匹配,故障排查时日志难以定位。
推荐的高效稳定落地方案
方案一:GitHub Actions 自动化部署(适配现有Droplet,零额外成本)
不需要重构现有架构,仅需完成一次服务器初始化,后续构建部署全流程自动化,出错率可降低90%以上。
一次性服务器初始化(仅执行一次)
- 修正防火墙规则:
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow OpenSSH # 有固定办公IP的话优先配置:sudo ufw allow from 你的办公IP to any port 22,禁止全网访问SSH sudo ufw allow 'Nginx Full' sudo ufw deny 5432 sudo ufw enable - 修复证书工具配置:
sudo add-apt-repository --remove ppa:certbot/certbot sudo apt remove python-certbot-nginx sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d 你的域名 sudo systemctl enable --now certbot.timer - 修正Nginx配置:
- 将
nginx.conf中SSL协议配置改为ssl_protocols TLSv1.2 TLSv1.3;,开启server_tokens off;配置 - 删除
sites-enabled/default默认站点配置,新建专属站点规则,配置HTTP强制跳转HTTPS,修正proxy.conf的拼写错误,配置反向代理指向本地Kestrel的Unix Socket地址 - 新建无登录权限的专用运行用户:
sudo useradd -r -s /sbin/nologin dotnet-run,发布目录权限设置为该用户只读,数据库连接字符串等敏感信息存放在专属环境变量文件中,权限设为600仅允许该用户读取
- 将
- 收紧数据库权限:重新创建应用专用数据库账号,仅授予业务库的读写、DDL执行必要权限,删除高权限授权;修改
pg_hba.conf禁止Postgres TCP远程访问,仅允许本地Unix Socket连接。 - 服务器仅安装.NET运行时,不安装SDK,减少攻击面。
- 新建专用部署用户,仅授予该用户更新发布目录、重启.NET服务的sudo权限,生成专用SSH密钥对,公钥加入部署用户的授权列表,私钥存入GitHub仓库的Secrets中。
GitHub Actions 自动化工作流配置
每次向主分支推送代码时自动触发以下流程:
- 拉取代码,使用对应版本.NET SDK完成依赖还原、编译、单元测试、发布打包,测试不通过直接终止部署
- 通过SSH将发布包传输到服务器临时目录
- 远程执行部署脚本:停止.NET服务,备份当前运行版本,解压新发布包到指定目录,执行数据库迁移(迁移脚本需提前在测试环境验证),启动服务后执行健康检查,若启动失败自动回滚到上一个备份版本。
方案二:Docker Compose 容器化方案(长期维护成本最低)
如果可以接受小幅重构部署流程,容器化方案是稳定性、可移植性最高的选择:
- 为.NET应用编写多阶段构建Dockerfile,构建阶段使用SDK镜像编译,运行阶段使用精简版runtime镜像,不包含多余依赖。
- 编写
docker-compose.yml定义三个服务,所有服务通过内部网桥通信,不对外映射不必要的端口:- Nginx服务:使用官方稳定版镜像,挂载配置文件、SSL证书目录,反向代理指向.NET应用服务
- .NET应用服务:使用自定义构建的应用镜像,挂载配置、静态资源等持久化目录,不映射公网端口
- Postgres服务:使用官方Postgres镜像,挂载数据卷做持久化存储,不映射公网端口,配置强密码
- 服务器一次性安装Docker、Docker Compose,完成UFW配置、证书自动续期配置即可。
- GitHub Actions工作流调整为:构建应用镜像推送到GitHub容器镜像仓库,SSH登录服务器拉取最新镜像,执行
docker compose up -d完成滚动更新,数据库迁移可通过初始化容器在应用启动前自动执行。
该方案不存在环境差异问题,服务器迁移时仅需复制compose配置和数据卷即可快速恢复服务,容器间网络天然隔离,安全管控更简单。
额外优化建议
- 生产环境数据库迁移不要完全自动化,建议在工作流中增加人工确认步骤,或先在预发布环境验证迁移脚本无锁表、误删数据风险后再执行生产迁移。
- 配置统一日志收集,将Nginx、.NET应用、Postgres日志集中存储,降低故障排查成本。
- 配置Nginx健康检查规则,应用异常时自动返回维护页面,避免用户直接看到错误信息。
内容的提问来源于stack exchange,提问作者ChristianO'Connor
相关产品推荐
相关产品推荐

