本家様 https://headscale.net/stable/
github https://github.com/juanfont/headscale
外部からのアクセスで WireGuard を使うのですが、いつ、だれが接続したのかがつかめずらい。
接続認証はそもそも秘密鍵なので、それを持っているのが認証になるのかなと思うのだが、「いつ」「だれ」かをログに取りたい。
っで調べていて見つけたのが「tailscale」. こちらは有償で、個人ユースには無償版もある。っでオープンソースなものを調べて見つけたのが「Headscale」
でも「Headscale」が提供するのは「tailscale」のコントロールサーバー部分. windowsやmacOSに入れるクライアントトールは「公式Tailscaleアプリ」を使うみたい
OSはrockylinux9を使ってます
プログラムの置き場所は「/usr/local/bin」です
[root@headscale ~]# cat /etc/redhat-release
Rocky Linux release 9.8 (Blue Onyx)
[root@headscale ~]#
[root@headscale ~]# dnf install curl wget git nginx
[root@headscale ~]# cd /usr/local/bin/
[root@headscale bin]# wget https://github.com/juanfont/headscale/releases/download/v0.29.3/headscale_0.29.3_linux_amd64
[root@headscale bin]# mv headscale_0.29.3_linux_amd64 headscale
[root@headscale bin]# chmod +x headscale
[root@headscale bin]# ls -lh
:
-rwxr-xr-x. 1 root root 50M Jul 29 21:50 headscale
[root@headscale bin]#
[root@headscale bin]# ./headscale version
headscale version v0.29.3
commit: 5aff68b5b9921db5ccb88013bb1740077ab872fb
build time: 2026-07-29T12:35:31Z
built with: go1.26.5 linux/amd64
[root@headscale bin]#プログラムはこれでOkで次にこの headscale を稼働するユーザ「headscale」を作ります
このアカウント「headscale」は、systemアカウントにして、uid/gidを1000以下とします
[root@headscale ~]# useradd \
--create-home \
--home-dir /var/lib/headscale/ \
--system \
--user-group \
--shell /usr/sbin/nologin \
headscale
[root@headscale ~]# id headscale
uid=995(headscale) gid=994(headscale) groups=994(headscale)
[root@headscale ~]#次に設定ファイルを取得します. ここhttps://headscale.net/stable/ref/configuration/
に記載のようにgitリポジトリにある設定例を取得します
[root@headscale ~]# mkdir -p /etc/headscale
[root@headscale ~]# cd /etc/headscale/
[root@headscale headscale]# wget -O config.yaml https://raw.githubusercontent.com/juanfont/headscale/refs/tags/v0.29.3/config-example.yaml一応このファイルの中身は
[root@headscale ~]# sed -e '/^[[:space:]]*#/d' -e '/^[[:space:]]*$/d' /etc/headscale/config.yaml
---
server_url: https://headscale.chaperone.jp
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
trusted_proxies: []
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
allocation: sequential
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
verify_clients: true
stun_listen_addr: "0.0.0.0:3478"
private_key_path: /var/lib/headscale/derp_server_private.key
automatically_add_embedded_derp_region: true
ipv4: 198.51.100.1
ipv6: 2001:db8::1
urls:
- https://controlplane.tailscale.com/derpmap/default
paths: []
auto_update_enabled: true
update_frequency: 3h
disable_check_updates: false
node:
expiry: 0
ephemeral:
inactivity_timeout: 30m
routes:
ha:
probe_interval: 10s
probe_timeout: 5s
database:
type: sqlite
debug: false
gorm:
prepare_stmt: true
parameterized_queries: true
skip_err_record_not_found: true
slow_threshold: 1000
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
wal_autocheckpoint: 1000
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""
log:
level: info
format: text
policy:
mode: file
path: ""
dns:
magic_dns: true
base_domain: tail.chaperone.jp
override_local_dns: true
nameservers:
global:
- 1.1.1.1
- 1.0.0.1
- 2606:4700:4700::1111
- 2606:4700:4700::1001
split: {}
search_domains: []
extra_records: []
unix_socket: /run/headscale/headscale.sock <-- 「/var/run/headscale/headscale.sock」から「/run/headscale/headscale.sock 」へ
unix_socket_permission: "0770"
logtail:
enabled: false
taildrop:
enabled: true
auto_update:
enabled: false
[root@headscale ~]#設定ファイルの次は service ファイル
[root@headscale ~]# wget -O /etc/systemd/system/headscale.service https://raw.githubusercontent.com/juanfont/headscale/refs/heads/main/packaging/systemd/headscale.service
[root@headscale ~]# vi /etc/systemd/system/headscale.service
[Unit]
After=network.target
Description=headscale coordination server for Tailscale
X-Restart-Triggers=/etc/headscale/config.yaml
[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve <-- headscale の保存場所に合わせて修正
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
WorkingDirectory=/var/lib/headscale <-- ユーザ headscale のホームディレクトリとかで
ReadWritePaths=/var/lib/headscale <-- ユーザ headscale のホームディレクトリとかで
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN
LockPersonality=true
NoNewPrivileges=true
PrivateDevices=true
PrivateMounts=true
PrivateTmp=true
ProcSubset=pid
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
RuntimeDirectory=headscale
RuntimeDirectoryMode=0750
StateDirectory=headscale
StateDirectoryMode=0750
SystemCallArchitectures=native
SystemCallFilter=@chown
SystemCallFilter=@system-service
SystemCallFilter=~@privileged
UMask=0077
[Install]
WantedBy=multi-user.target
[root@headscale ~]#[root@headscale ~]# chown -R headscale:headscale /var/lib/headscale
[root@headscale ~]# chmod 750 /var/lib/headscaleっで headscaleを試しに動かす
[root@headscale ~]# systemctl daemon-reload
[root@headscale ~]# systemctl enable headscale --now
[root@headscale ~]# journalctl -f -u headscale
Mar 22 02:16:08 headscale systemd[1]: Started headscale coordination server for Tailscale.
Mar 22 02:16:08 headscale headscale[12631]: 2026-03-22T02:16:08+09:00 INF No private key file at path, creating... path=/var/lib/headscale/noise_private.key
Mar 22 02:16:08 headscale headscale[12631]: 2026-03-22T02:16:08+09:00 INF Opening database database=sqlite3 path=/var/lib/headscale/db.sqlite
Mar 22 02:16:08 headscale headscale[12631]: 2026-03-22T02:16:08+09:00 INF Starting Headscale commit=97fa117c48a58bee3941e5e8b4393873501afe14 version=v0.28.0
Mar 22 02:16:08 headscale headscale[12631]: 2026-03-22T02:16:08+09:00 INF Clients with a lower minimum version will be rejected minimum_version=v1.74
Mar 22 02:16:09 headscale headscale[12631]: 2026-03-22T02:16:09+09:00 INF listening and serving HTTP on: 127.0.0.1:8080
Mar 22 02:16:09 headscale headscale[12631]: 2026-03-22T02:16:09+09:00 INF listening and serving debug and metrics on: 127.0.0.1:9090
:
:[root@headscale ~]# dnf install httpd certbot python3-certbot-apache
[root@headscale ~]# echo "ok" >> /var/www/html/index.html
[root@headscale ~]# cat<<_EOF_> /etc/httpd/conf.d/headscale.conf
<VirtualHost *:80>
ServerName headscale.chaperone.jp
DocumentRoot "/var/www/html"
</VirtualHost>
<VirtualHost *:443>
ServerName headscale.chaperone.jp
DocumentRoot "/var/www/html"
</VirtualHost>
_EOF_
[root@headscale ~]# systemctl enable httpd --now
[root@headscale ~]# firewall-cmd --add-service=http --add-service=https --permanent
[root@headscale ~]# firewall-cmd --reload
(headscale.chaperone.jpに対して httpアクセスを試みる)
[root@headscale ~]# certbot --apache -d headscale.chaperone.jp
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel): XXXXXXXX@YYYYYYYYYYY.jp <-- 受け取れるメールアドレスを記載
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf. You must agree
in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y <-- 加入者契約書に同意ならY
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N <-- 米国のデジタル権利擁護団体 電子フロンティア財団(EFF)が発行するニュースを受け取るならY
Account registered.
Requesting a certificate for headscale.chaperone.jp
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/headscale.chaperone.jp/fullchain.pem
Key is saved at: /etc/letsencrypt/live/headscale.chaperone.jp/privkey.pem
This certificate expires on 2026-06-23.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for headscale.chaperone.jp to /etc/httpd/conf.d/headscale.conf <-- certbot が「/etc/httpd/conf.d/vpn.conf」を書き換えてます
Congratulations! You have successfully enabled HTTPS on https://headscale.chaperone.jp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[root@headscale conf.d]#[root@headscale ~]# systemctl restart httpdにて headscale.chaperone.jp への https アクセスを試みる
[root@headscale ~]# vi /etc/httpd/conf.d/headscale.conf
<VirtualHost *:80>
ServerName headscale.chaperone.jp
DocumentRoot "/var/www/html"
RewriteEngine on <-+
RewriteCond %{SERVER_NAME} =headscale.chaperone.jp | letsencryptのcertbot で追加された行
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] +----
</VirtualHost>
<VirtualHost *:443>
ServerName headscale.chaperone.jp
DocumentRoot "/var/www/html"
SSLEngine On <-+
SSLCertificateFile /etc/letsencrypt/live/headscale.chaperone.jp/fullchain.pem <-+
SSLCertificateKeyFile /etc/letsencrypt/live/headscale.chaperone.jp/privkey.pem <-+ letsencryptのcertbot で追加された行
Include /etc/letsencrypt/options-ssl-apache.conf <-+
ProxyPreserveHost On <-- 追加
ProxyPass / http://127.0.0.1:8080/ upgrade=any <-- 追加
ProxyPassReverse / http://127.0.0.1:8080/ <-- 追加
</VirtualHost>
[root@headscale ~]#[root@headscale ~]# systemctl restart headscale
[root@headscale ~]# systemctl reload httpd
[root@headscale ~]# setsebool -P httpd_can_network_connect 1外部からheadscaleのチェックを行います
https://headscale.chaperone.jp/healthにアクセスして「{"status":"pass"}」がでるならok
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale users create saber
User created
(確認)
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale users list
ID | Name | Username | Email | Created
1 | | saber | | 2026-08-24 02:17:44
[root@headscale ~]#クライアントアプリは tailscale のアプリを使います。結構タダ乗りしてない?
https://tailscale.com/download
からクライアントプラットホームにあうパッケージをダウンロードして入れます。

