云服务器配置记录

最近对静态博客比较感兴趣,再加上静态博客相较于动态博客可以减少一大笔性能开销,给其他服务腾出了空间,因此将博客从 WordPress 迁移到了 Hexo 上。既然博客都迁移了,那不如就给服务器也来一次翻新吧!

基础配置

安装系统、配置SSH

我的服务器是阿里云的轻量应用服务器,如果是其他家的服务器,也可以适当参考一下。系统镜像我选择了最新的“CentOS 8.2”。系统安装完成后,首先在控制台配置防火墙。由于我会在服务器上配置 Firewalld 作为防火墙,并不需要用到阿里云的控制台中的防火墙。找到 安全 - 防火墙,删除自动生成的允许 SSH 的规则,选择 添加规则 - 应用类型 - 全部TCP+UDP,这样控制台中的防火墙就会允许所有流量通过。结果应该如下图:

配置完防火墙之后,需要设置一下服务器的系统密码。选择 服务器运维 - 远程连接,打开在线终端。如图:

在终端中,输入如下命令:

sudo su
passwd

配置完密码之后,更改一下主机名:

hostnamectl set-hostname [新的主机名]

再安装几个常用软件:

yum install -y nano screen htop

接下来,需要更改一下 SSH 的端口,以减少被爆破的风险。编辑配置文件:

nano /etc/ssh/sshd_config

找到如下字样:

#Port 22

修改成:

Port 22
Port [SSH 端口]

保存。现在需要重启 SSH 服务使改动生效:

systemctl restart sshd
由于 Firewalld 默认只允许 22 端口,这里保留 SSH 服务的 22 端口的目的,是为了防止 SSH 服务的非 22 端口被 Firewalld 阻挡从而锁死的情况。
要在 nano 中搜索,只需按下 `Ctrl + W`,输入关键字,再按下 `Enter` 即可。再次按下 `Ctrl + W` 会保留上一次输入的关键字,可以直接按下 `Enter` 搜索下一个匹配的目标。
按下 `Ctrl + O`,再按下 `Enter` 即可保存改动。再按下 `Ctrl + X` 即可退出 nano。

配置防火墙

现在可以使用终端软件来连接了!连接到服务器之后,就可以开始配置 Firewalld 了。在默认情况下,Firewalld 是被禁用的状态,需要手工启用:

systemctl start firewalld
systemctl enable firewalld

现在检查一下 Firewalld 服务的状态:

systemctl status firewalld

会得到类似这样的输出:

● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-11-27 12:43:33 CST; 1h 34min ago
     Docs: man:firewalld(1)
 Main PID: 2704 (firewalld)
    Tasks: 2 (limit: 12399)
   Memory: 27.1M
   CGroup: /system.slice/firewalld.service
           └─2704 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork --nopid

至此,Firewalld 就已经启动了。服务启动后,默认规则就会生效。现在查看一下默认规则:

firewall-cmd --list-all

会得到类似这样的输出:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
可以看到,默认规则仅允许了 SSH 服务,即 22 端口。如果当前 SSH 会话使用的是非 22 端口,仍然可以继续通讯;但是断开连接后将无法再次连接。在完成后续操作前,尽量不要断开连接。如果不小心断开了连接,可以使用 22 端口再次连接。

现在配置防火墙规则:

firewall-cmd --remove-service=cockpit --permanent
firewall-cmd --remove-service=dhcpv6-client --permanent
firewall-cmd --remove-service=ssh --permanent
firewall-cmd --add-port=[SSH 端口]/tcp --permanent
firewall-cmd --reload

检查防火墙规则:

firewall-cmd --list-all

会得到类似这样的输出:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services:
  ports: [SSH 端口]/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
同样的,当前的规则已经不再允许 22 端口的通讯。如果当前的 SSH 会话使用了 22 端口,连接不会立即中断;但是断开连接后就无法再次通过 22 端口连接了,只能使用非 22 端口连接。

同时,由于阿里云的控制台中的在线终端使用了 22 端口,将无法使用。

至此,Firewalld 配置完毕。

配置Fail2ban

虽然已经修改了 SSH 的默认端口,但是为了防止被更高阶的扫描器爆破,我选择安装 Fail2ban 来加强防护。

由于系统自带的软件源中不包含 Fail2ban,需要安装新的软件源:

yum install -y epel-release

如果在安装过程中,出现了类似这样的报错:

Error: Failed to download metadata for repo 'epel-modular'

则说明网络存在问题,可以更换阿里云的镜像。编辑配置文件:

nano /etc/yum.repos.d/epel-modular.repo

metalink= 一行注释,并在 #baseurl= 一行后新增一行 baseurl=http://mirrors.cloud.aliyuncs.com/epel/8/Everything/$basearch。修改结果如下:

[epel-modular]
name=Extra Packages for Enterprise Linux Modular $releasever - $basearch
# It is much more secure to use the metalink, but if you wish to use a local mirror
# place its address here.
#baseurl=https://download.example/pub/epel/$releasever/Modular/$basearch
baseurl=http://mirrors.cloud.aliyuncs.com/epel/8/Everything/$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-modular-$releasever&arch=$basearch&infra=$infra&content=$
enabled=1
gpgcheck=1
countme=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8

保存改动,再次运行命令即可。

安装完软件源之后可以安装 Fail2ban:

yum install -y fail2ban

在默认情况下,Fail2ban 是被禁用的状态,需要手工启用:

systemctl start fail2ban
systemctl enable fail2ban

现在检查一下 Fail2ban 的统计信息:

fail2ban-client status

会得到类似这样的输出:

Status
|- Number of jail:      0
`- Jail list:

可以看到 Fail2ban 默认没有任何规则。现在添加一个规则来保护 SSH 服务。编辑配置文件:

nano /etc/fail2ban/jail.local

输入如下内容:

[sshd]

enabled   = true
port      = [SSH 端口]
banaction = firewallcmd-rich-rules
bantime   = 24h # 封禁时长

保存,重启一下服务:

fail2ban-client reload

再次查看统计信息:

fail2ban-client status

会看到刚刚设置的规则已经被启用了:

Status
|- Number of jail:      1
`- Jail list:   sshd

而进一步查看 SSH 服务的封禁情况:

fail2ban-client status sshd

会看到目前没有被封禁的 IP:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

如果拥有一个以上的公网地址,也可以使用不同的 IP 多次输入错误密码进行测试。失败次数达到 5 次之后,SSH 通讯将被阻断。查看 SSH 服务的封禁情况:

fail2ban-client status sshd

会看到用于测试的 IP 已经被封禁了:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 1
|  |- Total failed:     6
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:   [测试 IP]

而查看 Firewalld 的规则:

firewall-cmd --list-all

也可以看到相关规则已经被添加到 rich rules 中了:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services:
  ports: [SSH 端口]/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
        rule family="ipv4" source address="[测试 IP]" port port="[SSH 端口]" protocol="tcp" reject type="icmp-port-unreachable"

如要解封测试 IP,可以输入以下命令:

fail2ban-client unban [测试 IP]

如要解封所有 IP,可以输入以下命令:

fail2ban-client unban --all
在默认的情况下,封禁前允许的最大失败次数由 `/etc/fail2ban/jail.conf` 文件中的 `maxretry` 定义,其值为 5。
由于一次 SSH 会话可能允许多次身份验证尝试,而 Firewalld 不会断开已经建立的连接,因此实际可以尝试的次数可能会大于设置的阈值。

至此,Fail2ban 配置完毕。

删除云盾

如果服务器是不同家的,需要参考对应的官方文档。

执行官方的卸载脚本,并删除相关文件,最后重启即可生效:

wget http://update.aegis.aliyun.com/download/uninstall.sh && chmod +x uninstall.sh && ./uninstall.sh
wget http://update.aegis.aliyun.com/download/quartz_uninstall.sh && chmod +x quartz_uninstall.sh && ./quartz_uninstall.sh
pkill aliyun-service
rm -rf /etc/init.d/agentwatch /usr/sbin/aliyun-service
rm -rf /usr/sbin/aliyun*
rm -rf /usr/local/aegis*
rm -rf /etc/systemd/system/aliyun.service
reboot

配置LNMP

安装

创建一个 screen 的实例:

screen -S lnmp

安装 LNMP 环境:

wget http://soft.vpser.net/lnmp/lnmp1.8.tar.gz -cO lnmp1.8.tar.gz && tar zxf lnmp1.8.tar.gz && cd lnmp1.8 && ./install.sh lnmp

全部选择默认选项即可。

查看所有的 screen 实例:

screen -ls

恢复到某一个 screen 实例(留空则恢复到上一个实例):

screen -r [实例名称]

创建虚拟主机

首先确保相关域名已经解析到服务器的 IP 上,之后就可以创建虚拟主机了。执行以下命令:

lnmp vhost add

根据情况选择选项即可,可根据情况部署 SSL 证书。

配置rewrite规则

如果有 HTTP 跳转 HTTPS,A 域名跳转 B 域名等需求,可以通过 rewrite 规则来实现。编辑配置文件:

nano /usr/local/nginx/conf/vhost/[域名].conf

找到 server {} 句块,加入跳转语句:

rewrite ^(.*)$ https://[目标域名]/$1 permanent;

如果需要条件跳转,则加入语句:

if ($host != '[匹配域名]'){
    rewrite ^/(.*)$ https://[目标域名]/$1 permanent;
}

重启 Nginx 即可生效:

lnmp nginx restart

开放端口

LNMP 安装完成后,需要开放 HTTP 和 HTTPS 的端口。执行以下命令:

firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload

配置frps

关于 frp 的原理和部署,之前已经在别的文章中讲解过了,因此这里只讲一下部署过程。

安装与配置

