新安装 Linux 上的必要操作

每次新安装完 Linux,都需要进行一些基本的配置和工具安装。可是由于这个操作比较低频,每次回忆一些细节都很费劲,还得重新搜索。

这次重装了某个服务器(CentOS 7),顺便记录下来,避免下次重复浪费时间,顺便供网友参考。

后来顺便整理了装有 Ubuntu 的测试机,追加 Ubuntu 部分。

如果涉及到国内的服务器,需要更换镜像以加速,参考 镜像清单 ,这也是一个不定时更新的清单。

因为是不定时更新,内容时间跨度比较长,更新的内容可能会出现(系统 / 软件)前后版本不一致。个别下载地址也会有更新。

另外,根据具体安装的工具不同,包管理器可能是 yum 也可能是 apt,系统服务管理命令可能是 service、chkconfig 或者 systemctl。照着操作时要理解操作的意图。

本清单主要是提供一个线索,具体操作细节根据实际情况变通。

确认发行版本

一般情况下,系统是自己装的,你会知道版本。但也有可能是 VPS / 云主机 直接提供了一个系统。或者隔太久没登录,忘了。

1
2
3
4
5
6
7
8
9
10
11
lsb_release -a
# 但是 lsb_release 不是所有发行版本都支持,那就试试下面的
# 仅限 redhat 系
cat /etc/redhat-release
# 仅限 cent-os
rpm -q centos-release
# 其它
cat /etc/issue
# 查看内核信息
cat /proc/version
uname -a

创建 Linux 用户

直接使用 root 进行操作,是相当危险的行为。上来应该赶紧创建一个用户,然后授予 sudo 权限。

1
2
3
4
5
6
7
8
9
# 新建用户
useradd <newuser>
# 设置密码,这个密码既不能太弱有安全风险,也不能太难记——毕竟每次 sudo 都得敲一遍。
# 个人建议想一句名言,抽取拼音或者首字母,再随机加少量符号和数字,这样既保证强度,又不太难记
passwd <newuser>
# 加入 wheel 组获得管理员权限
usermod -g wheel <newuser>
# 如果有必要,调整 sudo 设置。我一般会给 env_keep 加上 PATH。免密就算了,不是好习惯。
visudo

后续重新登录,在新用户下操作。

基本工具

默认情况下,预装的软件源和工具都比较有限,很多工具找不到,需要添加一些额外的源。

CentOS 7

EPEL repo

1
2
# 查看 https://fedoraproject.org/wiki/EPEL 换成对应的系统版本
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

常用工具

1
2
3
4
5
6
7
8
9
# 非常惊讶有些发行版本居然连 vim 都有没有
sudo yum install vim
# ssh 多路复用工具 byobu,以 tmux 或 screen 为后端
sudo yum install byobu
# 启动一下 byobu 然后退出,生成配置文件
# 将后端从 tmux 改为 screen。这纯粹个人习惯而已,按理说 tmux 更强大
vim .byobu/backend
# 再次进入 byobu,然后 Ctrl+A ,触发 escape 选项,一般选 Screen mode
# F9 设置 screen 常用选项

Ubuntu

如果服务器在国内,把软件源换成速度快一点的镜像,如阿里云 http://mirrors.aliyun.com/ 。如果直接就是阿里云的机器,换成 http://mirrors.aliyuncs.com/ 可以走内网流量。

国外的服务器就没必要折腾了。

工具安装方面,直接把命令里的 yum 换成 apt-get ,常用工具貌似不用添加额外的源。

远程作业,网络不好随时断掉,byobu 还是很必要的。

安装好之后后续操作尽量在 byobu 上完成,避免因为网络抖动引起操作中断。

启用 BBR

Google 的 TCP BBR(Bottleneck Bandwidth and Round-trip propagation time) 可以改善 TCP 的网络传输,在不同网络状况下,大约可以提高 4%~14% 的效率。

注意并不是 BBR 就一定比别的算法好,具体需要看所处的网络环境和看重的指标。