ここではwindows版 tailscale-setup-1.102.3.exe( 1,363 KB ) を入手して、インストールしました
これを起動してアプリをインストールします

と進みます。その後に下記画面が表示されます

このまま進むと、tailscaleの設定になるので、右上の「X」を押下して画面を閉じます。
そうすると、インストーラー画面が出てきますが、これも閉じます

その後にwindowsの検索欄から「cmd」と打って、「コマンドプロンプト」を立ち上げます。
そこで、ログイン先を先ほど作ったheadscaleサーバあてにします。
C:\Users\supervisor> "C:\Program Files\Tailscale\tailscale.exe" up --login-server=https://headscale.chaperone.jp
To authenticate, visit:
https://headscale.chaperone.jp/register/hskey-authreq-XXXXXXXXXXXXXXXXXXXXXXXX
これで認証キーが得られます。この認証キーを headscale側に登録します
今haedscaleに登録されているユーザは
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale users list
ID | Name | Username | Email | Created
1 | | saber | | 2026-08-24 02:17:44
[root@headscale ~]#で、ユーザに認証キーを登録します
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale auth register \
--user saber \
---auth-id hskey-authreq-XXXXXXXXXXXXXXXXXXXXXXXX
[root@headscale ~]#これが成功すると、windows側のコマンドプロンプトでは
Success.
C:\Users\supervisor>と「Success」が表示されて、プロンプトが戻ります
そしてこのwindowsにはheadscaleから割り当てられたipを持つようになって
C:\Users\supervisor> tailscale ip -4
100.64.0.1
C:\Users\supervisor> tailscale status
100.64.0.1 at20 saber windows -
C:\Users\supervisor>と確認できます。
一方headscale側では
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale nodes list
ID | Hostname | Name | MachineKey | NodeKey | User | Tags | IP addresses | Ephemeral | Last seen | Expiration | Connected | Expired
1 | at20 | at20 | [p6zl8] | [M0oJS] | saber | | 100.64.0.1 | false | 2026-08-24 02:50:13 | N/A | online | no
| | | | | | | fd7a:115c:a1e0::1 | | | | |
[root@headscale ~]#と確認できます。
ここでは rockylinux9 にクライアントアプリ tailscale を入れます
単に「curl -fsSL https://tailscale.com/install.sh | sh」を実行するだけで、tailscaleがインストールされサービスとして動きます
[root@rockylinux9 ~]# curl -fsSL https://tailscale.com/install.sh | sh
:
:
[root@rockylinux9 ~]# systemctl status tailscaled.service
● tailscaled.service - Tailscale node agent
Loaded: loaded (/usr/lib/systemd/system/tailscaled.service; enabled; preset: disabled)
Active: active (running) since Mon 2026-08-24 12:14:06 JST; 1min 52s ago
:
[root@rockylinux9 ~]#windows版と同じく
[root@rockylinux9 ~]# tailscale up --login-server=https://headscale.chaperone.jp
To authenticate, visit:
https://headscale.chaperone.jp/register/hskey-authreq-YYYYYYYYYYYYYYYYYYYYYYYY
と認証キーが得られます。これをheadscale側に登録します
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale auth register --user saber --auth-id hskey-authreq-YYYYYYYYYYYYYYYYYYYYYYYY登録が完了するとクライアントは
[root@rockylinux9 ~]# tailscale up --login-server=https://headscale.chaperone.jp
To authenticate, visit:
https://headscale.chaperone.jp/register/hskey-authreq-YYYYYYYYYYYYYYYYYYYYYYYY
Success.
[root@rockylinux9 ~]#と「Success」と表示されプロンプトが戻ります。
そしてこのクライアントには
[root@rockylinux9 ~]# tailscale ip -4
100.64.0.2
[root@rockylinux9 ~]# ip a
:
:
3: tailscale0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 qdisc fq_codel state UNKNOWN group default qlen 500
link/none
inet 100.64.0.2/32 scope global tailscale0
valid_lft forever preferred_lft forever
inet6 fd7a:115c:a1e0::2/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::386c:ddf:1993:48cc/64 scope link stable-privacy
valid_lft forever preferred_lft forever
[root@rockylinux9 ~]#とipが振られて、
[root@rockylinux9 ~]# tailscale status
100.64.0.2 rockylinux9 saber linux -
100.64.0.1 at20 saber windows -
[root@rockylinux9 ~]#仲間も見れる.
headscale側では
[root@headscale ~]# sudo -u headscale /usr/local/bin/headscale nodes list
ID | Hostname | Name | MachineKey | NodeKey | User | Tags | IP addresses | Ephemeral | Last seen | Expiration | Connected | Expired
1 | at20 | at20 | [p6zl8] | [M0oJS] | saber | | 100.64.0.1 | false | 2026-08-24 02:50:13 | N/A | online | no
| | | | | | | fd7a:115c:a1e0::1 | | | | |
2 | rockylinux9 | rockylinux9 | [2zPyt] | [HPmhc] | saber | | 100.64.0.2 | false | 2026-08-24 03:22:58 | N/A | online | no
| | | | | | | fd7a:115c:a1e0::2 | | | | |
[root@headscale ~]#となる
windowsとlinuxがheadscaleの中に入ったので、windowsからlinuxに接続してみると
C:\Users\supervisor> ssh -l root rockylinux9
root@100.64.0.2's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Mon Aug 24 13:22:29 2026 from 100.64.0.1
[root@rockylinux9 ~]#とダイレクトに行ける...すっごぃ.
この通信を阻止するには?
この通信は接続先情報をheadscaleノードに登録、参照後、あとはお互い同士の通信になるので、headscaleノードへの通信を遮断しても、それ以降なら有効だけど遮断前ならあんまり有効ではないみたい
っで通信は443で行うので、その遮断となるとインターネットが使えないので無理. そうなるとここ個別のクライアントに tailscape プログラムがないか調べてそいつをブロックするとかになるそうな.
あとポリシーが作れて、windows A --> server B:22 のみ通信を許可して、windows A --> server:80 とかは拒否とか出来るそうな。通信制御が可能っぽい