介绍
本指南旨在为 DigitalOcean 教程的作者总结已建立的最佳实践和强烈建议。 它旨在为 DigitalOcean 的教学材料的一致性、技术正确性和易用性提供基础。
基于内部技术作家和编辑、社区经理和工程师的不断增长的经验,这本质上既是一项正在进行的工作,也是一份固执己见的文件。 它的建议可能会发生变化,并且是专门针对具有广泛读者和最终用户的教育内容而编写的。
软件源和安装
首选来源
粗略地,按偏好降序排列,使用以下安装机制:
- 项目推荐的方法,当评估为最佳时。 许多项目变化很快,建议超越官方存储库,但有些安装(如
curl | bash
模式)需要判断是否使用它们。 - 当前分发和发布的 官方软件包存储库。
- 语言专用官方包(NPM、CPAN、PIP、RubyGems、Composer等)
- 项目特定的包存储库(例如 Nginx 为最新版本提供自己的存储库),或者在 Ubuntu 上提供受信任的 PPA。 确保这些来自受信任的来源,例如项目的开发人员或 Debian/Ubuntu 软件包维护者。
- 来自项目的 GitHub 发布页面 或类似的官方网络源的二进制文件。
- wget 或 curl 安装脚本 通过管道传输到 shell,并带有关于检查脚本的适当警告。
首选安装位置
一般来说,避免不必要的并发症。 对于从源代码或二进制文件安装的未打包软件,您通常应该接受默认安装前缀,除非它非常不寻常或引入冲突。
如果软件包或其他安装方法未提供,则应为面向服务的软件提供符合官方发布建议的 init 脚本。
在 Linux 系统上,将自包含的二进制文件或目录放在 /opt
中,将独立脚本放在 /usr/local/bin
中。
软件和系统维护
Ubuntu 和 Debian 系统应该有 unattended-upgrades
至少安装和配置安全更新。 我们建议不要自动重启或自动更新所有,给定上下文。
我们通常推荐 sudo apt-get dist-upgrade
而不是 sudo apt-get upgrade
,仔细查看提议的更改以确保没有破坏性发生。 这两个命令非常相似,但使用 upgrade
可能不太可预测,因为某些更改会被阻止。 保留某些软件包可能会导致版本不匹配,从而可能导致生产系统出现问题。 我们将继续在 Ubuntu 16.04 上使用 apt-get
,因为缺少 apt
的文档,而且发行版的首选包管理器存在一些混乱。
服务管理
确保使用本机 init 系统命令,即使旧的兼容性命令可用。 例如,使用 sudo systemctl start [service_name]
即使 sudo service [service_name] start
可以工作。
提供有关如何在启动时启用或禁用服务的信息。 指示在界面未明确指示时如何检查服务相关命令的结果(journalctl -u
、systemctl status
等)。
根据经验,更喜欢重新启动服务而不是重新加载服务。 在大多数情况下,确保已知状态比避免瞬间服务中断更重要,并且在服务完全失败的情况下重新启动也更有用。
自举系统
除非它是配置管理工作流程的一部分,否则在大多数情况下,更喜欢用户数据脚本,并且更喜欢 cloudinit 脚本而不是用户数据中的 bash 脚本。
日志记录和故障排除
说明在何处以及如何访问已安装服务的日志。 在相关的地方,解释用于检查服务状态和日志输出的 systemctl
和 journalctl
命令。 在可能的情况下,为诊断常见故障案例提供简明的建议。
确保在包或其他安装机制未处理的任何情况下处理日志轮换。
对于以下纯文本日志文件,请使用 tail -F
,而不是 tail -f
,因为后者不会跨重命名跟踪文件,并且如果在用户观看日志时轮换日志,可能会导致混淆。
用户和组管理
创建 sudo
用户,而不是直接使用 root。 参考相应的初始服务器设置指南,该指南将此任务解释为先决条件。
在基于 Debian 的发行版上,分别使用 adduser sammy
和 deluser --remove-home sammy
添加和删除用户; 在基于 RHEL 的发行版上,使用 adduser sammy
(如有必要,使用 passwd sammy
设置密码)和 userdel -r sammy
。
在 Ubuntu 上使用 usermod -aG sudo sammy
授予 sudo
权限。 CentOS 稍微复杂一些。 现代版本使用 usermod -aG wheel sammy
,但有些版本需要 visudo
先取消注释 wheel
组权限。 具体来说,在 CentOS 5 上,需要安装 sudo
并且需要用 visudo
取消注释 wheel 组; 在 CentOS 6 上,sudo
已经安装,但 wheel 需要取消注释; CentOS 7 有 sudo
并且 wheel 组已经设置好了。
使用提权命令时,请确保按书面方式对其进行测试。 要通过 sudo
传递环境变量,请使用 sudo -E command_to_run
(如果整个环境受信任)或 sudo FOO=BAR command_to_run
。 对于需要 root shell 的实例,请使用 sudo -i
。 对于需要重定向的实例,使用 tee -a
追加而不是替换目标文件:[sudo] command_to_run | sudo tee [-a] file_to_change
。
首选工具
对于交互式 shell,假设在 GNU/Linux 系统上使用 Bash,相关时明确提及。 在 FreeBSD 上,使用 tcsh,因为它是开箱即用的并且具有有用的特性。
对于文本编辑器,我们包含“使用 [首选] 或您最喜欢的文本编辑器”的副本,并在用于复制和粘贴的命令中包含以下对初学者友好的编辑器。 在 Linux 上,我们默认为 nano
; 在 FreeBSD 上,我们默认为 ee
。 vi(m) 是允许的,但要避免在介绍性主题中使用它,因为它可能会成为初学者的绊脚石。
对于文件传输,我们通常推荐 sftp
在大多数情况下,因为它的交互和类似 scp 的用途,虽然它缺乏推送功能,所以 scp
也是可以接受的。 rsync
对于备份和大型传输(或许多小文件)很有用。 在任何情况下都不要使用 FTP。 我们还努力在 curl
上标准化 wget
,因为它具有鲁棒性。 wget
的优势多是递归下载(即 一个特殊的用例,对于我们的内容来说并不常见)。
在附带 iproute2
实用程序的机器上,我们更喜欢它们而不是 net-tools
套件, 被认为已过时 。 通常,ss
等 iproute2
实用程序将对多接口、IPv6、新内核功能等提供更好的支持。 所以同样地,我们应该在 route
上使用 ip route
,在 ifconfig
上使用 ip addr show
等等。 有时较旧的实用程序输出默认情况下更干净一些,但输出本身的可信度有点低,因为它们也不处理边缘情况。 如果可能,我们将使用可用标志来控制更详细的输出。
脚本
在系统管理教程的上下文中,通常避免冗长的自定义脚本和冗长的 shell 脚本。
作者编写的脚本(可能还有其他资源)应位于 do-community GitHub 帐户中的每篇文章存储库中,并带有返回已发布教程的链接。 一般遵循良好的脚本编写实践。 例如,将用户必须填写的任何变量放在脚本的顶部,最好放在标记清楚的部分。 还要确保认真地发表评论; DO 教程中内联的脚本正文不应充当黑匣子。 用户应该能够通过阅读来理解含义。
优先考虑 /bin/sh
而不是 bash
并在考虑可移植性或跨平台重用时避免 Bash 特定的功能。 使用 shell 和 coreutils/标准 Unix 工具来完成小任务; 避免纯粹为胶合语言任务引入新的依赖关系,除非好处是巨大的。 首选 #!/usr/bin/env interpreter
到 #!/path/to/interpreter
。
通常,使用 cron
来调度重复任务,但也可以使用 systemd 计时器。
文件系统位置
下载脚本或数据时,请确保用户位于可写目录或明确指定路径。 对于应该可供参考或重用的文件,请使用用户的主目录,除非它们属于文件系统上其他地方的某个标准定义良好的路径(例如 /opt
或 /etc
)。 对于一次性文件,请使用 /tmp
。
网络服务器
对于默认情况下不采用这种结构的发行版,我们建议使用 Debian 风格的配置目录。 始终测试配置更改(Apache 使用 sudo apachectl configtest
,Nginx 使用 sudo nginx -t
)。 /var/www/html
应该用作所有 Web 服务器的文档根目录。 应该更改 Nginx 的 /usr/share/nginx/html
默认值,因为该目录归包更新所有并且可能被包更新修改。 这在 Ubuntu 16.04 中不再是问题,但仍与以前的版本相关。
展望未来,更喜欢创建新的 Apache 虚拟主机文件或 Nginx 服务器块文件,而不是修改提供的默认文件。 这有助于避免一些常见错误,并将默认文件保持为预期的后备配置。
安全
加密和验证系统之间的所有连接。 不要鼓励(明示或暗示)用户发送凭证或明文传输非公开数据。
具体而言,不得通过不安全的连接传输密码和密钥材料。 理想情况下,数据库连接、日志记录、集群管理和其他服务应始终加密。 基于 Web 的控制面板必须 通过 HTTPS 连接 提供服务,并且 TLS/SSL 应该用于支持它的服务。 像普通 HTTP 这样的面向公众的服务是允许的,因为用户可能仍然希望或需要提供它们,但在一般情况下应强烈反对,特别是对于动态内容。
避免通过晦涩难懂或戏剧性的方式构成低效益安全性的做法,例如更改默认 SSH 端口。 一定要配置防火墙。 我们针对发行版的建议是 ufw
用于 Ubuntu,iptables
用于 Debian,firewalld
用于 CentOS。 然而,iptables
是跨平台最一致的,并且有很多工具可以与之挂钩。
SSH
我们建议不要更改默认的 SSH 端口,以避免低效益的隐匿安全实践。 更改端口可能有助于减少日志中的杂物,但这仅应在这是主要问题的特定情况下进行。
禁用密码身份验证并对 root 使用仅密钥身份验证,或者完全禁用 root 登录。 确保使用强 SSH 密钥,至少 2048 位 RSA,但建议使用 4096; 由于技术原因不再推荐 ECDSA,而且 Ed25519 和椭圆曲线算法支持不够广泛。
对任何交互式密钥使用密码短语,但不可用于非交互式进程。 设置或复制和更改从 root 帐户到用户主目录的 SSH 密钥的所有权。 在实用的地方安装 fail2ban。
请注意,虽然 SSH 代理转发对于 CoreOS 等平台上的正常工作流是必需的,但它带来了一些安全问题。 本质上,任何对您的主机具有权限的人都可以使用转发套接字连接到您的本地 ssh-agent。
SSL/TLS
我们强烈建议使用 Let's Encrypt 以方便使用,并推荐使用 TLS。 使用强大的 SSL 安全性; 查看 https://cipherli.st/(现代和传统建议)。
对于没有域名的主机,我们建议使用足够强度的自签名证书。 再次查看 https://cipherli.st/ 以及 this Self-Signed Certification on Nginx guide 等指南中使用的自签名证书创建。 启用加密时设置强 Diffie-Hellman 密钥,如 自签名 SSL 认证 on Apache 和 Nginx。
VPN
我们推荐 VPN 作为服务器之间一般加密通信的解决方案。 当服务器之间需要保护多种服务时,VPN 变得越来越有价值; 所有内部通信都可以通过管道传输到 VPN,而不是单独加密每个服务。 如果相关服务不支持本机加密,这将特别有用。
我们通常推荐使用 Tinc over OpenVPN 进行服务器到服务器的通信。 你可以阅读 这篇关于 Ansible 和 Tinc 的文章,了解更多细节和实现。
结论
这本质上是一个固执己见的活文档,并且会经常更新。 技术变化很快,我们 DigitalOcean 尽最大努力跟上,但如果您发现任何错误或有反馈,我们将监控下面的评论。