Nginx の conf ファイルでサブドメインを変数に入れる

> Nginx でサブドメインによるアクセスをサブ・ディレクトリに転送させたい。

つまり、Nginx で <code>http://<font color=darkorange>xxx</font>.sample.com/</code> を <code>​http<font color=red>s</font>://sample.com/<font color=darkorange>xxx</font>/</code> に転送させたるために "<font color=darkorange><code>xxx</code></font>" の部分、**ドメインの一部（サブドメイン部分）を変数に入れたい**のです。

:::note info
<sup>🐒 &nbsp; 2018/08/06 追記：[2018/03/02 に Let's Encrypt がワイルドカード（`*`の使用）に対応](https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578)しました。本記事の「サブドメインのアクセスを別ドメインのディレクトリ下に転送する」のではなく、[ワイルドに SSL を使いたい場合は、他の Qiita 記事を参照](https://www.google.co.jp/search?q=site%3Aqiita.com+%22Let%27s+Encrypt%22+%E3%83%AF%E3%82%A4%E3%83%AB%E3%83%89%E3%82%AB%E3%83%BC%E3%83%89)ください。</sup>
:::

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. 正規表現でサブドメインを変数にキャプチャして使いまわす。

    ```bash:$subhostにサブドメインをキャプチャする例
    server_name  ~^(?<subhost>.+)\.sample\.com$;
    ```

2. Nginx の `http` アクセスを <code>http<font color=red>s</font></code> に変更しながらサブディレクトリに転送<br><code>http://<font color=darkorange>xxx</font>.sample.com/</code> → <code>​http<font color=red>s</font>://sample.com/<font color=darkorange>xxx</font>/</code>

    ```conf:/etc/nginx/conf.d/_http.conf
    ## default HTTP
    server {
         listen       80;
         server_name  ~^(?<subhost>.+)\.sample\.com$;
         return       301 https://sample.com/$subhost$request_uri;
    }
    ```

3. Nginx の `https` アクセスでサブディレクトリに転送<br>`https://xxx.sample.com/` → `https://sample.com/xxx/`

    ```conf:/etc/nginx/conf.d/_ssl.conf
    ## default SSL
    server {
         listen       443 ssl;
         server_name  ~^(?<subhost>.+)\.sample\.com$;
         return       301 https://sample.com/$subhost$request_uri;
    }
    ```

## TS; DR <sub><sup><sub><sup>（`nginx` のドメイン変数とコマケーこと）</sup></sub></sup></sub>

### 「*.sample.com」のサブドメインをディレクトリ下に転送する

[NS](https://ja.wikipedia.org/wiki/DNS%E3%82%B5%E3%83%BC%E3%83%90) の DNS 設定で [CNAME](https://ja.wikipedia.org/wiki/DNS%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%82%BF%E3%82%A4%E3%83%97%E3%81%AE%E4%B8%80%E8%A6%A7) 設定を以下のように設定すると全てを１つのサーバーに向けることができます。

- `* CNAME @`, `@ A xxx.xxx.xxx.xxx`

つまり「`kyoto.sample.com`, `yokohama.sample.com`, `...`, `?????.sample.com`」は同じサーバーで処理できます。サブドメインの `Catch All` 的な設定です。

今まで、PHP 側で URL を解析して分岐処理をしていたのですが、全てのサブ・ドメインで [Let'sEnctypt](https://ja.wikipedia.org/wiki/Let%27s_Encrypt) を使って SSL 対応することにしました。しかし、不特定多数のサブドメインごとに SSL 認証を取得するのが~~面倒~~大変になったため、以下のように転送させることにしました。

`http://yokohama.sample.com/?hoge=huga` → `https://sample.com/yokohama/?hoge=huga`

[Nginx の設定ファイル（conf ファイル）で使える環境変数](http://qiita.com/FoxBoxsnet/items/21316143c0f7929fc068)に `$host` があるのですが、これを使うと以下のよう転送されてしまいます。

#### 悪い設定

```conf:/etc/nginx/conf.d/_http.conf
## default HTTP
server {
    listen       80;
    server_name  default_server;
    return       301 https://example.com/$host$request_uri;
}
```

#### 悪い転送結果

`http://hoge.sample.com/` → `https://sample.com/hoge.sample.com/`

当然と言えば当然なのですが、ホスト情報全体が渡されてしまうので、サブドメインだけが欲しいんです。

### 正しい転送方法

[StackOverflow に聞いた](https://stackoverflow.com/questions/45318758/nginx-variable-for-subdomain)ところ、「[正規表現使えばよくね？](https://stackoverflow.com/a/45321927/8367711)」って事でした。Oh...。

```conf:/etc/nginx/conf.d/_ssl.conf
## default SSL
server {
     listen       443 ssl;
     server_name  ~^(?<subhost>.+)\.sample\.com$;
     return       301 https://sample.com/$subhost$request_uri;
}
```

そこは Apache と同じ概念なのね。Nginx 慣れていないので基本的な事を忘れてました。

「読んだのに、読んだつもりで、読んでない [英語の公式ドキュメント](http://nginx.org/en/docs/http/server_names.html#regex_names)」ですな。Nginx って Apache と比べて意外に日本語訳って整っていないのね。

## 参考文献

- Nginx variable for subdomain? @ Stack Overflow<br>https://stackoverflow.com/questions/45318758/nginx-variable-for-subdomain
- Server names | Regular expressions names @ Nginx.org<br>http://nginx.org/en/docs/http/server_names.html#regex_names