前言

本文针对 Alpine Linux 整理了一套标准作业程序 (SOP),是 新到手的 Linux 服务器,我这样设置 的姊妹篇。

安装 Alpine Linux

通过自定义 ISO 安装

若服务商(如 Netcup、BuyVM、BeroHost)支持上传自定义 ISO,建议使用 Alpine LinuxVIRTUAL 版 ISO,其针对 KVM 虚拟化进行了精简与优化。

virtual-iso.webp

一键 DD 脚本重装

对于不支持挂载自定义 ISO 的服务商,可使用一键 DD 重装脚本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 下载脚本

curl -O https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh || wget -O ${_##*/} $_

# 重装 Alpine Linux

bash reinstall.sh alpine 3.23 --password '强密码'

# 重启

reboot

完成后,使用 SSH 登录新服务器系统,下面开始我们的配置。

修改主机名

1
2
3
4
5
hostname <主机名>

# 永久生效

echo "主机名" > /etc/hostname

配置普通用户和 sudo 权限

日常操作中,避免直接使用 root 账户:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 安装 sudo 软件包

apk add sudo

# 创建用户

adduser dejavu

# 将 dejavu 添加到 wheel 组

addgroup dejavu wheel

# 开启 wheel 组免密 sudo 权限

sed -i 's/# %wheel ALL=(ALL:ALL) NOPASSWD: ALL/%wheel ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers

安装基础软件包

 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
27
28
29
# 更新并升级系统现有包

sudo apk update && sudo apk upgrade

# 常用工具

sudo apk add \

    ca-certificates \

    tzdata \

    git \

    curl \

    wget \

    unzip \

    tmux \

    btop \

    bind-tools \

    tree \

    vim

启用 BBR 算法

 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
27
28
29
30
31
# 加载内核 BBR 模块

sudo modprobe tcp_bbr

# 写入配置文件,确保开机自动加载

echo "tcp_bbr" | sudo tee /etc/modules-load.d/bbr.conf

# 确保 modules 服务开机自启

sudo rc-update add modules boot

#  写入内核参数

sudo cat > /etc/sysctl.d/99-bbr.conf <<'EOF'

net.core.default_qdisc = fq_codel

net.ipv4.tcp_congestion_control = bbr

EOF

# 应用配置

sudo service sysctl restart

# 验证

lsmod | grep bbr

sysctl net.ipv4.tcp_congestion_control

SSH 加固

将公钥添加至 SSH 服务器,替代传统密码登录方式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 切换到普通用户

su dejavu

# 创建公钥目录

mkdir -p ~/.ssh

# 手动编辑 SSH 公钥

vim ~/.ssh/authorized_keys

# 或者上传 SSH 公钥

# ssh -i /path/to/your/ed25519_key username@<IP> -p <port>

# 设置权限

chmod 700 ~/.ssh

chmod 600 ~/.ssh/authorized_keys

参考 SSH 配置 ,进行基础 SSH 加固:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 编辑 SSH 服务器配置

sudo vim /etc/ssh/sshd_config

# 检查配置

sudo sshd -t

# 重启 SSH 服务

sudo rc-service sshd restart

配置 ZRAM 和 Swap

根据个人习惯,可以参考的配置比例:

CPU RAM ZRAM Swap
1vCPU 1GB 512MB (50%) 2GB
1vCPU 4GB 2GB (50%) 4GB
2vCPU 4GB 2GB (50%) 4GB
4vCPU 20GB+ 4GB (20%) 0~2GB

对于小内存服务器 (RAM ≤ 4GB),我一般开启 ZRAM 配合磁盘 Swap 以使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 创建 4GB 的 Swap 文件

sudo fallocate -l 4G /swapfile

# 上面命令也可以使用 dd 代替

# sudo dd if=/dev/zero of=/swapfile bs=1M count=4096

# 设置权限与格式化

sudo chmod 600 /swapfile

sudo mkswap /swapfile

# 开机自动挂载配置(pri=10 是优先级设置)

echo '/swapfile none swap sw,pri=10 0 0' | sudo tee -a /etc/fstab

# 启动服务

sudo rc-update add swap boot

sudo service swap start

配置 ZRAM,优先级应高于 Swap 交换空间:

1
2
3
4
5
6
7
# 安装 ZRAM 初始化工具

sudo apk update && sudo apk add zram-init

# 编辑 ZRAM 配置文件

sudo vim /etc/conf.d/zram-init

注意以下字段:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# /etc/conf.d/zram-init

load_on_start=yes

unload_on_stop=yes

num_devices=1

type0=swap

# 根据需求调整 (MB)

size0=2048

# 使用 zstd 压缩算法

algo0=zstd

启动服务:

1
2
3
sudo rc-update add zram-init default

sudo service zram-init start

优化内核内存调度:

1
2
3
4
5
6
7
8
9
sudo cat >> /etc/sysctl.conf <<'EOF'

vm.swappiness = 80

vm.watermark_scale_factor = 125

vm.page-cluster = 0

EOF

应用内核参数:

1
sudo sysctl -p

验证效果:

1
2
3
4
5
sudo zramctl

sudo cat /proc/swaps

sudo swapon --show

配置 Nftables 防火墙

1
2
3
4
5
6
7
# 安装

sudo apk update && sudo apk add nftables

# 编辑规则

sudo vim /etc/nftables.nft

示例配置:

  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
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/sbin/nft -f

# 清空所有规则

flush ruleset

table inet filter {

    # ============================================================

    # Cloudflare CDN IP 集合 (Sets)

    # ============================================================

    set cloudflare_v4 {

        type ipv4_addr; flags interval;

        elements = {

            173.245.48.0/20, 103.21.244.0/22, 103.22.200.0/22, 103.31.4.0/22,

            141.101.64.0/18, 108.162.192.0/18, 190.93.240.0/20, 188.114.96.0/20,

            197.234.240.0/22, 198.41.128.0/17, 162.158.0.0/15, 104.16.0.0/13,

            104.24.0.0/14, 172.64.0.0/13, 131.0.72.0/22

        }

    }

    set cloudflare_v6 {

        type ipv6_addr; flags interval;

        elements = {

            2400:cb00::/32, 2606:4700::/32, 2803:f800::/32, 2405:b500::/32,

            2405:8100::/32, 2a06:98c0::/29, 2c0f:f248::/32

        }

    }

    # ============================================================

    # INPUT 链 (入站)

    # ============================================================

    chain input {

        type filter hook input priority filter; policy drop;

        # 放行回环接口和已建立的连接

        iif "lo" accept

        ct state { established, related } accept

        ct state invalid drop

        # 合并 Alpine 默认的关键 ICMPv4 规则,防止 PMTU 黑洞

        ip protocol icmp icmp type { echo-reply, destination-unreachable, echo-request, time-exceeded, parameter-problem } accept

        # 合并 Alpine 默认的关键 ICMPv6 规则

        icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } accept

        # 允许 IPv6 SLAAC 和邻居发现

        icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept

        # 允许 SSH 服务

        tcp dport 22122 accept

        # 仅限 Cloudflare IP 段访问 80/443

        ip saddr @cloudflare_v4 tcp dport { 80, 443 } accept

        ip6 saddr @cloudflare_v6 tcp dport { 80, 443 } accept

    }

    # ============================================================

    # FORWARD 链 (转发)

    # ============================================================

    chain forward {

        type filter hook forward priority filter; policy drop;

        ct state { established, related } accept

        ct state invalid drop

        # qBitTorrent Docker 端口放行

        # tcp dport 10880 accept

        # udp dport 10880 accept

        # 允许 Docker 容器出站及互通

        iifname "docker0" accept

        iifname "br-*" accept

        iifname "docker0" oifname "docker0" accept

        iifname "br-*" oifname "br-*" accept

    }

    # ============================================================

    # OUTPUT 链 (出站)

    # ============================================================

    chain output {

        type filter hook output priority filter; policy accept;

    }

}

