├── .gitignore ├── README.md ├── config ├── config.yaml ├── daemon.json ├── docker-compose.yml ├── nginx │ ├── 192.168.10.60.crt │ ├── 192.168.10.60.key │ ├── derp.json │ └── server.conf ├── sources2004.list └── tput_color_echo.sh ├── deploy.sh └── img ├── 24b1830a1dfeb7c25292d95f1bb425c649af8111f26994bc.png ├── 3d0d842e91bca36404357cd95cd4d6f5.jpeg ├── 5c3cd28310b212cf9dbc1648f6f894a6.png └── 960d7ab58421aa22a8c75aa8f4e0bf91.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # headscale-deploy 2 | 3 | headscale 一键部署,Ubuntu20.04LTS 环境 4 | 5 | 参考\ 6 | \ 7 | 8 | 9 | ```bash 10 | # 执行命令,按提示执行即可 11 | ./deploy.sh 12 | ``` 13 | 14 | ## 1.防火墙开放端口 15 | 16 | - headscale 17 | TCP:5010 18 | - ip_depr 19 | TCP:8443,UDP:3478 20 | - headscale-webui 21 | TCP:5000 22 | 23 | ## 2.headscale 24 | 25 | ### 2.1 修改配置文件 26 | 27 | - server_url 28 | 改为公网 IP 或域名 29 | - listen_addr: 0.0.0.0:5010 30 | 改为监听所有 IPV4 的端口 31 | - ip_prefixes 32 | 自定义私有网段,也可同时开启 IPv4 和 IPv6,建议开启 IPv6,有更大几率直接 IPv6 直连 33 | - magic_dns 34 | 如果暂时用不到 DNS 功能,可以先将 magic_dns 设为 false。 35 | 36 | ### 2.2 查看状态 37 | 38 | ```bash 39 | $ docker exec headscale headscale user create jl 40 | # 通过 Pre-Authkeys 接入,生成一个一小时的 pre-authkey 的 token 41 | $ docker exec headscale headscale preauthkeys create -e 10h -u jl 42 | 729fabe383247345c22f970af43219eb8aa500cc632f89eb 43 | ``` 44 | 45 | ### 2.3 常用命令 46 | 47 | - headscale 48 | 49 | ```bash 50 | # docker 的话命令前加 docker exec headscale 51 | # 查看命名空间 52 | headscale user list 53 | # 创建命名空间 default 54 | headscale user create default 55 | # 销毁命名空间 default 56 | headscale user destroy default 57 | # 查看所有节点 58 | headscale nodes list 59 | # 查看命名空间 default 下的节点 60 | headscale -n default nodes list 61 | # 删除节点 ID 为 2 的节点 62 | headscale nodes delete -i 2 63 | # 重命名 node 名称 64 | headscale node rename newname -i 2 65 | # 查看已经生成的 key 66 | headscale -n default preauthkeys list 67 | ``` 68 | 69 | - tailscale 70 | 71 | ```bash 72 | # 在 Tailscale 客户端上使用以下命令查看目前可以使用的 DERP 服务器 73 | $ tailscale netcheck 74 | Report: 75 | * UDP: true 76 | * IPv4: yes, 117.143.3.251:1600 77 | * IPv6: no, but OS has support 78 | * MappingVariesByDestIP: false 79 | * HairPinning: false 80 | * PortMapping: 81 | * CaptivePortal: false 82 | * Nearest DERP: Seattle 83 | * DERP latency: 84 | - sea: 194.6ms (Seattle) 85 | - sfo: 198.3ms (San Francisco) 86 | - lax: 199.6ms (Los Angeles) 87 | - syd: 203.1ms (Sydney) 88 | - tok: 209.6ms (Tokyo) 89 | - den: 221.1ms (Denver) 90 | - ord: 227.6ms (Chicago) 91 | - dfw: 229.5ms (Dallas) 92 | - hkg: 241.6ms (Hong Kong) 93 | - tor: 245.5ms (Toronto) 94 | - hnl: 248.9ms (Honolulu) 95 | - mia: 249.4ms (Miami) 96 | - nyc: 250.6ms (New York City) 97 | - sin: 262.4ms (Singapore) 98 | - lhr: 351.8ms (London) 99 | - sao: 354.2ms (São Paulo) 100 | - par: 359.7ms (Paris) 101 | - waw: 366.2ms (Warsaw) 102 | - ams: 369.7ms (Amsterdam) 103 | - fra: 371.3ms (Frankfurt) 104 | - mad: 382ms (Madrid) 105 | - blr: 389.7ms (Bangalore) 106 | - dbi: 469.5ms (Dubai) 107 | - jnb: 514.7ms (Johannesburg) 108 | # 查看与通信对端的连接方式,看到只 b0be835b5c26 是通过 DERP 服务器来中继流量的 109 | $ tailscale status 110 | fd7a:115c:a1e0::2 synologyds918 jl linux - 111 | fd7a:115c:a1e0::3 b0be835b5c26 jl macOS active; relay "tok", tx 13840472 rx 1633492 112 | fd7a:115c:a1e0::1 jldemac-pro jl macOS offline 113 | # 使用 Tailscale 命令行工具来测试 114 | $ tailscale ping 10.6.8.3 115 | pong from b0be835b5c26 (fd7a:115c:a1e0::3) via 101.82.215.60:19852 in 63ms 116 | # mac 117 | /Applications/Tailscale.app/Contents/MacOS/Tailscale status 118 | ``` 119 | 120 | ## 3.headscale-webui 121 | 122 | ### 3.1 bug 修复 123 | 124 | 参考: 125 | https://github.com/iFargle/headscale-webui/pull/127 126 | https://github.com/l00ps/headscale-webui/commit/8a7dc9b91a155ca6651c6a39a3efb0106a75c0e0 127 | 128 | ```bash 129 | # 容器启动后进入容器交互 130 | docker exec -u app -it headscale-webui /bin/sh 131 | # 修改文件 132 | cd /app 133 | vi headscale.py 134 | # 将 "machines" 修改为 "nodes",'machines' 修改为 'nodes',"machine" 改为 "node",'machine' 改为 'node',lastSuccessfulUpdate 改为 lastSeen 135 | vi renderer.py 136 | cd /app/static/js 137 | # 将 response.machine 修改为 response.node 138 | vi custom.js 139 | exit 140 | # 重启容器即可 141 | ``` 142 | 143 | ### 3.2 连接 headscale 144 | 145 | ```bash 146 | # 创建 API Key,(e.g. 30m, 24h) (default "90d") 147 | docker exec headscale headscale apikeys create 148 | ``` 149 | 150 | \ 151 | 根据提示填写 docker-compose.yml 填写的用户名密码,填写 API Key 并保存 152 | 153 | ### 3.3 免费 IP 证书 154 | 155 | \ 156 | 为了验证证书,需要将 nginx 的 80 端口暂时开放 157 | 158 | - https 配置, 159 | 160 | ```conf 161 | server { 162 | listen 443 ssl; 163 | server_name 192.168.10.60; 164 | ssl_prefer_server_ciphers on; 165 | ssl_certificate cert/192.168.10.60.crt; 166 | ssl_certificate_key cert/192.168.10.60.key; 167 | 168 | location / { 169 | root html; 170 | index index.html; 171 | } 172 | 173 | location /headscaleui/ { 174 | proxy_redirect off; 175 | proxy_set_header Host $host; 176 | proxy_set_header X-Real-IP $remote_addr; 177 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 178 | proxy_pass http://127.0.0.1:5000/; 179 | } 180 | 181 | } 182 | ``` 183 | 184 | 185 | 186 | ## 4.打通局域网 187 | 188 | ```bash 189 | # 群辉客户端修改注册节点的命令,在原来命令的基础上加上参数 --advertise-routes=192.168.10.0/24,告诉 Headscale 服务器“我这个节点可以转发这些地址的路由”。如果有多条路由则用英文逗号隔开。 190 | $ tailscale up --login-server=http://192.168.10.60:5010 --accept-dns=false --advertise-routes=192.168.10.0/24 --reset 191 | # 查看群辉所在的节点 ID 为 2 的节点是否开启路由 192 | $ headscale routes list -i 2 193 | Route | Enabled 194 | 192.168.10.0/24 | true 195 | # 显示 true 则否开启,否则以下命令开启路由 196 | $ headscale routes enable -r 2 197 | ``` 198 | 199 | ## 5.Exit Node 200 | 201 | Exit Node功能允许您通过网络上的特定设备路由所有非 Tailscale 互联网流量,这台特定的路由设备称为 Exit Node。 202 | 203 | 204 | ## 6.客户端接入 205 | 206 | ### 6.1 Synology 207 | 208 | 1. 下载安装 tailscale 客户端 209 | 210 | 2. 在 Synology 的终端 root 权限下通过 pre-authkey 的 token 加入 211 | 212 | ```bash 213 | tailscale up --login-server=http://192.168.10.60:5010 --accept-dns=false --authkey 729fabe383247345c22f970af43219eb8aa500cc632f89eb 214 | ``` 215 | 216 | 3. 配置Synology以启用出站连接\ 217 | 218 | ![5c3cd28310b212cf9dbc1648f6f894a6.png](img/5c3cd28310b212cf9dbc1648f6f894a6.png) 219 | ![960d7ab58421aa22a8c75aa8f4e0bf91.png](img/960d7ab58421aa22a8c75aa8f4e0bf91.png) 220 | 221 | ```bash 222 | /var/packages/Tailscale/target/bin/tailscale configure-host 223 | synosystemctl restart pkgctl-Tailscale.service 224 | ``` 225 | 226 | ### 6.2 mac 227 | 228 | 1. 美区商店下载 Tailscale 229 | 2. 修改控制服务器 230 | 浏览器访问: 231 | ![3d0d842e91bca36404357cd95cd4d6f5.jpeg](img/3d0d842e91bca36404357cd95cd4d6f5.jpeg) 232 | 点击下载描述文件并安装 233 | 3. 打开 Tailscale 点击 Log in... 会跳转到浏览器 234 | 4. 复制浏览器的命令并修改 NAMESPACE 后在服务器执行 235 | 5. 删除多余账号 236 | ![24b1830a1dfeb7c25292d95f1bb425c6.png](img/24b1830a1dfeb7c25292d95f1bb425c649af8111f26994bc.png) 237 | 238 | ### 6.3 linux 239 | 240 | ```bash 241 | wget https://pkgs.tailscale.com/stable/tailscale_1.34.1_amd64.tgz 242 | tar zxvf tailscale_1.34.1_amd64.tgz 243 | cp tailscale_1.34.1_amd64/tailscaled /usr/sbin/tailscaled 244 | cp tailscale_1.34.1_amd64/tailscale /usr/bin/tailscale 245 | cp tailscale_1.34.1_amd64/systemd/tailscaled.service /lib/systemd/system/tailscaled.service 246 | cp tailscale_1.34.1_amd64/systemd/tailscaled.defaults /etc/default/tailscaled 247 | systemctl enable --now tailscaled 248 | # 将 换成你的 Headscale 公网 IP 或域名 249 | tailscale up --login-server=http://192.168.10.60:5110 --accept-routes=true --accept-dns=false --authkey 729fabe383247345c22f970af43219eb8aa500cc632f89eb 250 | ``` 251 | 252 | ### 6.4 ios 253 | 254 | 1. tailscale 退出登录 255 | 2. 在设置中找到 tailscale,如果以前登陆过则打开 "Reset Keychain switch" 开关,在 "Alternate Coordination Server URL" 中填入 "http://192.168.10.60:5010" 256 | 3. 在iOS应用程序切换器中关闭应用程序重新启动应用程序,根据提示会跳转到新的页面 257 | 4. 将页面中出现的命令在 headscale 服务器执行,这时应该页面会自动关闭并登录,如果没有,多试几遍 258 | 259 | ### 6.5 Windows 260 | 261 | 262 | 263 | ## 7.clash与tailscale的兼容问题 264 | 265 | 266 | 267 | ## 8.解决开启 headscale 后网速慢的问题 268 | 269 | config.yaml 修改 dns,即不使用 headscale 的 dns 270 | 271 | - 默认配置 272 | 273 | ```yaml 274 | dns_config: 275 | # Whether to prefer using Headscale provided DNS or use local. 276 | override_local_dns: true 277 | 278 | # List of DNS servers to expose to clients. 279 | nameservers: 280 | - 1.1.1.1 281 | ``` 282 | 283 | - 修改后的配置 284 | 285 | ```yaml 286 | dns_config: 287 | # Whether to prefer using Headscale provided DNS or use local. 288 | override_local_dns: false 289 | 290 | # List of DNS servers to expose to clients. 291 | nameservers: [] 292 | # - 1.1.1.1 293 | ``` 294 | 295 | ## 9.定时重启容器(可选) 296 | 297 | ```bash 298 | $ crontab -e 299 | 0 4 * * * docker-compose -f /opt/headscale/docker-compose.yml restart 300 | ``` 301 | -------------------------------------------------------------------------------- /config/config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order: 3 | # 4 | # - `/etc/headscale` 5 | # - `~/.headscale` 6 | # - current working directory 7 | 8 | # The url clients will connect to. 9 | # Typically this will be a domain like: 10 | # 11 | # https://myheadscale.example.com:443 12 | # 13 | server_url: http://192.168.10.60:5010 14 | 15 | # Address to listen to / bind to on the server 16 | # 17 | # For production: 18 | # listen_addr: 0.0.0.0:8080 19 | # web 界面监听端口 20 | listen_addr: 0.0.0.0:5010 21 | 22 | # Address to listen to /metrics, you may want 23 | # to keep this endpoint private to your internal 24 | # network 25 | # 26 | metrics_listen_addr: 127.0.0.1:9090 27 | 28 | # Address to listen for gRPC. 29 | # gRPC is used for controlling a headscale server 30 | # remotely with the CLI 31 | # Note: Remote access _only_ works if you have 32 | # valid certificates. 33 | # 34 | # For production: 35 | # grpc_listen_addr: 0.0.0.0:50443 36 | grpc_listen_addr: 127.0.0.1:50443 37 | 38 | # Allow the gRPC admin interface to run in INSECURE 39 | # mode. This is not recommended as the traffic will 40 | # be unencrypted. Only enable if you know what you 41 | # are doing. 42 | grpc_allow_insecure: false 43 | 44 | # The Noise section includes specific configuration for the 45 | # TS2021 Noise protocol 46 | noise: 47 | # The Noise private key is used to encrypt the 48 | # traffic between headscale and Tailscale clients when 49 | # using the new Noise-based protocol. 50 | private_key_path: /var/lib/headscale/noise_private.key 51 | 52 | # List of IP prefixes to allocate tailaddresses from. 53 | # Each prefix consists of either an IPv4 or IPv6 address, 54 | # and the associated prefix length, delimited by a slash. 55 | # It must be within IP ranges supported by the Tailscale 56 | # client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48. 57 | # See below: 58 | # IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71 59 | # IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33 60 | # Any other range is NOT supported, and it will cause unexpected issues. 61 | prefixes: 62 | v6: fd7a:115c:a1e0::/48 63 | v4: 100.64.0.0/10 64 | 65 | # Strategy used for allocation of IPs to nodes, available options: 66 | # - sequential (default): assigns the next free IP from the previous given IP. 67 | # - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand). 68 | allocation: sequential 69 | 70 | # DERP is a relay system that Tailscale uses when a direct 71 | # connection cannot be established. 72 | # https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp 73 | # 74 | # headscale needs a list of DERP servers that can be presented 75 | # to the clients. 76 | derp: 77 | server: 78 | # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config 79 | # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place 80 | enabled: false 81 | 82 | # Region ID to use for the embedded DERP server. 83 | # The local DERP prevails if the region ID collides with other region ID coming from 84 | # the regular DERP config. 85 | region_id: 999 86 | 87 | # Region code and name are displayed in the Tailscale UI to identify a DERP region 88 | region_code: "headscale" 89 | region_name: "Headscale Embedded DERP" 90 | 91 | # Listens over UDP at the configured address for STUN connections - to help with NAT traversal. 92 | # When the embedded DERP server is enabled stun_listen_addr MUST be defined. 93 | # 94 | # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/ 95 | stun_listen_addr: "0.0.0.0:3478" 96 | 97 | # Private key used to encrypt the traffic between headscale DERP 98 | # and Tailscale clients. 99 | # The private key file will be autogenerated if it's missing. 100 | # 101 | private_key_path: /var/lib/headscale/derp_server_private.key 102 | 103 | # This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically, 104 | # it enables the creation of your very own DERP map entry using a locally available file with the parameter DERP.paths 105 | # If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using DERP.paths 106 | automatically_add_embedded_derp_region: true 107 | 108 | # For better connection stability (especially when using an Exit-Node and DNS is not working), 109 | # it is possible to optionally add the public IPv4 and IPv6 address to the Derp-Map using: 110 | ipv4: 1.2.3.4 111 | ipv6: 2001:db8::1 112 | 113 | # List of externally available DERP maps encoded in JSON 114 | urls: 115 | # 默认 derp 116 | - https://controlplane.tailscale.com/derpmap/default 117 | # 自己的 derp 118 | - http://nginx/derp.json 119 | 120 | # Locally available DERP map files encoded in YAML 121 | # 122 | # This option is mostly interesting for people hosting 123 | # their own DERP servers: 124 | # https://tailscale.com/kb/1118/custom-derp-servers/ 125 | # 126 | # paths: 127 | # - /etc/headscale/derp-example.yaml 128 | paths: [] 129 | 130 | # If enabled, a worker will be set up to periodically 131 | # refresh the given sources and update the derpmap 132 | # will be set up. 133 | auto_update_enabled: true 134 | 135 | # How often should we check for DERP updates? 136 | update_frequency: 24h 137 | 138 | # Disables the automatic check for headscale updates on startup 139 | disable_check_updates: false 140 | 141 | # Time before an inactive ephemeral node is deleted? 142 | ephemeral_node_inactivity_timeout: 30m 143 | 144 | database: 145 | # Database type. Available options: sqlite, postgres 146 | # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. 147 | # All new development, testing and optimisations are done with SQLite in mind. 148 | type: sqlite 149 | 150 | # Enable debug mode. This setting requires the log.level to be set to "debug" or "trace". 151 | debug: false 152 | 153 | # GORM configuration settings. 154 | gorm: 155 | # Enable prepared statements. 156 | prepare_stmt: true 157 | 158 | # Enable parameterized queries. 159 | parameterized_queries: true 160 | 161 | # Skip logging "record not found" errors. 162 | skip_err_record_not_found: true 163 | 164 | # Threshold for slow queries in milliseconds. 165 | slow_threshold: 1000 166 | 167 | # SQLite config 168 | sqlite: 169 | path: /var/lib/headscale/db.sqlite 170 | 171 | # Enable WAL mode for SQLite. This is recommended for production environments. 172 | # https://www.sqlite.org/wal.html 173 | write_ahead_log: true 174 | 175 | # # Postgres config 176 | # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. 177 | # See database.type for more information. 178 | # postgres: 179 | # # If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank. 180 | # host: localhost 181 | # port: 5432 182 | # name: headscale 183 | # user: foo 184 | # pass: bar 185 | # max_open_conns: 10 186 | # max_idle_conns: 10 187 | # conn_max_idle_time_secs: 3600 188 | 189 | # # If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need 190 | # # in the 'ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1. 191 | # ssl: false 192 | 193 | ### TLS configuration 194 | # 195 | ## Let's encrypt / ACME 196 | # 197 | # headscale supports automatically requesting and setting up 198 | # TLS for a domain with Let's Encrypt. 199 | # 200 | # URL to ACME directory 201 | acme_url: https://acme-v02.api.letsencrypt.org/directory 202 | 203 | # Email to register with ACME provider 204 | acme_email: "" 205 | 206 | # Domain name to request a TLS certificate for: 207 | tls_letsencrypt_hostname: "" 208 | 209 | # Path to store certificates and metadata needed by 210 | # letsencrypt 211 | # For production: 212 | tls_letsencrypt_cache_dir: /var/lib/headscale/cache 213 | 214 | # Type of ACME challenge to use, currently supported types: 215 | # HTTP-01 or TLS-ALPN-01 216 | # See [docs/tls.md](docs/tls.md) for more information 217 | tls_letsencrypt_challenge_type: HTTP-01 218 | # When HTTP-01 challenge is chosen, letsencrypt must set up a 219 | # verification endpoint, and it will be listening on: 220 | # :http = port 80 221 | tls_letsencrypt_listen: ":http" 222 | 223 | ## Use already defined certificates: 224 | tls_cert_path: "" 225 | tls_key_path: "" 226 | 227 | log: 228 | # Output formatting for logs: text or json 229 | format: text 230 | level: info 231 | 232 | ## Policy 233 | # headscale supports Tailscale's ACL policies. 234 | # Please have a look to their KB to better 235 | # understand the concepts: https://tailscale.com/kb/1018/acls/ 236 | policy: 237 | # The mode can be "file" or "database" that defines 238 | # where the ACL policies are stored and read from. 239 | mode: file 240 | # If the mode is set to "file", the path to a 241 | # HuJSON file containing ACL policies. 242 | path: "" 243 | 244 | ## DNS 245 | # 246 | # headscale supports Tailscale's DNS configuration and MagicDNS. 247 | # Please have a look to their KB to better understand the concepts: 248 | # 249 | # - https://tailscale.com/kb/1054/dns/ 250 | # - https://tailscale.com/kb/1081/magicdns/ 251 | # - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/ 252 | # 253 | # Please note that for the DNS configuration to have any effect, 254 | # clients must have the `--accept-dns=true` option enabled. This is the 255 | # default for the Tailscale client. This option is enabled by default 256 | # in the Tailscale client. 257 | # 258 | # Setting _any_ of the configuration and `--accept-dns=true` on the 259 | # clients will integrate with the DNS manager on the client or 260 | # overwrite /etc/resolv.conf. 261 | # https://tailscale.com/kb/1235/resolv-conf 262 | # 263 | # If you want stop Headscale from managing the DNS configuration 264 | # all the fields under `dns` should be set to empty values. 265 | dns: 266 | # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). 267 | # Only works if there is at least a nameserver defined. 268 | magic_dns: false 269 | 270 | # Defines the base domain to create the hostnames for MagicDNS. 271 | # This domain _must_ be different from the server_url domain. 272 | # `base_domain` must be a FQDN, without the trailing dot. 273 | # The FQDN of the hosts will be 274 | # `hostname.base_domain` (e.g., _myhost.example.com_). 275 | base_domain: jial.com 276 | 277 | # List of DNS servers to expose to clients. 278 | nameservers: 279 | global: [] 280 | # - 1.1.1.1 281 | # - 1.0.0.1 282 | # - 2606:4700:4700::1111 283 | # - 2606:4700:4700::1001 284 | 285 | # NextDNS (see https://tailscale.com/kb/1218/nextdns/). 286 | # "abc123" is example NextDNS ID, replace with yours. 287 | # - https://dns.nextdns.io/abc123 288 | 289 | # Split DNS (see https://tailscale.com/kb/1054/dns/), 290 | # a map of domains and which DNS server to use for each. 291 | split: 292 | {} 293 | # foo.bar.com: 294 | # - 1.1.1.1 295 | # darp.headscale.net: 296 | # - 1.1.1.1 297 | # - 8.8.8.8 298 | 299 | # Set custom DNS search domains. With MagicDNS enabled, 300 | # your tailnet base_domain is always the first search domain. 301 | search_domains: [] 302 | 303 | # Extra DNS records 304 | # so far only A-records are supported (on the tailscale side) 305 | # See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations 306 | extra_records: [] 307 | # - name: "grafana.myvpn.example.com" 308 | # type: "A" 309 | # value: "100.64.0.3" 310 | # 311 | # # you can also put it in one line 312 | # - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" } 313 | 314 | # DEPRECATED 315 | # Use the username as part of the DNS name for nodes, with this option enabled: 316 | # node1.username.example.com 317 | # while when this is disabled: 318 | # node1.example.com 319 | # This is a legacy option as Headscale has have this wrongly implemented 320 | # while in upstream Tailscale, the username is not included. 321 | use_username_in_magic_dns: false 322 | 323 | # Unix socket used for the CLI to connect without authentication 324 | # Note: for production you will want to set this to something like: 325 | unix_socket: /etc/headscale/headscale.sock 326 | unix_socket_permission: "0770" 327 | # 328 | # headscale supports experimental OpenID connect support, 329 | # it is still being tested and might have some bugs, please 330 | # help us test it. 331 | # OpenID Connect 332 | # oidc: 333 | # only_start_if_oidc_is_available: true 334 | # issuer: "https://your-oidc.issuer.com/path" 335 | # client_id: "your-oidc-client-id" 336 | # client_secret: "your-oidc-client-secret" 337 | # # Alternatively, set `client_secret_path` to read the secret from the file. 338 | # # It resolves environment variables, making integration to systemd's 339 | # # `LoadCredential` straightforward: 340 | # client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret" 341 | # # client_secret and client_secret_path are mutually exclusive. 342 | # 343 | # # The amount of time from a node is authenticated with OpenID until it 344 | # # expires and needs to reauthenticate. 345 | # # Setting the value to "0" will mean no expiry. 346 | # expiry: 180d 347 | # 348 | # # Use the expiry from the token received from OpenID when the user logged 349 | # # in, this will typically lead to frequent need to reauthenticate and should 350 | # # only been enabled if you know what you are doing. 351 | # # Note: enabling this will cause `oidc.expiry` to be ignored. 352 | # use_expiry_from_token: false 353 | # 354 | # # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query 355 | # # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email". 356 | # 357 | # scope: ["openid", "profile", "email", "custom"] 358 | # extra_params: 359 | # domain_hint: example.com 360 | # 361 | # # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the 362 | # # authentication request will be rejected. 363 | # 364 | # allowed_domains: 365 | # - example.com 366 | # # Note: Groups from keycloak have a leading '/' 367 | # allowed_groups: 368 | # - /headscale 369 | # allowed_users: 370 | # - alice@example.com 371 | # 372 | # # If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed. 373 | # # This will transform `first-name.last-name@example.com` to the user `first-name.last-name` 374 | # # If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following 375 | # user: `first-name.last-name.example.com` 376 | # 377 | # strip_email_domain: true 378 | 379 | # Logtail configuration 380 | # Logtail is Tailscales logging and auditing infrastructure, it allows the control panel 381 | # to instruct tailscale nodes to log their activity to a remote server. 382 | logtail: 383 | # Enable logtail for this headscales clients. 384 | # As there is currently no support for overriding the log server in headscale, this is 385 | # disabled by default. Enabling this will make your clients send logs to Tailscale Inc. 386 | enabled: false 387 | 388 | # Enabling this option makes devices prefer a random port for WireGuard traffic over the 389 | # default static port 41641. This option is intended as a workaround for some buggy 390 | # firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information. 391 | randomize_client_port: false -------------------------------------------------------------------------------- /config/daemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "registry-mirrors": [ 3 | "https://hub-mirror.c.163.com", 4 | "https://ustc-edu-cn.mirror.aliyuncs.com", 5 | "https://ghcr.io", 6 | "https://mirror.baidubce.com" 7 | ] 8 | } -------------------------------------------------------------------------------- /config/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nginx: 3 | image: nginx 4 | container_name: nginx 5 | restart: always 6 | ports: 7 | - 81:80 8 | - 443:443 9 | volumes: 10 | - /opt/nginx/conf:/etc/nginx/conf.d 11 | - /opt/nginx/logs:/var/log/nginx 12 | - /opt/nginx/html:/usr/share/nginx/html 13 | - /opt/nginx/cert:/etc/nginx/cert 14 | - /etc/localtime:/etc/localtime:ro 15 | ip_derper: 16 | image: yangchuansheng/ip_derper 17 | container_name: derper 18 | restart: always 19 | environment: 20 | - DERP_ADDR=:8443 21 | network_mode: host 22 | # network_mode: bridge 23 | # ports: 24 | # - 8443:8443 25 | # - 3478:3478/udp 26 | depends_on: 27 | - nginx 28 | headscale: 29 | image: headscale/headscale:v0.23.0-beta1 30 | container_name: headscale 31 | restart: always 32 | environment: 33 | - TZ=Asia/Shanghai 34 | ports: 35 | - 0.0.0.0:5010:5010 36 | - 127.0.0.1:9090:9090 37 | volumes: 38 | - /etc/headscale/:/etc/headscale/ 39 | - /var/lib/headscale/:/var/lib/headscale/ 40 | command: serve 41 | depends_on: 42 | - nginx 43 | - ip_derper 44 | links: 45 | - nginx 46 | headscale-webui: 47 | image: ghcr.io/ifargle/headscale-webui:v0.6.2 48 | container_name: headscale-webui 49 | restart: always 50 | environment: 51 | - TZ=Asia/Shanghai 52 | - COLOR=red # Use the base colors (ie, no darken-3, etc) - 53 | - HS_SERVER=http://headscale:5010 # Reachable endpoint for your Headscale server 54 | - DOMAIN_NAME=http://headscale:5010 # The base domain name for this container. 55 | - KEY="RIyfKAqkmbe/IbWZJm5wr1swUV5WgTcQvloA98w+rY0=" # Generate with "openssl rand -base64 32" - used to encrypt your key on disk. 56 | - AUTH_TYPE=basic # AUTH_TYPE is either Basic or OIDC. Empty for no authentication 57 | - LOG_LEVEL=info # Log level. "DEBUG", "ERROR", "WARNING", or "INFO". Default "INFO" 58 | # ENV for Basic Auth (Used only if AUTH_TYPE is "Basic"). Can be omitted if you aren't using Basic Auth 59 | - BASIC_AUTH_USER=headscale # Used for basic auth 60 | - BASIC_AUTH_PASS=hwpassword # Used for basic auth 61 | ports: 62 | - 5000:5000 63 | volumes: 64 | - ./volume:/data # Headscale-WebUI's storage. Make sure ./volume is readable by UID 1000 (chown 1000:1000 ./volume) 65 | - /etc/headscale/:/etc/headscale/:ro # Headscale's config storage location. Used to read your Headscale config. ro:readonly. 66 | depends_on: 67 | - headscale 68 | links: 69 | - headscale 70 | - nginx 71 | -------------------------------------------------------------------------------- /config/nginx/192.168.10.60.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGYTCCBEmgAwIBAgIQH4vADzJc7LjEGNL9yzVUpTANBgkqhkiG9w0BAQwFADBL 3 | MQswCQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NT 4 | TCBSU0EgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTIzMDQwODAwMDAwMFoXDTIz 5 | MDcwNzIzNTk1OVowGjEYMBYGA1UEAxMPMTI0LjIyMy4yMDAuMTA1MIIBIjANBgkq 6 | hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzINN81+VZvBo7nSU0JemsTha+TnBeip6 7 | qkAjAEDunXgegkSX77EJSc0ouVlysr3r36Cmx8cdcZXrlbIX001ayiH+T2Z1dBPd 8 | aDKt1Z3JR4KZzdvQXCoAEbO809GUwF1ZDXsz7J7uZIG4MboSWz8a1SPGepsTBq2C 9 | Nd+7VMH1tgZg5w7tXU1b3yndPkL1lGUvLtnBCZXcBUzH3r71wrqu0/TO+cSRiQAy 10 | Bhm70McaDkrldAz/1WiGOGi2qLu7zork2sx+4yxVldsHryzmUx82JY/EW+UA9prE 11 | ydVF+96OMyuSAuZrv8Fi5/w357k9c0JUsOEHVU1ezR1wwnroLBHa5wIDAQABo4IC 12 | cDCCAmwwHwYDVR0jBBgwFoAUyNl4aKLZGWjVPXLeXwo+3LWGhqYwHQYDVR0OBBYE 13 | FNhEPHvs2ww99BeSHRYN0c4HaYrAMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8E 14 | AjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQG 15 | CysGAQQBsjEBAgJOMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20v 16 | Q1BTMAgGBmeBDAECATCBiAYIKwYBBQUHAQEEfDB6MEsGCCsGAQUFBzAChj9odHRw 17 | Oi8vemVyb3NzbC5jcnQuc2VjdGlnby5jb20vWmVyb1NTTFJTQURvbWFpblNlY3Vy 18 | ZVNpdGVDQS5jcnQwKwYIKwYBBQUHMAGGH2h0dHA6Ly96ZXJvc3NsLm9jc3Auc2Vj 19 | dGlnby5jb20wggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdwCt9776fP8QyIudPZwe 20 | PhhqtGcpXc+xDCTKhYY069yCigAAAYdhN8QBAAAEAwBIMEYCIQDGTaWcPP5aD8Wz 21 | igHWWO0zrZnNJHY/AHjCltn5QpVOwwIhANmOfQLNI3nH9zVW8YSwt+e0hLvUu+BD 22 | fg6nbtKd2VFfAHUAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IAAAGH 23 | YTfEaAAABAMARjBEAiBwMS/sigZC/nQAKswthAGJxe89EwKAe/5o8TQr08ME/QIg 24 | chVVZlY7avQRmJpLMH2kE/6IaVVhe4te4fqj8pJj/e4wDwYDVR0RBAgwBocEfN/I 25 | aTANBgkqhkiG9w0BAQwFAAOCAgEAbSWlHogDeZTkmnpj8Nvxu+STc6248ORlYQzq 26 | +Q6Pfj58LUihqJ8b14YIsf3X19bprY4KhNEmC1+j2C+MqTjp+DQsK9Zx9cuI3Atd 27 | lZhS6WQ/vkzcf+9pwesfPHdsjasIjSXUYx3dzrGaVb6q2Yd1VENGRSaOflixuaKw 28 | 9unHDENbrhyaS8+FEPR9Zjrze8l1iTeb6WRxz2o3W2iTbmZSbxZkXgmxaysuhU0P 29 | rMwI0C11NRg+jMbbswKVKXBna/08Slh4fIGTMJXY4uz5AeEj5iux1shpTs29+ll6 30 | T6Q22Z+XREEcin4gAuQsafytoQviGV3Nqk6oiCVJpKTTkErBNCaj+P1DnC1+cen5 31 | oFQFtgeVb9I5WPaNVBuc0Qb80zVRm7QdLM0QcvCxcjX0lR7mmRFzk38dQIACDGJM 32 | 0/z7Hfu980qUnsPk/cFu/TQMDYOESMFVG4AHFCk2UiDFrfCBKpKCueaN0eh/hjGw 33 | FohsmZB+7gDrIkV52z5bI29uMixdzhCET+xOj4oOuw9I5QC8A6eTBLfsUFzQbgBu 34 | Y9vTHSRL5zrJrandLw759iAjE8EANAQiVnTl0Pf9sqIOAixDXMD1W31dR7AsPkfU 35 | JEMGBANOXUlyYICpURFW+QyEMzLTRCA7GRbu+8Im1sN0TbnskinqtY1mo1tLDgdB 36 | et5tUTs= 37 | -----END CERTIFICATE----- 38 | -----BEGIN CERTIFICATE----- 39 | MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB 40 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 41 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 42 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw 43 | MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE 44 | ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT 45 | aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj 46 | 4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs 47 | JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4 48 | t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF 49 | WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc 50 | RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U 51 | gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD 52 | hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt 53 | iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF 54 | x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W 55 | 2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp 56 | wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA 57 | FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c 58 | tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE 59 | FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC 60 | TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1 61 | c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG 62 | CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu 63 | Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw 64 | Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV 65 | ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4 66 | YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA 67 | Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ 68 | qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd 69 | 4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW 70 | +LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0 71 | 2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W 72 | kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4 73 | RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG 74 | ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5 75 | S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA== 76 | -----END CERTIFICATE----- 77 | -------------------------------------------------------------------------------- /config/nginx/192.168.10.60.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAzINN81+VZvBo7nSU0JemsTha+TnBeip6qkAjAEDunXgegkSX 3 | 77EJSc0ouVlysr3r36Cmx8cdcZXrlbIX001ayiH+T2Z1dBPdaDKt1Z3JR4KZzdvQ 4 | XCoAEbO809GUwF1ZDXsz7J7uZIG4MboSWz8a1SPGepsTBq2CNd+7VMH1tgZg5w7t 5 | XU1b3yndPkL1lGUvLtnBCZXcBUzH3r71wrqu0/TO+cSRiQAyBhm70McaDkrldAz/ 6 | 1WiGOGi2qLu7zork2sx+4yxVldsHryzmUx82JY/EW+UA9prEydVF+96OMyuSAuZr 7 | v8Fi5/w357k9c0JUsOEHVU1ezR1wwnroLBHa5wIDAQABAoIBAH+cCr6qTLHvnrnz 8 | uouxpMx+Cp3qQOR2rxWecXiOC5XsRrUoEdn5EH+haSDGRIBta0mdl5OelauzTU2Z 9 | 064AXX802Nc4al9kqcmDnd5l1xsszcWavBdWCbcB/Pf6lSO224NC9fJWdQ/3tTQq 10 | E5wl8xs9eHI2YxfOmin9kYlggW3yy6YOjhqLSrp25l64IxZIYiZq+YFBNHZqT0so 11 | 0/1f1FUnE+XGUtqBeDUV27EwT6Ve8WiDHVXazySgV7pGUF8McF5OvvE2ae0c7iMz 12 | L0hj5tcNYvgW/PS1StH2iedGVk8FaTFmxW+Fcp9eW+kQ8Jsau4hmTkPHFmbG5hfY 13 | EAU5oFECgYEA/5T8QaCuAdUyOFFbifpAXQB7ymUvAdKiLUxEIq7JVbzSnGhG2Xwn 14 | /Y3fFCDD1x9dg+Oa+OFCe52F1CBfJvAh3ApcppAA1PNkusirwPVWULOacJXERwXr 15 | Eyfo9TP/w0BqaRUkGdpOsCbU0t6zNaLhT1UqZuvvYpi++HZDjP9tWB8CgYEAzNjv 16 | nmbhNshkx7DfEgP1LYm9oGy7NF9vUJxbkPMgsi+r0OpvaQ2jOFdcyYlP2atbV/bl 17 | sTuAfUicdHlJZwEGO5Ll5I7CSScvtVbUd3wNRoKtkOPCAJn2Lk24e0n4FjTlTh87 18 | 5REB7OaYtAls1pblNUrGMRECBWhwmBhXyPiPRDkCgYEA9C7Ni44OcaXVI0Vnpb24 19 | PKK3orllXeJ2G70f49sGdKnAtrpR5nveYTtohHyBX0iSOe39JAdjU2M+d1quTi9i 20 | yi4EMwamJM6d0G7k2agMXXIa/bG5Ivoei+C3i32wwEUM5XTTVvfh8h5He2hV48rI 21 | ZNlDd622uoag/hVPmKh5OZUCgYEAgqzU1viMLNVTLOwQsT5jFkSq+f7CwVsr+IF2 22 | DBZ8wg6VDXWv0pVHjPZ2E36LuLCOWaP/zLrHcaRzYf3JLHND1ZcVHmNPXzknPwgA 23 | C6TQFy3fqPER3i5ZFBqyV7vNDeV6bgaQv8TEtKo5uYfVrWKfHwrvOXe/EVIZmXzV 24 | 6zdctUkCgYEA9P4/yCy+MT92ZV3EKH4zxBy+84QYFPUUa53m+uPeuA9L1omainOH 25 | ySAtfHdufAITtiCyL9F6YCBNw5RkqGBYiFGKZjW+z6s9B9z2Nk4VaqLaf56fpF7j 26 | diL1Q9irMLPfU01vKWqdlf17tCriXZiFoXfx9GpM4uX7EQQ7i9w+rjs= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /config/nginx/derp.json: -------------------------------------------------------------------------------- 1 | { 2 | "Regions": { 3 | "901": { 4 | "RegionID": 901, 5 | "RegionCode": "tx-sh", 6 | "RegionName": "Tencent Shanghai", 7 | "Nodes": [ 8 | { 9 | "Name": "901a", 10 | "RegionID": 901, 11 | "DERPPort": 8443, 12 | "HostName": "192.168.10.60", 13 | "IPv4": "192.168.10.60", 14 | "InsecureForTests": true 15 | } 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /config/nginx/server.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | server_name localhost; 5 | 6 | #access_log /var/log/nginx/host.access.log main; 7 | 8 | location / { 9 | root /usr/share/nginx/html; 10 | index index.html index.htm; 11 | } 12 | 13 | #error_page 404 /404.html; 14 | 15 | # redirect server error pages to the static page /50x.html 16 | # 17 | error_page 500 502 503 504 /50x.html; 18 | location = /50x.html { 19 | root /usr/share/nginx/html; 20 | } 21 | 22 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 23 | # 24 | #location ~ \.php$ { 25 | # proxy_pass http://127.0.0.1; 26 | #} 27 | 28 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 29 | # 30 | #location ~ \.php$ { 31 | # root html; 32 | # fastcgi_pass 127.0.0.1:9000; 33 | # fastcgi_index index.php; 34 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 35 | # include fastcgi_params; 36 | #} 37 | 38 | # deny access to .htaccess files, if Apache's document root 39 | # concurs with nginx's one 40 | # 41 | #location ~ /\.ht { 42 | # deny all; 43 | #} 44 | } 45 | 46 | server { 47 | listen 443 ssl; 48 | listen [::]:443 ssl; 49 | server_name 192.168.10.60; 50 | ssl_prefer_server_ciphers on; 51 | ssl_certificate /etc/nginx/cert/192.168.10.60.crt; 52 | ssl_certificate_key /etc/nginx/cert/192.168.10.60.key; 53 | 54 | location / { 55 | root /usr/share/nginx/html; 56 | index index.html; 57 | } 58 | 59 | location /headscaleui/ { 60 | proxy_redirect off; 61 | proxy_set_header Host $host; 62 | proxy_set_header X-Real-IP $remote_addr; 63 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 64 | proxy_pass http://headscale-webui:5000/; 65 | } 66 | } -------------------------------------------------------------------------------- /config/sources2004.list: -------------------------------------------------------------------------------- 1 | deb https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse 2 | deb-src https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse 3 | 4 | deb https://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse 5 | deb-src https://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse 6 | 7 | deb https://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse 8 | deb-src https://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse 9 | 10 | # deb https://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse 11 | # deb-src https://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse 12 | 13 | deb https://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse 14 | deb-src https://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse -------------------------------------------------------------------------------- /config/tput_color_echo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # e 是命令 echo 的一个可选项,它用于激活特殊字符的解析器 4 | 5 | # https://blog.csdn.net/fdipzone/article/details/9993961 6 | # tput Color Capabilities: 7 | 8 | # tput setab [0-7] – Set a background color using ANSI escape 9 | # tput setb [0-7] – Set a background color 10 | # tput setaf [0-7] – Set a foreground color using ANSI escape 11 | # tput setf [0-7] – Set a foreground color 12 | 13 | # Color Code for tput: 14 | 15 | # 0 – Black 16 | # 1 – Red 17 | # 2 – Green 18 | # 3 – Yellow 19 | # 4 – Blue 20 | # 5 – Magenta 21 | # 6 – Cyan 22 | # 7 – White 23 | 24 | # tput Text Mode Capabilities: 25 | 26 | # tput bold – Set bold mode 27 | # tput dim – turn on half-bright mode 28 | # tput smul – begin underline mode 29 | # tput rmul – exit underline mode 30 | # tput rev – Turn on reverse mode 31 | # tput smso – Enter standout mode (bold on rxvt) 32 | # tput rmso – Exit standout mode 33 | # tput sgr0 – Turn off all attributes 34 | 35 | ## blue to echo 36 | function blue() { 37 | echo -e "$(tput setaf 4)$1$(tput sgr0)" 38 | } 39 | 40 | ## green to echo 41 | function green() { 42 | echo -e "$(tput setaf 2)$1$(tput sgr0)" 43 | } 44 | 45 | ## Error 46 | function red() { 47 | echo -e "$(tput setaf 1)$1$(tput sgr0)" 48 | } 49 | 50 | ## warning 51 | function yellow() { 52 | echo -e "$(tput setaf 3)$1$(tput sgr0)" 53 | } 54 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source config/tput_color_echo.sh 3 | 4 | # set -e,脚本只要发生错误,就终止执行。 5 | set -o errexit 6 | # set -u,遇到不存在的变量就会报错,并停止执行 7 | set -o nounset 8 | # set -e 有一个例外情况,就是不适用于管道命令。所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。 9 | # set -o pipefail用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。 10 | set -o pipefail 11 | # 在脚本中设置 -x 参数,让命令执行时打印其命令本身和参数,+x 关闭 12 | #set -x 13 | 14 | function change_apt_sources() { 15 | green '换源' 16 | set -x 17 | cp /etc/apt/sources.list /etc/apt/sources.list.bak 18 | cp config/sources2004.list /etc/apt/sources.list 19 | apt update 20 | set +x 21 | } 22 | 23 | function install_docker() { 24 | green 'docker 换源' 25 | set -x 26 | mkdir -p /etc/docker 27 | cp config/daemon.json /etc/docker 28 | set +x 29 | green '安装 docker' 30 | set -x 31 | # apt-get remove docker docker-engine docker.io containerd runc 32 | apt-get update 33 | apt-get install \ 34 | ca-certificates \ 35 | curl \ 36 | gnupg 37 | install -m 0755 -d /etc/apt/keyrings 38 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 39 | chmod a+r /etc/apt/keyrings/docker.gpg 40 | echo \ 41 | "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ 42 | "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | 43 | tee /etc/apt/sources.list.d/docker.list >/dev/null 44 | apt-get update 45 | apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 46 | docker version 47 | set +x 48 | } 49 | 50 | function install_docker_compose() { 51 | green '安装 docker-compose' 52 | set -x 53 | curl -SL https://github.com/docker/compose/releases/download/v2.26.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose 54 | chmod +x /usr/local/bin/docker-compose 55 | docker-compose version 56 | set +x 57 | } 58 | 59 | function nginx_init() { 60 | green '初始化 nginx 配置' 61 | read -rp "输入服务器IP:" ip 62 | green "服务器IP:$ip" 63 | set -x 64 | mkdir -p /opt/nginx/{conf,html,cert} 65 | cp config/nginx/192.168.10.60.crt /opt/nginx/cert/"$ip".crt 66 | cp config/nginx/192.168.10.60.key /opt/nginx/cert/"$ip".key 67 | cp config/nginx/server.conf /opt/nginx/conf/server.conf 68 | sed -i "s/192.168.10.60/$ip/g" /opt/nginx/conf/server.conf 69 | cp config/nginx/derp.json /opt/nginx/html/derp.json 70 | sed -i "s/192.168.10.60/$ip/g" /opt/nginx/html/derp.json 71 | set +x 72 | } 73 | 74 | function headscale_init() { 75 | green '初始化 headscale' 76 | read -rp "输入服务器IP:" ip 77 | green "服务器IP:$ip" 78 | set -x 79 | mkdir -p /etc/headscale 80 | mkdir -p /var/lib/headscale 81 | touch /var/lib/headscale/db.sqlite 82 | cp config/config.yaml /etc/headscale 83 | sed -i "s/192.168.10.60/$ip/g" /etc/headscale/config.yaml 84 | set +x 85 | } 86 | 87 | function run_docker_compose() { 88 | green '运行 nginx、ip_derper、headscale、headscale-webui' 89 | set -x 90 | mkdir -p /opt/headscale 91 | cp config/docker-compose.yml /opt/headscale 92 | read -rp "输入 headscale-webui 密码:" hwpassword 93 | sed -i "s/hwpassword/$hwpassword/g" /opt/headscale/docker-compose.yml 94 | cd /opt/headscale 95 | docker-compose up -d 96 | chown 1000:1000 /opt/headscale/volume 97 | docker ps 98 | set +x 99 | } 100 | 101 | green "请选择服务类型" 102 | green "1) 更新源" 103 | green "2) 安装 docker" 104 | green "3) 安装 docker-compose" 105 | green "4) 初始化 nginx 配置" 106 | green "5) 初始化 headscale 配置" 107 | green "6) 运行容器" 108 | green "7) 按顺序执行123456" 109 | green "8) 退出" 110 | read -r number 111 | case $number in 112 | 1) 113 | change_apt_sources 114 | ;; 115 | 2) 116 | install_docker 117 | ;; 118 | 3) 119 | install_docker_compose 120 | ;; 121 | 4) 122 | nginx_init 123 | ;; 124 | 5) 125 | headscale_init 126 | ;; 127 | 6) 128 | run_docker_compose 129 | ;; 130 | 7) 131 | change_apt_sources 132 | install_docker 133 | install_docker_compose 134 | nginx_init 135 | headscale_init 136 | run_docker_compose 137 | ;; 138 | 8) 139 | exit 140 | ;; 141 | esac 142 | -------------------------------------------------------------------------------- /img/24b1830a1dfeb7c25292d95f1bb425c649af8111f26994bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jial08/headscale-deploy/31224ec8c31c7945e860623dd83431a31f4a7108/img/24b1830a1dfeb7c25292d95f1bb425c649af8111f26994bc.png -------------------------------------------------------------------------------- /img/3d0d842e91bca36404357cd95cd4d6f5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jial08/headscale-deploy/31224ec8c31c7945e860623dd83431a31f4a7108/img/3d0d842e91bca36404357cd95cd4d6f5.jpeg -------------------------------------------------------------------------------- /img/5c3cd28310b212cf9dbc1648f6f894a6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jial08/headscale-deploy/31224ec8c31c7945e860623dd83431a31f4a7108/img/5c3cd28310b212cf9dbc1648f6f894a6.png -------------------------------------------------------------------------------- /img/960d7ab58421aa22a8c75aa8f4e0bf91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jial08/headscale-deploy/31224ec8c31c7945e860623dd83431a31f4a7108/img/960d7ab58421aa22a8c75aa8f4e0bf91.png --------------------------------------------------------------------------------