首先下载 frps。打开官方发布页 https://github.com/fatedier/frp/releases,根据服务器的架构和系统找到合适的版本。比如我的服务器是 X86-64 架构的,使用的是 CentOS 系统,所以选择 linux_amd64 版本的。右键复制链接地址。在终端中输入以下命令:

wget frp_0.38.0_linux_amd64.tar.gz # 复制的链接地址
tar xzvf frp_0.38.0_linux_amd64.tar.gz # 下载的文件名称
cd frp_0.38.0_linux_amd64 # 解压得到的文件夹名称
cp frps /usr/bin/frps
mkdir /etc/frp
cp frps.ini /etc/frp/frps.ini

编辑 frps 的配置文件:

nano /etc/frp/frps.ini

输入以下内容:

[common]
bind_port = [frps 端口]
token = [frps 口令]
log_file = /var/log/frps.log
dashboard_port = [frps 控制面板端口]
dashboard_user = [frps 控制面板用户名]
dashboard_pwd = [frps 控制面板密码]

解决无日志的问题

默认安装完成后,即便在配置文件中启用了日志功能,也无法看到日志,这是没有权限导致的。现在修改服务项的配置文件:

nano /usr/lib/systemd/system/frps.service

找到 User=nobody,改为 User=root,保存并退出即可。

重新加载服务项:

systemctl daemon-reload

最后就可以启动服务:

systemctl start frps
systemctl enable frps

开放端口

执行以下命令:

firewall-cmd --add-port=[frps 端口]/tcp --permanent
firewall-cmd --add-port=[frps 控制面板端口]/tcp --permanent
firewall-cmd --reload

如果有服务通过 frps 进行内网穿透,也要开放对应的端口。

配置Python

安装

执行以下命令:

yum install -y python3

测试是否安装成功:

python3

看见类似这样的输出:

Python 3.6.8 (default, Apr 16 2020, 01:36:27)
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

说明 Python 已经被成功安装了。

配置虚拟环境

首先安装 virtualenv:

pip3 install virtualenv

在当前目录下创建一个虚拟环境:

virtualenv -p python3 [虚拟环境名称]

激活虚拟环境:

source [虚拟环境名称]/bin/activate

退出当前的虚拟环境:

deactivate

使用systemd部署Gunicorn+Flask服务

创建一个新的 systemd 服务项:

nano /usr/lib/systemd/system/[服务名称].service

输入以下内容:

[Unit]
Description=[服务描述]
After=syslog.target network.target

[Service]
WorkingDirectory=[工作目录]
ExecStart=[Gunicorn 路径] [模组名称]:[实例名称] -b [监听地址]:[监听端口]
Restart=on-failure

[Install]
WantedBy=multi-user.target

工作目录:填写 Flask 项目的路径,如 /root/flask_app
Gunicorn 路径:填写 Gunicorn 可执行文件的路径,如 /root/flask_venv/bin/gunicorn
模组名称和实例名称:填写 Flask 应用的模组名称和实例名称,例如,名为 run.py 的文件中定义了 app = Flask(),则填写 run:app
监听地址:如果希望通过 Nginx 代理给外部访问,则设置 127.0.0.1;如果希望直接开放端口给外部访问,则设置 0.0.0.0 或服务器地址,并使用以下命令开放端口:

firewall-cmd --add-port=[监听端口]/tcp --permanent
firewall-cmd --reload

重新加载服务项:

systemctl daemon-reload

之后,就可以用 systemd 来管理服务了:

systemctl [start|stop|restart|kill|status] [服务名称]

配置Nginx代理

编辑对应的 Nginx 虚拟主机的配置文件:

nano /usr/local/nginx/conf/vhost/[域名].conf

server {} 中,添加代理代码:

location / {
    proxy_pass http://[监听地址]:[监听端口];
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

如果有静态资源,也可以在上述代码片段之前加入以下代码:

location ^~ /static/ {
    root [静态资源路径];
}

这样所有 /statis/ 开头的请求都不会被转发,而会在静态资源路径中直接查找。

注意,如果请求的路径为 `/static/index.html`,则对应文件的位置应该在 `[静态资源路径]/static/index.html`。通常来说,*静态资源路径*不需要包含 `static` 字样。

安装Node.js

运行以下命令:

yum install -y nodejs

运行 node 产生类似这样的输出即为安装成功::

Welcome to Node.js v16.13.1.
Type ".help" for more information.
>

安装Java

运行以下命令:

yum install java-17-openjdk

运行 java --version 产生类似这样的输出即为安装成功:

openjdk 17.0.1 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)

参考文章

  1. CentOS 7安装fail2ban + Firewalld防止爆破与CC攻击
  2. yum安装插件报错Failed to download metadata for repo ‘epel-modular‘ 的解决方案
  3. CentOS 7下的VirtualEnv的安装配置简明教程
  4. 使用Nginx+Gunicorn+systemd部署flask应用
  5. 使用Nginx反向代理Flask站点