😎

Tailscale on Azureでオンプレミスとの閉域接続を月1,000円で実現する

に公開

はじめに

Azure 仮想ネットワーク (VNet) と自宅(または社内プライベートネットワーク)を、低コストで安全に接続する手順をまとめます。ここではAzure VPN や ExpressRoute を使わず、Tailscale を利用して「閉域的に」接続する方法を示します。

Tailscaleとは?

Tailscale は WireGuard をベースにしたゼロコンフィグの VPN サービスで、個々の端末やサーバを安全に接続するための管理プレーンを提供します。セットアップが簡単で、個人利用の無償プランでも基本的な接続やサブネットルーティングを試せます。

今回の確認ポイントとしては

  • 目標:追加コストを抑えつつ、Azure の VNet に安全にアクセスできること
  • 手段:Azure 上に小さな Linux VM を置き、Tailscale を subnet router として動かす

となります。

想定読者と前提

  • 想定読者:Azure と Linux の基本操作(VM 作成や SSH)ができる方
  • 前提環境:Azure サブスクリプション、Tailscale アカウント(無料プランで可)
  • ネットワーク構成:Azure 側に VNet(例:192.168.2.0/24)、自宅側にプライベート LAN(例:192.168.1.0/24)

Azure リソースを安くする工夫

ここでは実運用でのコストを下げるための具体的な工夫を示します。小さく安全に運用することで月額コストを抑えられます。

  • public ip は使わない(約 540 円/月 を回避)

    • public ip だけで約 540円/月のコストがかかるため、VM に直接 public ip を割り当てない運用を推奨します(Tailscaleはオンプレ共に専用のグローバルIPアドレスは不要)
    • 代替手段として Azure Bastion(後述)で接続し、VM を public に晒さないようにします。
  • VM は Ubuntu 22.04 LTS Minimal を使う

    • イメージは Ubuntu 22.04 LTS の Minimal を選択するとディスク/メモリ使用を抑えられます。
  • サイズは最安の B1ls を使う

    • Standard_B1ls (1 vCPU, 0.5 GB メモリ) のような最小構成を採用してください。サブネットルータ用途で負荷が低ければ十分です。
  • 管理用アクセスは Bastion Developer (0円/月) を使う

    • 初回セットアップやメンテナンス用の SSH 接続には、Bastion Developer(無料枠)を利用して、VM に public ip を割り当てずにアクセスする運用を推奨します。

構成の概要

自宅 LAN(192.168.1.0/24)
Azure Vnet(192.168.2.0/24)

img

今回は自宅から閉域ネットワーク経由でAzure OpenAIのAPIを叩けることを目指します。

Private LinkをVnetに繋げることで対応しているPaaSは一通りこちらの構成で繋げられるのではないかと思います。

手順(概要 → コマンド例)

大まかな流れ:

  1. Azure に小さな Linux VM を作成
  2. VM に Tailscale をインストールし、サブネット経路を広告(advertise-routes)
  3. 自宅側デバイスで Tailscale を有効化し、サブネットルートを受け入れる(Accept routes)

Azure側インフラの準備

以下は Azure CLI でインフラを作成する例です。

# 変数
LOCATION=japaneast
RG=rg-tailscale
ROUTE_TABLE=udr-tailscale
VNET=vnet-tailscale
NIC_NAME=nic-tailscale
VM_NAME=vm-tailscale
VM_ADMIN=tailadmin
VM_SSH_PUBKEY="~/.ssh/id_ed25519.pub"

# 固定プライベート IP を指定(snet-vms の範囲内: 192.168.2.0/25)
VM_PRIVATE_IP=192.168.2.100

# リソースグループ作成
az group create -n $RG -l $LOCATION

# ルートテーブル(UDR)
az network route-table create -g $RG -n $ROUTE_TABLE

az network route-table route create -g "$RG" \
  --route-table-name "$ROUTE_TABLE" -n route-to-onprem \
  --address-prefix 192.168.1.0/24 --next-hop-type VirtualAppliance \
  --next-hop-ip-address "$VM_PRIVATE_IP"

# VNet とサブネット作成(VNet: 192.168.2.0/24)
az network vnet create \
  -g $RG -n $VNET --address-prefix 192.168.2.0/24 \
  --subnet-name snet-vms --subnet-prefix 192.168.2.0/25

az network vnet subnet create \
  -g $RG --vnet-name $VNET -n snet-pe \
  --address-prefix 192.168.2.128/26

az network vnet subnet create \
  -g $RG --vnet-name $VNET -n AzureBastionSubnet \
  --address-prefix 192.168.2.192/27

# snet-vmsの規定のアウトバウンド通信を許可にする
az network vnet subnet update --default-outbound true -g $RG --vnet-name $VNET -n snet-vms

