🖥️

iOSのアプリのユニバーサルリンク設置のためにホームサーバーを構築してみた

2025/02/28に公開

背景

開発の際にユニバーサルリンク機能を実装する機会がありました。
アプリでユニバーサルリンクを設定するには、SSLが適用されたウェブサーバが必要です。今回の案件ではすでに用意されているサーバがあったため、実装には問題ありませんでした。
しかし、個人的にウェブサーバとアプリの連携に興味があったため、自分で環境を再現してみようと思い、ホームサーバを構築しました。

ユニバーサルリンクとは
ユニバーサルリンクとは、特定のURLを開くとアプリがインストールされていればアプリ内へ遷移し、未インストールならウェブサイトへ誘導する仕組みです。

必要なもの

  • ホームサーバ構築用のPC(1台)
  • サーバにアクセスするためのPC(クライアント端末)
  • ネットワーク機器(ルーター、LANケーブルなど)
  • OSインストール用のUSBメモリ

OSインストール

サーバ用のOSをインストールします。
本記事では Ubuntu を使用してサーバを構築します。
※ PCの機種やマザーボードによってBIOSのアクセス方法が異なるため、詳細な手順は記載しません。

  1. ubuntuのISOファイル をダウンロードします。
  2. Rufus、UNetbootin、Etcher などのツールを使用して、ブート可能なUSBメモリを作成します。
  3. サーバのBIOSでUSBから起動するように設定します。
  4. サーバを再起動します。
  5. Ubuntuのインストール画面が表示されたら、インストールガイドを参考にインストールを進めます。
  6. インストールが完了したら、クライアント端末からSSHでサーバにアクセスできるか確認します。
ssh ユーザー@ルーターから割り当てられたローカルIP
# 例
ssh root@192.168.0.20

ssh接続

OSのインストールが完了したら、クライアント端末からサーバにSSH接続できるように設定します。
今後、ポート開放を行う予定があるため、セキュリティを考慮して秘密鍵認証でのログインを設定しておきます。
まず、SSH鍵(秘密鍵と公開鍵)を作成しましょう。

1. SSH鍵の作成

以下のコマンドを実行し、SSH鍵を生成します。

ssh-keygen -t ed25519 -C "your_email@example.com"

このコマンドを実行すると、.ssh フォルダに秘密鍵 (id_rsa) と公開鍵 (id_rsa.pub) が作成されます。
※ 環境によっては、作成した鍵のアクセス権限 (chmod 600 ~/.ssh/id_rsa) を適切に設定する必要があります。

SSH鍵の作成とセキュリティについて

なぜこのコマンドを使うのか?

SSH鍵を生成する際、よく使われるコマンドは以下の通りです。

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

しかし、最近では Ed25519 を推奨する流れがあります。

ssh-keygen -t ed25519 -C "your_email@example.com"

※RSAとEd25519の違い

アルゴリズム セキュリティ 鍵サイズ パフォーマンス
RSA 4096 高い 4096bit 遅い
Ed25519 非常に高い 256bit 高速
  • Ed25519の方が短い鍵で高セキュリティを実現
  • 処理速度が速く、パフォーマンスに優れる

特別な理由がなければEd25519を使うことを推奨します。

その他コマンドのオプション説明

  • -t :鍵の種類(rsa や ed25519 など)
  • -b :鍵のビット長(RSAでは2048bit以上を推奨)
  • -C :コメントを追加(通常はメールアドレスを指定し、管理を容易にするため)
  • -f :鍵の保存場所を指定(デフォルトは ~/.ssh/id_rsa など)

https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

2. 公開鍵をサーバに登録

作成した公開鍵をサーバに登録し、秘密鍵を使ってログインできるようにします。
以下のコマンドで、公開鍵をサーバにコピーします。

ssh-copy-id -i ~/.ssh/id_rsa.pub ユーザー名@サーバのローカルIP
# 例:
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.5

このコマンドを実行すると、サーバの ~/.ssh/authorized_keys に公開鍵が追加されます。
これで、秘密鍵を使用したログインが可能になります

3. パスワード認証を無効化(外部アクセス用)

