更新系统

Terminal window
sudo apt update
sudo apt full-upgrade

配置防火墙

Terminal window
# 关闭防火墙
sudo ufw disable
# 设置默认规则
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 允许 22、80、443 端口访问
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 开启防火墙
sudo ufw enable

安装 fail2ban

安装:

Terminal window
sudo apt install fail2ban

删除自带配置:

Terminal window
sudo rm /etc/fail2ban/jail.d/defaults-debian.conf

添加默认封禁配置:

/etc/fail2ban/jail.d/01-defaults.conf
sudo tee /etc/fail2ban/jail.d/01-defaults.conf <<EOF
[DEFAULT]
bantime = 12h
findtime = 30m
maxretry = 3
ignoreip = 127.0.0.1/8 ::1/128 172.16.95.102/20
banaction = ufw
banaction_allports = ufw
EOF

添加 sshd 封禁配置:

/etc/fail2ban/jail.d/10-sshd.conf
sudo tee /etc/fail2ban/jail.d/10-sshd.conf <<EOF
[sshd]
enabled = true
port = 22
filter = sshd
backend = systemd
findtime = 5m
maxretry = 3
bantime = 1h
[sshd-slow]
enabled = true
port = 22
filter = sshd
backend = systemd
findtime = 6h
maxretry = 5
bantime = 24h
EOF

添加“累犯”封禁配置:

/etc/fail2ban/jail.d/99-recidive.conf
sudo tee /etc/fail2ban/jail.d/99-recidive.conf <<EOF
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
findtime = 1w
maxretry = 3
bantime = -1
EOF

检查:

Terminal window
sudo fail2ban-client -t
sudo fail2ban-client -d

启动:

Terminal window
sudo systemctl enable --now fail2ban

加固 SSH

配置:

/etc/ssh/sshd_config.d/99-hardening.conf
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf <<EOF
# 禁用 root 登录
PermitRootLogin no
# 禁用密码认证,仅允许密钥
PasswordAuthentication no
PubkeyAuthentication yes
# 限制算法
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# 限制尝试次数
MaxAuthTries 3
MaxSessions 5
ClientAliveInterval 300
ClientAliveCountMax 3
# 仅允许特定用户
AllowUsers ecs-user
EOF

检查:

Terminal window
sudo sshd -t && echo "Syntax OK"

重载 sshd 配置:

Terminal window
sudo systemctl reload sshd

安装 Podman

修改系统配置:

/etc/sysctl.d/99-unprivileged-ports.conf
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf
sudo sysctl --system

配置 Linger:

Terminal window
sudo loginctl enable-linger $USER

安装 podman:

Terminal window
sudo apt install podman

配置镜像加速器

/etc/containers/registries.conf
sudo tee /etc/containers/registries.conf <<EOF
unqualified-search-registries = ["docker.io"]
[[registry]]
prefix = "docker.io"
location = "docker.io"
blocked = false
insecure = false
[[registry.mirror]]
location = "xxx.mirror.aliyuncs.com"
EOF

检查用户权限:

Terminal window
grep ecs-user /etc/subuid /etc/subgid
# 预期输出:
# /etc/subuid:ecs-user:100000:65536
# /etc/subgid:ecs-user:100000:65536
#
# 配置命令:
# sudo usermod --add-subuids 100000-165535 ecs-user
# sudo usermod --add-subgids 100000-165535 ecs-user

安装 Nginx

拉取镜像:

Terminal window
podman pull docker.io/library/nginx:alpine

准备目录:

Terminal window
mkdir -p ~/nginx-gateway/logs
cd ~/nginx-gateway

生成 nginx.conf 配置文件:

~/nginx-gateway/nginx.conf
tee ~/nginx-gateway/nginx.conf <<EOF
user nginx;
worker_processes auto; # 自动识别
worker_cpu_affinity auto; # 绑定 CPU 核心
worker_rlimit_nofile 65535; # 单个 worker 最大文件描述符
pid /var/run/nginx.pid;
error_log /var/log/nginx/error.log warn;
events {
use epoll; # Linux 最高效事件模型
multi_accept on; # 一次性接受所有新连接
worker_connections 2048; # 单 worker 2048 连接
}
http {
# 基础设置
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
# 设置访问日志
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
# 网络传输优化
sendfile on; # 零拷贝发送静态文件
tcp_nopush on; # 累积数据包再发送
tcp_nodelay on; # 小数据包立即发送
# 连接超时管理
keepalive_timeout 60; # 连接复用 60 秒
keepalive_requests 10000; # 单连接最大请求数
client_header_timeout 10; # 读取请求头超时
client_body_timeout 10; # 读取请求体超时
send_timeout 10; # 发送响应超时
reset_timedout_connection on; # 超时后主动关闭连接
# 客户端缓冲区限制
client_header_buffer_size 4k;
large_client_header_buffers 4 8k;
client_body_buffer_size 128k;
client_max_body_size 50m; # 按需调整上传限制
# 代理缓冲区
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_temp_file_write_size 64k;
# 静态文件缓存
open_file_cache max=2000 inactive=180s;
open_file_cache_min_uses 2;
open_file_cache_valid 300s;
open_file_cache_errors off;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_buffers 4 16k;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css application/javascript application/json text/xml application/xml image/svg+xml;
# 隐藏版本号
server_tokens off;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444; # 直接关闭连接
}
# 引入站点配置
include /etc/nginx/conf.d/*.conf;
}
EOF

运行容器:

Terminal window
podman run -d --replace \
--name nginx-gateway \
--security-opt=no-new-privileges:true \
--cap-drop=ALL \
--cap-add=CHOWN \
--cap-add=SETUID \
--cap-add=SETGID \
--cap-add=NET_BIND_SERVICE \
-p 80:80 -p 443:443 \
-v ~/nginx-gateway/logs:/var/log/nginx:Z \
-v ~/nginx-gateway/nginx.conf:/etc/nginx/nginx.conf:ro \
--tmpfs /tmp:noexec,nosuid,size=64m \
--tmpfs /var/tmp:noexec,nosuid,size=64m \
--tmpfs /var/run:noexec,nosuid,size=1m \
--tmpfs /var/cache/nginx:noexec,nosuid,size=128m \
--cpus=1.0 \
--cpu-shares=2048 \
--memory=512m \
--memory-swap=512m \
--pids-limit=100 \
--restart=always \
docker.io/library/nginx:alpine

配置容器持久化:

~/.config/containers/systemd/nginx-gateway.container
tee ~/.config/containers/systemd/nginx-gateway.container <<EOF
[Container]
Image=docker.io/library/nginx:alpine
ContainerName=nginx-gateway
NoNewPrivileges=true
DropCapability=ALL
AddCapability=CHOWN
AddCapability=SETUID
AddCapability=SETGID
AddCapability=NET_BIND_SERVICE
PublishPort=80:80
PublishPort=443:443
Volume=%h/nginx-gateway/logs:/var/log/nginx:Z
Volume=%h/nginx-gateway/nginx.conf:/etc/nginx/nginx.conf:ro
Tmpfs=/tmp:noexec,nosuid,size=64m
Tmpfs=/var/tmp:noexec,nosuid,size=64m
Tmpfs=/var/run:noexec,nosuid,size=1m
Tmpfs=/var/cache/nginx:noexec,nosuid,size=128m
PodmanArgs=--cpus=1.0
PodmanArgs=--cpu-shares=2048
PodmanArgs=--memory=512m
PodmanArgs=--memory-swap=512m
PodmanArgs=--pids-limit=100
[Service]
Restart=always
RestartSec=10
ExecReload=podman kill -s HUP nginx-gateway
[Install]
WantedBy=default.target
EOF

重载 systemd 配置并启动 nginx-gateway.service 服务:

Terminal window
systemctl --user daemon-reload
systemctl --user start nginx-gateway.service

验证状态:

Terminal window
systemctl --user status nginx-gateway.service
podman ps | grep nginx-gateway

部署个人博客

使用 fnm 管理 node.js

安装依赖:

Terminal window
sudo apt install unzip

安装 fnm:

Terminal window
curl -fsSL https://fnm.vercel.app/install | bash

安装 node.js:

Terminal window
fnm install --lts

安装 pnpm:

Terminal window
npm install -g pnpm

构建项目

生成 SSH 密钥:

Terminal window
ssh-keygen -t ed25519 -C "deploy@github" -f ~/.ssh/github

将公钥添加到 Github

Terminal window
cat ~/.ssh/github.pub

添加 Github 服务器的公钥指纹:

Terminal window
ssh-keyscan github.com >> ~/.ssh/known_hosts

配置 SSH 客户端:

~/.ssh/config
tee ~/.ssh/config <<EOF
Host github
HostName github.com
User git
IdentityFile ~/.ssh/github
IdentitiesOnly yes
EOF

拉取项目文件:

Terminal window
git clone git@github:justyycrazy/my-notes.git
git clone git@github:justyycrazy/my-vault.git

将代码仓库和笔记仓库关联:

Terminal window
cd ~/nginx-gateway/my-notes
git switch -c build
rm -rf ~/nginx-gateway/my-notes/src/content
ln -s ~/nginx-gateway/my-vault/src-content ~/nginx-gateway/my-notes/src/content
ln -s ~/nginx-gateway/my-vault/src-assets-images/etl-workflow-design-with-kettle ~/nginx-gateway/my-notes/src/assets/images/
cp -r ~/nginx-gateway/my-vault/public-uploads ~/nginx-gateway/my-notes/public/uploads

安装依赖并构建项目:

Terminal window
pnpm install
pnpm build

获取 SSL 证书

安装 acme.sh 并立即生效:

Terminal window
curl https://get.acme.sh | bash
source ~/.bashrc

设置默认证书服务器:

Terminal window
acme.sh --set-default-ca --server letsencrypt

获取 SSL 证书:

Terminal window
export Ali_Key=""
export Ali_Secret=""
acme.sh --issue --dns dns_ali \
-d yycrazy.net \
-d *.yycrazy.net

安装 SSL 证书:

Terminal window
mkdir -p ~/.local/share/certs
acme.sh --install-cert -d *.yycrazy.net \
--key-file ~/.local/share/certs/yycrazy.net.key \
--fullchain-file ~/.local/share/certs/yycrazy.net.cer \
--reloadcmd "systemctl --user reload nginx-gateway.service"

配置 Nginx 站点

~/nginx-gateway/yycrazy.net.conf
tee ~/nginx-gateway/yycrazy.net.conf <<EOF
server {
listen 80;
server_name yycrazy.net www.yycrazy.net;
return 301 https://\$host\$request_uri;
}
server {
listen 443 ssl http2;
server_name yycrazy.net www.yycrazy.net;
ssl_certificate /etc/nginx/ssl/yycrazy.net.cer;
ssl_certificate_key /etc/nginx/ssl/yycrazy.net.key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
root /usr/share/nginx/html;
index index.html;
# 静态资源长期缓存
location ~* \.(css|js|ico|svg|png|webp|jpeg|jpg|gif)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ^~ /uploads/php5-examples/ {
types {
text/plain php;
}
charset utf-8;
add_header Content-Disposition inline;
add_header X-Content-Type-Options nosniff;
}
}
EOF

添加挂载点

修改 nginx-gateway 的配置文件:

~/.config/containers/systemd/nginx-gateway.container
tee ~/.config/containers/systemd/nginx-gateway.container <<EOF
[Container]
Image=docker.io/library/nginx:alpine
ContainerName=nginx-gateway
NoNewPrivileges=true
DropCapability=ALL
AddCapability=CHOWN
AddCapability=SETUID
AddCapability=SETGID
AddCapability=NET_BIND_SERVICE
PublishPort=80:80
PublishPort=443:443
Volume=%h/nginx-gateway/logs:/var/log/nginx:Z
Volume=%h/nginx-gateway/nginx.conf:/etc/nginx/nginx.conf:ro
Volume=%h/nginx-gateway/yycrazy.net.conf:/etc/nginx/conf.d/yycrazy.net.conf:ro
Volume=%h/nginx-gateway/my-notes/dist:/usr/share/nginx/html:ro
Volume=%h/.local/share/certs:/etc/nginx/ssl:ro
Tmpfs=/tmp:noexec,nosuid,size=64m
Tmpfs=/var/tmp:noexec,nosuid,size=64m
Tmpfs=/var/run:noexec,nosuid,size=1m
Tmpfs=/var/cache/nginx:noexec,nosuid,size=128m
PodmanArgs=--cpus=1.0
PodmanArgs=--cpu-shares=2048
PodmanArgs=--memory=512m
PodmanArgs=--memory-swap=512m
PodmanArgs=--pids-limit=100
[Service]
Restart=always
RestartSec=10
ExecReload=podman kill -s HUP nginx-gateway
[Install]
WantedBy=default.target
EOF

重载 systemd 配置并重启 nginx-gateway.service 服务:

Terminal window
systemctl --user daemon-reload
systemctl --user restart nginx-gateway.service

验证状态:

Terminal window
systemctl --user status nginx-gateway.service
podman ps | grep nginx-gateway
``