部署指南¶
R-VPN 服务器生产环境部署最佳实践。
架构¶
单服务器部署¶
基础部署架构:
高可用部署¶
生产环境冗余部署:
┌─────────────┐
互联网 ────►│ 负载 │
│ 均衡器 │
└──────┬──────┘
│
┌───────────┴───────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ 服务器 1 │ │ 服务器 2 │
└──────────┘ └──────────┘
│ │
└───────────┬───────────┘
▼
┌──────────┐
│ 数据库 │
│ (Redis) │
└──────────┘
生产环境检查清单¶
安全¶
- 来自可信 CA 的 TLS 证书(推荐 Let's Encrypt)
- 防火墙配置(仅开放 443/tcp 和可选的 80/tcp)
- 安装并配置 Fail2ban
- 定期安全更新(
apt update && apt upgrade) - SSH 密钥认证(禁用密码认证)
- 禁用 Root 登录(使用 sudo)
- 服务器身份密钥权限设置为 600
- 私钥文件安全备份
- 适当配置速率限制
- 部署伪装网站以提高隐蔽性
性能¶
- 足够的带宽(每个并发用户至少 1 Mbps)
- 充足的内存(建议 2GB+,高负载建议 4GB+)
- 用于日志和临时数据的 SSD 存储
- 到目标用户的网络延迟低于 100ms
- 增加文件描述符限制(65536+)
- 优化 TCP 缓冲区以实现高吞吐量
- 支持 AES-NI 的 CPU 用于 TLS 加速
可靠性¶
- 配置 journalctl 监控
- 配置日志轮转
- 配置自动备份
- 配置健康检查
- 故障自动重启(systemd)
- 配置 TLS 自动续期
- 测试恢复脚本
- 记录灾难恢复计划
DNS 配置¶
主域名¶
客户端配置¶
客户端连接地址:
- 服务器:wss://vpn.example.com/connect
- 预密钥包:https://vpn.example.com/prekey-bundle.json
DNS TTL 建议¶
生产环境部署: - A/AAAA 记录:300-600 秒(5-10 分钟)以便快速故障转移 - 正常运营期间:3600 秒(1 小时)以获得更好的缓存效果
使用 Let's Encrypt 自动续期 TLS¶
初始证书设置¶
# 安装 certbot
sudo apt update
sudo apt install certbot
# 获取证书(独立模式 - 会停止 80 端口上的任何服务)
sudo certbot certonly --standalone -d vpn.example.com
# 复制证书到 R-VPN 目录
sudo cp /etc/letsencrypt/live/vpn.example.com/fullchain.pem /etc/rvpn/cert.pem
sudo cp /etc/letsencrypt/live/vpn.example.com/privkey.pem /etc/rvpn/key.pem
# 设置安全权限
sudo chmod 600 /etc/rvpn/key.pem
sudo chmod 644 /etc/rvpn/cert.pem
使用钩子自动续期¶
创建续期钩子脚本:
# 创建部署钩子
sudo tee /etc/letsencrypt/renewal-hooks/deploy/rvpn-server << 'EOF'
#!/bin/bash
# R-VPN 服务器证书续期钩子
set -e
DOMAIN="vpn.example.com"
RVPN_CERT_DIR="/etc/rvpn"
LE_DIR="/etc/letsencrypt/live/${DOMAIN}"
# 复制新证书
cp "${LE_DIR}/fullchain.pem" "${RVPN_CERT_DIR}/cert.pem"
cp "${LE_DIR}/privkey.pem" "${RVPN_CERT_DIR}/key.pem"
# 设置权限
chmod 600 "${RVPN_CERT_DIR}/key.pem"
chmod 644 "${RVPN_CERT_DIR}/cert.pem"
# 重新加载服务器(优雅地重新加载证书)
systemctl reload rvpn-server 2>/dev/null || systemctl restart rvpn-server
echo "$(date): R-VPN 证书已续期,服务器已重新加载" >> /var/log/rvpn/cert-renewal.log
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/rvpn-server
测试自动续期¶
# 测试续期过程(模拟运行)
sudo certbot renew --dry-run
# 强制续期进行测试
sudo certbot renew --force-renewal
# 检查续期定时器状态
sudo systemctl status certbot.timer
sudo certbot certificates
证书路径¶
[server]
tls_cert_file = "/etc/letsencrypt/live/vpn.example.com/fullchain.pem"
tls_key_file = "/etc/letsencrypt/live/vpn.example.com/privkey.pem"
或使用复制的文件:
使用 journalctl 监控¶
基础日志查看¶
# 实时查看日志
sudo journalctl -u rvpn-server -f
# 查看最后 100 行
sudo journalctl -u rvpn-server -n 100
# 查看自上次启动以来的日志
sudo journalctl -u rvpn-server --since today
# 查看特定时间段的日志
sudo journalctl -u rvpn-server --since "2024-01-01 10:00:00" --until "2024-01-01 12:00:00"
按日志级别过滤¶
# 仅错误
sudo journalctl -u rvpn-server -p err
# 警告及以上级别
sudo journalctl -u rvpn-server -p warning
# 所有日志及其优先级
sudo journalctl -u rvpn-server -o verbose | grep PRIORITY
持久化日志配置¶
确保启用持久化日志:
# 检查是否启用持久化日志
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
# 重启 journald
sudo systemctl restart systemd-journald
# 配置日志保留
sudo tee /etc/systemd/journald.conf.d/rvpn.conf << 'EOF'
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxFileSec=7day
EOF
sudo systemctl restart systemd-journald
日志导出和分析¶
# 导出日志到文件
sudo journalctl -u rvpn-server --since "24 hours ago" > /tmp/rvpn-logs.txt
# 以 JSON 格式导出以便分析
sudo journalctl -u rvpn-server -o json --since today > /tmp/rvpn-logs.json
# 按小时统计错误数
sudo journalctl -u rvpn-server --since today -p err -o short | awk '{print $1, $2, $3}' | uniq -c
日志轮转¶
Systemd Journal 轮转¶
Journald 自动处理轮转。配置保留策略:
# 创建自定义 journal 配置
sudo tee /etc/systemd/journald.conf.d/99-rvpn.conf << 'EOF'
[Journal]
# Journal 最大磁盘空间
SystemMaxUse=1G
# 单个 journal 文件最大大小
SystemMaxFileSize=100M
# 保留日志 30 天
MaxRetentionSec=30day
EOF
sudo systemctl restart systemd-journald
应用日志轮转(如果启用了文件日志)¶
创建 /etc/logrotate.d/rvpn:
/var/log/rvpn/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root adm
sharedscripts
postrotate
systemctl reload rvpn-server 2>/dev/null || true
endscript
}
测试日志轮转¶
# 测试 logrotate 配置
sudo logrotate -d /etc/logrotate.d/rvpn
# 强制轮转
sudo logrotate -f /etc/logrotate.d/rvpn
# 检查轮转后的日志
ls -la /var/log/rvpn/
备份和恢复脚本¶
备份脚本¶
创建 /usr/local/bin/rvpn-backup.sh:
#!/bin/bash
# R-VPN 服务器备份脚本
set -e
BACKUP_DIR="/backup/rvpn"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# 创建备份目录
mkdir -p "${BACKUP_DIR}"
# 备份密钥和配置
tar -czf "${BACKUP_DIR}/rvpn-backup-${DATE}.tar.gz" \
-C /etc/rvpn \
--exclude='*.log' \
. 2>/dev/null || true
# 备份预密钥包
tar -czf "${BACKUP_DIR}/rvpn-data-${DATE}.tar.gz" \
-C /var/lib/rvpn \
. 2>/dev/null || true
# 如果自定义了 systemd 服务,一并备份
if [ -f /etc/systemd/system/rvpn-server.service ]; then
cp /etc/systemd/system/rvpn-server.service "${BACKUP_DIR}/rvpn-server.service-${DATE}"
fi
# 创建备份清单
cat > "${BACKUP_DIR}/manifest-${DATE}.txt" << EOF
R-VPN 备份清单
=====================
日期: $(date)
主机名: $(hostname)
版本: $(rvpn-server --version 2>/dev/null || echo "unknown")
备份内容:
- 配置文件 (/etc/rvpn)
- 数据文件 (/var/lib/rvpn)
- Systemd 服务(如果自定义)
恢复方法:
1. 停止 rvpn-server: systemctl stop rvpn-server
2. 解压配置: tar -xzf rvpn-backup-${DATE}.tar.gz -C /etc/rvpn
3. 解压数据: tar -xzf rvpn-data-${DATE}.tar.gz -C /var/lib/rvpn
4. 恢复服务: cp rvpn-server.service-${DATE} /etc/systemd/system/rvpn-server.service
5. 重新加载 systemd: systemctl daemon-reload
6. 启动服务器: systemctl start rvpn-server
EOF
# 清理旧备份
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "*.service-*" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "manifest-*.txt" -mtime +${RETENTION_DAYS} -delete
echo "备份完成: ${BACKUP_DIR}/rvpn-backup-${DATE}.tar.gz"
设置可执行并定时运行:
sudo chmod +x /usr/local/bin/rvpn-backup.sh
# 添加到 crontab(每天凌晨 3 点)
echo "0 3 * * * root /usr/local/bin/rvpn-backup.sh >> /var/log/rvpn/backup.log 2>&1" | sudo tee /etc/cron.d/rvpn-backup
恢复脚本¶
创建 /usr/local/bin/rvpn-restore.sh:
#!/bin/bash
# R-VPN 服务器恢复脚本
set -e
if [ $# -lt 1 ]; then
echo "用法: $0 <备份日期> [备份目录]"
echo "示例: $0 20240115_030000"
exit 1
fi
BACKUP_DATE="$1"
BACKUP_DIR="${2:-/backup/rvpn}"
CONFIG_BACKUP="${BACKUP_DIR}/rvpn-backup-${BACKUP_DATE}.tar.gz"
DATA_BACKUP="${BACKUP_DIR}/rvpn-data-${BACKUP_DATE}.tar.gz"
if [ ! -f "${CONFIG_BACKUP}" ]; then
echo "错误: 未找到配置备份: ${CONFIG_BACKUP}"
exit 1
fi
echo "=== R-VPN 服务器恢复 ==="
echo "备份日期: ${BACKUP_DATE}"
echo ""
# 确认
read -p "这将覆盖当前配置。是否继续? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "已中止。"
exit 0
fi
# 停止服务器
echo "停止 rvpn-server..."
systemctl stop rvpn-server
# 备份当前配置(以防万一)
echo "创建当前配置的安全备份..."
tar -czf "${BACKUP_DIR}/rvpn-pre-restore-$(date +%Y%m%d_%H%M%S).tar.gz" -C /etc/rvpn . 2>/dev/null || true
# 恢复配置
echo "恢复配置..."
mkdir -p /etc/rvpn
tar -xzf "${CONFIG_BACKUP}" -C /etc/rvpn
# 恢复数据
echo "恢复数据..."
if [ -f "${DATA_BACKUP}" ]; then
mkdir -p /var/lib/rvpn
tar -xzf "${DATA_BACKUP}" -C /var/lib/rvpn
fi
# 如果存在则恢复 systemd 服务
SERVICE_BACKUP="${BACKUP_DIR}/rvpn-server.service-${BACKUP_DATE}"
if [ -f "${SERVICE_BACKUP}" ]; then
echo "恢复 systemd 服务..."
cp "${SERVICE_BACKUP}" /etc/systemd/system/rvpn-server.service
systemctl daemon-reload
fi
# 设置权限
echo "设置权限..."
chmod 600 /etc/rvpn/*.key 2>/dev/null || true
chmod 644 /etc/rvpn/*.pem 2>/dev/null || true
chmod 755 /var/lib/rvpn
# 启动服务器
echo "启动 rvpn-server..."
systemctl start rvpn-server
# 检查状态
sleep 2
if systemctl is-active --quiet rvpn-server; then
echo ""
echo "=== 恢复成功完成 ==="
systemctl status rvpn-server --no-pager
else
echo ""
echo "=== 警告: 服务器启动失败 ==="
echo "检查日志: journalctl -u rvpn-server -n 50"
exit 1
fi
设置可执行:
远程备份(可选)¶
性能调优¶
文件描述符¶
增加系统范围的文件描述符限制:
# 编辑 limits.conf
sudo tee -a /etc/security/limits.conf << 'EOF'
# R-VPN 服务器
* soft nofile 65536
* hard nofile 65536
rvpn soft nofile 65536
rvpn hard nofile 65536
EOF
# 编辑 systemd 服务限制
sudo mkdir -p /etc/systemd/system/rvpn-server.service.d/
sudo tee /etc/systemd/system/rvpn-server.service.d/limits.conf << 'EOF'
[Service]
LimitNOFILE=65536
LimitNOFILESoft=65536
EOF
sudo systemctl daemon-reload
sudo systemctl restart rvpn-server
# 验证
ulimit -n
cat /proc/$(pgrep rvpn-server)/limits | grep "Max open files"
TCP 设置¶
为高性能 VPN 优化 TCP:
# 创建 sysctl 配置
sudo tee /etc/sysctl.d/99-rvpn.conf << 'EOF'
# R-VPN 性能调优
# 增加 TCP 缓冲区大小
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
# TCP 内存调优
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 启用 TCP 窗口缩放
net.ipv4.tcp_window_scaling = 1
# 增加连接跟踪
net.netfilter.nf_conntrack_max = 524288
net.netfilter.nf_conntrack_tcp_timeout_established = 600
# 减少 TCP keepalive 时间
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 启用 TCP fast open
net.ipv4.tcp_fastopen = 3
# 增加本地端口范围
net.ipv4.ip_local_port_range = 1024 65535
# 启用 BBR 拥塞控制(如果可用)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
# 应用设置
sudo sysctl --system
# 验证 BBR 可用并已启用
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
VPN 内核参数¶
# 添加到 /etc/sysctl.d/99-rvpn.conf
# 启用 IP 转发
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
# 禁用 ICMP 重定向
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# 启用 SYN cookies
net.ipv4.tcp_syncookies = 1
# 减少 SYN 积压
net.ipv4.tcp_max_syn_backlog = 65536
# 为高数据包速率增加 netdev 预算
net.core.netdev_budget = 50000
net.core.netdev_budget_usecs = 5000
# 增加 SYN 队列中的最大连接数
net.ipv4.tcp_max_syn_backlog = 65536
net.core.somaxconn = 65535
EOF
网络接口调优¶
# 调优网络接口(将 eth0 替换为您的接口)
sudo tee /etc/networkd-dispatcher/routable.d/50-rvpn-tune << 'EOF'
#!/bin/bash
# R-VPN 网络调优
IFACE="eth0"
# 增加环形缓冲区大小
ethtool -G ${IFACE} rx 4096 tx 4096 2>/dev/null || true
# 启用卸载功能
ethtool -K ${IFACE} gro on 2>/dev/null || true
ethtool -K ${IFACE} gso on 2>/dev/null || true
EOF
sudo chmod +x /etc/networkd-dispatcher/routable.d/50-rvpn-tune
性能监控¶
# 检查当前连接
ss -s
# 监控带宽使用
iftop -i eth0
# 检查进程 CPU 使用
top -p $(pgrep rvpn-server)
# 监控网络吞吐量
sar -n DEV 1
# 检查丢包
ethtool -S eth0 | grep -i drop
Docker 部署¶
Dockerfile¶
# 构建阶段
FROM rust:1.75-slim-bookworm as builder
WORKDIR /app
COPY . .
# 安装依赖
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# 构建发布二进制文件
RUN cargo build --release -p rvpn-server
# 运行阶段
FROM debian:bookworm-slim
# 安装运行时依赖
RUN apt-get update && apt-get install -y \
ca-certificates \
iptables \
iproute2 \
&& rm -rf /var/lib/apt/lists/*
# 创建非 root 用户
RUN useradd -r -s /sbin/nologin -M rvpn
# 复制二进制文件
COPY --from=builder /app/target/release/rvpn-server /usr/local/bin/
# 创建目录
RUN mkdir -p /etc/rvpn /var/lib/rvpn /var/log/rvpn && \
chown -R rvpn:rvpn /etc/rvpn /var/lib/rvpn /var/log/rvpn
# 暴露端口
EXPOSE 443/tcp
EXPOSE 80/tcp
# 切换到非 root 用户
USER rvpn
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f -k https://localhost:443/ || exit 1
ENTRYPOINT ["rvpn-server"]
CMD ["--config", "/etc/rvpn/server.toml"]
Docker Compose¶
创建 docker-compose.yml:
version: '3.8'
services:
rvpn-server:
build: .
image: rvpn-server:latest
container_name: rvpn-server
restart: unless-stopped
# VPN 功能使用网络模式
network_mode: host
# 或使用端口映射(功能受限)
# ports:
# - "443:443/tcp"
# - "80:80/tcp"
volumes:
# 配置
- ./config:/etc/rvpn:ro
# 数据持久化
- rvpn-data:/var/lib/rvpn
# 日志
- rvpn-logs:/var/log/rvpn
# TLS 证书
- /etc/letsencrypt:/etc/letsencrypt:ro
# VPN 所需能力
cap_add:
- NET_ADMIN
- NET_RAW
# 网络 sysctl
sysctls:
- net.ipv4.ip_forward=1
- net.ipv6.conf.all.forwarding=1
environment:
- RUST_LOG=info
healthcheck:
test: ["CMD", "curl", "-f", "-k", "https://localhost:443/"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
volumes:
rvpn-data:
rvpn-logs:
构建和运行¶
# 构建镜像
docker build -t rvpn-server:latest .
# 使用 docker 运行
docker run -d \
--name rvpn-server \
--restart unless-stopped \
--network host \
--cap-add NET_ADMIN \
--cap-add NET_RAW \
-v /etc/rvpn:/etc/rvpn:ro \
-v /var/lib/rvpn:/var/lib/rvpn \
-v /etc/letsencrypt:/etc/letsencrypt:ro \
rvpn-server:latest
# 或使用 docker-compose
docker-compose up -d
# 查看日志
docker logs -f rvpn-server
# 停止
docker-compose down
Docker Swarm 部署¶
version: '3.8'
services:
rvpn-server:
image: rvpn-server:latest
deploy:
replicas: 1
restart_policy:
condition: any
delay: 5s
max_attempts: 3
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
networks:
- rvpn-network
volumes:
- /etc/rvpn:/etc/rvpn:ro
- rvpn-data:/var/lib/rvpn
configs:
- source: rvpn_config
target: /etc/rvpn/server.toml
networks:
rvpn-network:
driver: overlay
attachable: true
volumes:
rvpn-data:
configs:
rvpn_config:
external: true
故障排除¶
高连接数¶
检查活动连接:
# 连接摘要
ss -s
# 每个 IP 的连接数(流量大户)
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
# 连接状态
ss -tan | awk '{print $1}' | sort | uniq -c
# 检查 SYN 洪水
ss -tan state syn-recv | wc -l
# 监控连接速率
watch -n 1 'ss -tan | wc -l'
缓解措施:
# 添加连接速率限制
sudo iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 100 -j DROP
# 启用 SYN cookies
sudo sysctl -w net.ipv4.tcp_syncookies=1
内存问题¶
检查内存使用:
# 进程内存
ps aux | grep rvpn-server
# 详细内存信息
cat /proc/$(pgrep rvpn-server)/status | grep -i vm
# 系统内存
free -h
# 内存随时间变化
vmstat 1 10
# OOM killer 日志
dmesg | grep -i "out of memory"
# 检查内存泄漏
pmap $(pgrep rvpn-server)
解决方案:
# 重启服务
sudo systemctl restart rvpn-server
# 如果需要,添加交换空间
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
网络问题¶
检查防火墙:
# 列出所有规则
sudo iptables -L -n -v
# 检查特定端口
sudo ss -tlnp | grep 443
# 从外部测试端口
nc -zv vpn.example.com 443
# 检查路由
ip route
# 检查接口统计
ip -s link show eth0
# 追踪路径
mtr vpn.example.com
常见修复:
# 重置 iptables(小心!)
sudo iptables -F
sudo iptables -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
# 重新添加基本规则
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -j DROP
TLS 证书问题¶
# 验证证书
openssl x509 -in /etc/rvpn/cert.pem -text -noout
# 检查证书日期
openssl x509 -in /etc/rvpn/cert.pem -noout -dates
# 测试 TLS 连接
openssl s_client -connect vpn.example.com:443 -tls1_3 -servername vpn.example.com
# 检查证书链
openssl s_client -connect vpn.example.com:443 -showcerts </dev/null
# 验证 Let's Encrypt 续期
sudo certbot certificates
服务无法启动¶
# 检查服务状态
sudo systemctl status rvpn-server
# 检查错误
sudo journalctl -u rvpn-server -n 50
# 测试配置语法
cat /etc/rvpn/server.toml
# 检查文件权限
ls -la /etc/rvpn/
ls -la /var/lib/rvpn/
# 直接测试二进制文件
sudo rvpn-server --config /etc/rvpn/server.toml -vv
# 检查端口冲突
sudo ss -tlnp | grep 443
性能问题¶
# CPU 分析
perf top -p $(pgrep rvpn-server)
# 网络延迟
ping vpn.example.com
# 带宽测试
iperf3 -c vpn.example.com
# 检查丢包
netstat -i
# DNS 解析时间
dig vpn.example.com