セキュリティ強化のため、外部IPからのログインを秘密鍵認証のみに制限します。
まず、現在の設定でサーバにSSH接続した後、SSHの設定ファイルを開きます。

sudo vi /etc/ssh/sshd_config

次に、以下の設定を追加または変更します。

PasswordAuthentication no
PubkeyAuthentication yes

この設定により、パスワード認証が無効化され、公開鍵認証のみが許可されます。

4. 内部ネットワーク(ローカルIP)でのパスワード認証を許可(Optional)

もし、ローカルネットワーク内(例: 192.168..)ではパスワード認証を許可したい場合は、sshd_config に以下の設定を追加します。

Match Address 192.168.0.0/16
    PasswordAuthentication yes

この設定を追加すると、LAN内のデバイスからはパスワード認証が可能になります。

他のローカルネットワークIP帯を追加することも可能(CIDR表記で指定)
# 例: 10.0.0.0/8 からのアクセスもパスワード認証を許可する場合
 Match Address 192.168.0.0/16,10.0.0.0/8
     PasswordAuthentication yes

5. SSH設定の反映

設定を変更したら、SSHサービスを再起動して反映させます。

sudo systemctl restart ssh

これでSSHの鍵認証設定は完了です。

ポート設定

内部ネットワークから秘密鍵を使ってサーバにアクセスできるようになったら、次は外部からのアクセスを設定します。

1. 内部ファイアウォールの設定

外部からSSHアクセスするために、まずは内部のファイアウォールを開放します。
事前に設定した秘密鍵を使用し、クライアント端末からサーバにアクセスできることを確認します。

ssh -i 秘密鍵パス ユーザー名@サーバのローカルIP
# 例:
ssh -i ~/.ssh/id_rsa root@192.168.0.5

次に、以下のコマンドを実行してSSH用のポート (22) を開放します。
SSHの設定を特に変更していなければ、デフォルトのポートは 22 です。

sudo ufw allow 22/tcp 

設定が正しく反映されているかを確認するには、次のコマンドを実行します。

sudo ufw status verbose

以下のように表示されれば、設定は完了です。

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere

2. 外部アクセスの設定(ポートフォワーディング)

内部のファイアウォール設定が完了したら、次は外部からのアクセスを可能にします。
外部アクセスには ngrok や VPN など様々な方法がありますが、本記事では ポートフォワーディング を使用します。

ポートフォワーディングとは?
ポートフォワーディングとは、外部からのアクセスを特定の内部ネットワークのデバイスに転送する仕組みです。
以下のようなネットワーク構成になります。

3. ルーターのポートフォワーディング設定

ポートフォワーディングの設定はルーターの管理画面から行えます。
ルーターのメーカーによって操作方法が異なるため、詳細はルーターのマニュアルまたは公式サイトを参照してください。

本記事では、内部ポート 22 を外部ポート 2222 にマッピング するように設定します。

設定項目 設定値
プロトコル TCP
外部ポート 2222
内部IPアドレス 192.168.0.5
内部ポート 22

ポートフォワーディングの設定が完了したら、外部IPからのアクセスを試してみます。

4. 外部IPからのSSH接続テスト

まず、サーバの グローバルIP を確認します。

curl ifconfig.me

このコマンドを実行すると、サーバのグローバルIPが表示されます。
その値をコピーしておきます。

次に、外部ネットワーク(モバイルテザリングなど)を利用して、外部IPにアクセス できる環境を準備します。
※ ループバック機能のあるルーターを使用している場合は、テザリングは不要です。

以下のコマンドで、ポートフォワーディングされたサーバにSSH接続を試します

ssh -i 秘密鍵パス -p 外部ポート ユーザー@グローバルIP
# 例:
ssh -i ~/.ssh/id_rsa -p 2222 root@122.31.96.142

以下のように表示され、正常にログインできれば成功です

DDNS設定

一般的に、インターネット回線は動的IP(Dynamic IP) が割り当てられており、定期的にグローバルIPが変更されます。そのたびに手動でIPを確認するのは面倒ですし、固定IPを取得するには追加料金がかかるため、個人で契約するケースは少ないでしょう。そこで、DDNS(Dynamic DNS) を活用します。

