2026/07/08(水)nginxにクライアント証明書認証の設定をした

管理領域など、自分以外などにアクセスを許可したくない場所にパスフレーズ付きクライアント証明書で制限を掛け、自分以外アクセスできないようにしたので、そのログ。

確認環境

サーバーと証明書作成環境

Env Ver
OS Ubuntu 24.04.4 LTS
nginx 1.24.0
OpenSSL 3.0.13 30

クライアント証明書を設定してアクセスした環境1

Env Ver
OS Windows 11 Pro 25H2 (OSビルド 26200.8783)
クライアント Microsoft Edge バージョン 150.0.4078.48

クライアント証明書を設定してアクセスした環境2

Env Ver
OS Android 16
クライアント Microsoft Edge バージョン 149.0.4022.105

手順

CAやクライアント証明書の作成

ここから行うコマンドはその全てでパスワード入力プロンプトが出るため、個別に流す必要がある。

  1. 判別しやすくするためにファイル名の頭に付与する接頭辞を決める
    file_prefix=lyco_
    
  2. CA(認証局)を作成する

    1. CAの秘密鍵の作成
      # -pass=pass:<PASSWORD>でもパスワードを掛けられるが平文になるらしいので-aes-128-cbcでパスワードを掛ける
      openssl genpkey \
        -algorithm EC \
        -pkeyopt ec_paramgen_curve:P-256 \
        -out ${file_prefix}ca.key \
        -aes-128-cbc
      
    2. CAの証明書署名要求の作成

      # 適当に好きな値を設定(以下は私の設定例)
      # 最低限CommonNameさえあればあとは何でもいいらしい?
      
      CountryCode=JA # 国コードを指定するっぽいが多分何を指定してもいい
      Province=Hyogo # たぶん県を指定するっぽいが多分何を指定してもいい
      Location=Kobe # たぶん市区町村を指定するっぽいが多分何を指定してもいい
      Organization="Lycolia Rizzim" # 組織を設定を指定するっぽいが多分何を指定してもいい
      CommonName=lycolia.info # FQDNを指定するっぽいが多分何を指定してもいい
      
      # CA証明書署名要求作成
      
      openssl req \
        -new \
        -key ${file_prefix}ca.key \
        -out ${file_prefix}ca.csr \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CA"
      
    3. CAの証明書の作成
      openssl req \
        -new \
        -x509 \
        -key ${file_prefix}ca.key \
        -out ${file_prefix}ca.crt \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CA"
      
  3. クライアント証明書作成

    1. クライアントの秘密鍵の作成

      # -pass=pass:<PASSWORD>でもパスワードを掛けられるが平文になるらしいので-aes-128-cbcでパスワードを掛ける
      openssl genpkey \
        -algorithm EC \
        -pkeyopt ec_paramgen_curve:P-256 \
        -out ${file_prefix}client.key \
        -aes-128-cbc
      
    2. クライアントの証明書署名要求の作成

      openssl req \
        -new \
        -key ${file_prefix}client.key \
        -out ${file_prefix}client.csr \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CLIENT"
      
    3. クライアント証明書の作成

      openssl x509 \
        -req \
        -in ${file_prefix}client.csr \
        -CA ${file_prefix}ca.crt \
        -CAkey ${file_prefix}ca.key \
        -CAcreateserial \
        -out ${file_prefix}client.crt \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CLIENT"
      
  4. クライアントに食べさせる用の証明書を作る(PKCS12形式)
    openssl pkcs12 \
      -export \
      -out ${file_prefix}client.pfx \
      -inkey ${file_prefix}client.key \
      -in ${file_prefix}client.crt
    
  5. CA証明書の配置

    sudo mkdir /etc/nginx/ca
    sudo cp ${file_prefix}ca.crt /etc/nginx/ca
    
  6. nginxのsnippetsの作成

    cat <<EOF | sudo tee /etc/nginx/snippets/ssl_verify_client.conf
    ssl_verify_client on;
    ssl_client_certificate "ca/${file_prefix}ca.crt";
    EOF
    
  7. 各vhostの設定に埋め込む。https環境でないと設定しても意味ないので注意
    server {
      ...
      include snippets/ssl_verify_client.conf;
      ...
    }
    
  8. 設定を再読み込み
    sudo systemctl reload nginx
    
  9. 疎通確認
    curl -v \
      --cert ${file_prefix}client.crt \
      --key ${file_prefix}client.key \
      --cacert ${file_prefix}ca.crt \
      https://hoge.example.com/
    