不同 TCP 拥堵控制算法之间的差别,可以参考 TCP拥堵控制 ;网络调度器则参考 Network Scheduler

怕指令有不严谨或不兼容的情况,留一个参考互相对比 一键安装最新内核并开启 BBR 脚本

1
2
# 确认内核版本 >= 4.9
uname -r

假定内核版本过低,要升级内核。

CentOS 7 升级

1
2
3
4
5
6
7
8
9
10
# 引入对应的 repo
sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
# 安装
sudo yum --enablerepo=elrepo-kernel install kernel-ml -y
# 设置默认内核
sudo egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d \'
sudo grub2-set-default 0 # default 0 表示第一个内核设置为默认运行, 选择最新内核就对了
# 重启
sudo reboot

Ubuntu 14.04

升级内核有三种方案(看到最后,不要急着动手,推荐 HWE)

  • 手动安装最新的内核

    优点是可以尝试最新的内核,缺点是依赖地狱,和无法自动获得后续更新。

    https://www.kernel.org/ 确定内核版本(选择 Stable 或者 Longterm)。

    https://kernel.ubuntu.com/~kernel-ppa/mainline/ 找到对应内核的链接。

    由于较新的内核依赖较新的 linux-base 和 lib (如 libssl 1.1.0);而手动安装 linux-base ,以及解决其他依赖问题,还不如直接升级系统版本到 16.04 或者更新的 18.04。如果因为特殊原因,只要启用 BBR 而不愿意升级系统,建议直接安装 4.9.x 的内核。

    下载对应的架构(一般是 amd64)的 deb 文件,包括两个 headers,一个 image,如果是 4.17+,还有 modules。如果有不止一套 deb 文件,在没有特殊需求情况下 选 generic (通用)。

    1
    2
    3
    4
    5
    6
    7
    # 下载
    wget linux-headers-xxx_all.deb
    wget linux-headers-xxx_amd64.deb
    wget linux-image-xxx_amd64.deb
    wget linux-modules-xxx_amd64.deb
    # 安装,注意 dpkg 不会自动解决依赖,如果出现依赖问题,要按提示手动解决
    sudo dpkg -i linux-*.deb
  • 直接升级系统版本

    为了满足某个内核(我测试时尝试了 4.19)的依赖,而一路升级系统版本(因为 16.04 的 libssl 只有 1.0.2),最后升到 18.04 发现内核已经是 4.15 了,只是为了支持 BBR 已经没有必要自己再升级内核了。

  • 安装 HWE 内核 (HardWare Enablement stack,又叫 LTS Enablement)

    详情参考 https://wiki.ubuntu.com/Kernel/LTSEnablementStack

    简单说,就是 Ubuntu 为了老系统可以支持最新的硬件和内核,为 LTS (LongTerm Support 长期支持版本)系统打包测试最新的 内核 和 关键组件(如 XServer)。区别于稳定的 GA 内核(General Availability,通用可用性),过快应用新内核可能引入一些潜在的问题,但总比自己安装未经 Ubuntu 测试的内核要强。

    对14.04 来说,就是用 apt 安装以下内容

    1
    2
    3
    4
    5
    6
    7
    8
    # xserver 及后面的包仅 Desktop 需要, Server 版不用安装
    sudo apt-get install --install-recommends \
    linux-generic-lts-xenial \
    xserver-xorg-core-lts-xenial \
    xserver-xorg-lts-xenial \
    xserver-xorg-video-all-lts-xenial \
    xserver-xorg-input-all-lts-xenial \
    libwayland-egl1-mesa-lts-xenial

无论用哪种方法,成功安装之后:

1
2
3
4
5
# 更新 grub,手动安装记得先解决掉依赖问题
sudo update-grub
# 重启
sudo reboot
# 重启成功可以考虑清理一下不用的内核

如果升级了内核,等重启完毕,再次 uname -r 确认一下,继续。

以下内容与发行版本无关