DDNS(ダイナミックDNS)とは?
DDNSは、動的に変化するグローバルIPアドレスを自動で更新し、常に同じドメイン名でアクセスできるようにするサービス です。

一部のルーターにはDDNS機能が搭載されており、ルーター単体で対応できる場合もあります。
しかし、ルーターのDDNS機能を使用するとSSL証明書の発行ができない場合があるため、今回は外部のDDNSサービスを利用します。

代表的なDDNSプロバイダーとして、以下のようなものがあります。

No-IP
DuckDNS
Dynu
今回は、設定が簡単な「DuckDNS」 を利用して設定を進めます。

1. DuckDNSに登録

DuckDNS公式サイトにアクセスします。
GoogleやGitHubアカウントでログインが可能ですので、任意の方法でログインします。

ログイン後、ドメイン登録を行います。

ドメイン登録手順

  1. DuckDNSの管理画面で、任意のサブドメイン(例: test)を登録します。
  2. 現在のグローバルIPが正しく表示されているか確認 します。
    • もし異なる場合は、サーバのグローバルIPを手動で入力し、更新します。

2. 登録したドメインでSSH接続を確認

登録したドメインを使用して、SSH接続できるか確認します。
グローバルIPでの接続と同様に、ホスト部分を登録したドメインに置き換えてアクセスします。

ssh -i 秘密鍵パス -p 外部ポート ユーザー@DuckDNSで登録したドメイン
# 例:
ssh -i ~/.ssh/id_rsa -p 2222 root@test.duckdns.org

正常に接続できれば、DDNSの設定は完了です。

3. 動的IP更新の自動化(Crontab設定)

DuckDNSは、IPの自動更新機能がない ため、手動で更新リクエストを送る必要があります。
そのため、定期的にDuckDNSへIPアドレスの更新リクエストを送信 するようにサーバを設定します。

Crontabを使った自動更新の設定

  1. Crontabを開きます。
crontab -e

初めて実行すると、エディターの選択画面が表示されるので、好きなエディターを選択 してください。
2. 以下のコマンドを追加し、5分ごとにIPアドレスを更新 するように設定します。

*/5 * * * * curl -s "https://www.duckdns.org/update?domains=ducnDNSサブドメイン&token=duckDNSトークン&ip=" >/dev/null 2>&1
# 例
*/5 * * * * curl -s "https://www.duckdns.org/update?domains=test&token=f0fae79d-9b8d-401f-9233-69999e12e69a&ip=" >/dev/null 2>&1

この設定により、5分ごとにDuckDNSへIPアドレスの更新リクエストが送信 されます。

DuckDNSトークン確認

まとめ

今回の設定で、動的IP環境でも固定ドメインを使用してSSH接続が可能 になりました。
設定した内容を簡単に振り返ってみましょう。

  1. DDNSの概要を理解

    • 動的IP環境ではグローバルIPが定期的に変更されるため、手動でIPを確認するのは面倒。
    • DDNSを利用することで、常に同じドメイン名でアクセスできるようになる。
  2. DuckDNSを利用してドメインを登録

    • DuckDNSにGoogleやGitHubアカウントでログインし、サブドメインを取得。
    • 現在のグローバルIPを登録し、ドメイン名でアクセスできるように設定。
  3. 登録したドメインでSSH接続を確認

    • DuckDNSで設定したドメインを使用し、ポートフォワーディングを通じてSSH接続をテスト。
  4. IPアドレスの自動更新設定(Crontab)

    • DuckDNSのIP更新は自動ではないため、Crontabを利用して5分ごとに更新リクエストを送信。
    • DuckDNSのトークンを取得し、正しく設定することで自動更新を実現。

この設定により、動的IP環境でも手間なくサーバにアクセスできるようになりました。
次回は、Docker環境で簡単なウェブアプリをデプロイとSSL証明書を設定して、よりセキュアな環境を構築する方法について解説してみようと思います。

ファースト・スクラッチTech Blog

Discussion