# 引入外部依赖配置

include "/var/lib/nftables/*.nft"

include "/etc/nftables.d/*.nft"

应用并启动服务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 验证配置

sudo nft -c -f /etc/nftables.nft

# 启动服务

sudo rc-update add nftables default

sudo service nftables start

# 检查生效规则

sudo nft list ruleset

# 后续修改应用规则

sudo nft -f /etc/nftables.nft

sudo service nftables restart

# Docker 和 Fail2ban 在 nftables 后重启

sudo service fail2ban restart && sudo service docker restart

配置 Fail2ban

1
2
3
4
5
# 安装 Fail2ban

sudo apk update && sudo apk add fail2ban

sudo vim /etc/fail2ban/jail.local

保护 SSH 服务器:

 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
27
[DEFAULT]

ignoreip = 127.0.0.1/8 ::1

bantime  = 1d

findtime = 10m

maxretry = 3

banaction = nftables-multiport

banaction_allports = nftables-allports

[sshd]

enabled = true

# SSH 服务的监听端口(务必正确匹配)

port    = 22122

backend = auto

logpath = /var/log/messages

mode    = aggressive

启动服务:

1
2
3
4
5
6
7
sudo rc-update add fail2ban default

sudo service fail2ban start

# 查看服务状态

sudo service fail2ban status

测试封禁:

1
2
3
4
5
6
7
# 模拟封禁 IP

sudo fail2ban-client set sshd banip 2400:6180:0:d2:0:2:9699:d000

# 检查 nftables 规则中是否存在 f2b 动态表

sudo nft list ruleset | grep f2b

巡查规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 查看哪些 jail 正在运行

sudo fail2ban-client status

# 查看 sshd 具体封禁情况

sudo fail2ban-client status sshd

# 测试完毕,解封测试 IP

sudo fail2ban-client set sshd unbanip 2400:6180:0:d2:0:2:9699:d000

# 重启服务

sudo service fail2ban restart

安装配置 Nginx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 安装 Nginx 软件包

sudo apk add nginx openssl

# 加入开机启动项

sudo rc-update add nginx default

# 立即启动服务

sudo service nginx start