WindowsのEdgeからアクセスする

  1. 作成したPKCS12形式の証明書をWindowsにもってきてダブルクリックする。保存場所→現在のユーザーで次へ
  2. 何もせず次へ
  3. パスワードを入力して次へ
  4. 何もせず次へ
  5. スマートカードを挿入をキャンセルする
  6. プライベートモードでEdgeを開き設定したvhostにアクセスして証明書を選択しなかったときに400エラーが出ることを確認
  7. プライベートモードを閉じて再度アクセスしたときに証明書を選択したときに正常にアクセスできることを確認

AndroidのEdgeから確認する

  1. 作成したPKCS12形式の証明書をAndroidにもってきて開く
  2. 適当にインポートする
  3. プライベートモードでEdgeを開き設定したvhostにアクセスして証明書を選択しなかったときに400エラーが出ることを確認
  4. プライベートモードを閉じて再度アクセスしたときに証明書を選択したときに正常にアクセスできることを確認

メモ

genrsaよりgenpkeyを使った方がいい

Generation of RSA Private Key. Superceded by genpkey.

https://linux.die.net/man/1/openssl

トラブルシューティング

証明書の選択画面が出ない

httpsになってないと出ない。

http://localhostとかhttp://dev.localみたいなアクセスをしていると出てこない。

HTTPSでアクセスしているのに400エラーが出る

CAの証明書とクライアントの証明書でCNの値が同じだと自己署名証明書扱いされて上手くいかないのでCNの値を変える。

今回手順に書いた内容ではCAとクライアント用でCNの値が相違するよう書いているので手順通りにしていれば起きない。

ED25519で証明書を作ったらなんか動かない

openssl genpkey-algorithm ed25519にするとEdgeは上手く解釈できないっぽいので-algorithm EC -pkeyopt ec_paramgen_curve:P-256として作る必要がある。

今回手順に書いた手順通りにしていれば起きない。

参考記事

2026/07/07(火)うろこ取りの買い替えと骨抜きの購入

投稿日:

手持ちのうろこ取りについて、購入以来ずっと使いづらかったので買い替えたのと、骨抜きを買った。

金属調理器具は貝印と決めているので、いつもの貝印。

今まで使っていたうろこ取り

昔突然うろこ取りが必要になったのでスーパーで買ったやつだが、どう見てもまともに使えそうにないやつである。

頑張れば取れるレベル。

今回買ったうろこ取り

金属製なのでガリガリ行けて大変便利だ。先は細かくなっており、鯛アラのような削り取る面積が少なく、形が複雑なものでもちゃんと取れる。

骨抜き

骨抜きにするという言葉があるが、その語源だろうか?

骨を抜くのに便利かなと思って買ったが、今のところ余り使えていない。肥やしになりそう。

2026/07/06(月)ConoHa VPSからIPv4のアクセスを自宅サーバーにIPv6でリバースプロキシするときにやったこと

更新日:
投稿日:

ログを取っていないので記憶で書いているし、順序は効率よくなるように変えているため、上手くいかない可能性がある。

前提

  • IPv4接続だけをConoHa VPSに移し、IPv4はConoHa VPSに立てたリバプロから受ける
  • ConoHa VPSスペックとしてOSはDebian GNU/Linux 13、メモリは512MB、CPU 1コアの最安インスタンス
  • ConoHa VPSから自宅サーバーへはIPv6でリバースプロキシする
  • ConoHa VPSから自宅サーバーへはHTTP通信で接続する
    • つまりIPv4側のTLS終端はConoHa VPS、IPv6側は自宅サーバーという構成
  • ConoHa VPSのIPv6アドレスは2400:8500:2002:3175:160:251:206:248

1. ConoHa VPS側でSSH接続できるようにする

この時点ではSSHで繋げないためWeb画面からすべて行う。

  1. SSHとICMPが繋がるようにする
  2. SSHDの設定方法
  3. 秘密鍵を作成し、公開鍵を取り出し.ssh/authorized_keysに追加
    • rootユーザーに追加した

