0
1

Docker上にNext.js+nginxサーバーを構築し、httpsでアクセスできるようにする

Last updated at Posted at 2024-06-06

はじめに

注意事項

  • Docker, Next.js, nginxは1ヶ月触った程度の初学者
  • あくまで開発中のテスト用の構築

環境

  • OS:Ubuntu 20.04.6
  • Docker: 26.1.3
  • Docker Compose: 2.27.0
  • node: 21.7.1

経緯

ブラウザ上でマイクやカメラといった機能を使用したい場合、https通信でアクセスしなければいけません。

localhostで試している分にはブラウザがよしなに対応してくれたり、Next.jsの--experimental-httpsオプションがあるためそこまで困りませんが、スマートフォン上のブラウザから試してみたい場合や、実ネットワークを介して試してみたい場合などはhttps通信でのアクセスが必須です。

そこで、nginxをリバースプロキシとしてNext.jsアプリケーションを配信しつつ、nginxへのアクセスを自己署名証明書を用いたhttps通信に対応させることで、なんちゃってhttps通信を実現します。

実際のWebサイトとして公開する際は当然Let’s Encryptのような認証局を通した証明書を用いる必要がありますが、開発環境として試す際は上記の方がお手軽に試せると思います。

実践編

準備

ディレクトリ構造

今回は以下のようなディレクトリ構造で試します。

- root
  - app
    - /* create-next-appで作成した各種ファイルとフォルダ */
    - Dockerfile
  - nginx
    - Dockerfile
    - nginx.conf
  - compose.yaml

appフォルダはcreate-next-appコマンドで自動的に作成されるため、nginxフォルダだけ作成しておきます。

各種インストール

詳細なインストール方法は割愛しますが、以下をインストールしておきます。
nodeはcreate-next-appを実行するためにnpxを使用します。
(もしnpxが入っていない場合はnpm install -g npxでインストールできると思います。)

  • node
  • dockerとdocker compose

実装

Next.js

今回はとりあえずcreate-next-appで作成されるサンプルアプリを使用します。

$ npx create-next-app
✔ What is your project named? … app
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … No

Next.jsのプロジェクト名をapp、その他のオプションはとりあえずそのままに作成しました。

Docker

上記のcreate-next-appで作成したappフォルダ、およびnginxフォルダそれぞれにDockerfileを、プロジェクトのルートディレクトリにcompose.yamlファイルを作成していきます。

Dockerfile(Next.js)
FROM node:latest

WORKDIR /app

Next.js側のDockerfileはシンプルにnodeイメージをベースに作成しておきます。WORKDIRで後ほどバインドマウントする/appフォルダを指定しておきます。

Dockerfile(nginx)
FROM nginx:latest

RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y openssl sudo

RUN mkdir -p /etc/nginx/ssl
RUN openssl genrsa 2048 > /etc/nginx/ssl/nginx.key && \
    openssl req -subj '/CN=/O=/C=' -new -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.csr && \
    openssl x509 -req -days 365 -in /etc/nginx/ssl/nginx.csr -signkey /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt 

COPY ./nginx.conf /etc/nginx/nginx.conf

CMD ["nginx", "-g", "daemon off;"]

nginx側のDockerfileではnginxイメージをベースに、httpsのために必要となる証明書をopensslで作成しています。
また、同じフォルダに作成するnginx.conf(後述)をDocker上の/etc/nginx/nginx.confにコピーします。

compose.yaml
services:
  app:
    container_name: sample_next
    build:
      context: ./app
      dockerfile: Dockerfile
    tty: true
    volumes:
      - ./app:/app
    environment:
      - WATCHPACK_POLLING=true
    ports:
      - "3000:3000"
    command: sh -c "npm install && npm run dev"

  nginx:
    container_name: sample_nginx
    build:
      context: ./nginx
      dockerfile: Dockerfile
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - app

最後にこれら二つのDockerを起動するためのcompose.yamlファイルを作成します。

Next.jsのDockerイメージではcreate-next-appで作成したappフォルダをそのままDocker上の/appフォルダとして使用できるようにバインドマウントしています。
Next.jsで使用するポート番号をpackage.jsonなどから変更している場合は適宜書き換えてください。

nginxのDockerイメージではhttp通信で使用される80番ポートとhttps通信で使用される443番ポートを記載しておきます。今回、http通信でアクセスされた際はhttps通信を使用するようにリダイレクトさせたいと思います。

nginx

nginx.conf
events {
    worker_connections 1024;
}

http {
    server {
        # http(80番ポート)はhttpsへリダイレクト
        listen 80;
        listen [::]:80;

        return 301 https://$host$request_uri;
    }

    server {
        # httpsで使用される443番ポートで待つ
        listen       443 ssl;
        listen       [::]:443 ssl;
        http2 on;

        # 作成した証明書のファイルを指定
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;

        # Next.jsへ接続
        location / {
            proxy_pass http://sample_next:3000;
        }
    }
}

nginxフォルダのnginx.confでは、以下の二点を記載しています。

  1. http(80番ポート)でのアクセスはhttps://$host$request_uriへリダイレクト(301)
  2. https(443番ポート)でのアクセスはproxy_passを使用してhttp://sample_next:3000へ転送
    • sample_nextcompose.yamlで指定したNext.jsのコンテナ名
    • ssl_certificateおよびssl_certificate_keyにはnginx側のDockerfileで作成した証明書のファイルの場所を指定
余談 nginxが自動で作成したnginx.confに443番ポート周りの設定をしたserverを追記すればいいだろ~と思っていたら、以下の行があるせいでリダイレクトしてくれない、という状況にハマってかなりの時間を浪費してしまいました。
include /etc/nginx/conf.d/*.conf;

お気を付けください。

動作確認

Dockerfileをビルドし、起動します。

$ docker compose build
$ docker compose up -d

Dockerを起動したマシンのIPアドレスをブラウザのURL欄に直接打ち込んでみます。

以下ではマシンのIPアドレスを127.0.0.1に置き換えてあります。
適宜自分の環境と読み替えてください。

すると自動的にhttps://127.0.0.1にリダイレクトされるはずです。

リダイレクトされた後、初回は以下のような警告がブラウザによって表示されます。(IPアドレス部分は加工しています)

image.png

このページの作者である自分が悪意のあるユーザーではないという方は(もちろん全員がそうだと思いますが)、詳細設定から 127.0.0.1にアクセスするをクリックしましょう。
image.png
上記のようなNext.jsのサンプルページが表示されればOKです。これでなんちゃってhttps通信でNext.jsアプリケーションへアクセスできるようになりました。

ブラウザ上ではセキュリティ保護なしと表示されてしまいますが、マイクやカメラなどの機能へはアクセスすることができます。

おわりに

nginxを使用することで簡単に自己署名証明書を使用したhttps通信の実現と、Next.jsアプリケーションへの転送を実現することができました。

Let's Encryptなどの認証局の登場によってhttps通信が簡単に実現しやすくなったことは良いことだと思いますが、ブラウザ側もhttp通信を排除しようという動きが進んで、サクッと開発したい時に対応することが増えていくのは難しい点ですね。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1