Nginxで色々なプログラムをプロキシーしてみる

# 1.Nginxとはどのようなソフトウェアか?
Nginxは高機能なWebサーバーです。色々なモジュールが用意されており,例えばStreamモジュールを使うことでリバースプロキシサーバーとして機能させることも出来ます。また,オープンソースかつフリーなソフトウェアなのでソースコードを自由に改変したり,ソースコードから必要な機能のみを有効にしたプログラムをビルドすることも可能です。私はApache2やマインクラフトサーバーのリバースプロキシーとしてNginxをよく使っています。それらの設定を備忘録として残しておこうと思います。マインクラフトサーバーの構築については過去に解説している記事があるのでここでは解説しません。

### **リバースプロキシーとは?**
サーバー側に設置するプロキシーサーバーのことです。インターネット接続する際に別途設定することも可能なWebプロキシーやVPNはフォワードプロキシーと呼ばれるものであり,リバースプロキシーと違いクライアント側で使用するプロキシーサーバーです。以下はWebサーバーにおけるリバースプロキシーサーバーの配置図になります。イメージとしてはこのようになります。
![スクリーンショット 2025-05-30 6.20.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1807755/94aea524-e4a9-484d-885f-8af3b578e57d.png)
リバースプロキシーサーバーはクライアントからのリクエストを受け取りそれを対象のサーバーにリクエストを転送する役割をします。このような動作をさせることによりセキュリティー・パフォーマンスの向上などをすることが可能です。リバースプロキシーを間に挟むことでサーバー本体を隠すことができるのでセキュリティーが上がります。他にもリバースプロキシーが受け取ったリクエストを適切に転送するので転送されたリクエストを受け取るサーバーが無駄にリクエストを受ける頻度が減るため,パフォーマンスが向上することが見込めます。

リバースプロキシーとしてもNginxはよく利用されます。Webサーバーでセキュリティー対策をしたい時,Nginxを使っていないならNginxをリバースプロキシーとして使いましょう。それをするだけでかなり変わるはずです。Nginxは非常に軽量動作をするプログラムで少ないリソースで多量のリクエストを処理することを得意とするサーバーです。よく利用される例としては, Apache2 + WordPressのリバースプロキシーとして利用することです。では実際にやってみましょう。
# 2.Apache2にリバースプロキシーを設定
実際に設定していきます。クライアントからのリクエストをNginxを通してからApache2に転送されるようにすることが目的です。ですので,Apache2(httpd)のポート番号の変更を行います。

<details><summary>手順1 :Ubuntu/Debianの場合</summary>
ファイルを2種類編集する必要があります。

```apache:/etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:8080>  #80を8080などに変更する
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>
```
```apache: /etc/apache2/ports.conf
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf

Listen 8080 #80から8080に変更する

<IfModule ssl_module>
        Listen 8443 #443から8443に変更する
</IfModule>

<IfModule mod_gnutls.c>
        Listen 8443 #443から8443に変更する
</IfModule>
```
あとはApache2の再起動をしましょう。 
```zsh:zsh
user@localhost:~% sudo systemctl restart apache2
```
</details>

<details><summary>手順1: RHEL系の場合</summary>

```apache:/etc/httpd/conf/httpd.conf
Listen 8080 #80を8080に変更する
```
あとはhttpdの再起動します。
```zsh:zsh
user@localhost:~% sudo systemctl restart httpd
```
</details>

