三合一脚本支持alpine&ubuntu&debian系统
Docker
安装与准备:
docker一键安装脚本
curl -fsSL https://raw.githubusercontent.com/hanigege/scripts/main/docker.sh -o docker.sh && sh docker.shNginx Proxy Manager (简称:npm)
安装与准备
mkdir -p ~/data/docker_data/nginxproxymanager # 创建一个npm的文件夹
cd ~/data/docker_data/nginxproxymanager # 进入该文件夹
nano docker-compose.yamldocker-compose.yaml 配置:
services:
app:
image: 'docker.io/jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '12332:80'
- '81:81'
- '12335:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt默认登陆的用户名:admin@example.com 密码:changeme 第一次登陆会提示更改用户名和密码,建议修改一个复杂一点的密码。 至此,我们已经完成了Nginx Proxy Manager的搭建。
(修改为你的内网对应的vm地址)
- 登录平台内网地址:http://10.20.20.8:81
添加三个对应域名,开启https:由于是内网,上面的配置中可以看到,443端口映射到12335端口了。例:
| 域名 | ip | 功能 |
|---|---|---|
| hs.jgaga.tk | 10.20.20.8 | headscale的注册服务 |
| derps.jgaga.tk | 10.20.20.8 | derp的服务地址 |
| hs-ui.jgaga.tk | 10.20.20.8 | headscale的管理平台地址 |
npm域名配置功能里里添加各域名的高级配置(右上脚的小齿轮图标)(必须)
hs.jgaga.tk
# 1. 针对 UI 的 API 请求,允许跨域(解决你说的保存密钥问题)
location ~ ^/(admin|web|api) {
proxy_pass http://10.20.20.8:8080;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
# 跨域头只在这些路径生效
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;
add_header Access-Control-Allow-Headers * always;
if ($request_method = OPTIONS) {
return 204;
}
}
# 2. 针对手机客户端的 Noise 协议通讯,保持纯净(解决 Out of sync)
location / {
proxy_pass http://10.20.20.8:8080;
proxy_http_version 1.1;
# 核心:必须使用动态 Upgrade,不要硬编码 Connection "upgrade"
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_upgrade;
proxy_set_header Host $http_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;
# 实时性优化
proxy_buffering off;
proxy_request_buffering off;
proxy_socket_keepalive on;
tcp_nodelay on;
# 延长超时
proxy_connect_timeout 60s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}derps.jgaga.tk
location / {
proxy_pass http://10.20.20.8:8082;
proxy_http_version 1.1;
# --- 关键修正:去掉端口号,仅透传域名 ---
# 这样可以匹配 DERP 容器内部的证书/域名校验
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;
# --- 保持长连接稳定性 ---
proxy_buffering off;
proxy_request_buffering off;
proxy_socket_keepalive on;
tcp_nodelay on;
# 超时设置,防止感叹号
proxy_connect_timeout 60s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
# --- 必须:WebSocket 协议升级 ---
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}headscale&derp&tailscale
安装与准备
headscale&derp&tailscale一键安装脚本(包含开启tun及ip转发功能)
mkdir -p ~/data/docker_data/hdt # 创建一个npm的文件夹
cd ~/data/docker_data/hdt # 进入该文件夹
nano hdt.sh添加以下内容:
#!/bin/bash
set -e
echo "=================================================="
echo " Headscale + Derper 自动化交互部署脚本"
echo " (包含底层内核与路由环境自动配置)"
echo "=================================================="
echo ""
# 0. 权限检查
if [ "$EUID" -ne 0 ]; then
echo "错误: 请使用 root 用户或 sudo 执行此脚本。"
exit 1
fi
# 1. 采集用户输入
read -p "1. 请输入 DERP 节点的外部访问域名 (例如 derps.jgaga.xyz): " DERP_DOMAIN
read -p "2. 请输入 Headscale 控制端的外部访问域名 (例如 hs.jgaga.xyz): " HS_DOMAIN
read -p "3. 请输入 Headscale UI 界面的外部访问域名 (例如 hs-ui.jgaga.xyz): " UI_DOMAIN
read -p "4. 请输入当前宿主机的内网物理 IP (例如 10.20.20.8): " HOST_IP
read -p "5. 请输入内网自定义 DNS 服务的 IP (例如 10.20.20.6): " DNS_IP
echo ""
echo "正在配置宿主机底层网络与内核转发..."
# [新增核心模块] 自动配置内核与网络
# 开启 IPv4 转发
if ! grep -q "^net.ipv4.ip_forward.*=.*1" /etc/sysctl.conf; then
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p >/dev/null 2>&1 || true
echo " -> 已开启 IPv4 路由转发"
fi
# 尝试加载 TUN 和 iptables 模块 (兼容 Alpine/Ubuntu)
modprobe tun 2>/dev/null || true
modprobe ip_tables 2>/dev/null || true
modprobe iptable_filter 2>/dev/null || true
modprobe iptable_nat 2>/dev/null || true
# 确保 /dev/net/tun 设备存在且权限正确
if [ ! -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 666 /dev/net/tun
echo " -> 已创建并赋权虚拟网卡设备 /dev/net/tun"
fi
# 针对 Alpine 系统自动写入开机自启名单
if [ -f /etc/alpine-release ]; then
for mod in tun ip_tables iptable_filter iptable_nat; do
if ! grep -q "^${mod}$" /etc/modules; then
echo "${mod}" >> /etc/modules
fi
done
echo " -> 已为 Alpine 系统配置内核模块开机自启"
fi
echo ""
echo "正在生成目录结构与 Docker 配置文件..."
# 2. 创建目录结构
mkdir -p headscale/config headscale/data tailscale-state
# 3. 生成 docker-compose.yml
cat < docker-compose.yml
services:
headscale:
image: headscale/headscale:latest
container_name: headscale-server
restart: always
volumes:
- ./headscale/config:/etc/headscale
- ./headscale/data:/var/lib/headscale
ports:
- "8080:8080"
- "9090:9090"
command: serve
headscale-ui:
image: ghcr.io/gurucomputing/headscale-ui:latest
container_name: headscale-ui
restart: always
ports:
- "9443:8080"
depends_on:
- headscale
derper:
image: fredliang/derper
container_name: derper
restart: always
ports:
- "8082:80" # 内部 HTTP 监听,供 NPM 转发
- "3478:3478/udp" # STUN 打洞端口
command: /app/derper --hostname=${DERP_DOMAIN} --a=:80 --http-port=-1 --verify-clients=false
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale-node
hostname: home-gateway
restart: always
network_mode: "host"
cap_add:
- NET_ADMIN
- NET_RAW
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./tailscale-state:/var/lib/tailscale
- /lib/modules:/lib/modules:ro
environment:
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
command: tailscaled --port=7829
EOF
# 4. 生成 Headscale 的 derp.yaml 节点配置
cat < headscale/config/derp.yaml
regions:
900:
regionid: 900
regioncode: Gary2Derp
regionname: Gary2Derp
nodes:
- name: MyDerp-office
regionid: 900
hostname: ${DERP_DOMAIN}
derpport: 12335
stunport: 3478
stunonly: false
EOF
# 5. 动态生成 Headscale 的 config.yaml 主配置文件
cat < headscale/config/config.yaml
# Headscale 容器版完整配置
server_url: https://${HS_DOMAIN}:12335
# 容器内必须监听 0.0.0.0 才能接收来自 NPM 的转发
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false
noise:
# 路径映射到容器内的 /var/lib/headscale
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
allocation: sequential
derp:
server:
enabled: false # 独立容器运行 DERP,此处关闭
automatically_add_embedded_derp_region: false
urls: [] # 禁用官方节点,专注自建
paths:
- /etc/headscale/derp.yaml # 映射在 config 目录下的文件
auto_update_enabled: true
update_frequency: 1h
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
# 日志级别设为 info,确保能看到 DERP 加载记录
log:
level: info
format: text
dns:
magic_dns: true
base_domain: i.love.you
override_local_dns: true # 核心:设为 true,强行接管手机的所有 DNS 请求
nameservers:
global:
- ${DNS_IP} # 唯一出口:所有解析全部扔进隧道,交给内网 MosDNS 处理
- 1.1.1.1 # 救命稻草,负责在隧道断开时解析控制端域名
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
randomize_client_port: false
taildrop:
enabled: true
EOF
echo "=================================================="
echo " 所有配置与系统环境准备已完成!"
echo " 请立即执行: docker compose up -d"
echo "=================================================="
echo ""
echo "【NPM 反向代理配置终极清单】"
echo "请登录 Nginx Proxy Manager,添加/修改对应的 Proxy Host:"
echo ""
echo ">> [1] DERP 节点配置 (对应域名: ${DERP_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 8082"
echo " * Websockets Support: 开启 (必须)"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo ""
echo ">> [2] Headscale 控制端配置 (对应域名: ${HS_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 8080"
echo " * Websockets Support: 开启 (必须)"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo ""
echo ">> [3] Headscale UI 界面配置 (对应域名: ${UI_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 9443"
echo " * Websockets Support: 开启"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo "=================================================="添加执行权限并执行安装
chmod +x hdt.sh
./hdt.shROS
开启ros转发端口 (请修改你相应的端口和ip)
# 1. 【清场】删除所有之前乱掉的 Tailscale 和 DERP 规则和脚本
/ip firewall nat remove [find comment~"Tailscale"]
/ip firewall nat remove [find comment~"DERP"]
/ip firewall mangle remove [find comment~"Tailscale"]
/ip firewall raw remove [find comment~"Tailscale"]
/system scheduler remove [find name="Sync_Tailscale_WAN"]
/system script remove [find name="Update_Tailscale_NAT"]
# 2. 【核心规则】出站精准锁定 (必须加上 src-port=7829 防止误杀其他 UDP)
/ip firewall nat add chain=srcnat action=src-nat to-addresses=1.1.1.1 to-ports=7829 \
protocol=udp src-address=10.20.20.8 src-port=7829 comment="Tailscale_Outbound_Fixed" place-before=0
# 3. 添加:映射 Tailscale 直连 (UDP 7829)
/ip firewall nat add chain=dstnat action=dst-nat protocol=udp dst-port=7829 \
to-addresses=10.20.20.8 to-ports=7829 comment="Tailscale_Inbound_Fixed"
# 4. 添加:映射 DERP STUN 打洞探测 (UDP 3478)
/ip firewall nat add chain=dstnat action=dst-nat protocol=udp dst-port=3478 \
to-addresses=10.20.20.8 to-ports=3478 comment="DERP_STUN_Inbound"
# 5. 添加:映射 DERP TCP 业务流 (TCP 12335)
/ip firewall nat add chain=dstnat action=dst-nat protocol=tcp dst-port=12335 \
to-addresses=10.20.20.8 to-ports=12335 comment="DERP_TCP_Inbound"
# 6. 【组合脚本】获取 pppoe-out1 的实时公网 IP 并填入 Rule 0
/system script add name="Update_Tailscale_NAT" source={
:local currentIP [/ip address get [find interface=pppoe-out1] address];
:set currentIP [:pick $currentIP 0 [:find $currentIP "/"]];
:if ([:len $currentIP] > 0) do={
/ip firewall nat set [find comment="Tailscale_Outbound_Fixed"] to-addresses=$currentIP;
# :log info ("Tailscale NAT 已同步为公网 IP: " . $currentIP);
}
}
# 6. 【自动化】设置每分钟运行一次脚本
/system scheduler add name="Sync_Tailscale_WAN" interval=1m on-event="Update_Tailscale_NAT"
# 7. 【立即执行】刷新状态
/system script run Update_Tailscale_NAT
### 终端下输入:- 99年密钥生成:(hs-ui.jgaga.tk:12335平台注册使用)
docker exec headscale-server headscale apikeys create --expiration 99y然后登录headscale管理平台UI,例: hs-ui.jgaga.tk:12335 进行配置,包含注册系统,添加用户设备等,请自行操作
- 终端下进行tailscale启动路由命令:(包括重新注册–force-reauth ,第一次使用可以把这个去除)
docker exec tailscale-node tailscale up --login-server https://hs.116160.xyz:12335 --advertise-routes=fd88::/64,10.20.20.0/24,f2b0::/18,28.0.0.0/8,100.100.200.0/24,91.108.56.0/22,91.108.4.0/22,91.108.8.0/22,91.108.16.0/22,91.108.12.0/22,149.154.160.0/20,91.105.192.0/23,91.108.20.0/22,185.76.151.0/24,2001:67c:4e8::/48,2001:b28:f23f::/48,2a0a:f280::/32,2001:b28:f23c::/48,2001:b28:f23d::/48 --accept-dns=false -reset --force-reauth 手机客户端等自行安装配置。 完事~
附:
上面的一键脚本包含了对alpine系统及ubuntu系统的判断,提供相应的tun开启服务以及ip转发的配置,如果想手动操作,上面的三合一脚本删除,按下面的操作:
开始安装
docker一键安装
curl -fsSL https://raw.githubusercontent.com/hanigege/scripts/main/docker.sh -o docker.sh && sh docker.shdocker.sh
该脚本用于自动安装 docker 以及 docker 插件(composes、buildx 等), 同时该脚本将会自动配置 /etc/docker/daemon.json 文件, 目前针对 docker daemon 的配置逻辑如下:
默认开启 init 支持, 防止容器产生僵尸进程
切换 docker 存储目录为 /data/docker, 此后所有 docker 数据将会存放于此
限制容器日志文件大小, 单个容器最多 5 个日志文件, 单个日志文件最大 10m, 防止容器 stdout 过量输出导致占满磁盘空间
开启 live-restore 防止 docker daemon 意外重启导致容器重启
Debian、Redhat 系列系统默认 CGroups Driver 切换为 systemd, Alpine 系统保持默认 cgroupfs v2
该脚本安装完成后默认会 Pin 住 docker 相关软件包, 防止自动升级导致容器重启或出现不可逆故障.
如果是linux下的用普通用户操作的,请记的添加到docker组:
- 一步解决
把用户加入 docker 组:
sudo usermod -aG docker $USER然后 重新登录一次系统(很重要)。
如果是 SSH:
exit再重新登录。
然后再测试
docker ps如果成功,会显示:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES1. 宿主机底层网络与内核准备 (TUN & iptables)
在部署 Tailscale 容器前,必须确保宿主机内核支持虚拟网卡和底层防火墙路由。
针对 Alpine 系统(当前环境):
Alpine 内核精简,需手动加载模块并设置开机自启。在宿主机终端执行:
加载虚拟网卡与防火墙模块
modprobe tun
modprobe ip_tables
modprobe iptable_filter
modprobe iptable_nat写入开机自启名单
echo "tun" >> /etc/modules
echo "ip_tables" >> /etc/modules
echo "iptable_filter" >> /etc/modules
echo "iptable_nat" >> /etc/modules开启 IPv4 转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p针对 Ubuntu 系统(迁移备用):
Ubuntu 默认已内置并加载了所需的 tun 和 iptables 模块,无需手动 modprobe。仅需开启内核 IP 转发即可:
#### 开启 IPv4 转发
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p2.
三合一一键脚本:
headscale&derp&tailscale一键安装脚本(不包含开启tun及ip转发功能)
mkdir -p ~/data/docker_data/hdt # 创建一个npm的文件夹
cd ~/data/docker_data/hdt # 进入该文件夹
nano hdt.sh#!/bin/bash
set -e
echo "=================================================="
echo " Headscale + Derper 自动化交互部署脚本"
echo "=================================================="
echo ""
# 1. 采集用户输入
read -p "1. 请输入 DERP 节点的外部访问域名 (例如 derps.jgaga.xyz): " DERP_DOMAIN
read -p "2. 请输入 Headscale 控制端的外部访问域名 (例如 hs.jgaga.xyz): " HS_DOMAIN
read -p "3. 请输入 Headscale UI 界面的外部访问域名 (例如 hs-ui.jgaga.xyz): " UI_DOMAIN
read -p "4. 请输入当前宿主机的内网物理 IP (例如 10.20.20.8): " HOST_IP
read -p "5. 请输入内网自定义 DNS 服务的 IP (例如 10.20.20.6): " DNS_IP
echo ""
echo "正在生成目录结构与配置文件..."
# 2. 创建目录结构
mkdir -p headscale/config headscale/data tailscale-state
# 3. 生成 docker-compose.yml
cat < docker-compose.yml
services:
headscale:
image: headscale/headscale:latest
container_name: headscale-server
restart: always
volumes:
- ./headscale/config:/etc/headscale
- ./headscale/data:/var/lib/headscale
ports:
- "8080:8080"
- "9090:9090"
command: serve
headscale-ui:
image: ghcr.io/gurucomputing/headscale-ui:latest
container_name: headscale-ui
restart: always
ports:
- "9443:8080"
depends_on:
- headscale
derper:
image: fredliang/derper
container_name: derper
restart: always
ports:
- "8082:80" # 内部 HTTP 监听,供 NPM 转发
- "3478:3478/udp" # STUN 打洞端口
command: /app/derper --hostname=${DERP_DOMAIN} --a=:80 --http-port=-1 --verify-clients=false
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale-node
hostname: home-gateway
restart: always
network_mode: "host"
cap_add:
- NET_ADMIN
- NET_RAW
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./tailscale-state:/var/lib/tailscale
- /lib/modules:/lib/modules:ro
environment:
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
command: tailscaled --port=7829
EOF
# 4. 生成 Headscale 的 derp.yaml 节点配置
cat < headscale/config/derp.yaml
regions:
900:
regionid: 900
regioncode: Gary2Derp
regionname: Gary2Derp
nodes:
- name: MyDerp-office
regionid: 900
hostname: ${DERP_DOMAIN}
derpport: 12335
stunport: 3478
stunonly: false
EOF
# 5. 动态生成 Headscale 的 config.yaml 主配置文件
cat < headscale/config/config.yaml
# Headscale 容器版完整配置
server_url: https://${HS_DOMAIN}:12335
# 容器内必须监听 0.0.0.0 才能接收来自 NPM 的转发
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false
noise:
# 路径映射到容器内的 /var/lib/headscale
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
allocation: sequential
derp:
server:
enabled: false # 独立容器运行 DERP,此处关闭
automatically_add_embedded_derp_region: false
urls: [] # 禁用官方节点,专注自建
paths:
- /etc/headscale/derp.yaml # 映射在 config 目录下的文件
auto_update_enabled: true
update_frequency: 1h
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
# 日志级别设为 info,确保能看到 DERP 加载记录
log:
level: info
format: text
dns:
magic_dns: true
base_domain: i.love.you
override_local_dns: true # 核心:设为 true,强行接管手机的所有 DNS 请求
nameservers:
global:
- ${DNS_IP} # 优先级最高,所有解析全部扔进隧道,交给内网 MosDNS 处理
- 1.1.1.1 # 救命稻草,负责在隧道断开时解析控制端域名
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
randomize_client_port: false
taildrop:
enabled: true
EOF
echo "=================================================="
echo " 所有配置文件 (包含 config.yaml) 已精准生成!"
echo " 请立即执行: docker compose up -d"
echo "=================================================="
echo ""
echo "【NPM 反向代理配置终极清单】"
echo "请登录 Nginx Proxy Manager,添加/修改对应的 Proxy Host:"
echo ""
echo ">> [1] DERP 节点配置 (对应域名: ${DERP_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 8082"
echo " * Websockets Support: 开启 (必须)"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo ""
echo ">> [2] Headscale 控制端配置 (对应域名: ${HS_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 8080"
echo " * Websockets Support: 开启 (必须)"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo ""
echo ">> [3] Headscale UI 界面配置 (对应域名: ${UI_DOMAIN})"
echo " - Details 标签页:"
echo " * Scheme: http"
echo " * Forward Hostname/IP: ${HOST_IP}"
echo " * Forward Port: 9443"
echo " * Websockets Support: 开启"
echo " - SSL 标签页: 请求/选择有效证书并开启 Force SSL"
echo "=================================================="