生成自签 TLS/SSL 证书,设置默认站点拒绝未匹配域名的扫描流量。

 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
27
28
29
30
31
32
33
34
35
# 存放证书目录

sudo mkdir -p /etc/nginx/cert

sudo chmod 700 /etc/nginx/cert

# 生成自签证书

sudo openssl req -x509 -new -nodes -newkey rsa:2048 \

  -sha256 \

  -days 3650 \

  -keyout /etc/nginx/cert/deny.key \

  -out /etc/nginx/cert/deny.pem \

  -subj "/C=XX/ST=Denied/L=Denied/O=Denied/CN=invalid.local" \

  -addext "subjectAltName=DNS:invalid.local"

# 设置权限

sudo chmod 600 /etc/nginx/cert/deny.key

sudo chmod 644 /etc/nginx/cert/deny.pem

# 备份默认配置

sudo mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.conf.bak

# 新建默认虚拟主机配置

sudo vim /etc/nginx/http.d/00-default.conf

修改内容如下:

 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
27
28
29
30
31
32
33
34
35
server {

    listen 80 default_server;

    listen [::]:80 default_server;

    server_name _;

    return 444; 

}

server {

    listen 443 ssl default_server;

    listen [::]:443 ssl default_server;

    server_name _;

    

    ssl_certificate /etc/nginx/cert/deny.pem; 

    ssl_certificate_key /etc/nginx/cert/deny.key;

    ssl_protocols TLSv1.2 TLSv1.3;

    ssl_prefer_server_ciphers off;

    error_page 497 =444 /dev/null;

    return 444;

}

如果仅限 Cloudflare CDN 回源,服务端获取真实客户端 IP 地址:

1
sudo vim /etc/nginx/nginx.conf

http 部分加入:

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# ...

# ...

http {

    # ...

        set_real_ip_from 173.245.48.0/20;

        set_real_ip_from 103.21.244.0/22;

        set_real_ip_from 103.22.200.0/22;

        set_real_ip_from 103.31.4.0/22;

        set_real_ip_from 141.101.64.0/18;

        set_real_ip_from 108.162.192.0/18;

        set_real_ip_from 190.93.240.0/20;

        set_real_ip_from 188.114.96.0/20;

        set_real_ip_from 197.234.240.0/22;

        set_real_ip_from 198.41.128.0/17;

        set_real_ip_from 162.158.0.0/15;

        set_real_ip_from 104.16.0.0/13;

        set_real_ip_from 104.24.0.0/14;

        set_real_ip_from 172.64.0.0/13;

        set_real_ip_from 131.0.72.0/22;

        set_real_ip_from 2400:cb00::/32;

        set_real_ip_from 2606:4700::/32;

        set_real_ip_from 2803:f800::/32;

        set_real_ip_from 2405:b500::/32;

        set_real_ip_from 2405:8100::/32;

        set_real_ip_from 2a06:98c0::/29;

        set_real_ip_from 2c0f:f248::/32;

        real_ip_header CF-Connecting-IP;

    # ...

}

重载 Nginx 配置使生效:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 验证配置

sudo nginx -t

# 重载 Nginx 配置

sudo nginx -s reload

# 或者重启 Nginx 服务

sudo service nginx reload

安装 Docker

1
sudo apk update && sudo apk add docker docker-cli-compose

可选添加IPv6 支持, daemon.json 内容参考可 Docker IPv6 配置

1
2
3
4
5
sudo mkdir -p /etc/docker

# 编辑配置文件

sudo vim /etc/docker/daemon.json

启动 Docker 服务:

1
2
3
4
5
6
7
sudo rc-update add docker boot

sudo service docker start

# 可选测试 IPv6 出网

sudo docker run --rm curlimages/curl curl -s -I -6 https://blog.zsh.moe

SSD 使用 Trism 优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 创建每周定时任务

sudo tee /etc/periodic/weekly/fstrim <<'EOF'

#!/bin/sh

/sbin/fstrim -v / >> /var/log/fstrim.log 2>&1

EOF

# 赋予可执行权限

sudo chmod +x /etc/periodic/weekly/fstrim

NTP 时间同步

设置系统为 UTC 时区:

1
2
3
4
5
sudo setup-timezone -z UTC

# 验证

date

Alpine 默认使用 ntpd 进行时间同步,推荐精度更高、收敛更快的 chrony 服务:

1
2
3
4
5
sudo apk add chrony

# 编辑配置

sudo vim /etc/chrony/chrony.conf

示例配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# default config

#pool pool.ntp.org iburst

server time.cloudflare.com iburst

#initstepslew 10 pool.ntp.org

initstepslew 10 time.cloudflare.com

driftfile /var/lib/chrony/chrony.drift

rtcsync

#ucmdport 0

启动 Chony 服务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 停止 ntpd 服务

sudo service ntpd stop

sudo rc-update del ntpd default

# 启动 chrony 服务

sudo rc-update add chronyd default

sudo service chronyd start

# 验证时间同步状态

chronyc sources -v

至此,这台 Alpine Linux 服务器已完成所需的基础配置。