2. ConoHa VPS側でnginxの設定

ここからはSSHで快適操作!

  1. nginxをインストールして証明書置き場を作る

    apt update
    apt upgrade -y
    apt install -y nginx
    
    mkdir -p /etc/nginx/cert/lycolia.info
    
  2. 証明書をSFTPで移す

  3. 自宅サーバーへのリバプロ設定の作成。メンテナンスを最小限にするためにワイルドカードで飛ばす

    cat <<'EOF' | tee /etc/nginx/conf.d/lycolia-info.conf
    map $http_upgrade $connection_upgrade {
      default upgrade;
      ''    close;
    }
    
    upstream backend {
      server [2400:4153:8f01:c800:c14b:3f7a:2b54:353a];
    }
    
    server {
      http2 on;
      listen 443 ssl;
      server_name lycolia.info *.lycolia.info;
    
      ssl_certificate   /etc/nginx/cert/lycolia.info/fullchain1.pem;
      ssl_certificate_key /etc/nginx/cert/lycolia.info/privkey1.pem;
    
      client_max_body_size 500m;
    
      location / {
        proxy_pass http://backend;
    
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    
        proxy_http_version 1.1;
        proxy_set_header Upgrade  $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
      }
    }
    EOF
    
    # enbaleは勝手にやってくれた気がする
    systemctl enable nginx
    systemctl restart nginx
    

3. 自宅サーバー側で疎通可能にする

  1. OpenWrtで80番ポートを開く
    1. LuCIを開き、Network→Firewall→Traffic Rulesで443を開けてるところに80を追加
  2. ufwにある既存の設定からIPv4で443に繋ぐ設定を消す
  3. ufwに新しい設定を足す

    # IPv6のみ許可する
    sudo ufw allow to ::/0 port 443
    # ConoHa VPSからの接続のみ80で受けられるようにする
    sudo ufw allow from 2400:8500:2002:3175:160:251:206:248 to any port 80
    
  4. nginx側でConoHa VPSを信頼するようにする
    set_real_ip_from 2400:8500:2002:3175:160:251:206:248;
    real_ip_header X-Real-IP;
    
  5. ConoHa VPSから来たX-Forwarded-Protoがhttpsならhttps、それ以外なら$schemeと解釈できるようなmapを書く
    これはConoHa→自宅サーバーがhttpで結ばれており、標準ではスキーマがhttpになってしまうが、それを回避しつつ、IPv6からの自作場への直アクセスがhttpないしhttpsだった場合は、そちらを取れるように変換するためである
    map "$realip_remote_addr:$http_x_forwarded_proto" $real_scheme {
      default $scheme;
      "2400:8500:2002:3175:160:251:206:248:https" "https";
    }
    
  6. 対応するスキーマのバインドを全部変更する。以下はMastodonの例(4.5.4では二箇所ある)
    CGIであればCGIヘッダを書き換えるとよいと思うが、今回は該当がなかった
    +    proxy_set_header X-Forwarded-Proto $real_scheme;
    -    proxy_set_header X-Forwarded-Proto $scheme;
    

4. DNSの切り替えをする

  1. AレコードをすべてConoHa VPSのIPv4に変更

5. nginxの設定を再読み込みする

DNSレコードが伝播するまでの間に粉うことでダウンタイムを最小化できる!

  1. nginxの設定を再読み込みする
    sudo systemctl reload nginx
    

6. 疎通確認

  1. 現時点で一般公開しているサイトに対し疎通するかどうか確認する
    curl -4 https://lycolia.info
    curl -4 https://blog.lycolia.info
    curl -4 https://mstdn.lycolia.info
    curl -4 https://eco.lycolia.info/wiki/
    
  2. 落ちてたら設定を見直し再試行

7. 掃除

  1. OpenWrtでIPv4向けの443を閉じる
    1. LuCIを開き、Network→Firewall→Traffic Rulesで443を開けてるところを消す
  2. OpenWrtのDDNSスクリプトを無効化
  3. nginxの設定でIPv4で443をlistenしてるところを全部消す

あとがき

やるだけやったが、結果的に現時点では全部撤回したので実証実験みたいになってしまった。

