🕌

ローカルのWeb開発でTLSとドメインを得るやり方

2024/02/15に公開

結論

ngrokを使います。
この後はdocker composeを使ってフロントとバックエンドを統合する方法を書いていきます。

目的

ローカルで開発している時にインターネットに晒したいことがあります。

  • OAuth認証のコールバックURLでTLSが要求される
  • スマートフォンの実機で確認したい

クラウドやVPSにデプロイすればいいんですが、ちょっと面倒です。

ngrok

ngrokコマンドをインストールして実行すると、その場でドメインが発行されてTLSで動作するようになります。指定してホストとポートにプロキシーしてくれます。
アカウント登録して認証キーを発行などありますが、詳しいことはぐぐってください。

docker compose

ローカルにインストールしたくない主義なので、開発用のdocker composeに組み込みます。
WebはフロントをVue.js,バックエンドをRustのaxumで動かします。
フロントは「/」に、バックエンドは「/api」に流れるようにnginxで制御します。
バックエンドは起動後、コンテナに入って手動でサーバーを起動しています。
ディレクトリー構成は以下のようになります。

- apps
  - api
  - frontend
- development
  .env
  docker-compose.yaml
  Dockerfile
  nginx.conf
  ngrok.conf 
docker-compose.yaml
services:
  nginx:
    image: nginx:latest
    ports:
      - '9000:80'
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - api
      - frontend

  ngrok:
    image: ngrok/ngrok:latest
    restart: unless-stopped
    environment:
      NGROK_AUTHTOKEN: ${NGROK_AUTHTOKEN}
    command:
      - "start"
      - "--all"
      - "--config"
      - "/etc/ngrok.yml"
    volumes:
      - ./ngrok.yml:/etc/ngrok.yml
    ports:
      - 4040:4040

  frontend:
    image: node:20.11.0-bookworm
    working_dir: /app
    volumes:
      - ../apps/frontend:/app
    command: ["npm", "run", "dev", "--", "--host"]
    ports:
      - 5173:5173

  api:
    build:
      context: .
    environment:
      CLIENT_KEY: ${CLIENT_KEY}
      CLIENT_SECRET: ${CLIENT_SECRET}
      CARGO_TARGET_DIR: /tmp/target
      CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
      PG_URL: postgres://user:pass@db:5432/web
    volumes:
      - ../apps/api:/app
      - sample_web_cargo_cache:/usr/local/cargo/registry
      - sample_web_target_cache:/tmp/target
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    working_dir: /app
    security_opt:
      - seccomp:unconfined

  db:
    image: postgres:16
    environment:
      - POSTGRES_DB=web
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - TZ=Asia/Tokyo
      - PGTZ=Asia/Tokyo
    ports:
      - 5432:5432
    volumes:
      - sample_web_postgresql_data:/var/lib/postgresql/data

volumes:
  sample_web_postgresql_data:
  sample_web_cargo_cache:
  sample_web_target_cache:
Dockerfile
FROM rust:1.75

RUN apt -y update && apt -y install musl-tools libssl-dev pkg-config build-essential

RUN rustup update && \
  cargo install cargo-watch && \
  rustup component add rustfmt clippy
nginx.conf
worker_processes auto;

events {
  worker_connections 1024;
}

http {
  server {
    listen 80;

    location /api {
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $http_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 $http_x_forwarded_proto;
      real_ip_header X-Forwarded-For;
      real_ip_recursive on;

      proxy_pass http://api:3000;
    }

    location / {
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $http_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 $http_x_forwarded_proto;
      real_ip_header X-Forwarded-For;
      real_ip_recursive on;

      proxy_pass http://frontend:5173/;
    }
  }
}
ngrok.yaml
version: "2"
tunnels:
  website:
    proto: http
    addr: nginx:80
    host_header: rewrite
.env
NGROK_AUTHTOKEN=xxx
CLIENT_KEY=xxx
CLIENT_SECRET=xxx

まとめ

これでドメイン付きでTLSで外部からアクセスできるようになります。実は想定してなかったメリットとしてVue.jsのホットリロードが効きました。実機で直ぐに反映されるのはちょっと感動します。
またいくつかデメリットもありました。

  • 初回だけ確認ページが出る
  • ngrokが起動する度にドメインが変わってしまう。

最初のものはデモとか実機確認なのであまり影響が無いです。後のはOAuth認証のコールバックURLでは不便です。毎回修正するのもありなんですが、サービスによってはコールバックURLを変更しても承認レビューが必要になります。
今はなるべくngrokだけは再起動しないようにしてます。または自分で管理しているドメインがあるならCNAMEを使って調整しても良いと思います。 追記(2024/02/15) CNAMEでやるには有料プランに入る必要がありました。

Discussion