自宅のファイルサーバーに外出先から安全にアクセスするには、「ファイル共有のポートをインターネットに直接公開する」以外の方法があります。本ガイドは、セルフホスト型VPN(Headscale等、Tailscale互換)と、OIDC対応のアイデンティティプロバイダー(authentik等)を組み合わせ、ファイル共有ポートを一切外部公開せずに、VPN参加そのものをログイン認証で保護する構成の運用手順をまとめたものです。中でも、パスワードに加えてスマートフォンで行う多要素認証(MFA/TOTP)が、この構成全体の安全性を支える最も重要な要素です。実際に外部端末から、MFA込みでの接続・ファイル操作まで確認しています。
目次
1. なぜこの構成にしたか
ファイル共有(SMB等)のポートをそのままインターネットに公開する方法は、設定は簡単ですが、常時世界中からの接続試行にさらされることになります。今回採用したのは、以下の考え方に基づく構成です。
- ファイル共有用のポートはルーターで一切開放しない
- 外部からアクセスできる唯一の経路は、認証されたVPN参加のみ
- VPNへの参加自体を、パスワード+多要素認証(TOTP)で保護されたログイン画面の通過が必要な形にする
ルーター側では、ファイル共有用ポート(445番等)はもちろん、VPN用のポートすら着信を待ち受けるだけで、認証なしに内部へは一切到達できません。
2. 登場する技術要素
| 用語 | 役割 |
|---|---|
| VPNコントロールサーバー | VPNクライアント同士の参加・経路をまとめて管理するサーバー(Tailscale互換のセルフホスト実装等) |
| アイデンティティプロバイダー(IdP) | ログイン画面を一元的に提供するOIDC認証サーバー。VPN参加時の認証をここに委譲する |
| TOTP(多要素認証) | スマートフォンの認証アプリが30秒ごとに生成する6桁のワンタイムコード。パスワードに加えて入力する |
| ファイル共有(SMB等) | Windowsのエクスプローラーからアクセスできる共有フォルダ。VPN参加後、LAN内到達扱いでアクセスする |
3. 【ゼロトラストの核心】多要素認証(MFA)とは
ゼロトラストとは「境界の内側にいるから安全」ではなく、「毎回、本人であることを証明できて初めてアクセスを許可する」という考え方です。この構成の中で、その考え方を実際に体現しているのが、スマートフォンで行う多要素認証(MFA/TOTP)です。
VPNへの参加をパスワードだけで許可してしまうと、パスワードが一つ漏えいした瞬間に境界を突破されてしまいます。「知っているもの(パスワード)」に加えて、「持っているもの(スマートフォンの認証アプリ)」の両方を要求することで、パスワードの漏えいだけでは絶対に突破できない状態を作っているのが、この構成の一番のポイントです。
この構成における本当の砦は、ファイアウォールではなくMFAです
インバウンドポートを閉じることは「入口を減らす」対策にすぎません。実際に「あなたが本人かどうか」を判定しているのはログイン画面のMFAです。ファイアウォール設定やVPNの仕組みをどれだけ強固にしても、MFAを設定していなければ、パスワードの流出ひとつでゼロトラストの前提が崩れます。
| 認証要素 | 具体例 | 本構成での採用 |
|---|---|---|
| 知っているもの(Something you know) | ログインパスワード | 採用 |
| 持っているもの(Something you have) | スマートフォンの認証アプリ(TOTP) | 採用(今回追加) |
| 備わっているもの(Something you are) | 指紋・顔認証、パスキー(WebAuthn) | 今後の検証課題 |
「知っているもの」と「持っているもの」の2種類を組み合わせることで、多要素認証(Multi-Factor Authentication)が成立します。片方だけが漏れても、もう片方がなければログインは完了しません。
4. 事前準備:スマートフォンでMFAを設定する
VPNクライアントのインストール
外出先で使う端末に、VPNクライアント(Tailscale互換の公式クライアント)をインストールします。管理者からIdPのアカウント(ユーザー名・初期パスワード)も合わせて発行してもらいます。
スマートフォンに認証アプリをインストールする
以下のような、TOTP(Time-based One-Time Password)に対応した認証アプリをスマートフォンにインストールします。特別なアカウント登録は不要で、いずれも無料で利用できます。
- Google Authenticator
- Microsoft Authenticator
- Authy など、TOTP対応の認証アプリであればどれでも構いません
IdPの管理画面でMFAデバイスを登録する
IdP(authentik等)のユーザー設定画面から、「MFAデバイス」または「セキュリティ」に相当するメニューを開き、TOTPデバイスの登録を開始します。
- 登録画面にQRコードが表示される
- スマートフォンの認証アプリを開き、「+」やスキャンボタンからカメラでこのQRコードを読み取る
- 読み取ると、アプリの一覧に新しい項目(サイト名やユーザー名で表示される)が追加され、6桁の数字が表示され始める
- その6桁の数字を、IdP側の登録画面に入力して確定する
- 登録完了後、デバイス一覧に今登録したTOTPデバイスが表示されることを確認する
QRコードは一度しか表示されないことが多い
登録画面を閉じたり離れたりすると、同じQRコードは再表示できないことがほとんどです。その場で確実に認証アプリへ読み取らせてください。万が一失敗した場合は、未登録のデバイスを削除してから、登録をやり直します。
スマートフォンを機種変更・紛失した場合
認証アプリ内のTOTPデータは機種変更時に自動では引き継がれない場合があります(アプリによっては引き継ぎ機能あり)。もし新しい端末でコードが表示できなくなった場合、自分では復旧できません。管理者にIdP側の古いMFAデバイスを削除してもらい、新しい端末で登録をやり直す必要があります。事前にアプリの引き継ぎ手順を確認しておくか、機種変更前に必ずMFAの移行を済ませておくことを推奨します。
5. 日常の接続手順
VPN接続
コマンドプロンプトまたはターミナルで、VPNコントロールサーバーを指定して接続します。
tailscale up --login-server=<VPNコントロールサーバーのURL> --accept-routes
--accept-routes を付け忘れると、VPNには参加できても自宅LANへの経路を受け取れないため必須です。
ブラウザでログイン(MFA込み)
自動的にブラウザが開き、IdPのログイン画面が表示されます(開かない場合は、表示されたURLを手動でブラウザに貼り付けます)。
- ユーザー名・パスワードを入力
- 続けて「認証コード」入力欄が表示されるので、4章で登録したスマートフォンの認証アプリを開き、表示されている6桁のコードを入力する
ここでパスワードとMFAコードの両方が揃って初めてログインが完了します。この2段階のどちらか一方だけでは、VPNへの参加自体が許可されません。
接続確認
tailscale status
ping <ファイルサーバーのLAN内IPアドレス>
ファイル共有へ接続(Windows)
エクスプローラーのアドレスバーに直接パスを打ち込むよりも、コマンドで明示的に接続する方が安定します(認証情報のキャッシュが崩れて再入力を求められにくいため)。
net use \\<ファイルサーバーのIPアドレス>\<共有名> /user:<ユーザー名> <パスワード>
接続がうまくいかない場合は、一度削除してからやり直します:net use \\<ファイルサーバーのIPアドレス>\<共有名> /delete
ファイル共有へ接続(Linux/Ubuntu等)
GUI(ファイルマネージャー)とコマンドライン、どちらでも接続できます。
GUIの場合
- ファイルマネージャー(Nautilus等)を開き、「他の場所」→「サーバーへ接続」を選ぶ
- アドレス欄に
smb://<ファイルサーバーのIPアドレス>/<共有名>と入力して接続 - 認証ダイアログでは「匿名」ではなく「登録ユーザー」を選び、ユーザー名・パスワードを入力する
コマンドラインの場合
# 一覧表示のみ(対話式)
smbclient //<ファイルサーバーのIPアドレス>/<共有名> -U <ユーザー名>
# フォルダとしてマウントする場合
sudo mkdir -p /mnt/share
sudo mount -t cifs //<ファイルサーバーのIPアドレス>/<共有名> /mnt/share -o username=<ユーザー名>,vers=3.0,sec=ntlmssp
作業終了後
# Windows
net use \\<ファイルサーバーのIPアドレス>\<共有名> /delete
tailscale down
# Linux(マウントした場合)
sudo umount /mnt/share
sudo tailscale down
この手順は、実際の外部ネットワーク(自宅LAN外)から、多要素認証込みのログイン〜ファイル共有への書込・読込・削除まで、通しで動作確認済みです。
6. デスクトップアイコンで簡単に接続する
毎回コマンドを手入力するのは手間なので、ダブルクリック一発で接続・切断できるアイコンを作っておくと日常使いが格段に楽になります。ここではWindows・Linux(GNOME)それぞれの作り方を、実際に使っているスクリプトの中身つきで紹介します。
6.1 Windowsの場合
接続用バッチファイルを作成
デスクトップ等にzerotrust_connect.batという名前でテキストファイルを作成し、以下を貼り付けます。
@echo off
echo === Headscaleへ接続 (login-server=<VPNコントロールサーバーのURL>) ===
echo ブラウザが自動的に開かない場合は、表示されるURLを手動でブラウザに貼り付けてください。
tailscale up --login-server=<VPNコントロールサーバーのURL> --accept-routes
echo.
echo === 接続状態 ===
tailscale status
echo.
echo === 疎通確認 ===
ping <ファイルサーバーのLAN内IPアドレス>
pause
切断用バッチファイルを作成
同様にzerotrust_disconnect.batを作成します。
@echo off
echo === Tailscaleを切断 ===
tailscale down
tailscale status
pause
作成後、それぞれのファイルを右クリック→「ショートカットの作成」でデスクトップにアイコンを置けば、ダブルクリックだけで接続・切断できるようになります。
6.2 Linux(GNOME)の場合・実機検証済み
Ubuntu(GNOME)で、ダブルクリックすると接続・切断が実行される.desktopアイコンを実際に作成し、動作確認済みの構成です。
接続スクリプト本体:~/tailscale_connect.sh
#!/bin/bash
# Headscale経由でTailscale(ゼロトラスト)に接続する
# SoftEtherと同時使用不可なため、先にSoftEtherを切断してからTailscaleへ接続する
echo "=== SoftEther VPN (my_vpn) が繋がっていれば切断します ==="
sudo /usr/local/vpnclient/vpncmd localhost /client /cmd AccountDisconnect my_vpn 2>&1 || true
sudo dhclient -r vpn_vpn0 2>&1 || true
sudo ip addr flush dev vpn_vpn0 2>&1 || true
echo
echo "=== Headscaleへ接続 (login-server=<VPNコントロールサーバーのURL>) ==="
echo "ブラウザが自動的に開かない場合は、下に表示されるURLを手動でブラウザに貼り付けてログインしてください。"
echo "(IdPのユーザー名・パスワード → スマートフォン認証アプリの6桁コード)"
echo
sudo tailscale up --login-server=<VPNコントロールサーバーのURL> --accept-routes
echo
echo "=== 接続状態 ==="
tailscale status
echo
echo "=== 疎通確認 ==="
ping -c 3 <ファイルサーバーのLAN内IPアドレス>
chmod +x ~/tailscale_connect.sh
切断スクリプト本体:~/tailscale_disconnect.sh
#!/bin/bash
# Tailscale(Headscale経由のゼロトラスト接続)を切断する
echo "=== Tailscaleを切断 ==="
sudo tailscale down
echo
echo "=== 接続状態 ==="
tailscale status
chmod +x ~/tailscale_disconnect.sh
「接続」アイコン本体:~/デスクトップ/ゼロトラスト接続.desktop
[Desktop Entry]
Type=Application
Name=ゼロトラスト接続
Comment=Tailscale/Headscale経由で自宅ラボへゼロトラスト接続します
Exec=bash -c "/home/USERNAME/tailscale_connect.sh; echo; echo '終了しました。何かキーを押すとウィンドウを閉じます...'; read -n1"
Icon=network-vpn
Terminal=true
Categories=Utility;
「切断」アイコン本体:~/デスクトップ/ゼロトラスト切断.desktop
[Desktop Entry]
Type=Application
Name=ゼロトラスト切断
Comment=Tailscale(ゼロトラスト接続)を切断します
Exec=bash -c "/home/USERNAME/tailscale_disconnect.sh; echo; echo '終了しました。何かキーを押すとウィンドウを閉じます...'; read -n1"
Icon=network-offline
Terminal=true
Categories=Utility;
USERNAMEは実際のログインユーザー名に置き換えてください。作成後は実行権限を付与します。
chmod +x ~/デスクトップ/"ゼロトラスト接続.desktop" ~/デスクトップ/"ゼロトラスト切断.desktop"
初回ダブルクリック時の確認ダイアログ
GNOMEでは初回、「信頼されていない実行可能ファイルです」という確認が出ることがあります。アイコンを右クリック→「起動を許可する」を選べば、以降はダブルクリックだけで実行できます。
接続スクリプトがSoftEtherを自動で切断している理由
このPCではSoftEther VPN(L2ブリッジ方式)とゼロトラスト(Tailscale/Headscale)の両方を切り替えながら検証しており、同時接続すると経路が競合して両方とも通信不能になることを確認しています。そのため接続スクリプトの先頭でSoftEther側を安全に切断してからTailscaleへ接続する構成にしています。片方しか使わない環境では、この部分は不要です。
7. MFAログイン時によくある詰まりどころ
TOTPはプッシュ通知ではない
スマートフォンに自動的に通知が届く方式ではありません。認証アプリを自分で開き、画面に表示されている6桁の数字を読み取って入力する必要があります。「スマホに何も表示されない」と感じたときは、通知を待つのではなく、まずアプリ自体を開いてください。
コードは30秒ごとに切り替わる
TOTPコードには有効時間があり、一定時間ごとに新しい数字に切り替わります。表示された数字を確認してから入力までに時間がかかると、切り替わってしまい「無効なコード」と判定されることがあります。コードが表示された直後に、間を置かず入力してください。
認証コード入力画面が出てこない場合
ブラウザに既にIdPへのログイン済みセッションが残っていると、パスワード入力もMFAもスキップされてそのままログインが完了する(SSO)ことがあります。テストの際は、一度IdPからログアウトしてブラウザタブを閉じてから接続をやり直すか、シークレット/InPrivateウィンドウを使うと切り分けやすくなります。
8. うまく繋がらないときのチェック
- VPNクライアントの起動時に
--accept-routesを付けているか - VPNには参加できるが自宅LANにpingが通らない → サーバー側で経路を広告するノード(サブネットルーター)が有効になっているか、管理側で経路が承認(enable)されているかを確認
- ファイル共有への接続だけ失敗する → 一度
net use ... /deleteで古い接続情報を消してからやり直す - MFAの入力画面が出ない → 上記5章の「既存セッション」の可能性をまず疑う
- (Linux)
smbclientのsmb: \>プロンプトに入ったまま、通常のコマンド(sudo等)を打ってしまう →exitで一度抜けてから、普通のターミナルで実行する - (Linux)
mountでSTATUS_LOGON_FAILUREになる → まずsmbclientで同じユーザー名・パスワードが通るか確認する。通るのにmountだけ失敗する場合は、パスワード入力が正しく渡っていない可能性が高いため、-oオプションに直接password=...を追加して切り分ける - (Linux)GUIの認証画面で「匿名」のまま接続しようとして失敗する → 「登録ユーザー」に切り替えてユーザー名・パスワードを入力する
9. コマンドプロンプトでの状態確認コマンド集
「今どの段階まで繋がっているか」を切り分けるための確認コマンドをまとめます。上から順に実行し、どこで想定通りの結果が返らなくなるかを見ることで、原因の切り分けができます。
| 確認したいこと | コマンド | 正常な場合の見え方 |
|---|---|---|
| VPNに参加できているか | tailscale status | 自分の端末とファイルサーバー側のノードが、両方ともIPアドレス付きで一覧表示される |
| VPN経由の仮想IPが割り当たっているか | ipconfig /all | 「Tailscale」等の名前のアダプタに、100.x.x.xで始まる仮想IPが表示される |
| VPNレベルで相手ノードに到達できるか | tailscale ping <相手のノード名> | 応答が返る(pingコマンドとは別に、VPN層だけを見て切り分けられる) |
| LANレベルでファイルサーバーに到達できるか | ping <ファイルサーバーのIPアドレス> | 応答が返る。ここが失敗する場合、サーバー側の経路広告(advertise-routes)が有効になっていない可能性が高い |
| 現在接続中の共有ドライブを確認 | net use | 接続済みの共有が一覧表示される(引数なしで実行) |
| 共有フォルダの中身を確認 | dir \\<ファイルサーバーのIPアドレス>\<共有名> | ファイル・フォルダの一覧が表示される |
| 古い接続情報をリセット | net use \\<ファイルサーバーのIPアドレス>\<共有名> /delete | 「コマンドは正常に終了しました」と表示される |
切り分けの読み方
tailscale statusで相手が見えない→VPN参加や認証の問題。見えるがpingが通らない→サーバー側のルーティング(経路広告・承認)の問題。pingは通るがnet useが失敗する→ファイル共有側のユーザー名・パスワード、または権限の問題、というように上から順に切り分けます。
10. 接続中はIPアドレスがどうなっているか
「VPNに繋いだら結局どんなIPアドレスになっているのか」は、仕組みを一度理解しておくと、うまく繋がらないときの切り分けが格段にやりやすくなります。この章では、実際に外部端末から接続した状態を例に、内部で何が起きているかを整理します。
端末は「物理IP」と「VPN仮想IP」の2つを同時に持つ
VPN接続中の端末は、実は2種類のIPアドレスを同時に持っている状態になります。
| 種類 | 役割 | 見え方の例 |
|---|---|---|
| 物理側のIP(従来通り) | 今いる場所のネットワーク(自宅WiFi・外出先のWiFi・スマートフォンのテザリング等)から普通に受け取るIP。VPNの接続・切断に関係なく変化しない | 接続先の回線次第(192.168.x.x、10.x.x.x等) |
| VPN仮想IP(新しく増える) | VPNコントロールサーバーがこの端末専用に払い出す、VPN参加者だけの世界の固定IP。どこから接続しても、この端末は常に同じ番号になる | 100.x.x.xで始まるアドレス |
なぜ見慣れない「100.x.x.x」という範囲なのか
一般的な家庭・オフィスのLANは192.168.x.xや10.x.x.x、172.16.x.x〜172.31.x.xのいずれかを使っていることがほとんどです。VPN仮想IPにあえてこれらと異なる100.64.0.0/10という特殊な範囲(CGNAT用に予約された帯域を転用したもの)を使うことで、接続先がどんなLAN構成であっても、VPN仮想IPと衝突しないように設計されています。
教訓:この設計がない方式では、実際にIP衝突事故が起きた
別方式(自宅LANへ直接ブリッジするタイプのVPN)を検証していた際、自宅WiFi(192.168.x.x帯)に接続したままそのVPNへ誤って接続したところ、VPN側が同じ192.168.x.x帯のIPを払い出してしまい、物理側とVPN側で経路・IPの奪い合いが起きて、VPNとは無関係なはずの通常のLAN通信まで不安定になる事故が実際に発生しました。仮想IP専用の帯域(100.x.x.x)を使う本構成では、この種の衝突は原理的に起こりません。
ファイルサーバーへは仮想IPではなく「本来のLAN内IP」でアクセスする
ここが最も分かりにくいポイントです。VPN接続後、自分の端末には100.x.x.xの仮想IPが割り当てられますが、5章の手順でファイルサーバーへアクセスする際に指定するのは、その仮想IPではなくファイルサーバー本来のLAN内IP(192.168.x.x等)です。これは、自宅LAN側の1台が「このサブネットは私経由で届けます」とVPNコントロールサーバーに申告するサブネットルーティングという仕組みによるものです。接続時に付けている--accept-routesオプションは、この申告された経路を自分の端末が受け取るためのものです。
つまり、外出先の端末は「自分は100.x.x.xの仮想IPを持つVPN参加者」でありながら、自宅LAN内の機器に対しては「本来のLAN内IPのまま」到達できる、という二重構造になっています。この経路広告がサーバー側で有効化(承認)されていないサブネットには、VPNに参加できていてもpingすら通りません(7章のチェックリスト参照)。
直接接続か、中継経由か
tailscale status相当のコマンドを実行すると、相手ノードとの接続方式も確認できます。
| 表示 | 意味 |
|---|---|
active; direct <IP>:<port> | NAT越え(穴あけ)に成功し、コントロールサーバーを介さず相手と直接通信できている状態。速度・遅延の面で最も効率が良い |
active; relay "..." | 直接経路が見つからず、中継サーバー(DERP等)経由で通信している状態。動作はするが直接接続より遅くなることがある |
offline | そのノードは現在VPNに参加していない(電源オフ・未接続等) |
11. セキュリティ設計のポイント
- インバウンドポートを一切開放しない:ファイル共有ポートはもちろん、VPN自体も着信のみで、未認証のパケットから内部構成が推測されることはない
- Identity-First:「ネットワークに参加できるか」ではなく「誰が、多要素認証を経てログインしたか」でアクセスを判断する
- 多要素認証(MFA)が本構成の核心:3章・4章の通り、パスワード単体の漏えいだけでは絶対に接続できない状態にしている。ファイアウォールやポート非公開はあくまで補助であり、実際に本人確認をしているのはMFAである
- 接続はコマンドで明示的に:エクスプローラー直打ちは認証キャッシュの崩れによる意図しない再入力を招きやすく、運用上はコマンドでの接続・切断を徹底する方が事故が少ない