### **手順2: Nginxでの設定**
まずはNginxのバージョンを表示されないようにします。
```nginx:/etc/nginx/nginx.conf
http {
    server_tokens off; #追記またはコメントアウトを外す
```
次に実際にApache2のリバースプロキシーの設定をします。SSL/TLSを設定したい場合も同じように設定します。ただし,証明書はApache2ではなくNginxで読み込ませるように設定する必要があるので注意します。
```nginx:/etc/nginx/conf.d/reverse.conf
server {
  listen 80;               # http接続時の設定
  listen [::]:80;          # IPv6接続時の設定
  server_name example.com;   # サーバー名。必要に応じて変更する

  location / {
    proxy_pass http://localhost:8080; # どこにアクセスさせるか
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-Proto      $scheme;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
  }
}

### SSL/TLSの設定の例
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    location / {
    proxy_pass http://localhost:8080; # どこにアクセスさせるか
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-Proto      $scheme;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
  }
}
```
設定が完了したらNginxを再起動します。
```zsh:zsh
user@localhost:~% sudo systemctl restart nginx
```
これでリバースプロキシーの設定ができました。あとは http://example.com にアクセスしたらhttp://localhost:8080 と同じ内容が表示されるようになっているはずです。

# 3.マインクラフトサーバーのリバースプロキシーに設定
マインクラフトのプロキシーサーバーと言えば,Spigot/Bukkit用のWaterfall,BungeeCord,バニラサーバーならVanillaCordが有名ですね。ですが,Nginxをプロキシーサーバーとして利用することも可能です。ただ,マインクラフトサーバー用のプロキシーサーバーではないのでコマンドを使って切断せずに別のサーバーに移動するというなことはできないと言うことは念頭に置いておいてください。二重にプロキシーサーバー設置すると言うやり方でも問題ありません。`Proxy Protocol`を使ってリバースプロキシーを組んでみようと思います。ここからはUbuntu/Debianでの設定の話になるのでRHEL系のLinuxを使っている人は相応のパッケージを探してインストールしてください。
Nginxを入れるだけではモジュールが入っていないので,`apt`でStreamモジュールをインストールします。
```zsh:zsh
user@localhost:~% sudo apt install libnginx-mod-stream
```
Streamモジュールをインストールできたら`/etc/nginx/nginx.conf`にStreamモジュールを使うための設定を書き込みます。

:::note alert
Streamディレクティブは**Eventsディレクティブ**より前に書く必要があります。これを守らないとNginxのSyntaxエラーが発生し,起動や再起動ができなくなります。
:::
:::note
文法ミスが発生していないかなどを確認する際は以下のコマンドを実行してみましょう。エラーがあればどの部分が間違っているかを教えてくれます。
```zsh:zsh
user@localhost:~% sudo nginx -t
```
:::

```nginx:/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

#この内容を書き足します。
stream {
        include /etc/nginx/stream.d/*.stream;
}

events {
        worker_connections 768;
        # multi_accept on;
}
```
設定が出来たら次に`/etc/nginx`ディレクトリに新しくディレクトリを作ります。
その次に拡張子が`.stream`になるように`touch`コマンドで空ファイルを作成しましょう。
```zsh:zsh
user@localhost:~% sudo mkdir /etc/nginx/stream.d                   #ディレクトリ作成
user@localhost:~% sudo touch /etc/nginx/stream.d/minecraft.stream  #空ファイルの作成
```
では作成した空ファイルに設定を記述していきます。
```nginx:/etc/nginx/stream.d/minecraft.stream
proxy_protocol on;
#UDPポートの設定をしたい場合はソースコードからビルドしたNginxを使用する必要があるので注意
upstream mc-server-1.20.1 {
    server 127.0.0.1:1201;
    server [::1]:1201; #IPv6アドレスは[IPv6アドレス]という風に記述する。
}

#転送設定
server {
    listen 25565;
    listen [::]:25565;
    proxy_pass mc-server-1.20.1;
}
```
これで設定は終わりです。複数`proxy_pass`を設定したりすることも可能です。最後に`Nginx`の構文チェックを行い,問題が無いか確かめましょう。