元々はフレッツ光クロスに切り替えてIPv4が失われることを想定して行ったが、よくよく考えたら切り替えたところで、今使っているルーターであるR86S U1のSFP+ポートが片方不安定で現状活用できないことや、IPv4のポート枯渇のためレスポンスが返せなくなる恐れを考えると、今やることではないなと思い、全撤回することにした。

ただまぁせっかくだしログを残していれば将来役に立つこともあるだろうというので残したが、色々あり構築時のログが消え去っていたので記憶を頼りに書くことになってしまったのは反省点である。

しかしR86S U1のSFP+が片側死んでいるのはどうしたものか。最近は何もかもすべてが高いのでおいそれと買い替えなどできないし…。まぁ現状困ってないし、IPv4は無料で手に入るし、別にクロスに変えなくてもいい気はした。

ところで全然関係ないけどWiFi 7を入れようと思ったもののSFP+の口が付いてるWiFiルーターは価格が高く、そうでなくとも、まともに速度が出る奴はどれもこれもデカく場所も取るので難しいね…。ひとまずやるとしたら1WくらいのトランシーバーでRJ45に変換するのが無難そうだと思った。その場合、10GtekのASF-10G-T80辺りはいい選択肢になりそうだ。

ルーターも最低でもトライバンドないと速度が出ないっぽいのでWXR18000BE10P辺りが5万円程度で、比較的小さいので無難だろう。この製品は過去に設置したことがあるのでサイズ的には問題ないことは確認済みである。今は手放しているので持っていない。経緯としてはかつてクロスを入れようとして導入したが、結局入れなかったし、デカくて邪魔だったので売った。

とはいえWiFiの速度には大きな不満があるので再導入を検討するのはありかもしれない。トランシーバーとセットで6万とかになるので眩暈がしそうだが…w

2026/07/06(月)nginxのリバースプロキシが上手くいかない問題を解消した

ConoHa VPSをフロントエンドにし、自宅サーバーにリバースプロキシする構成を組んだ時のトラブルメモ。

起きていた条件

nginxからnginxへリバースプロキシする構成で前段がTLS終端で、後段へはHTTPで接続していた。前段はVPS、後段は物理サーバーで別の環境。

起きていた事象

lycolia.info*.lycolia.info全体で前段が後段に接続できない状態になっていた。

curl -iSsl4 https://blog.lycolia.info/
HTTP/2 000 
server: nginx
date: Fri, 03 Jul 2026 15:24:44 GMT

前段のnginxにcurlを投げるとステータスコード000が返ってきて、curlが終了コード23で異常終了していた。

2026/07/04 00:11:33 [error] 2537#2537: *12468 upstream sent no valid HTTP/1.0 header while reading response header from upstream, client: xxx.xxx.xxx.xxx, server: lycolia.info, request: "GET /pub/lycolia/rss.xml HTTP/2.0", upstream: "http://[2400:4153:8f01:c800:c14b:3f7a:2b54:353a]:80/pub/lycolia/rss.xml", host: "blog.lycolia.info", referrer: "https://blog.lycolia.info/pub/lycolia/rss.xml"

nginxのエラーログには「アップストリームからのレスポンスヘッダーの読み取り中に、アップストリームが有効な HTTP/1.0 ヘッダーを送信しませんでした。」という意味のエラーを出力していた。

後段のnginxには何もログが出ていなかった。

