はじめに
自分でNext.jsでアプリを作っているときにスマホからPCのIPにアクセスして
デザインを確認したい場面があった。
しかし、位置情報を使うアプリだったためスマホからはHTTP通信で位置情報はHTTPS通信を使うため
実行エラーになる時があった。
スマホで手っ取り早くHTTPSアクセスするためになにか方法がないか調べたがどうやらNginxが良さげだったので使ってた。
今回のサンプルは以下githubにあります。
なるべく公式ドキュメントも見るようにしているが、英語の翻訳があっているか怪しいので
参考に載せておく
実行結果
実装
今回はNext.js,FastAPI,NginxをすべてDocker上に構築している。
Dockerの構築は以下のようにしている
.
|_fastapi_sample
| |_DockerFile
|_next_sample
| |_DockerFile
|_nginx
| |_Dockerfile
|_docker-compose.yml
Docker
Dockerの設定は以下のようにしている
docker-compose.yml
version: "3.0"
services:
nextjs:
image: nextjs_image
container_name: nextjs_containe
build:
context: .
dockerfile: ./next_sample/Dockerfile
networks:
- my_network
fastapi:
image: fastapi_image
container_name: fastapi_container
build: ./fastapi_sample
networks:
- my_network
nginx:
image: nginx_image
container_name: nginx_container
build:
context: .
dockerfile: ./nginx/Dockerfile
ports:
- "80:80"
- "81:81"
- "443:443"
depends_on:
- nextjs
- fastapi
networks:
- my_network
networks:
my_network:
driver: bridge
今回はNginxからのアクセスを想定している。
そのため、直接 Next.jsとFastAPIのアプリにはアクセスしないようにしたいため
Next.js と FastAPI のコンテナには直接アクセスできないようにポートはマッピングしていない。
そのため、my_networkにNginx,Next.js,FastAPIを入れることで
ポートをマッピングしているNginxからのアクセスを可能にしている。
ちなみにだが、別に同一アプリの場合実際は設定しなくても、接続可能らしいが…..
デフォルトで Compose はアプリに対して1つの ネットワーク を作成します。サービス用の各コンテナはデフォルトのネットワークに接続し、そのネットワーク上で他のコンテナと相互に「 接続可能reachable 」になります。
https://docs.docker.jp/compose/networking.html
fastapi_sample/Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app/ .
# ポート開放
EXPOSE 8080
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8080"]
requirements.txt は以下のようにしている
fastapi
uvicorn
next_sample/DockerFile
FROM node:18-alpine
# 作業ディレクトリ
WORKDIR /app
# pnpm install
RUN npm install -g pnpm
# コード全体を /app にコピー
COPY ./next_sample /app
# 依存関係をインストール
RUN pnpm install
# ビルド
RUN pnpm run build
# ポート開放
EXPOSE 3000
# 起動
CMD [ "pnpm", "start" ]
今回は実装を丸々コピーしてそれをコンテナ内に入れて
ビルド->起動をしている。
node_modulesファイルをコピーすると無駄に時間がかかるので.gitignoreファイルを作って
コピーはしないようにしている。
node_modules
README.md
build
nginx/Dockerfile
FROM nginx:alpine
#設定ファイルコピー
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
#証明書コピー
COPY ./nginx/ssl/crt.pem /etc/nginx/ssl/fullchain.pem
COPY ./nginx/ssl/privkey.pem /etc/nginx/ssl/privkey.pem
COPY ./nginx/ssl/passwd /etc/nginx/ssl/passwd
今回はSSL化するためCOPYで証明書やパスワードなどをまるっとコピーしている
nginx.conf をコピーして、デフォルト設定を書き換えている
SSLのディレクトリは今回は、用意していないので自分で証明書を作る必要がある。
自分は以下を参考に、nginx/ssl ディレクトリに証明証を作成した。