1
2
3
4
5
6
7
# 查看内核模块是否有加载 bbr
lsmod | grep bbr
# 输出以下两个值,看是不是包含 bbr
# 可用的拥堵控制算法
sysctl net.ipv4.tcp_available_congestion_control
# 当前使用的拥堵控制算法
sysctl net.ipv4.tcp_congestion_control

如果有,下面的就不用执行了

1
2
3
4
# 加载内核模块
sudo modprobe tcp_bbr
# 加入开机自动加载
echo "tcp_bbr" | sudo tee --append /etc/modules-load.d/modules.conf

到这里,内核模块(lsmod | grep bbr)和 可用算法(sysctl net.ipv4.tcp_available_congestion_control)应该已经可以看到 bbr 了,可以先检查一下。

接下来启用:

1
2
3
4
# 修改网络分组调度器,一般默认是 fq_codel 公平受控延迟,改为 fq 公平队列
sudo sysctl net.core.default_qdisc=fq
# 修改当前的拥堵控制算法
sudo sysctl net.ipv4.tcp_congestion_control=bbr

docker-ce

现在 docker 分为了 社区版(CE) 和 企业版(EE),安装的最新方式参考 https://docs.docker.com/install/linux/docker-ce/centos/

CentOS 7

同样先以 CentOS 7 为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 可能带有老版本,先卸载
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 用 yum repo 安装,先安装相关工具
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
# 添加 stable repo
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 安装最新版本
sudo yum install docker-ce docker-ce-cli containerd.io
# 启动服务
sudo systemctl start docker
# 测试效果
sudo docker run hello-world

Ubuntu 16.04

docker-ce 支持的 Ubuntu 最低版本是 16.04。如果太低,先要升级系统版本。

在满足系统要求之后:

1
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
# 先卸载可能存在的旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安装用到的工具
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# 添加官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 通过搜索指纹的后八位,确认密钥正确安装
# 完整的指纹是 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
sudo apt-key fingerprint 0EBFCD88
# 添加 apt-get 仓库,根据需要可以替换 架构,和 channel
# (除了 stable,还可以选不稳定的 nightly 和 test)
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# 安装
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 测试效果
sudo docker run hello-world

自动证书管理

不是用作 web 服务器的可以跳过

如果服务器是用作 web 服务器,那么在互联网安全化的浪潮下,用 HTTPS 基本上是个必选项,否则你的访问者会整天看到来自浏览器的警告,某些浏览器甚至会直接拒绝访问。当然 HTTPS 也通过加密保护了通信的数据安全。

启用 HTTPS ,当然可以手动申请、乃至买一个(知名机构签发的)SSL 证书,然后每年快到期的时候,记得手动一个个去更新。但 更方便的方式 是通过 Let’s Encrypt 来签 一个证书;并且设置一个定期任务,在证书到期时自动续签。

引用官方的自我介绍

我们以尽可能对用户友好的方式免费提供为网站启用 HTTPS(SSL/TLS)所需的数字证书。 这是因为我们想要创建一个更安全,更尊重隐私的 Web 环境。

Let’s Encrypt 是免费、开放和自动化的证书颁发机构。由非盈利组织互联网安全研究小组(ISRG)运营。

使用 Let’s Encrypt 有好几种方式,如果仅仅是申请和更新证书,可以选择 certbot(Python)、lego(go)或 acme.sh 脚本。

这里有一个官方的推荐客户端清单:https://letsencrypt.org/zh-cn/docs/client-options/

其中有一些不仅仅是一个证书管理工具,证书管理只是它一部分的功能。例如 Caddy 就是一个自带 LE 支持的完整 web 服务器,可以用来替代 Nginx。

需要注意 LE 正在淘汰它们的 v1 版 API,需要确认你使用的客户端支持 v2 API。如果是早期安装的客户端,需要确认升级到最新版本。

certbot

这里的内容可能过时,最新的指引,请参考 https://certbot.eff.org/instructions