# サブネットにルートテーブルを適用
az network vnet subnet update -g $RG --vnet-name $VNET -n snet-vms --route-table $ROUTE_TABLE
az network vnet subnet update -g $RG --vnet-name $VNET -n snet-pe --route-table $ROUTE_TABLE

# NIC を作成(パブリックIP を割り当てず、IP フォワーディングを有効化)
az network nic create \
  -g $RG -n $NIC_NAME --vnet-name $VNET --subnet snet-vms --ip-forwarding true \
  --private-ip-address $VM_PRIVATE_IP

# VM を作成(public-ip を割り当てない、NSG は作らない、ssh 鍵でユーザーを作成)
az vm create \
  -g $RG -n $VM_NAME --nics $NIC_NAME \
  --image canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts-gen2:latest \
  --size Standard_B1ls \
  --admin-username $VM_ADMIN --ssh-key-values $VM_SSH_PUBKEY

# Bastion を作成(Developer SKU)
az network bastion create \
  -g $RG -n bastion-dev --vnet-name $VNET -l $LOCATION --sku Developer

はい、できました。

img

作成したVMメニューからBastionを選び、必要事項を入力・設定して接続します。

img

無事ブラウザ経由で接続完了。

img

VM に Tailscale をインストールしてサブネットを広告する

まずは Tailscale をインストール(公式インストーラを利用)。

curl -fsSL https://tailscale.com/install.sh | sh

サブネットルータとして動作させるため、IPフォワードの設定を行う

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

Tailscale の認証は通常ブラウザで行います。自動化する場合は管理コンソールで Auth Key(--authkey tskey-...)を発行することで行えるようです。

VM 側では次のように起動して VNet のサブネット(例: 192.168.2.0/24)を広告しつつ、さらにオンプレミス(自宅)側のルート情報も学習するオプションを指定します。

sudo tailscale up --advertise-routes=192.168.2.0/24 --accept-routes

これでこの VM が "subnet router" として 192.168.2.0/24 への経路を Tailscale に広告します。

ターミナル画面にデバイス認証用のURLが表示されるので、そちらにアクセスするとTailscaleコンソールにて接続確認画面が出ます。

こちらは「Connect」で繋げましょう。

img

デバイスは正常に登録されました。

img

続いて該当ノードの経路広告を承認(Accept routes)する必要があります。

一覧右のメニューから「Edit route settings...」を選択後の画面から広告したい(自分が所属しているネットワークCIDR)にチェックを入れて保存します。

img

また、デフォルトで認証キーの有効期限が7日と短いので無期限に変更します。

こちらも右のメニューから「Disable key expiry」を選択します。

こんな感じになっていればOK。

img

自宅側デバイスで Tailscale を有効にし、経路を受け入れる

自宅の PC や Raspberry Pi に Tailscale をインストールし、同じ tailnet に参加します。

基本手順はAzure VM側と同じで、広告するネットワークセグメントが異なるだけなので、詳細は割愛しますね。

sudo tailscale up --advertise-routes=192.168.1.0/24 --accept-routes

Tailscaleのデバイス一覧は最終的にはこんな感じになるでしょう。

img

動作確認

  • 自宅側端末から Azure VNet のプライベート IP(例: 192.168.2.100)へ ping
ping -c 10 192.168.2.100

img

私の場合ですが、他のリソースグループにAzure OpenAIがありましたので、プライベートリンクで今回作成したVnetのsnet-peにプライベートエンドポイントを作成して、自宅PCからTailscale VM経由でちゃんとアクセスできることを確認しました。

特にRoute Table(UDR)がちゃんと機能するかの確認ですね。

export AZURE_API_KEY="<<OpenAIのアクセスキー>>"

curl -X POST -s --resolve aoai-XXXXXX.openai.azure.com:443:192.168.2.132 \
  "https://aoai-XXXXXX.openai.azure.com/openai/deployments/gpt-4.1-nano/chat/completions?api-version=2025-01-01-preview" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AZURE_API_KEY" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "おはよう"
      }
    ],
    "max_completion_tokens": 13107,
    "temperature": 1,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "model": "gpt-4.1-nano"
  }' \
  | jq -r '.choices[0].message.content'

うまくいきました。

img

ちゃんと以下の経路で繋がっているようです。

img

まとめ

Tailscale を使えば、既存のクラウドネットワーク(Azure VNet)と自宅やプライベートネットワークを手軽に結びつけられます。

小さな Azure VM をサブネットルータにすることで、商用の閉域接続サービスを使わずに「閉域的」なアクセスを実現可能です。コストは工夫次第でおおむね月額 1,000 円前後に抑えられます(たぶん)。

Discussion