curl -v --http1.1 -H 'Host: blog.lycolia.info' "http://[2400:4153:8f01:c800:c14b:3f7a:2b54:353a]:80/"
*   Trying [2400:4153:8f01:c800:c14b:3f7a:2b54:353a]:80...
* Connected to 2400:4153:8f01:c800:c14b:3f7a:2b54:353a (2400:4153:8f01:c800:c14b:3f7a:2b54:353a) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: blog.lycolia.info
> User-Agent: curl/8.14.1
> Accept: */*
> 
* Request completely sent off
* Received HTTP/0.9 when not allowed
* closing connection #0
curl: (1) Received HTTP/0.9 when not allowed

前段のnginxのあるVPSから、後段のnginxに対してhttpバージョン1.1を明示して叩くと「HTTP/0.9 when not allowed」というエラーが出てきた。HTTP/0.9…?初めて聞く概念だ…。

curl -s --http0.9 'http://[2400:4153:8f01:c800:c14b:3f7a:2b54:353a]/' | xxd           
00000000: 0000 1204 0000 0000 0000 0300 0000 8000  ................
00000010: 0400 0100 0000 0500 ffff ff00 0004 0800  ................
00000020: 0000 0000 7fff 0000 0000 0807 0000 0000  ................
00000030: 0000 0000 0000 0000 01                   .........

httpバージョン0.9を明示して叩き、帰ってきたレスポンスのバイナリ。端的に言うとプロトコルエラーで帰れと言われているが、理由は後述する。

解決した方法

+listen [::]:80;
-listen [::]:80 http2;

後段のmstdn.lycolia.infoの設定を上記に変更することで、他のドメインでも問題が解決した。

何故解決したかはわからないが、恐らく80 http2と書くと、他の80番ポートのリッスンにも影響が波及するのだと思う。

http2通信にしなくても問題ないのかでいうと、Mastodonは問題なさそうに見えたのでたぶん大丈夫なんだと思う。知らんけど。

何故解決したのか

使用しているnginxのバージョンがproxy_passするときにhttp 2.0をサポートしてなかったからだ。

nginx 1.29.4になるとproxy_passでhttp 2.0がサポートされるようで、2025年12月9日のリリースには以下の一文があった。

*) Feature: the ngx_http_proxy_module supports HTTP/2.

この時ばかりは今までnginxのバージョンに興味が微塵になかった私もバージョンを上げたくなった瞬間だった。

ただ後続のバージョンのバグフィックスを見るに結構バグが出てそうなので、今あげるのは時期尚早かもしれない。まぁ現状困ってないので上げなくてもいいのは幸いだ。

ところでv1.25.1になるとlisten単位のhttp2が非推奨になり、代わりにhttp2 onという全体単位?が推奨設定になるため、将来的に現状のポート単位にhttpバージョンを分ける技は使えなくなりそうである。

あとがき

バイナリ読解

前述したHTTP 2.0のバイナリレスポンスを読んでみようのコーナー。

curl -s --http0.9 'http://[2400:4153:8f01:c800:c14b:3f7a:2b54:353a]/' | xxd           
00000000: 0000 1204 0000 0000 0000 0300 0000 8000  ................
00000010: 0400 0100 0000 0500 ffff ff00 0004 0800  ................
00000020: 0000 0000 7fff 0000 0000 0807 0000 0000  ................
00000030: 0000 0000 0000 0000 01                   .........

そのバイナリを見るといいという情報をやってみたので試してみた結果。

まず16進数なので1桁に0-Fが入る。これは0000~1111ということだ。つまり1桁が4bitであることが分かる。

さて、HTTP/0.9は一旦忘れて、先ほどやってきたHTTP/2.0として解釈してRFC 9113 - HTTP/2を読んでみる。

「4. HTTPフレーム」によればHTTPフレームの先頭24bitがLength、8bitがType、8bitがFlag、1bitがReserved、31bitがStream Identifierらしい。

つまり先頭を分解するとこうなる。

Length: 00 00 12
Type: 04
Flag: 00
Reserved+Stream Identifier: 00 00 00 00

Lengthだ。0x000012なので18個の8bitフィールドがある。

次の8bitがTypeで0x04となっている。0x046.5.1. 設定フォーマットだ。

Reserved+Streamは全て0なので無価値だろう。

設定フォーマットではそこから48bit単位が設定フィールドとなる。先頭16bitがIdentifier、後ろ32bitがValueだ。

18個の8bitフィールドが設定になるため18 * 8 = 144, 144 / 48 = 3で3つの設定が存在すると読める。

00 03 00 00 00 80

つまりこの部分になる。

Identifierは00 03なのでSETTINGS_MAX_CONCURRENT_STREAMS。最大同時ストリーム数だ。

Valueは00 00 00 80なので128

次は00 00 00 00 10なのでSETTINGS_HEADER_TABLE_SIZE。ヘッダ圧縮テーブルの最大サイズ。

04 00 01 00なので67,109,120。オクテット単位なので単位はバイトと思われる。オクテットのオクはオクトパスのOctと同じなのでタコの脚は八本と考えると覚えやすい。Octoberも旧暦の8月だからOct。

次は00 00 05なので、SETTINGS_MAX_FRAME_SIZE

00 ff ff ff 00なので4,294,967,040。これも単位なので単位はバイトと思われる。

これで設定が終わり、またフレームに戻る。

00 0004 0800
0000 0000 7fff 0000 0000 0807 0000 0000
0000 0000 0000 0000 01

これが残り。

Length: 00 00 04 → 4 * 8 = 32bit
Type: 08WINDOW_UPDATE
Unused Flags: 00
Reserved+Stream: 00 00 00 00
Reserved+Window Size Increment: 7f ff 00 002,147,418,112

次の残り

0000 0807 0000 0000
0000 0000 0000 0000 01

Length: 00 00 08 → 64bit
Type: 07帰れ
ここまでくれば尻だけ読めばいいので中間は読み飛ばす。
最後の32bitがエラーコードらしいので00 00 00 01が恐らくエラーコード。意味合い的にはPROTOCOL_ERROR

要するにHTTP 2に対してHTTP 1.1で接続していたのでプロトコルエラーが返却され、しかしnginxは理解できなかったのでHTTP 0.9として解釈していたのだろう。

今回組んだ構成

今回nginxからnginxにリバースプロキシをしたわけだが、結果として上図のような構成にした。前段にはConoHa VPSを利用している。

これをした理由としては、以前フレッツ光クロスでフルポート使えるIPv4が取れないことが判明したため、クロスに移行出来るようにするためというのと、IPv4のためにDDNSし続けるのが地味に面倒なのと、宅内からIPv4を排除したかったところによる。

ただこれはこれでVPS側にもTLS証明書が必要になるため、DDNSが消えてもIPv4保守のための呪いはまだ残る。DDNSよりはマシだが…。

また、この構成では前後でnginxのバージョンが異なり前段がv1.26.3、後段がv1.24.0となっているため、前段ではhttp2 onにしないと警告が出るなど、バージョン差異による違いが微妙にある。

結果的にできた構成

今回の施策によって自宅サーバーからIPv4が失われても、AレコードをConoHa VPSに向けることでIPv4を受けることが可能な体制の検証をすることができた。これによってフレッツ光クロスに乗り換えたときのIPv4不在問題を解消できる状態となった。

実運用に移すためにはVPS側にもTLS証明が必要になるので自宅サーバーからSCPで送るか、VPS側でも取得する必要が出てくるので、まだまだ対策が必要だ。後者は同一ドメインに二重に証明書が存在する状態になるのでなんか嫌だし、恐らく前者でやるだろう。TCP パススルーなる技術も健闘したが、真のクライアントIP転送問題など、いろいろ厄介そうなのでやめた。

SCPで送る場合はパスフレーズ付きの鍵認証を突破させ、更にnginxをリロードさせないといけないからこちらもやや頭が痛い。パスフレーズ付きのSSH鍵を無人突破させるにはどこかに平文でパスフレーズを持つ必要がある。暗号化もできるがどんどん複雑に…。

或いはDNS-PERSIST-01を使うことで証明書更新を不要にするのも一つの選択肢かもしれないので、こちらも検討していいかもしれない。

しかしVPSがあることで監視対象が増えるなど、なかなか複雑化してしまうので、これを軌道に乗せるかどうかは現時点では不透明だ。ただConoHa VPSは最低スペックで36ヶ月契約であれば月額293円のため、36ヶ月換算でも10,548円にしかならず、IPv4を保持する手段としてはお手頃である。安いISPでもv4を買おうとすると月2~3,000円はするし、まともなところだと一万円以上するので、IPv4にサーバーがついてこの価格は破格と言える。

帯域は100Mbpsだが、100Mbpsあれば十分だろう。

おまけConoHa VPSで帯域実測

自宅サーバーとConoHa VPS間でiperf3をやってみた結果。自宅サーバーへの穴あけが面倒だったので自宅サーバー→ConoHaという逆経路でしか試していない。

Interval Transfer Bitrate Retr Cwnd
0.00-1.00 sec 24.4 MBytes 204 Mbits/sec 0 1.42 MBytes
1.00-2.00 sec 10.9 MBytes 91.2 Mbits/sec 0 1.43 MBytes
2.00-3.00 sec 12.2 MBytes 103 Mbits/sec 0 1.43 MBytes
3.00-4.00 sec 11.0 MBytes 92.3 Mbits/sec 0 1.43 MBytes
4.00-5.00 sec 10.9 MBytes 91.2 Mbits/sec 0 1.43 MBytes
5.00-6.00 sec 12.2 MBytes 103 Mbits/sec 0 1.43 MBytes
6.00-7.00 sec 11.0 MBytes 92.3 Mbits/sec 11 1.26 MBytes
7.00-8.00 sec 11.0 MBytes 92.3 Mbits/sec 169 762 KBytes
8.00-9.00 sec 11.0 MBytes 92.3 Mbits/sec 0 807 KBytes
9.00-10.00 sec 12.2 MBytes 103 Mbits/sec 0 838 KBytes
  • sender: 106 Mbits/sec
  • receiver: 103 Mbits/sec

2026/07/03(金)ConoHaのVPSのポートに穴をあけて外部通信できるようにした

更新日:
投稿日:

任意のポートでSSH接続をしようとしたら全然繋がらず、ググっても出てこなかったので書く。

この記事ではSSH接続に限らず、IP制限なく任意のポートを開放する方法について扱う。

1. セキュリティグループの作成

  1. コントロールパネルにログインする
  2. 左のメニューからセキュリティ→セキュリティグループを開く
  3. 「+セキュリティグループ」ボタンを押し、MySSHとか適当な名前で設定を作る
  4. 作成したセキュリティグループを開き、左下の「+」を押す
  5. 通信方向:IN
    イーサタイプ:IPv4 or IPv6
    プロトコル:TCP or UDP。1つの設定でTCPとUDP両方開けることはできない
    ポート範囲:単体の場合は10092、範囲の場合は10000-11000のように指定すると思うが範囲指定は試していない
    IP/CIDR:IPv4なら0.0.0.0/0、IPv6なら::/0
  6. コンソールに入る
  7. 初期設定

2. NICへセキュリティグループを割り当て

  1. 左のメニューからサーバーを開き、適用するVPSを開く
  2. ネットワーク情報の「セキュリティグループ」を開く
  3. 「+」ボタンを押し、先ほど作成したセキュリティグループを選択
  4. 保存ボタンを押し、セキュリティグループが追加されていることを確認
  5. この時に、プリセットに存在するICMPのルールも割り当てておくと良い。「IPv4v6-ICMP」がそれだ

この設定の反映は即座には反映されないようで、数秒のタイムラグがあった。3秒くらい待つと繋がった。

3. VPSのファイアーウォールに穴をあける

  1. コンソールからVPSのシェルに入る
  2. /etc/nftables.confを開き、先ほどセキュリティグループで開けた穴が開くように設定する

    #!/usr/sbin/nft -f
    
    flush ruleset
    
    table inet filter {
        chain input {
            type filter hook input priority 0;
            policy drop;
    
            iif "lo" accept
    
            ct state established,related accept
    +
    +         meta l4proto { icmp, ipv6-icmp } accept
    +
    +         tcp dport 3000 accept
        }
    
        chain forward {
            type filter hook forward priority 0;
        }
    }
    
  3. nftablesを再起動する
    systemctl restart nftables
    

おまけ:公開鍵認証を使ったSSH接続について

コントロールパネルのセキュリティ→SSH Keyという項目があるが、ここを設定する必要はない。

/etc/ssh/sshd_configを書き換えて、公開鍵を所定の場所に設置すれば普通に設定できるので、わざわざWeb画面から設定する必要はない。

ここから追加したところでパスワード認証が無効になるのかどうかもわからないし、そもそもこれがSSHDに関連するのかもわからないし、謎設定だと思う。ひょっとしたら単に鍵を生成するだけなのかもしれないが、それならssh-keygenなどを使えばいいわけで…。

あとがき

Conoha公式のVPSスタートアップガイドにはSSH接続でVPSにログインするというのがあるが、セキュリティグループに関する記述がないので、そのままでは標準の22番ポートにすら繋がらないのが困りものだ。

VPSスタートアップガイドと言うからにはそのくらい書いてくれてもいいんじゃないだろうか?と思った。