はじめに
最近、外出先から自宅サーバーへとSSHを繋ぎたいことがあってTailscale VPNを導入しましたのですが、せっかくプライベートなネットワークなので自宅のサーバーに常駐するセルフホストのサービスを立ててみました。
しかし、残念なことにポート番号が覚えづらくてならない。
べつにVPNの中なのでわざわざドメインにIPを紐付けなくとも同じIPですし、なんならTailscaleの場合はマシンごとに勝手にドメインを割り当ててくれる(MagicDNS)のでDNSなんてわざわざ建てる必要ないな、なんて思っていたのですが、私の脳ではたった3つ程度のセルフホストのサービスのポート番号すら間違えてしまいます。
そんなわけで、先人たちに倣って私も自前のDNSを建てることにしました。
前提条件
- Ubuntu 24.04を利用しています
- 自前の使い道のないドメインを持っている前提です
- この方法ではドメインのネームサーバーはCloudflareである必要があります
(Cloudflareでドメインを管理していない場合は移管するなりLet's encryptのチャレンジを解決する用のサーバーを建てるなりしてもらう必要があります…)
自前のDNSを立てて、TailscaleのDNSに参照させる
Split DNS
の設定
まず、TailscaleのDNSには、Split DNS
という便利な機能があります。これは、特定のドメインにアクセスする場合にのみ、特定のDNSを使用して名前解決を図る仕組みです。
ここでは、利用するドメインをexample.com
と仮定します。
Tailscaleにアクセスした後、DNS
のタブのNameservers
にあるAdd nameserver
をクリックします。その後、選択肢の中でCustom
を選択すると設定できます。この際、Restrict to domain
のトグルをONにしてSplit DNSの機能を利用するようにしてください。
まず、ここにDNSを運用するサーバーのVPN上でのIPアドレスと、利用するドメインを登録しておきましょう。
sytemd-resolvedと利用するポートが被る問題を解消
まず、Ubuntuの場合、DNSに利用したい53番ポートはsystemd-resolved
によって使用されています。これは、名前解決のキャッシュや.local
でアクセスできるようなローカルネットワークのデバイスIPの名前解決を行ってくれる便利な機能なのですが、今回に限ってはこれの一部機能をOFFにする必要があります。本来であればNameserverのポート番号を指定できれば良い話ですが、残念ながらTailscaleではできないようです。
53番ポートを利用するために、systemd-resolvedのコンフィグを編集しましょう。
sudo bash -c "echo 'DNSStubListener=no' >> /etc/systemd/resolved.conf"
sudo systemctl restart systemd-resolved
DNSサーバーを建てる
つぎに適当なDNSサーバーを立てます。設定が簡単なのはdnsmasq
とかだと思います。
sudo apt update
sudo apt install dnsmasq
sudo bash -c "echo 'address=/sample.example.com/xxx.xxx.xxx.xxx' >> /etc/dnsmasq.conf"
sudo systemctl restart dnsmasq
おそらくこれで、dnsmasqが53番で動作していると思います。
動作確認
TailscaleでSplit DNSが機能し、dnsmasqを動作させコンフィグが適切に設定されていれば、これで名前の解決は可能になったはずです。試しに、digコマンドで確認してみましょう。
dig @127.0.0.1 sample.example.com #自分のサーバーで動いているDNS
dig @100.100.100.100 sample.example.com #tailscaleのDNS
dig sample.example.com #現在利用しているDNS
適切に設定されていれば、それぞれのコマンドで同じIPに辿り着くはずです。
nginxとかで適当に振り分ける
例えば、セルフホストのサービスがlocalhost:8080
で動作している場合は、以下のようになります。
server {
listen 80;
server_name sample.example.com;
location / {
proxy_pass http://localhost:8080;
}
}
設定後は以下のようにしてコンフィグを有効にします。
ln -s /etc/nginx/sites-available/sample.example.com /etc/nginx/sites-enabled
sudo nginx -t #コンフィグが正しいか確認
sudo systemctl restart nginx
HTTPSで接続できるようにする
そもそもいる?
セルフホストの、さらにVPNの中で動いているサービスを、わざわざHTTPSにする必要があるのかと疑問に思うかもしれません。
まあ、ぶっちゃけ必要ないのですが、普段使っているブラウザで危険なサイトとして扱われたりしてアクセスするのが面倒だったりします。それを回避するための手段と思ってもらってたら良いかもしれません。
Let's encryptで署名付き証明書を手にいれる
HTTPSで通信するためには、適切に署名された証明書を手に入れる必要があります。しかしながら、これはあくまでVPNのサーバー。外界からは遮断され、よくある方法でDNSの所有権を証明することはできません。
そこで、ドメインのテキストレコードをプラグインで自動的に編集する方法をとります。一度証明書を取得するだけであれば手動で問題ないのですが、let's encryptの証明書の有効期限は三ヶ月です。三ヶ月ごとに毎回作業をするのはダルいので、今回は出回っているプラグインを利用する方法をとります。
sudo apt update
sudo apt install certbot python3-certbot-dns-cloudflare
mkdir -p ~/.secrets/certbot
touch ~/.secrets/certbot/cloudflare.ini
chmod 600 ~/.secrets/certbot/cloudflare.ini
最後に作成した~/.secrets/certbot/cloudflare.ini
にはCloudflareのサイトで取得したAPIトークンを登録します。このAPIのトークンはDNSレコードの編集権限を持つだけのものが良いかと思います。
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
さて、これでコマンドを実行できるようになるはずです。
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-d example.com \
-d *.example.com
ワイルドカードを利用して取得することで証明書取得の手間が省けますが、気になる場合は個別に取得していただいて構いません。
自動更新の設定をする
[Unit]
Description=Certbot Renewal
Documentation=https://certbot.eff.org/
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "/bin/systemctl reload nginx"
[Install]
WantedBy=multi-user.target
[Unit]
Description=Run Certbot renewal every day
[Timer]
OnCalendar=*-*-1 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
以下のように登録します。
sudo systemctl daemon-reload
sudo systemctl enable certbot-renew.timer
sudo systemctl start certbot-renew.timer
これで、毎月1日に証明書の自動更新と、それに付随するnginxの再起動が行われます。
nginxの設定を変更する
server {
listen 80;
server_name sample.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sample.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
}
}
書き換え後にnginxを再起動します。
sudo nginx -t
sudo systemct restart nginx
これで https://sample.example.com にアクセスすると、セルフホスト運用しているサービスへとアクセスできるはずです。
最後に
セルフホストのサービスの中で、特におすすめなのがminifluxです。マジでおすすめです。CSS改造すると、マジでいいですよ。皆さんもぜひ、自宅サーバーライフのご満喫を。
参考