はじめに
普段は主にクラウドサービスを使っているのですが、「ローカル環境のマシンをインターネットに公開する場合どうするんだろう」と思ったので勉強を兼ねてやってみました。
長くなったので
- インターネット公開編
- アプリ編
の2つに分けて書きました。これはインターネット公開編です。
アプリ編はこちらです。
アプリ紹介
ボタンを押すと曲(のキック)がランダムに1秒流れるアプリです。
全体構成
全体の構成は上記のような形です。
今記事では主に黄色枠部分について記載します。
環境
- サーバー : Raspberry Pi 5 8GB
- OS : Debian 12
- ルーター : TP-Link Archer AX55
- フロント&バックエンドライブラリ : Reflex
- DB : MariaDB
- CRUD API : Flask
- Webサーバーアプリ : Apache2
- クラウドストレージ : Amazon S3
- SSL証明書 : Let's Encrypt
- DNS : Lightsail DNS
設定
ルーター設定
TP-Linkルーターの管理画面から設定を行います。
アドレス予約
DHCPサーバーが有効になっており、サーバーが再起動するとローカルIPアドレスが変更される可能性があるので、MACアドレスを指定しローカルIPアドレスの予約設定をします。
ポートフォワーディング設定
3つのポートを使用したいので、以下のように設定しました。
これにより、グローバルIPの特定ポートにアクセスが来た時、先ほど設定したローカルIPアドレスの特定ポートに転送されます。
DNS設定
私は数年前からドメインをお名前.comで購入し所有しています。
それをLightsail DNSに登録して管理しています。
グローバルIPを以下コマンドで確認し、
$ curl -4 ifconfig.co
xxx.xxx.xxx.xxx
AレコードにドメインとグローバルIPを記載して登録します。
動的グローバルIPアドレスへの対処
グローバルIPアドレスですが、個人契約の場合基本的には動的になっており、ある程度期間が立つと変わるようです。
Lightsail DNSにはcliが提供されているので、cronでグローバルIPアドレスをフェッチし、DNSをUpdateするスクリプトを作成・実行します。
#!/bin/bash
dns_setting_json=`/usr/local/bin/aws lightsail get-domain --domain-name "${MY_DOMAIN}" --region us-east-1 | /usr/bin/jq '.domain.domainEntries[] | select(.name == "home.'"${MY_DOMAIN}"'" and .type == "A")'`
ip=`/usr/bin/curl -4 -s ifconfig.co`
updated_dns_setting_json=$(echo "$dns_setting_json" | /usr/bin/jq --arg new_ip "$ip" '.target = $new_ip')
/usr/local/bin/aws lightsail update-domain-entry --domain-name "${MY_DOMAIN}" --region us-east-1 --domain-entry "$updated_dns_setting_json"
*/10 * * * * /home/xxx/update_grobal_ip.sh >> /home/xxx/update_grobal_ip.log 2>&1
数分のダウンタイムはありますが、これでグローバルIPアドレスが変わっても大丈夫です。
これで指定のドメインからアクセスできるようになります。
# 諸々設定済みの為301が返ってきていますが、本来は200が返ってきます。
# 尚、完成してから記事を書いているので、本来はアプリサーバー側ポートもLISTENしていないと通信成功しません。
$ curl -I curl -I http://home.quark-hardcore.com/kick-preview/
curl: (6) Could not resolve host: curl
HTTP/1.1 301 Moved Permanently
Date: Sat, 19 Oct 2024 06:34:53 GMT
Server: Apache/2.4.62 (Debian)
Location: https://home.quark-hardcore.com/kick-preview/
Content-Type: text/html; charset=iso-8859-1
TP-Link DDNS設定について
TP-LinkにはDDNS機能があります。これを使えば動的なグローバルIPアドレスであっても、TP-Linkが提供するドメインでインターネットから接続できるのですが、ルーターにSSL証明書のインポート機能がなく、httpsの接続は対応していません
httpsでの通信とDDNSは全く違う話ですが、TP-LinkがDDNSで提供する*.tplinkdns.com
については
「ルーターにSSL証明書がインポートできない→TP-LinkからDDNS機能により提供されるドメインではhttps通信ができない」
という認識です。間違っていたら教えていただきたいです。
ということで、TP-LinkのDDNSは使っていないです。
SSL証明書
ルーターの設定により特定のドメインから自宅のサーバーへアクセスさせることが可能になりました。
自宅のサーバーにSSL証明書をインポートし、https通信ができるようにします。
Let's Encrypt証明書を作成
無料でSSL証明書を作成できるLet's Encryptを使います。
手順はこちらが分かりやすいです。
また、事前にnginx or apache2どちらかを先にインストールします。
Lightsailインスタンスに入っているBitnamiで使ったことがあるApache2を選択しました。
$ sudo apt update
$ sudo apt install apache2
$ sudo apt install python3 python3-venv libaugeas0
$ sudo python3 -m venv /opt/certbot/
$ sudo /opt/certbot/bin/pip install --upgrade pip
$ sudo /opt/certbot/bin/pip install certbot certbot-apache
$ sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
$ sudo certbot --apache
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel): home.quark-hardcore.com
Requesting a certificate for home.quark-hardcore.com
Successfully received certificate.
This certificate expires on 2024-12-30.
These files will be updated when the certificate renews.
Deploying certificate
Successfully deployed certificate for home.quark-hardcore.com to
Congratulations! You have successfully enabled HTTPS on https://home.quark-hardcore.com
NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Let's Encryptは有効期間が90日と短いので、定期的に更新するようcronで設定しておきます。
0 3 1 * * /usr/bin/certbot renew --quiet
これでhttpsでの通信が可能になりました
通信成功です!
$ curl -I https://home.quark-hardcore.com/kick-preview/
HTTP/1.1 200 OK
Date: Sat, 19 Oct 2024 06:35:22 GMT
Server: Apache/2.4.62 (Debian)
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
ETag: "14m1wwi91dj5y7"
Content-Type: text/html; charset=utf-8
Content-Length: 7745
Vary: Accept-Encoding