从零开始的VPS搭建日记:Docker部署与Nginx SNI分流Xray五合一配置
在开始折腾VPS前可以先重装一个干净的系统,root用户一键重装VPS脚本(重装前一定要先备份好重要数据!!!):
curl -O https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh || wget -O ${_##*/} $_比如重装成debian13
bash reinstall.sh debian 13重装过程会让输入密码,请记好,等跑完命令后重启:
reboot用root+刚才设置的密码登录,ssh默认端口22,添加用户名为 admin 的普通用户
useradd -m -s /bin/bash admin授予admin用户sudo权限
tee /etc/sudoers.d/admin <<< 'admin ALL=(ALL) NOPASSWD: ALL' && chmod 440 /etc/sudoers.d/admin在admin用户下配置SSH密钥登录一键脚本(前提是已经在GitHub中上传了公钥,并且在电脑本地已经保存有对应的私钥,其中xxx为你的GitHub用户名,-p 2222 修改ssh端口为2222,-d 禁止密码登录)
bash <(curl -fsSL git.io/key.sh) -og xxx -p 2222 -d
此时可以新开一个shell用admin+你的私钥验证是否可以成功登录,登录成功后就可以愉快的开始你的折腾之旅啦
curl -fsSL https://get.docker.com | sudo sh把当前用户admin加入docker组
sudo usermod -aG docker $USER
newgrp docker创建文件夹
sudo mkdir -p /opt/jellyfin /opt/aria2 /opt/ghost /opt/portainer /srv/media安装jellyfin并启动:
sudo tee /opt/jellyfin/docker-compose.yml<< 'EOF'
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
restart: unless-stopped
ports:
- "8096:8096/tcp"
- "7359:7359/udp"
volumes:
- /opt/jellyfin/config:/config
- /opt/jellyfin/cache:/cache
- type: bind
source: /srv/media
target: /media
EOF
docker compose -f /opt/jellyfin/docker-compose.yml up -d安装aria2并启动:
cd /opt/aria2 && sudo nano docker-compose.ymlservices:
# --- WARP 网络核心 (负责拨号和端口转发) ---
warp-wg:
image: lscr.io/linuxserver/wireguard:latest
container_name: warp-wg
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=0
- PGID=0
- TZ=Asia/Shanghai
volumes:
# ⚠️ 请确保在该目录下放好你生成的 wg0.conf
- ./wg-config:/config
ports:
# 原本 host 模式不需要映射,现在因为有了隔离,必须在这里手动映射
- "6800:6800" # RPC 端口
- "6888:6888/tcp" # BT 监听端口 (匹配你截图的端口)
- "6888:6888/udp" # DHT 监听端口 (匹配你截图的端口)
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
# --- Aria2 下载器 (流量强制走上面的容器) ---
aria2:
image: p3terx/aria2-pro
container_name: aria2
# 🌟 核心修改:取消 network_mode: host,改为借用 warp-wg 的网络
network_mode: "service:warp-wg"
restart: unless-stopped
logging:
options:
max-size: "1m"
environment:
- PUID=0
- PGID=0
- RPC_SECRET=your_password # 保持你的原密码
- SPECIAL_MODE=move # 保持你的特殊模式
volumes:
# 保持你原有的宿主机路径映射
- /opt/aria2/config:/config
- /opt/aria2/downloads:/downloads
- /srv/media:/completed
depends_on:
- warp-wg
docker compose up -daria2配置要修改一下dest-dir以实现下载的媒体文件自动移动到/srv/media中,一键修改:
sudo sed -i 's|dest-dir=/downloads/completed|dest-dir=/completed|' /opt/aria2/config/script.conf安装nginx,可以直接apt install nginx安装,也可以用官方源安装(推荐,因为安装的版本比较新,功能更齐全)
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyringcurl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null# 创建 .gnupg 目录并设置正确权限(GPG 对权限要求严格)
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
# 再次执行你的命令
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg输出如截图再继续往下

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.listecho -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginxsudo apt update
sudo apt install nginx下载AriaNg并解压到/usr/share/nginx/html
curl -L $(curl -s https://api.github.com/repos/mayswind/AriaNg/releases/latest \
| grep "browser_download_url.*AllInOne" \
| cut -d '"' -f 4) -o AriaNg-AllInOne.zip \
&& sudo unzip AriaNg-AllInOne.zip -d /usr/share/nginx/htmlroot用户下载安装acme.sh并设置默认ca服务器为Letsencrypt
curl https://get.acme.sh | sh
. .bashrc
acme.sh --upgrade --auto-upgrade
acme.sh --set-default-ca --server letsencrypt 导入CF_Token,在Cloudflare>profile>API Token中创建
export CF_Token="xxx" 申请域名证书并安装到/etc/nginx/ssl文件夹
mkdir -p /etc/nginx/ssl && chmod 700 /etc/nginx/sslacme.sh --issue --dns dns_cf -d yourdomain.com --keylength ec-256 --force
acme.sh --install-cert -d yourdomain.com --ecc --fullchain-file /etc/nginx/ssl/xxx.crt --key-file /etc/nginx/ssl/xxx.key --reloadcmd "nginx -s reload"修改nginx配置:
sudo nano /etc/nginx/nginx.confworker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
}
# ─── Stream (SNI 分流) ──────────────────────────────────────────────────────
stream {
map $ssl_preread_server_name $backend {
web1.com unix:/dev/shm/vless.sock;
web2.com unix:/dev/shm/cdn.sock;
web3.com unix:/dev/shm/docker.sock;
web4.com unix:/dev/shm/ghost.sock;
}
server {
listen 443;
ssl_preread on;
proxy_protocol on;
proxy_pass $backend;
}
}
# ─── HTTP ───────────────────────────────────────────────────────────────────
http {
include mime.types;
default_type application/octet-stream;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
map $request $secretfilter {
~*^(?<p>.*[\?&]api_key=)[^&]*(?<s>.*)$ "${p}***$s";
~*^(?<p>.*[\?&]ApiKey=)[^&]*(?<s>.*)$ "${p}***$s";
default $request;
}
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format stripsecrets '$remote_addr $host - $remote_user [$time_local] '
'"$secretfilter" $status $body_bytes_sent '
'$request_length $request_time $upstream_response_time '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main buffer=32k flush=5m;
# ── 基础性能 ───────────────────────────────────────────────────────────
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server_tokens off;
# ── 全局代理默认值(各 server/location 内无需重复声明)────────────────
proxy_http_version 1.1;
proxy_socket_keepalive on;
proxy_headers_hash_max_size 1024;
proxy_headers_hash_bucket_size 128;
# ── TLS ───────────────────────────────────────────────────────────────
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on; # 仅对 TLS 1.2 生效,TLS 1.3 由客户端决定
# ── Gzip ──────────────────────────────────────────────────────────────
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/css text/xml
application/json application/javascript
application/rss+xml application/atom+xml
image/svg+xml;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# ══════════════════════════════════════════════════════════════════════════════
# Web1 — VLESS /Openclaw Aria2
# ══════════════════════════════════════════════════════════════════════════════
server {
# reality.sock = Reality 伪装回源,由 Xray realitySettings.target 转入,非 stream 直接转发
listen unix:/dev/shm/reality.sock ssl proxy_protocol;
http2 on;
set_real_ip_from unix:;
real_ip_header proxy_protocol;
ssl_certificate /etc/nginx/ssl/web1.crt;
ssl_certificate_key /etc/nginx/ssl/web1.key;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
proxy_pass http://127.0.0.1:18789;
include snippets/proxy-headers.conf;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
location ^~ /aria2 {
alias /usr/share/nginx/html;
index index.html;
autoindex off;
expires 30d;
}
location /jsonrpc {
proxy_pass http://localhost:6800/jsonrpc;
proxy_redirect off;
include snippets/proxy-headers.conf;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
# ══════════════════════════════════════════════════════════════════════════════
# Web2 — Jellyfin (CDN 域)
# ══════════════════════════════════════════════════════════════════════════════
server {
listen unix:/dev/shm/cdn.sock ssl proxy_protocol;
http2 on;
set_real_ip_from unix:;
real_ip_header proxy_protocol;
client_max_body_size 20M;
ssl_certificate /etc/nginx/ssl/web2.crt;
ssl_certificate_key /etc/nginx/ssl/web2.key;
access_log /var/log/nginx/access.log stripsecrets;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), battery=(), bluetooth=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), payment=(), publickey-credentials-get=(), serial=(), sync-xhr=(), usb=(), xr-spatial-tracking=()" always;
add_header Content-Security-Policy "default-src https: data: blob: ; img-src 'self' https://* ; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; font-src 'self'" always;
location /xhttp_path {
grpc_pass grpc://unix:/dev/shm/xhttp.sock;
grpc_set_header Host $host;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
proxy_pass http://127.0.0.1:8096;
proxy_buffering off;
include snippets/proxy-headers.conf;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
location /socket {
proxy_pass http://127.0.0.1:8096;
include snippets/proxy-headers.conf;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
# ══════════════════════════════════════════════════════════════════════════════
# Web3 — Docker / Portainer
# ══════════════════════════════════════════════════════════════════════════════
server {
listen unix:/dev/shm/docker.sock ssl proxy_protocol;
http2 on;
set_real_ip_from unix:;
real_ip_header proxy_protocol;
ssl_certificate /etc/nginx/ssl/web3.crt;
ssl_certificate_key /etc/nginx/ssl/web3.key;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
proxy_pass https://127.0.0.1:9443;
include snippets/proxy-headers.conf;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
# ══════════════════════════════════════════════════════════════════════════════
# Web4 — Ghost Blog
# ══════════════════════════════════════════════════════════════════════════════
server {
listen unix:/dev/shm/ghost.sock ssl proxy_protocol;
http2 on;
set_real_ip_from unix:;
real_ip_header proxy_protocol;
ssl_certificate /etc/nginx/ssl/web4.crt;
ssl_certificate_key /etc/nginx/ssl/web4.key;
client_max_body_size 50M;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
proxy_pass http://127.0.0.1:2368;
include snippets/proxy-headers.conf;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
}sudo mkdir -p /etc/nginx/snippets && sudo tee /etc/nginx/snippets/proxy-headers.conf<< 'EOF'
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
EOF
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install在修改xray配置前先执行以下命令获取必要的uuid、reality和cloudflare warp的私钥和公钥等信息
xray uuid
xray uuid
xray uuid
xray x25519
bash -c "$(curl -L warp-reg.vercel.app)"修改配置:
sudo nano /usr/local/etc/xray/config.json{
"log": {
"loglevel": "warning",
"error": "/var/log/xray/error.log",
"access": "/var/log/xray/access.log"
},
"dns": {
"servers": ["https+local://1.1.1.1/dns-query","localhost"]
},
"policy": {
"levels": {
"0": {
"handshake": 7,
"connIdle": 420
}
}
},
"inbounds": [
{
"listen": "/dev/shm/vless.sock,0666",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "", //uuid1
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/xhttp.sock"
}
]
},
"streamSettings": {
"network": "raw",
"security": "reality",
"realitySettings": {
"target": "/dev/shm/reality.sock",
"xver": 1,
"serverNames": [
"web1.com"
],
"privateKey": "", //x25519私钥
"shortIds": [""]
},
"rawSettings": {
"acceptProxyProtocol": true
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls",
"quic"
]
}
},
{
"listen": "/dev/shm/xhttp.sock,0666",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "" //uuid2
},
{
"id": "", //uuid3
"email": "Reserved"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "xhttp",
"xhttpSettings": {
"path": "/xhttp_path" //路径
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls",
"quic"
]
}
}
],
"outbounds": [
{
"tag":"direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
}
},
{
"tag": "block",
"protocol": "blackhole"
},
{
"tag": "warp",
"protocol": "wireguard",
"settings": {
"secretKey": "", //私钥
"address": [
"172.16.0.2/32",
"/128" //IPV6地址
],
"peers": [
{
"publicKey": "", //公钥
"endpoint": "162.159.192.4:2408" //endpoint地址
}
],
"mtu": 1420,
"reserved": [35, 176, 72]
}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "warp"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "warp"
},
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "block"
},
{
"type": "field",
"user": ["Reserved"],
"outboundTag": "warp"
}
]
}
}
安装hysteria2并修改配置
HYSTERIA_USER=root bash <(curl -fsSL https://get.hy2.sh/) && sudo nano /etc/hysteria/config.yamllisten: :443
tls:
cert: /etc/nginx/ssl/web3.crt #web3对应的证书和密钥
key: /etc/nginx/ssl/web3.key
auth:
type: password
password: your_strong_password #修改密码
masquerade:
type: proxy
proxy:
url: https://127.0.0.1:9443 #portainer监听的端口
rewriteHost: true
congestion:
type: bbr
bbrProfile: standard
quic:
initStreamReceiveWindow: 26843545
maxStreamReceiveWindow: 26843545
initConnReceiveWindow: 67108864
maxConnReceiveWindow: 67108864
acl:
inline:
- reject(geoip:cn)
- reject(geosite:cn)
- direct(all)
geoip: /usr/local/share/xray/geoip.dat
geosite: /usr/local/share/xray/geosite.dat
普通用户admin中安装openclaw:
curl -fsSL https://openclaw.ai/install.sh | bash修改配置~/.openclaw/openclaw.json,实现openclaw网页访问,其中代码片段gateway如下:
"gateway": {
"mode": "local",
"bind": "lan",
"auth": {
"mode": "token",
"token": "your openclaw gateway token" //默认自动生成token,也可以自行修改
},
"port": 18789,
"tailscale": {
"mode": "off",
"resetOnExit": false
},
"controlUi": {
"allowedOrigins": [
"http://localhost:18789",
"http://127.0.0.1:18789",
"https://web1.com" //修改为自己的域名,对应nginx中的web1
],
"allowInsecureAuth": false
},
"nodes": {
"denyCommands": [
"camera.snap",
"camera.clip",
"screen.record",
"contacts.add",
"calendar.add",
"reminders.add",
"sms.send",
"sms.search"
]
}
}openclaw gateway restart
openclaw gataway status 安装portainer并启动
cd /opt/portainer && sudo nano docker-compose.ymlservices:
portainer:
container_name: portainer
image: portainer/portainer-ce:sts
restart: always
command:
- --sslcert=/certs/web3.crt #nginx中web3对应的证书和密钥
- --sslkey=/certs/web3.key
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
- /etc/nginx/ssl:/certs:ro
ports:
- 9443:9443
- 8000:8000
volumes:
portainer_data:
name: portainer_data
networks:
default:
name: portainer_networkdocker compose up -d安装ghost,安装前需要先在resend里绑定博客域名并创建API key用于后续发送邮件验证:
cd /opt/ghost && sudo tee docker-compose.yml<< 'EOF'
services:
ghost:
image: ghost:5-alpine
container_name: ghost
restart: unless-stopped
ports:
- "127.0.0.1:2368:2368"
environment:
url: ${GHOST_URL}
database__client: mysql
database__connection__host: db
database__connection__user: ghost
database__connection__password: ${GHOST_DB_PASSWORD}
database__connection__database: ghost
TZ: Asia/Shanghai
mail__transport: SMTP
mail__options__host: smtp.resend.com
mail__options__port: 465
mail__options__secure: "true"
mail__options__auth__user: resend
mail__options__auth__pass: ${RESEND_API_KEY}
mail__from: "[email protected]" # 必须是在 Resend 验证过的域名
volumes:
- ghost_content:/var/lib/ghost/content
depends_on:
db:
condition: service_healthy
networks:
- ghost_network
db:
image: mysql:8.0
container_name: ghost_db
restart: unless-stopped
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ghost
MYSQL_USER: ghost
MYSQL_PASSWORD: ${GHOST_DB_PASSWORD}
TZ: Asia/Shanghai
volumes:
- ghost_db:/var/lib/mysql
networks:
- ghost_network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost",
"-u", "ghost", "-p${GHOST_DB_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
ghost_content:
ghost_db:
networks:
ghost_network:
driver: bridge
EOF
sudo nano .envMYSQL_ROOT_PASSWORD=your_password
GHOST_DB_PASSWORD=your_password
#替换为自己网站域名
GHOST_URL=https://web4.com
#Resend API key
RESEND_API_KEY=xxxdocker compose up -d启动nginx、xray、hysteria2并设置开机启动
sudo nginx -t && sudo systemctl restart nginx
sudo systemctl enable xray hysteria-server --now设置一个定时任务,每天自动更新xray的geoip和geosite,root用户创建脚本:
mkdir -p /root/script && tee /root/script/update_geodata.sh<< 'EOF'
#!/usr/bin/env bash
# shellcheck disable=SC2268
# This Bash script to install the latest release of geoip.dat and geosite.dat:
# https://github.com/v2fly/geoip
# https://github.com/v2fly/domain-list-community
# Depends on cURL, please solve it yourself
# You may plan to execute this Bash script regularly:
# install -m 755 install-dat-release.sh /usr/local/bin/install-dat-release
# 0 0 * * * /usr/local/bin/install-dat-release > /dev/null 2>&1
# You can set this variable whatever you want in shell session right before running this script by issuing:
# export DAT_PATH='/usr/local/lib/v2ray'
DAT_PATH=${DAT_PATH:-/usr/local/share/xray}
DOWNLOAD_LINK_GEOIP="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
DOWNLOAD_LINK_GEOSITE="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
file_ip='geoip.dat'
file_dlc='geosite.dat'
dir_tmp="$(mktemp -d)"
curl() {
$(type -P curl) -L -q --retry 5 --retry-delay 10 --retry-max-time 60 "$@"
}
check_if_running_as_root() {
# If you want to run as another user, please modify $UID to be owned by this user
if [[ "$UID" -ne '0' ]]; then
echo "WARNING: The user currently executing this script is not root. You may encounter the insufficient privilege error."
read -r -p "Are you sure you want to continue? [y/n] " cont_without_been_root
if [[ x"${cont_without_been_root:0:1}" = x'y' ]]; then
echo "Continuing the installation with current user..."
else
echo "Not running with root, exiting..."
exit 1
fi
fi
}
download_files() {
if ! curl -R -H 'Cache-Control: no-cache' -o "${dir_tmp}/${2}" "${1}"; then
echo 'error: Download failed! Please check your network or try again.'
exit 1
fi
if ! curl -R -H 'Cache-Control: no-cache' -o "${dir_tmp}/${2}.sha256sum" "${1}.sha256sum"; then
echo 'error: Download failed! Please check your network or try again.'
exit 1
fi
}
check_sum() {
(
cd "${dir_tmp}" || exit
for i in "${dir_tmp}"/*.sha256sum; do
if ! sha256sum -c "${i}"; then
echo 'error: Check failed! Please check your network or try again.'
exit 1
fi
done
)
}
install_file() {
install -m 644 "${dir_tmp}"/${file_dlc} "${DAT_PATH}"/${file_dlc}
install -m 644 "${dir_tmp}"/${file_ip} "${DAT_PATH}"/${file_ip}
rm -r "${dir_tmp}"
}
main() {
check_if_running_as_root
download_files $DOWNLOAD_LINK_GEOIP $file_ip
download_files $DOWNLOAD_LINK_GEOSITE $file_dlc
check_sum
install_file
}
main "$@"
systemctl restart xray
systemctl restart hysteria-server
EOF
chmod +x /root/script/update_geodata.sh每天早上7点更新,并且重启xray和hysteria2
crontab -e0 7 * * * bash /root/script/update_geodata.sh开启bbr拥塞控制算法、TCP Fast Open和提高TCP全连接队列最大长度并验证是否生效
sudo tee /etc/sysctl.d/99-bbr.conf << 'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_fastopen=3
net.core.somaxconn=32768
EOF
sudo sysctl --system
sudo sysctl net.ipv4.tcp_congestion_control
sudo sysctl net.ipv4.tcp_fastopen
sudo sysctl net.core.somaxconn安装ufw、fail2ban
sudo apt install ufw fail2banufw默认拒绝所有入站,放行所有出站,开放tcp80/443、ssh自定义端口2222和udp443端口
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
#放行ssh,如果没自定义ssh端口,请改回22,重要!!!否则将与vps失联!!!
sudo ufw allow 2222/tcp && sudo ufw enable
#查看ufw状态
sudo ufw status verbose
创建fail2ban配置并启动、查看状态
sudo tee /etc/fail2ban/jail.local<< 'EOF'
[DEFAULT]
bantime = 24h
findtime = 10m
backend = systemd
maxretry = 5
banaction = ufw
[sshd]
enabled = true
port = 2222 #修改为ssh自定义端口
maxretry = 3
bantime = 24h
EOF
sudo systemctl enable fail2ban --now && sudo fail2ban-client status sshd针对低内存VPS,增加虚拟内存:
# 创建一个 1G 的空文件
sudo fallocate -l 1G /swapfile
# 如果上面的命令报错,请尝试这个备用命令:
# sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
# 设置权限
sudo chmod 600 /swapfile
# 格式化为 Swap 格式
sudo mkswap /swapfile
# 激活 Swap 文件
sudo swapon /swapfile
# 将挂载信息写入 fstab
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# 优先使用物理内存
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-bbr.conf && sudo sysctl --system至此在服务器上
1、实现了nginx前置监听TCP443端口,sni分流,其中
①web1.com为openclaw网页,web1.com/aria2为AriaNg网页
②web2.com为jellyfin网页,媒体播放
③web3.com为portainer网页,docker管理
④web4.com为ghost网页,博客网站
2、xray五合一配置,与参考链接实现方式不一样,参考链接是xray前置监听443,本案例是nginx前置监听443,但是实现的效果是一样的。
①XTLS(Vision)+Reality 直连
②xhttp+Reality 直连
③上行 xhttp+TLS+CDN | 下行 xhttp+Reality (上下行不同sni)
④xhttp+TLS 过CDN
⑤上行 xhttp+Reality | 下行 xhttp+TLS+CDN(上下行不同sni)
其中,安全协议为Reality的伪装网站(sni)是1.①即openclaw网页,安全协议为TLS的伪装网站(sni)是1.②即jellyfin网页
3、hysteria2监听UDP443端口,与nginx监听的TCP443不冲突,hysteria2的伪装网站为1.③即portainer网页
4、安装了openclaw,可以和龙虾在网页web1.com上对话,指挥它干活,至于怎么和聊天应用比如telegram对接,请自行google。
5、安装了jellyfin,通过web2.com访问,实现媒体播放。
6、安装了aria2,通过web1.com/aria2访问,通过web1.com:443连接后端aria2 RPC接口,如截图所示

下载完成后会自动把文件移动到服务器的/srv/media这个文件夹,在AriaNg里指定下载路径如/downloads/tv,就会下载到/srv/media/tv文件夹,以此类推,可以对下载的文件类型进行分类,jellyfin会读取/srv/media里所有文件

7、安装了portainer,通过web3.com访问,docker管理页面。
8、安装了ghost博客程序,通过web4.com访问,本博客就是通过此方式实现。
9、服务器网络优化,开启了bbr拥塞控制算法;服务器安全加固,安装了ufw,fail2ban,仅对外开放2222(ssh)、80和443端口。