自宅サーバを外部公開したい。
ただ、グローバルIPが割り当てられていないため、なるべく金銭的負担が増えない方法を知りたい。
こんなお悩みを解決します。
本記事の内容を読み進める上で、VPSを用意する必要があります。
どの会社のVPSサーバを選択しようか悩んでいる場合、以下の記事を参考に検討していただければと思います。
【比較】おすすめのVPS 4選
続きを見る
VPSの契約・構築方法については、以下で解説しているので、参考にしてください。
【解説】VPS+VPN(WireGuard)による自宅サーバの公開方法を分かりやすく解説!(VPS契約編)
続きを見る
今回は、VPS上にVPN Serverを構築し、グローバルIPアドレスが割り当てられていない状況下で、自宅サーバを公開する方法について解説します。
必要な設定を順番に解説していきますので、興味がある方はぜひ最後までご覧ください。
現状整理と対応方針
まず、現状のネットワーク構成を共有します。
その上で、グローバルIPアドレスが割り当てられていない状況下で、自宅サーバを外部公開する際の対応方針を示します。
現状整理
私の環境では、以下のようなネットワーク構成になっています。
この状況下では、自宅のルータ(= ルータ2)でポート開放を行っても、マンションのルータ(= ルータ1)で通信が遮断されてしまうため、自宅サーバを外部に公開できません。
対応方針
対策として、外部のVPSにVPN Serverを構築し、自宅サーバとVPSをVPNで接続します。
上記により、以下のようにインターネットからのリクエストを自宅サーバに転送することで、外部にサーバを公開できます。
構築するネットワークの全体構成
最終的なネットワークの全体構成は、以下のようになります。
また、今回は、VPNの実現にWireGuard
というアプリケーションを利用します。
インターネットからのリクエストが来た時のフローを示すと以下のようになります。(レスポンス部分は省略しています)
- インターネットからのリスクエストをNginx(Reverse Proxy)でWireGuard Serverに中継する。
- WireGuard ServerのIP MasqueradeによりIPアドレスを変換する。
- WireGuard NetworkでVPN Clientにデータを送信する。
- WireGuard ClientのIP MasqueradeによりIPアドレスを変換する。
- Nginx(Web)で公開されているサイトを引き当て、レスポンスとして返却する。
事前準備
今回は、Dockerを用いて環境構築を行うため、事前準備としてDockerとDocker-Composeのインストール方法について解説します。
DockerとDocker-Composeは、VPSサーバと自宅サーバの両方にインストールしてください。
Dockerのインストール
下記のコマンドを順番に実行し、Dockerをインストールします。
インストールには管理者権限が必要となるため、下記のコマンドはsudo
グループに属しているユーザで実行してください。
# インストール用の shell scriptの取得
curl -fsSL https://get.docker.com -o get-docker.sh
# 動作確認(dry-run)
DRY_RUN=1 sh ./get-docker.sh
# インストール
sudo sh ./get-docker.sh
# Dockerを操作するユーザをdockerグループに追加
# (usernameは、例を参考に、環境に合わせて変更すること)
sudo usermod -aG docker yuruto
# フォーマット
# sudo usermod -aG docker [username]
Docker-Composeのインストール
Docker-Composeは、下記の2ステップでインストールできます。
- 該当するDocker-Composeのスクリプトファイルをダウンロードする。
- ダウンロードしたスクリプトファイルに実行権限を付与し、
/usr/local/bin
以下に格納する。
Docker-Composeのスクリプトファイルのダウンロード
Docker-Composeは、以下のサイトで最新版が公開されています。下記のサイトから該当するファイルをダウンロードし、サーバに格納してください。
探す際にOSとarchitectureの情報が必要になります。
それぞれ、下記のコマンドを実行することで調べることができます。
# OS
uname -a
出力例:Linux
# architecture
uname -m
出力例:x86_64
また、ダウンロード時は、curl
コマンドを利用すると楽に取得できます。
curl -s -L "https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-linux-x86_64" -o docker-compose
Docker-Composeコマンドの有効化
ダウンロードしたDocker-Composeのスクリプトファイルに実行権限を付与し、/usr/local/bin
以下に格納してください。
格納後、コマンドを実行し、期待通りのバージョンが出力されれば成功です。
# 実行権限の付与
chmod +x docker-compose
# /usr/local/binへ格納
sudo mv docker-compose /usr/local/bin
# バージョンの確認
docker-compose -v
Docker Compose version v2.12.2
環境構築の詳細
今回は、以下の条件で環境構築を行います。
カテゴリ | 項目 | 値 |
---|---|---|
Nginx (Reverse Proxy) | VPSでHTTPのリクエストを待ち受ける際のポート番号 | 443 |
WireGuard Server/Client | VPN ServerのIPアドレスVPN ServerのIPアドレス | 10.1.2.1 |
VPN ClientのIPアドレス | 10.1.2.2 | |
VPN Server/Clientが属するサブネット | 10.1.2.0/24 | |
VPN接続時のポート番号 | 51820 | |
VPN接続中に利用するDNS | 8.8.8.8,10.1.2.1 | |
VPN Server経由で通信するIPアドレス | 10.1.2.0/24 | |
Nginx (Web) | Docker ContainerのIPアドレス | 10.0.16.3 |
待ち受けポート | 8080 |
VPN Serverの設定・構築
VPN Serverを構築する上では、以下の3点に対応する必要があります。順に説明していきます。
- WireGuardを起動する際の
UID
、GID
を設定する。 - VPN Server構築時の環境変数(WireGuard、Nginx)を設定する。
- Docker Imageを作成する。(Nginxのみ)
- VPN Serverのiptablesを設定する。
- HTTPとWireGuardで通信する際に利用するポートを開放する。
また、該当するコードは、GitHubの下記に保存してあります。git clone
して利用してください。
https://github.com/yuruto-free/vpnaccess-wireguard-nginx/tree/v0.2.0
UIDとGIDの設定
VPS上で以下のコマンドを実行し、UID
とGID
を確認します。
ここで、表示されるのはコマンド実行時のユーザの情報となります。
id
uid=1000(yuruto) gid=1000(yuruto) groups=1000(yuruto),27(sudo),999(docker)
次に、docker-compose.yml
をエディタで開き、下記の部分を環境に合わせて書き換えます。
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000 # 【変更箇所1】uidの数値を設定
- PGID=1000 # 【変更箇所2】gidの数値を設定
- TZ=Asia/Tokyo
VPN Serverの環境変数設定
ここでは、以下の2パターンに分けて環境変数を設定していきます。
- WireGuard固有の環境変数
- Nginx固有の環境変数
WireGuard固有の環境変数
ここで設定する環境変数は、以下の9点となります。
環境変数名 | 説明 | 補足 |
---|---|---|
SERVERURL | VPN Server接続時のIPアドレス/FQDN | WireGuard imageで使用する |
SERVERPORT | VPN接続時のポート番号 | WireGuard imageで使用する |
PEERS | VPN Client一覧 | WireGuard imageで使用する |
PEERDNS | VPN接続中に利用するDNS | WireGuard imageで使用する |
INTERNAL_SUBNET | VPN Server/Clientが属するサブネット | WireGuard imageで使用する |
MTU | MTUの値 | - |
KEEP_ALIVE | keep-aliveの値 | - |
ALLOWEDIPS | VPN Server経由で通信するIPアドレス | WireGuard imageで使用する |
SERVER_ALLOWEDIPS_PEER_PublicServer | WireGuardのサブネット以外において、VPN Clientが属するサブネット | WireGuard imageで使用する |
上記に対し、下記のように設定し、envs/wireguard/.env
に保存します。
ここで、SERVERURL
やSERVERPORT
などは、ご自身の環境に合わせて設定してください。
SERVERURL=example.vpn.com
SERVERPORT=51820
PEERS=PublicServer
PEERDNS=8.8.8.8,10.1.2.1
INTERNAL_SUBNET=10.1.2.0/24
MTU=1380
KEEP_ALIVE=10
ALLOWEDIPS=10.1.2.0/24
SERVER_ALLOWEDIPS_PEER_PublicServer=10.0.16.0/24
Nginx固有の環境変数
ここで設定する環境変数は、以下の10点となります。
環境変数名 | 説明 | 補足 |
---|---|---|
MYDNSJP_MASTER_ID | MyDNSのmaster id | オプション。Let's EncryptでSSL証明書を取得する際に利用 |
MYDNSJP_PASSWORD | MyDNSのpassword | オプション。Let's EncryptでSSL証明書を取得する際に利用 |
BASE_DOMAIN_NAME | FQDN | - |
VHOST_NAME | Virtual hostname | Webサイトへのアクセス時に利用するhostname |
SSL_CERT_PATH | crtファイルパス | Nginxの設定ファイルで利用 |
SSL_CERTKEY_PATH | keyファイルパス | Nginxの設定ファイルで利用 |
SSL_STAPLING_VERIFY | OCSP(証明書の失効状態を取得するための通信プロトコル)の検証有無(on/offによる設定) | Nginxの設定ファイルで利用 |
SSL_TRUSTED_CERTIFICATE_PATH | trusted CA certificatesで利用する際のファイルパス(ssl_stapling 有効時に参照される) | Nginxの設定ファイルで利用 |
PUBLIC_SERVER_IP_ADDR | VPN Clientで公開するサーバのIPアドレス | Nginxの設定ファイルで利用 |
PUBLIC_SERVER_PORT | VPN Clientで公開するサーバで待ち受ける際のポート番号 | Nginxの設定ファイルで利用 |
上記に対し、下記のように設定し、envs/nginx/.env
に保存します。
ここで、オプションとしているMyDNSのIDやパスワード等は、ご自身の環境に合わせて設定してください。
MYDNSJP_MASTER_ID=masterid
MYDNSJP_PASSWORD=password
BASE_DOMAIN_NAME=example.com
VHOST_NAME=www.example.com
SSL_CERT_PATH=/etc/letsencrypt/live/example.com/fullchain.pem
SSL_CERTKEY_PATH=/etc/letsencrypt/live/example.com/privkey.pem
SSL_STAPLING_VERIFY=on
SSL_TRUSTED_CERTIFICATE_PATH=/etc/letsencrypt/live/example.com/chain.pem
PUBLIC_SERVER_IP_ADDR=10.0.16.3
PUBLIC_SERVER_PORT=8080
Let's Encryptの設定・NginxのDocker Image作成
ここでは、Let's Encrypt向けの設定とNginxのDocker Image作成について説明します。
Let's Encryptの設定
nginx
のディレクトリに移動し、sample.cli.ini
をコピーします。
# nginxのディレクトリへ移動
cd nginx
# sample.cli.iniのコピー
cp -f sample.cli.ini cli.ini
そして、cli.ini
をエディタで開き、email
の部分を修正します。
これは、Let's Encryptからメールを受信する際に利用します。
# Set E-mail
email = foo@example.com # ←自身の環境に合わせて修正
また、Let's EncryptのSSL証明書更新時に使用する設定ファイルもあわせて修正します。
MyDNSを利用する方
環境変数MYDNSJP_MASTER_ID
とMYDNSJP_PASSWORD
を設定してください。
MyDNS以外を利用する方
チャレンジ方式(現時点では、DNS-01を指定)に合わせて、各自、スクリプトファイルを用意してください。
また、Dockerfileとcli.ini
のそれぞれに対し、該当行を環境に合わせて修正してください。
# Dockerfile
# add dns-01 script
COPY ./direct_edit /data/direct_edit # ←環境に合わせて使用するスクリプトに変更
# cli.ini
# 以下を環境に合わせて修正
authenticator = manual
preferred-challenges = dns
manual-auth-hook = /data/direct_edit/txtregist.php
manual-cleanup-hook = /data/direct_edit/txtdelete.php
NginxのDocker Image作成
wrapper.sh
があるディレクトリに移動し、以下のコマンドを実行します。
chmod +x wrapper.sh
./wrapper.sh build
VPN Serverのiptablesの設定
wireguard/iptables_script
に移動し、conf.up.d
とconf.down.d
にそれぞれ以下のようなconfファイルを作成し、保存してください。
ここで、10.0.16.0/24
は、環境変数SERVER_ALLOWEDIPS_PEER_PublicServer
やPUBLIC_SERVER_IP_ADDR
と同じサブネットに属するように設定してください。
基本的には、環境変数SERVER_ALLOWEDIPS_PEER_PublicServer
と同じ内容を設定しておけば問題ないです。
conf.up.d
conf.up.d/01-forwarding-to-public-server.conf
に以下の内容を記載し、保存します。
iptables -t nat -A POSTROUTING -d 10.0.16.0/24 -j MASQUERADE
conf.down.d
conf.down.d/01-forwarding-to-public-server.conf
に以下の内容を記載し、保存します。
iptables -t nat -D POSTROUTING -d 10.0.16.0/24 -j MASQUERADE
VPN Serverの起動
VPS上で以下のコマンドを実行し、VPN ServerとNginx (Reverse Proxy) を起動します。
./wrapper.sh start
正常に起動している場合、wireguard
直下に以下のディレクトリ/ファイルが生成されます。
ls wireguard
coredns peer_PublicServer server templates wg0.conf
また、wireguard/wg0.conf
やwireguard/peer_PublicServer/peer_PublicServer.conf
は以下のようになっていると思います。
wireguard/wg0.conf
[Interface]
Address = 10.1.2.1
ListenPort = 51820
MTU = 1380
PrivateKey =
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE; iptables -A FORWARD -i %i -o %i -j ACCEPT
PostUp = /config/iptables_script/postup.sh
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE; iptables -D FORWARD -i %i -o %i -j ACCEPT
PostDown = /config/iptables_script/postdown.sh
[Peer]
# peer_PublicServer
PublicKey =
PresharedKey =
AllowedIPs = 10.1.2.2/32,10.0.16.0/24
ここで、PostUp
とPostDown
はそれぞれ1行で表現してください。
# 以下は1行で表現すること
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE; iptables -A FORWARD -i %i -o %i -j ACCEPT
# 以下は1行で表現すること
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE; iptables -D FORWARD -i %i -o %i -j ACCEPT
wireguard/peer_PublicServer/peer_PublicServer.conf
[Interface]
Address = 10.1.2.2
PrivateKey =
ListenPort = 51820
MTU = 1380
DNS = 8.8.8.8,10.1.2.1
[Peer]
PublicKey =
PresharedKey =
Endpoint = example.vpn.com:51820
AllowedIPs = 10.1.2.0/24
PersistentKeepAlive = 10
このうち、wireguard/peer_PublicServer/peer_PublicServer.conf
は、VPN Clientで利用します。
ポート開放
現時点では、外部からの通信をファイアウォールで遮断しているため、以下のコマンドを実行し、ポート開放をします。
# HTTP通信向けの設定
sudo ufw allow 443/tcp
# WireGuard向けの設定
sudo ufw allow 51280/udp
VPN Clientの設定・構築
VPN Clientを構築する上では、以下の5点に対応する必要があります。
このうちUID
、GID
の設定方法はすでに解説済みのため、2つ目以降について解説します。
- WireGuardを起動する際の
UID
、GID
を設定する。 - VPN Server側で作成されたconfigファイルを格納・修正する。
- VPN Client構築時の環境変数(Nginx)を設定する。
- docker-compose.ymlを作成する。
- Docker Imageを作成する。(Nginxのみ)
また、該当するコードは、GitHubの下記に保存してあります。
https://github.com/yuruto-free/wireguard-client/tree/v0.1.0
configファイルの格納・修正
wireguard-client
直下にconfig
というディレクトリがあります。
このconfig直下にpeer_PublicServer.conf
の内容をwg0.conf
というファイル名で保存します。
その後、wg.conf
のInterface
の末尾に、以下の2行を追加します。
これは、VPN ClientでIP MasqueradeによりIPアドレスを変換するために必要となります。
PostUp = iptables -t nat -A POSTROUTING -d 10.0.16.0/24 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -d 10.0.16.0/24 -j MASQUERADE
上記の修正を行うと、config/wg0.conf
の内容は、以下のようになります。
[Interface]
Address = 10.1.2.2
PrivateKey =
ListenPort = 51820
MTU = 1380
DNS = 8.8.8.8,10.1.2.1
PostUp = iptables -t nat -A POSTROUTING -d 10.0.16.0/24 -j MASQUERADE # 追加部分
PostDown = iptables -t nat -D POSTROUTING -d 10.0.16.0/24 -j MASQUERADE # 追加部分
[Peer]
PublicKey =
PresharedKey =
Endpoint = example.vpn.com:51820
AllowedIPs = 10.1.2.0/24
PersistentKeepAlive = 10
VPN Clientの環境変数設定
ここで設定する環境変数は以下の2点となります。
環境変数名 | 説明 |
---|---|
SERVER_HOSTNAME | VPN Clientで公開するサーバのIPアドレス |
SERVER_PORT | VPN Clientで公開するサーバで待ち受ける際のポート番号 |
ここでは、下記のように設定し、envs/nginx/.env
に保存します。
SERVER_HOSTNAME=_
SERVER_PORT=8080
docker-compose.ymlの作成
今回は、Docker環境下でWireGuard ClientとNginxを動作させるため、bridge-mode.yml
ファイルをdocker-compose.yml
として利用します。
このため、以下のコマンドを適用します。
cp -f bridge-mode.yml docker-compose.yml
Docker Imageの作成
以下のコマンドを実行し、Docker Imageを作成します。
docker-compose build --no-cache
VPN Clientの起動
自宅サーバ上で以下のコマンドを実行し、VPN ClientとNginx (Web) を起動します。
docker-compose up -d
起動後、docker-compose logs wireguard
のコマンドを実行し、「Client mode」で起動していることを確認してください。
wireguard | -------------------------------------
wireguard | GID/UID
wireguard | -------------------------------------
wireguard |
wireguard | User uid: 1000
wireguard | User gid: 1000
wireguard | -------------------------------------
wireguard |
wireguard | Uname info: Linux 7430de24220f 5.15.61-v7+ #1579 SMP Fri Aug 26 11:10:59 BST 2022 armv7l armv7l armv7l GNU/Linux
wireguard | **** It seems the wireguard module is already active. Skipping kernel header install and module compilation. ****
wireguard | **** Client mode selected. ****
wireguard | [custom-init] No custom files found, skipping...
wireguard | **** Disabling CoreDNS ****
wireguard | Warning: `/config/wg0.conf' is world accessible
wireguard | [#] ip link add wg0 type wireguard
wireguard | [#] wg setconf wg0 /dev/fd/63
wireguard | [#] ip -4 address add 10.1.2.2 dev wg0
wireguard | [#] ip link set mtu 1380 up dev wg0
wireguard | [#] resolvconf -a wg0 -m 0 -x
wireguard | [#] ip -4 route add 10.1.2.0/24 dev wg0
wireguard | [#] iptables -t nat -A POSTROUTING -d 10.0.16.0/24 -j MASQUERADE
wireguard | [ls.io-init] done.
参考
「`/config/wg0.conf` is world accessible
」という警告が出ていますが、この警告は無視しても問題ないです。
これはファイルのパーミッションに関する警告となるため、気になる方はホストマシン上で下記を実行し、ファイルのパーミッションを修正してください。
chmod 600 config/wg0.conf
また、Raspberry PiでVPN Clientを構築している場合、「libseccomp」のエラーが発生する可能性があります。
その場合は、README.md
のFAQを参考に、ライブラリをインストールしてください。
https://github.com/yuruto-free/wireguard-client/blob/v0.1.0/README.md
動作確認
WebブラウザからVPN Serverで設定したVirtual Hostのリンク名でアクセスし、Nginxのトップページが表示されることを確認してください。
今回の例の場合、以下のようになります。こちらのリンクにアクセスしても、Nginxのトップページは表示されないので、気を付けてください。
https://www.example.com
まとめ
今回の実装は、下記のリンク先を参考にしてください。
VPN Server側の実装
https://github.com/yuruto-free/vpnaccess-wireguard-nginx/tree/v0.2.0
VPN Client側の実装
https://github.com/yuruto-free/wireguard-client/tree/v0.1.0
注意点
上記を動作させる際は、環境変数の設定が必要になります。詳細は、同封されているREADME.md
または以下を参照してください。
制約事項
ドメインを利用して、自宅サーバへアクセスできるようにするため、Dynamic DNSを利用しています。
このため、SSL証明書取得時に利用しているDynamic DNS(= MyDNS)の設定が含まれています。※詳細はコチラの3行目~11行目を参照してください。
このため、利用時はご自身の環境に合わせて設定の変更をお願いいたします。
例えば、ConoHa VPSで割り当てられているドメイン名を利用する場合、ConoHa API等を参考にドメイン情報を取得する必要があります。