注意在做以下操作之前,需要 先注册了域名,并且已经将域名指向了对应地址 。域名注册 以及 添加 DNS 记录,每个服务商操作有所不同,而且不难,不再展开。只记住两个关键:

  • 非商用的话,免费的 DNS 服务足以。国内有老牌的 DNSPod(已被腾讯云收购),国外有 Cloudflare。因为 Cloudflare 还是一个 CDN 供应商,还能提供免费的 CDN 服务,推荐。
  • A 记录指向 IP,CNAME 记录指向另一个域名,MX 记录指向邮箱服务。注册一个域名,可以把不同的子域名用于不同用途,但是免费的 DNS 服务商可能会限制 DNS 记录数,所以要好好规划一下。

CentOS 7 安装

首先启用 EPEL repo (上面已经提过)。

1
2
3
4
5
6
# yum-utils 在 docker-ce 也安装过
sudo yum -y install yum-utils
# 启用 optional channel
sudo yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional
# 安装
sudo yum install certbot

然后以下部分,与发行版无关:

然后是获取证书

1
2
3
# 这里假定真正的 web 服务还没启动,由 certbot 启动一个临时的 webserver 来完成认证
# 如果真正的 webserver 已经运行中且不能暂停,请参考 --webroot 参数
sudo certbot certonly --standalone

整个过程会询问 邮箱,确认几个问题,询问 域名,然后 Let’s Encrypt 就会发起一个 ACME (Automatic Certificate Management Environment, 自动证书管理环境) Challenges,完成后,证书储存在

/etc/letsencrypt/live/<YOUR.DOMAIN.COM/> ,阅读里面的 README 可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
This directory contains your keys and certificates.
`privkey.pem` : the private key for your certificate.
`fullchain.pem`: the certificate file used in most server software.
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
`cert.pem` : will break many server configurations, and should not be used
without reading further documentation (see link below).
WARNING: DO NOT MOVE OR RENAME THESE FILES!
Certbot expects these files to remain in this location in order
to function properly!
We recommend not moving these files. For more information, see the Certbot
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.

有什么文件,都干嘛用,注意事项都说了。注意证书有效期是 90 天,所以需要启动一个定期任务,去更新证书:

1
2
# 如果不是第一次操作,先看一下有没有相应的任务
sudo crontab -l | grep "certbot renew"

如果没有,则创建

这是 certbot 官方推荐的操作

1
echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q --pre-hook 'service haproxy stop' --post-hook 'service haproxy start'" | sudo tee -a /etc/crontab > /dev/null

这个任务的特点是:

  • 每天 0 时和 12 时各执行一次。
  • 调用 Python 随机休眠若干秒(random() 返回值在 [0.0,1.0),显然是为了避免扎堆)。
  • 尝试更新证书(没有用 --force-renewal 参数,如果不是接近到期是不会实际更新的)。
  • 定义了 --pre-hook--post-hook ,在更新期间停掉 haproxy,如果用的不是它,要自行修改。
  • 任务写入的是系统任务,如果想放在用户任务并以 root 执行,去掉任务里的用户(root),放在 /var/spool/cron/root

个人感觉官方这个设定过于麻烦,居然每天执行两次,而且还调用了 Python 脚本休眠最长一小时。由于不设置 --force-renewal 的情况下,只有到期前 30 天的证书会更新,所以这些任务绝大多数的执行都是无用功。我的配置如下:

1
2
3
4
# 每个月 5 号 和 20 号 的 11 时尝试更新证书
# 具体日期时分秒的数字建议大家随机改一个,避免集中对 Let's Encrypt 的服务造成压力
# 如果更新过程中需要停一下服务器,还是可以加 --pre-hook 和 --post-hook 参数
echo "0 11 5,20 * * /usr/bin/certbot renew -q" | sudo tee -a /var/spool/cron/root

当然也可以改为执行

1
sudo crontab -e

然后在打开的编辑界面,将 echo 后面的任务,单独放一行,然后 :wq 保存生效。

lego

Caddy

MySQL

虽然这里写的是 MySQL,但我一般倾向于安装它的兼容替代 MariaDB。