:::note warn
マインクラフトサーバーの設定ファイルの1つに`server.properties`というファイルがあります。そのファイルの設定項目の中に`prevent-proxy-connections`という項目がありますがこれを`true`にすると`not authenticated with minecraft.net`というエラーが発生することがあるため,有効にしないことをお勧めします。ただし,これは**サーバーのプロキシーとしてNginxしか利用していない場合**の話であって,二重プロキシー(例:NginxとBungeeCord)にしているのであれば有効にする必要があります。
:::
# 4.Cockpitのリバースプロキシーとして設定
CockpitはWeb管理コンソールの1つですね。このプログラムはデフォルトでは9090/tcpを使用するのでこれをリバースプロキシーで80/tcpや443/tcpに飛ばしてしまおうって言うことですね。そんなことせんでもSSHのローカルポートフォワーディングで簡単に解決できるので正直設定する必要はない気はしますけどねw。
設定を記述していきましょう。まずは適当に空ファイルを`/etc/nginx/conf.d`に作成しておきます。`vim`でも`nano`でも好きなテキストエディターを使って編集していきます。
```zsh:zsh
user@localhost:~% sudo touch /etc/nginx/conf.d/cockpit.conf
```
```nginx:/etc/nginx/conf.d/cockpit.conf
server {
    listen 80;
    listen [::]:80;
    server_name console.example.com; #適当なサブドメインでも割り当てておきます

    location / {
    proxy_pass http://localhost:9090; # どこにアクセスさせるか
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-Proto      $scheme;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
  }
}
### SSL/TLSの設定の例
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name console.example.com;

    ssl_certificate /etc/letsencrypt/live/console.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/console.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    location / {
    proxy_pass http://localhost:9090; # どこにアクセスさせるか
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-Proto      $scheme;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
  }
}
```
こんな感じで設定すれば大丈夫だと思います。あとは`Nginx`の構文チェックをして問題なければ再起動して完了です。

### おまけ: SSHでローカルポートフォワーディング
使っている人はよく使うと思うので読み飛ばしていただいて良いと思います。まず,SSHのポートフォワーディングというのは,非常に強力な暗号化がされているSSH接続をしているトンネルに別のプログラムの通信を載せて安全にSあるホストのポート番号への通信を,別のホストのポート番号に転送することを指します。例えば暗号化されていない通信といえばVNCがあります。直接VNC接続をしてしますと通信が暗号化されていないので傍受されてしまう危険性がありますが,SSHトンネルにVNCの通信を通すことで安全にVNCの通信を行うことができるようになります。実際にやってみましょう。
今回はSSHの接続先つまりリモートホストではNginxのWebサーバーが動いている状態だとします。このWebサーバーはポート開放されておらず直接みることができません。ですがSSHポートフォワーディングを行うことで見ることができるようになります。以下の内容はあくまで例ですので実際の環境に合わせて変更してください。SSH Agentと組み合わせると非常に便利ですよ。
| サーバー | ローカルIP | グローバルIP |ポート番号|
|:-----------|------------:|:------------:|:------------:|
| SSHサーバー  | 10.7.1.6   | 100.3.2.1     |22|
| Webサーバー  | 10.7.1.2   | 100.3.2.1     |80|

ユーザー名は`test`,秘密鍵名は`ed25519`としておきます。公開鍵認証接続が前提で話します。
```zsh:zsh
user@localhost:~% ssh -fNL 8080:107.1.2:80 test@100.3.2.1 -p 22 -i ed25519
```
SSH接続が出来たらWebブラウザーを開きます。 http://localhost:8080 にアクセスしてみましょう。すると,非公開状態になっているWebサーバーを閲覧することができます。これを応用すればNTTのルーター(192.168.1.1)に外出先からログインしたりすることも可能なわけです。これを利用すればCockpitとかも開けるのでわざわざNginxでリバースプロキシーする必要性は無いかもしれないっていうことです。

# 最後に
Nginxは非常に優秀で高機能なWebサーバーです。リバースプロキシーとしても使えるし,メールのプロキシーとしても使えるしなどなど。Webサーバーで利用されているソフトウェアでは現在シェア率が１位ですからそれだけ使われる理由が存在するわけですね。Webサーバー,プロキシーサーバーに困ったらNginx置いとけって言われるのはこれが理由なのかなぁと個人的に思っています。実際便利ですからね。

何かご意見やご質問があれば気軽にコメントをお願いします。答えれる範囲で対応します。