1. 先理解问题:公网服务器默认会被扫描
个人服务器只要有公网地址,就应默认会被自动化扫描系统发现。扫描通常不针对某个人,而是批量寻找低成本目标。
常见扫描包括:
- SSH 用户名和弱密码尝试。
- Web 常见路径探测,例如配置文件、源码目录、后台路径、测试接口。
- 对旧框架、旧组件、路由器、摄像头、开发工具入口的批量请求。
- 对不存在服务的协议探测。
因此,服务器安全的第一步不是“隐藏到没人知道”,而是承认它一定会被看到,然后让扫描器只能看到最少、最普通、最难利用的入口。
这台服务器的安全目标可以归纳为:
- 公开服务看起来像一个正常网站。
- 管理入口不直接暴露给全互联网。
- 内部服务不直接监听公网。
- 敏感文件不进入 Web 根目录,也不对普通用户可读。
- 临时权限有明确生命周期,用完即删。
- 日志能够支持事后判断是否被真正命中。
2. 第一层:登录入口只允许公钥
服务器初始化后,优先处理 SSH 登录安全。
采用的策略包括:
- 禁用密码登录。
- 启用公钥认证。
- root 仅允许通过公钥登录。
- 关闭交互式密码认证。
- 使用 fail2ban 监控 SSH 失败登录。
这样做的原因很直接:SSH 是公网服务器最常被扫描的入口。只要密码登录开启,就会持续承受用户名和密码组合爆破。
禁用密码登录后,攻击者即使知道用户名,也无法通过猜密码进入系统。fail2ban 进一步降低重复失败尝试带来的日志噪声和资源消耗。
这里需要注意:公钥登录不是“永久安全”。如果私钥泄露,攻击者仍然可以登录。因此私钥应只保存在可信设备上,并设置本地保护措施。更高安全需求下,可以进一步限制 SSH 来源地址,或把 SSH 管理入口放到专门的受控访问体系后面。
3. 第二层:用域名作为稳定入口
服务器没有要求用户直接记忆公网 IP,而是使用域名作为访问入口。
使用域名的原因有三点。
第一,域名把访问入口和源站地址解耦。服务器迁移、IP 更换、入口策略调整时,只需要调整 DNS 或边缘网络配置,不需要让访问者记住新的地址。
第二,域名是 HTTPS 正常化的基础。证书签发、浏览器信任、搜索引擎收录、安全策略配置,基本都围绕域名展开。
第三,域名可以接入 CDN、WAF、访问控制、日志分析和速率限制等边缘安全能力。源站只负责提供服务,边缘网络先承担一部分过滤、缓存和审计工作。
这一步的核心价值是:不要把源站 IP 当成唯一入口,也不要把所有流量都直接交给源站处理。
4. 第三层:公开网站放到 CDN 和边缘安全之后
适合公开访问的 Web 流量放到 CDN/边缘网络后面。这样普通访问者访问的是域名,浏览器首先连接边缘网络,而不是直接连接源站。
典型访问过程如下:
- 用户访问公开网站域名。
- DNS 返回边缘网络地址。
- 用户浏览器连接边缘网络。
- 边缘服务完成基础检查,例如 TLS、缓存、速率限制、恶意请求过滤和访问策略判断。
- 如果静态资源缓存命中,边缘服务直接返回内容。
- 如果需要回源,边缘服务再访问源站公开入口。
- 源站入口把请求交给对应容器服务。
CF 类平台可以提供几类实用安全能力:
- DNS 托管与边缘接入:让公开 Web 流量优先经过边缘网络。
- TLS 策略:保证浏览器到边缘、边缘到源站之间都使用 HTTPS。
- WAF 规则:拦截常见扫描路径、异常方法和明显不属于本站业务的请求。
- 速率限制:限制短时间内大量请求,降低自动化扫描和资源消耗。
- 访问控制:管理后台和内部入口要求额外身份验证。
- 日志分析:把边缘访问日志作为第一层审计来源,再结合源站日志判断是否有真实命中。
CDN 的意义不是让服务器“不可见”,而是把大量低质量流量挡在源站之前,并减少源站直接暴露的信息。
同时,CDN 不是万能防护。某些内部业务如果对连接行为、协议特征或端到端握手有特殊要求,不应机械地放到同一种接入模式下。正确做法是按业务类型分层:公开网站走边缘网络,管理入口走受控访问,内部服务默认不直接公开。
5. 第四层:源站只暴露必要端口
源站的公网暴露面被控制在很小范围内:
- 维护入口。
- Web 明文入口,用于跳转和必要的 Web 访问。
- Web 加密入口,作为统一公开入口。
其他管理端口和内部业务端口只绑定到本机回环地址,不直接监听公网。
这样做的安全收益是:
- 扫描器无法直接访问管理后台端口。
- 内部业务接口不会被公网随意枚举。
- 即使某个内部服务存在问题,也不会天然成为公网攻击面。
- 端口列表更容易审计,异常开放更容易被发现。
端口控制的原则是:能不暴露就不暴露,必须暴露的入口再加访问控制、边缘防护和日志审计。
6. 第五层:统一入口再做边界分流
公开 Web 加密入口由边界层服务接管。边界层根据连接初期可见的信息和访问目标,把请求转发到不同后端。
大致逻辑是:
- 正常网站访问进入静态网站服务。
- 管理访问进入受控后台链路。
- 非公开业务流量进入对应内部后端。
- 未匹配的流量回到默认公开网站。
这样做有几个好处。
第一,公网入口更少,服务指纹更少。
第二,正常访问者、搜索引擎和常规扫描器看到的是公开网站,而不是内部服务结构。
第三,网站流量和内部业务流量不会混在同一个应用层服务里处理。
第四,边界层只负责入口分发,不承担复杂业务逻辑,配置更容易审计。
需要强调的是,这不是隐身方案。公网仍然能看到服务器有 Web 服务,也能看到连接行为。它的价值在于把公开服务和非公开后端职责拆开,减少错误暴露。
7. 第六层:服务容器化,边界清晰
主要服务使用 Docker Compose 管理,包括:
- 边界入口与流量分发服务。
- 静态网站服务。
- 非公开后端业务服务。
- 管理后台访问所需的受控通道服务。
容器化的安全收益主要有三点。
第一,服务边界清晰。每个服务有自己的容器、网络和挂载目录,配置更容易审计。
第二,迁移和回滚更简单。核心配置、数据库、证书和网站构建产物集中放在固定目录中,后续迁移服务器时不需要从系统各处拼凑文件。
第三,减少对宿主机环境的污染。大多数服务依赖留在容器中,宿主机只负责 Docker、网络、证书和少量维护脚本。
但 Docker 也有明确边界:不要把不可信用户加入 docker 组。Docker 组通常等价于 root 能力,因为用户可以通过挂载宿主机目录或创建高权限容器绕过普通文件权限。
8. 第七层:公开网站静态化
公开网站采用静态站点生成方式,本地构建后发布到服务器,由 Web 容器提供访问。
静态网站相对动态应用的攻击面小很多:
- 没有在线数据库。
- 没有后台登录入口。
- 没有服务器端模板执行。
- 没有上传接口。
- 没有运行时业务代码。
这并不等于静态网站没有风险。错误的 Web 配置仍可能暴露环境变量文件、备份文件、源码目录、构建缓存等敏感内容。
因此公开网站增加了几类保护:
- 隐藏点号开头的路径。
- 拒绝常见敏感扩展名。
- 拒绝备份、配置、私密目录类路径。
- 静态资源设置缓存。
- 未命中文件时再交给前端路由 fallback。
这里有一个重要细节:SPA 或静态博客常用 fallback 到首页。如果配置不谨慎,扫描器访问不存在的敏感路径时也可能收到首页内容和成功状态码。虽然没有泄露文件,但会让扫描器误判“目标存在”,增加后续噪声。
更好的做法是先对敏感路径和敏感扩展名返回错误,再对正常前端路由做 fallback。
9. 第八层:管理后台不直接公开
管理后台没有直接开放公网端口,而是绑定到服务器本地回环地址,再通过受控访问机制进入。
这样做的原因是管理后台通常比普通静态网站危险:
- 它有登录入口。
- 它可以修改关键服务配置。
- 它可能持有用户、访问凭据、后端服务状态等敏感信息。
- 一旦后台被暴力扫描或撞库,风险远高于静态页面。
因此,管理后台应尽量避免直接暴露。通过受控访问通道和额外身份验证,可以把风险从“全互联网可探测”降低到“需要先通过访问控制层”。
其他内部接口也采用类似思路:服务实际监听在本机回环地址,由受控访问机制转发访问。这样公网扫描器无法直接扫到内部端口。
10. 第九层:敏感配置集中保存并限制权限
服务相关配置集中放在固定目录中,包括:
- Compose 配置。
- Web 服务配置。
- 后台数据库。
- 证书文件。
- 环境变量文件。
- 部署脚本。
- 站点构建产物。
其中敏感文件使用严格权限,例如环境变量文件只允许 root 读取。
集中管理的价值是:
- 迁移时知道哪些文件必须带走。
- 审计时知道敏感信息集中在哪里。
- 权限检查更简单。
- 不容易把密钥散落在脚本、历史命令或项目仓库中。
同时,本地和服务端都应使用忽略规则排除敏感文件,避免把环境变量、数据库、私钥、证书账户文件误提交到 Git 仓库。
11. 第十层:临时用户按生命周期管理
曾经为他人临时创建过独立用户。创建时采用:
- 独立 home。
- 独立 SSH key。
- 不给 sudo。
- 不给 Docker 权限。
- home 私有权限。
使用结束后执行:
- 终止该用户进程。
- 删除用户。
- 删除 home。
- 删除同名组。
- 清理临时目录。
- 确认 SSH 权限只剩自己的 key。
这体现了一个重要运维原则:临时权限必须有明确结束时间。账号不用了就删除,而不是“先留着以后可能用”。
长期闲置账号是常见风险来源。它们可能使用旧密钥、过期权限或无人监控的后台进程。
12. 第十一层:日志审计验证安全假设
上线后检查日志可以看到两类典型攻击噪声。
第一类是 SSH 字典扫描。表现为大量不存在用户名、root 登录尝试、失败认证等记录。
第二类是 Web 扫描。常见路径包括:
- 环境变量文件路径。
- 源码仓库配置路径。
- 常见后台登录路径。
- 框架调试接口。
- IoT 和路由器历史漏洞路径。
这些扫描说明服务器已经被互联网自动化扫描系统收录。它不一定表示“被针对”,而是公网服务的常态。
有效的判断方式不是看到扫描就恐慌,而是检查:
- 是否有异常成功登录。
- 是否新增陌生 SSH key。
- 是否新增用户或高权限组成员。
- 是否出现陌生进程。
- 是否出现陌生 systemd 服务、cron 任务。
- 是否有未知容器。
- 敏感文件是否可被普通用户读取。
本次检查中,没有发现明确入侵证据,但发现了持续扫描噪声。这说明现有防护在发挥作用,同时也说明后续仍应保持最小暴露面。
13. 当前设计的安全收益
从整体看,这套部署的安全收益主要来自分层:
- SSH 通过公钥认证降低登录面风险。
- fail2ban 降低爆破噪声。
- 域名和 CDN 把公开访问入口从源站地址中解耦。
- 边缘安全能力降低源站直接承受的扫描压力。
- 管理后台只监听本机,减少公网暴露。
- 统一入口分发降低端口和服务指纹暴露。
- Docker Compose 让服务边界清晰。
- 静态网站独立运行,业务攻击面小。
- 敏感文件集中存放并限制权限。
- 临时用户按生命周期删除,减少遗留权限。
这些措施没有依赖单一工具,而是多层小措施叠加。真实安全通常就是这样:每一层都降低一部分风险,最终让攻击成本明显上升。
14. 仍然需要注意的边界
这套方案仍有边界。
第一,公网 SSH 仍然会被扫描。虽然禁用了密码登录,但如果私钥泄露,攻击者仍可能登录。更进一步的做法是限制 SSH 来源 IP、改用 Zero Trust 管理入口,或关闭公网 SSH。
第二,CDN 主要保护适合公开访问的 Web 入口。它不能替代源站权限控制,也不能解决所有内部服务的安全问题。
第三,Docker 本身是高权限组件。不要把不可信用户加入 Docker 组,不要运行来源不明的高权限容器。
第四,管理后台依赖受控访问通道和访问控制。访问通道 token、后台密码、内部接口地址都应视为敏感信息。
第五,静态网站也需要持续注意构建产物。不要把环境变量、源码仓库、备份包、数据库导出放进 Web 根目录。
第六,日志审计应定期做。尤其要关注成功登录、用户变更、计划任务、systemd 服务、Docker 容器变化。
15. 教学总结
个人服务器安全不是只装一个防火墙,也不是只换一个端口。更可靠的思路是循序渐进地建立边界:
- 先假设公网扫描一定会发生。
- 再把登录入口收紧到公钥认证。
- 用域名和 CDN 承接公开 Web 访问。
- 让源站只暴露必要入口。
- 用边界层把不同流量交给不同后端。
- 用容器化让服务职责清晰。
- 用静态化降低公开网站攻击面。
- 让管理后台和内部接口默认不直接公开。
- 集中保存敏感配置并限制权限。
- 临时用户用完即删。
- 定期用日志验证安全假设。
这套部署的核心价值在于:即使服务器持续被扫描,攻击者直接能接触到的东西也很少;即使某个公开服务出现问题,也不应该自然扩散到管理后台、密钥文件或其他内部服务。
安全不是让服务器“看起来没人知道”,而是在它必然被看到之后,仍然没有容易被利用的入口。