1
2
3
4
5
6
7
## Ubuntu
# 更新软件包索引
sudo apt update
# 安装,只需要指定安装 server,其它被依赖的软件包会自动包含
sudo apt install mariadb-server
## CentOS 把包管理器改为 yum 即可,不再赘述

直接从发行版的软件库安装非常方便,但不是最新版本。例如在更新这一部分的当下(2020 年 9 月),Ubuntu 18.04 软件索引的最新版本是 10.1,但 MariaDB 官方已经去到 10.5 了。如果对新版本有需求,则可以通过 MariaDB 官方的软件库安装。

1
2
# 下载并执行 MariaDB 官方提供的脚本,自动添加官方软件源
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash

以下内容与平台无关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 兼容版本信息(为了与 MySQL 兼容,CLI 命令是一样的)
mysql -V
# 检查配置,其中编码一定要修改
# 默认编码一般是 latin1,但涉及到中文要用 utf8mb4
# 详细内容这里不展开
sudo vim /etc/my.cnf
# 查看运行状态,此时大概率还没启动
sudo systemctl status mariadb
# 启动服务
sudo systemctl start mariadb
# 开机启动
sudo systemctl enable mariadb
# 此时可以再看一次运行状态
# 运行安全初始化,帮助确保安全性,对于生产环境,建议全部问题回复 yes,设置比较强的密码
sudo mysql_secure_installation

如果全部回答了 yes,就意味着禁止了 root 用户远程连接,此时如果还是有远程连接的需求,就需要新建用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 禁止远程连接后,只能服务器上本地登录
mysql -u root -p
# 输入密码后登录,接下来的操作都在数据库的交互终端下,这里加 > 提示符区分
# 创建用户时需要制定用户名、允许访问的来源IP、密码
# 如果不限制来源IP,可以用 % 代替
> CREATE USER 'name'@'192.168.1.100' IDENTIFIED BY 'password';
# 创建用户之后并没有任何权限,需要授权
# 授予所有操作权限,可以用 ALL PRIVILEGES 代替具体的操作权限
# 授权操作所有的数据库或表的权限,则可以用 * 代替库名或表名,例如 *.*
> GRANT SELECT, INSERT ON mydb.mytable TO 'name'@'192.168.1.100';
# 最后为了让设置事实生效
> FLUSH PRIVILEGES;
退出
> exit

这里如果为了方便,可以给新建用户授权所有权限(除了 GRANT 权限),并且不限地址。跟默认用 root 相比,起码第三方不知道用户名,不能直接穷举密码。

完成以上操作之后,可以尝试用新用户远程登录。如果登录失败,就要重新回到服务器上测试原因

1
2
3
4
5
6
7
8
# 首先测试新用户确实可用,最后 exit 退出
mysql -u newuser -p
# 然后分别测试内网地址和外网地址
mysql --host=服务器的地址 --protocol=tcp --port=3306 test
# 注意,出现以下结果属于成功(成功访问只是没密码)
# ERROR 1045 (28000): Access denied for user 'newuser'@'xxxx' (using password: NO)
# 出现以下结果则意味着无法访问
# ERROR 2002 (HY000): Can't connect to MySQL server on 'xx.xx.xx.xx' (115)

根据通过内网和外网地址访问的结果,有几种组合:

  • 都访问失败:大概率是两种情况
  • 内网成功、外网失败:大概率是防火墙造成的,所以只拦截外网的访问。查看服务器上当前使用的防火墙是 iptables 还是 firewalld,对症下药配置就好。内容比较多,不再展开。特别提醒,如果你使用的是云服务器,千万不要忘了控制面板上很可能还有一道防火墙配置。

知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议
本文为本人原创,采用知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议进行许可。
本作品可自由复制、传播及基于本作品进行演绎创作。如有以上需要,请留言告知,在文章开头明显位置加上署名(Jayce Chant)、原链接及许可协议信息,并明确指出修改(如有),不得用于商业用途。谢谢合作。
请点击查看协议的中文摘要。