Nginx
ここからは今回のキモ(多分)であるNginxの設定を見ていく。
全体の構成は以下になっている
server {
listen 80;
server_name localhost;
# HTTPからHTTPSへリダイレクト
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_password_file /etc/nginx/ssl/passwd;
location / {
proxy_pass http://nextjs:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /_next/ {
proxy_pass http://nextjs:3000/_next/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /static/ {
proxy_pass http://nextjs:3000/static/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# FastAPI コンテナへのリバースプロキシ設定
location /api { # ここでFastAPIのエンドポイントを"/api/"以下に設定
proxy_pass http://fastapi:8080; # FastAPIコンテナのホスト名とポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
ここからは詳細を紐解いていきたい
SSLの基本設定
server {
listen 80;
server_name localhost;
# HTTPからHTTPSへリダイレクト
return 301 https://$host$request_uri;
}
ここはHTTP通信できたときにHTTPS通信にリダイレクトしている
ListenにHTTPポート(80)を指定している。
今回はlocalhostで開発を前提にしているので、localhostをserver_nameに指定している
公式ドキュメントを見るとserverブロックにはlistenするポートとserver_nameを入れるらしい。
Generally, the configuration file may include several server blocks distinguished by ports on which they listen to and by server names.
https://nginx.org/en/docs/beginners_guide.html
returnは元々公式を見ると、処理を中断してステータスを返すために使われていたようにみえる
バージョン0.8.42からリダイレクトとしても機能するようにしたぜ!って書いている。
301ステータス自体は永続的にリダイレクトするという意味らいい
Stops processing and returns the specified code to a client.
The non-standard code 444 closes a connection without sending a response header.
Starting from version 0.8.42, it is possible to specify either a redirect URL (for codes 301, 302, 303, 307, and 308) or the response body text (for other codes). A response body text and redirect URL can contain variables.
As a special case, a redirect URL can be specified as a URI local to this server, in which case the full redirect URL is formed according to the request scheme ($scheme) and the server_name_in_redirect and port_in_redirect directives.https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
returns a permanent redirect with the 301 code.https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
公式分だけだと??だったが以下を参考にすると、なんとなくhttp通信は永続的にhttps通信に変えたいというふうに思えば
良いのかなと理解した。

server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_password_file /etc/nginx/ssl/passwd;
NginxでHTTPS通信をするためにはserver blockのlistenソケットにsslをつけろとのことだ
また、サーバ証明書と秘密鍵の場所も定義してねとのこと
To configure an HTTPS server, the ssl parameter must be enabled on listening sockets in the server block, and the locations of the server certificate and private key files should be specified:https://nginx.org/en/docs/http/configuring_https_servers.html
ssl_certificate,ssl_certificate_keyはpem形式のファイルを指定してと、公式ドキュメントにある。
証明書の仕組みは今回は、理解していないので別途理解を深めたいところではある。
Specifies a file with the certificate in the PEM format for the given virtual server. If intermediate certificates should be specified in addition to a primary certificate, they should be specified in the same file in the following order: the primary certificate comes first, then the intermediate certificates. A secret key in the PEM format may be placed in the same file.
Since version 1.11.0, this directive can be specified multiple times to load certificates of different types, for example, RSA and ECDSA:https://nginx.org/en/docs/http/ngx_http_ssl_module.html
ssl_password_file は読んで字のごとく秘密鍵のパスワードを書くとのこと
Specifies a file with passphrases for secret keys where each passphrase is specified on a separate line. Passphrases are tried in turn when loading the key.https://nginx.org/en/docs/http/ngx_http_ssl_module.html
まずはここまでの実装でHTTPS通信をするための、基本設定ができたと言えよう。
HTTPS通信でNext.jsのアプリへアクセス
location / {
proxy_pass http://nextjs:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
以下のようにURIを指定すると、そのURIにアクセスした場合の処理をかけるらしい
location URI {
context
}
proxy_pass は受け取ったリクエストを http://nextjs:3000 に転送する設定のようだ。
今回 nextjs はDockerのコンテナ名を指定している。
proxy_http_version は HTTP/1.1 で通信するように設定している。
WebSocket とかを使うときに HTTP/1.0 だと非対応だから指定する必要があるらしい。
ただ、今回は必要ないのでいらないかも….(参考元のコピペだから今後調査が必要)
公式ドキュメントだと NTLM認証とkeepalive接続とのときに使うと良いよとのこと。(2つとも私はまだしらない)
Version 1.1 is recommended for use with keepalive connections and NTLM authentication.
https://nginx.org/en/docs/http/ngx_http_proxy_module.html
以下の4点は自分の中で調べてみたが、必要性がわかっていないので別途調査をしたい
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection “upgrade”;
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
公式を参考にすると、指定したエラーに対して表示するURIを表示するらしい
Defines the URI that will be shown for the specified errors. A uri value can contain variables.
Next.js
Next.jsのDocker化については別記事で書く予定
FastAPI
FastAPIのDocker化については以下の記事で紹介しているので、参考にしてください

さいごに
なるべく公式のドキュメントを参考にしたけど
読みにくかった…..
英語の勉強しないとな
コメント