GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。 NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは 別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
15 KiB
NodeSrv
Node.js WEBアプリを個別に開発し、既存の Dokploy 環境(AWS Lightsail上でセルフホスト稼働中)へデプロイ・運用するためのプロジェクト。Synology NASは開発機のローカルストレージ用途であり、アプリの実行基盤ではない。
構成
NodeSrv/
apps/
_template/ # 新規アプリのひな形(コピーして使う)
<app-name>/ # 実際の各アプリ
deploy/
dokploy.env.example # Dokploy接続情報のテンプレート(実値はdokploy.envに。gitignore済み)
AUTH_SECRETS.md # 認証基盤の機密情報(Client Secret等)。gitignore済み、リポジトリには含まれない
1アプリ = 1フォルダ = 1 Dokploy Application/Compose リソース。アプリ同士は完全に独立しており、片方の開発・再デプロイがもう片方に影響しない。
運用方針
- デプロイ先: Dokploy(AWS Lightsail上のセルフホストPaaS)
- Gitソース: 自前ホストのGitea(
https://git73.next-hd.net/mygit-admin/NodeSrv.git)経由でビルド - 公開ドメイン:
*.apps.next-hd.net配下(ワイルドカードAレコード登録済み。新規アプリは個別のDNS登録不要、<app-name>.apps.next-hd.netで命名しデプロイするだけでよい) - TLS証明書: Let's Encrypt(Traefikのcertresolverで自動発行、HTTP-01方式。新規サブドメインも初回アクセス時に自動発行される)
- 認証: デフォルトは認証なしで公開。 認証が必要なアプリのみ、下記「認証ゲートウェイ」章の手順でオプトインする(全アプリ共通の必須事項ではない)
新規アプリはまず認証なしの最小構成でデプロイし、稼働・疎通を確認してから、必要な場合のみ認証を追加する段階的な進め方を基本とする。
dokploy45/auth91/gate66等の既存インフラは next-hd.net 直下(ランダム数字命名)のまま。個別アプリ用の apps.next-hd.net サブゾーンとは名前空間を分離している。
新規アプリの作り方
apps/_templateをapps/<新アプリ名>としてコピーpackage.jsonのnameを変更、必要な依存関係を追加- ローカルで開発(詳細は
apps/_template/README.mdおよび各アプリの README を参照) docker-compose.yml内の以下3つを実際の値に置換(テンプレートのままで認証なし公開ができる。下記「ポートをports:で直接ホスト公開しない」ルールのみ厳守)your-app-name: Dockerサービス名・Traefikルーター識別子(内部識別子。外部には露出しない)yourapp.apps.next-hd.net: 公開ドメイン(先頭ラベルはyour-app-nameと一致させる必要はなく、自由に決めてよい)- ポート番号
- Giteaへpush → Dokployに登録しデプロイ(.claude/skills/dokploy-webapp/SKILL.md 参照)
- 認証が必要な場合のみ、下記「認証ゲートウェイ」章の手順を追加で適用
共通ルール
- Compose の Provider は必ず「Raw」を選ぶ(Dokploy標準の「Domains」タブは使わない)。Gitea自体もこの方式で稼働実績があり、後から認証ミドルウェアを追加する場合もシームレスに拡張できるため、無認証アプリでも統一して使う
- ポートを
ports:で直接ホスト公開しない。ports: - "3000:3000"のようにホストへポートを直接公開すると、Traefikを経由しない直アクセス経路が生まれる(将来認証を追加した場合の迂回経路にもなる)。必ずexposeを使い、dokploy-network経由でのみ到達可能にすること。
認証ゲートウェイ(oauth2-proxy + Keycloak)── 任意オプション
デフォルトでは適用しない。 特定のアプリに認証を必須化したい場合のみ、以下の手順で追加する。 アプリ側でログイン画面やOIDC処理を自前実装する必要はない。認証はTraefik層(oauth2-proxy経由)で強制される。
前提となる構成
- IdP: Keycloak(
https://auth91.next-hd.net、realm:nexthd) - 認証ゲートウェイ: oauth2-proxy(
https://gate66.next-hd.net、Dokploy上のapp-gatewayプロジェクトで稼働) - Cookieドメイン:
.next-hd.net(この配下のサブドメイン間でログインセッションが共有される=一度ログインすれば他アプリも再ログイン不要) - Dokploy管理画面:
https://dokploy45.next-hd.net
追加ルール
1. ドメインは必ず next-hd.net のサブドメインにする
Cookie共有の前提が .next-hd.net のため、別ドメイン・別TLD(例: next-hd.co.jp側や外部ドメイン)で公開するとSSOが機能しない。
2. _template の compose に認証ミドルウェアを1行追加する
apps/_template/docker-compose.yml(共通ルール通りRaw provider・手書きラベル)に、...-websecure ルーターへ以下の1行を追加するだけでよい。
- traefik.http.routers.your-app-name-websecure.middlewares=oauth-errors@file,oauth-auth@file
web(HTTPリダイレクト用)ルーターには追加しないこと(HTTP→HTTPSへの転送のみを担当させる)。
補足: 複数アプリで1つのHostを共有し
/<app名>パスプレフィックスで振り分ける方式(DNS登録の手間を減らす狙い)を検証中。確定後、この節に追記する。
ログインユーザー情報の取得方法
認証済みリクエストには、oauth2-proxyが以下のヘッダーを付与してアプリに転送する。
| ヘッダー名 | 内容 |
|---|---|
X-Auth-Request-User |
Keycloak上のユーザー名 |
X-Auth-Request-Email |
メールアドレス |
Node.js例:
const userEmail = req.headers['x-auth-request-email'];
const userName = req.headers['x-auth-request-user'];
Python (Flask) 例:
user_email = request.headers.get('X-Auth-Request-Email')
user_name = request.headers.get('X-Auth-Request-User')
これらのヘッダーは、Traefik/oauth2-proxyを正しく通過したリクエストにのみ付与される。アプリ側で改めてJWT検証等を行う必要はない(ただし本番運用でセキュリティ要件が上がった場合は、アプリ側でもヘッダーの信頼境界を見直すこと。ポート直公開さえしていなければTraefik経由以外の到達手段がないため、現状はこの前提で問題ない)。
ローカル開発時の注意
localhost でのローカル起動時はTraefik/oauth2-proxyを経由しないため、上記ヘッダーは存在しない。ローカル開発では以下のようなフォールバックを入れておくと開発しやすい。
const userEmail = req.headers['x-auth-request-email'] || 'dev-local@next-hd.co.jp';
機密情報の扱い
- Keycloakのクライアントシークレットやoauth2-proxyのcookie secret、SendGrid APIキー等は、このリポジトリやアプリのコード・
.envには書かない。値はAUTH_SECRETS.md(gitignore済み・リポジトリ非追跡)でのみ管理する。 - アプリ自体は認証ゲートウェイの設定を一切知る必要がない(ヘッダーを読むだけ)。
トラブルシューティング
| 事象 | 確認ポイント |
|---|---|
| ずっと401が返る/画面が真っ白 | oauth-errors@file がミドルウェアの1番目に指定されているか(oauth-errors@file,oauth-auth@file の順序を保つ) |
| ログインループになる | Cookieドメインが .next-hd.net になっているか、アプリのドメインが next-hd.net 配下か |
| 別アプリで再ログインを求められる | 初回ログインからのCookie有効期限切れ、またはドメインがnext-hd.net配下でない可能性 |
| X-Auth-Request-* ヘッダーが空 | ports: でポートを直接ホスト公開し、Traefikを迂回してアクセスしていないか確認 |
インフラ環境詳細
対象サーバー: Dokploy (dokploy45.next-hd.net) / Keycloak (auth91.next-hd.net)
mail-infra (postfix-relay)
Dokployプロジェクト「mail-infra」→サービス「postfix-relay」(Docker Compose、production環境)
- コンテナ名:
mailinfra-postfixrelay-jodrpy - 内部ホスト名:
postfix-relay(dokploy-networkの他コンテナから到達可能) - リッスンポート: 587(expose、外部公開なし)
- ネットワーク:
dokploy-network(external) - Compose環境変数:
ALLOWED_SENDER_DOMAINS=next-hd.co.jp、RELAYHOST="[smtp.sendgrid.net]:587"、RELAYHOST_USERNAME=apikey、RELAYHOST_PASSWORD=<AUTH_SECRETS.md参照>、POSTFIX_smtp_tls_security_level=encrypt、POSTFIX_smtpd_tls_security_level=none
Dokploy通知設定(Settings > Notifications)
- Name:
postfix-relay - SMTP Server:
postfix-relay/ Port:587 - Username:
noreply(ダミー値、認証は使用されません) - Password: ダミー値(画面上マスク済み、実際の認証には使われません)
- From Address / To Address: 設定値が
dokploy-admin@next-hd.co.jpにリセットされる挙動あり(編集ダイアログを開くたびに表示がリセットされるUI上の癖の可能性)。正しい値(From:no-reply@next-hd.co.jp、To:kenichiro.nogi@next-hd.co.jp)を維持したい場合は保存前に必ず確認。
Keycloak メール送信設定(nexthd レルム)
Realm settings > Email タブ
- Host:
postfix-relay/ Port:587 - SSL/StartTLS: OFF、Authentication: OFF
- From:
keycloak-admin@next-hd.co.jp
Keycloak クライアント「app-gateway」(nexthd レルム)
| 項目 | 値 |
|---|---|
| Client ID | app-gateway |
| Name | 個別アプリ認証ゲートウェイ |
| Client type | OpenID Connect / Confidential(Client authentication ON) |
| Authentication flow | Standard flow のみ |
| Valid redirect URIs | https://gate66.next-hd.net/oauth2/callback |
| Valid post logout redirect URIs | https://gate66.next-hd.net/* |
| Web origins | https://gate66.next-hd.net |
| Client Secret | AUTH_SECRETS.md参照 |
| Issuer URL | https://auth91.next-hd.net/realms/nexthd |
Dokploy「app-gateway」プロジェクト / oauth2-proxy サービス
- プロジェクト:
app-gateway(production環境) - サービス:
oauth2-proxy(コンテナ名:appgateway-oauth2proxy-y7xl6r) - 公開ドメイン:
https://gate66.next-hd.net(Container Port: 4180、HTTPS/Let's Encrypt) - Compose環境変数:
OAUTH2_PROXY_PROVIDER=keycloak-oidc、OAUTH2_PROXY_OIDC_ISSUER_URL=https://auth91.next-hd.net/realms/nexthd、OAUTH2_PROXY_CLIENT_ID=app-gateway、OAUTH2_PROXY_CLIENT_SECRET=<AUTH_SECRETS.md参照>、OAUTH2_PROXY_COOKIE_SECRET=<AUTH_SECRETS.md参照>、OAUTH2_PROXY_COOKIE_DOMAINS=.next-hd.net、OAUTH2_PROXY_WHITELIST_DOMAINS=.next-hd.net、OAUTH2_PROXY_REDIRECT_URL=https://gate66.next-hd.net/oauth2/callback、OAUTH2_PROXY_EMAIL_DOMAINS="*"、OAUTH2_PROXY_HTTP_ADDRESS=0.0.0.0:4180、OAUTH2_PROXY_UPSTREAMS=static://202、OAUTH2_PROXY_REVERSE_PROXY="true"、OAUTH2_PROXY_SET_XAUTHREQUEST="true"、OAUTH2_PROXY_SKIP_PROVIDER_BUTTON="true"
Traefikミドルウェア(/etc/dokploy/traefik/dynamic/middlewares.yml)
既存の redirect-to-https に加え、以下を追記済み(他アプリのルーターに oauth-auth ミドルウェアを適用することで認証を強制できる)。
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
permanent: true
oauth-auth:
forwardAuth:
address: https://gate66.next-hd.net/oauth2/auth
trustForwardHeader: true
authResponseHeaders:
- X-Auth-Request-User
- X-Auth-Request-Email
oauth-errors:
errors:
status:
- "401-403"
service: oauth-backend-svc
query: /?rd={url}
services:
oauth-backend-svc:
loadBalancer:
passHostHeader: false
servers:
- url: https://auth-redirect.apps.next-hd.net
statusRewritesは使っていない(2026-07-25判明)。Traefikのerrorsミドルウェアは、リダイレクト先のHTMLボディは反映するが、レスポンスのステータスコード自体は元のエラーコード(401)のまま保持する既知の制約がある(Traefik issue #10720)。ブラウザはステータスコードに関わらずHTMLボディをレンダリングするため、代わりにapps/auth-redirect(meta refreshでgate66.next-hd.net/oauth2/sign_inへ自動遷移する薄いページ)を用意し、oauth-errorsの転送先をここに向けることで自動リダイレクトを実現している。auth-redirect自体はwebappsproject配下の通常のCompose(composeId: 2OUXZISkrQ2Wk5uG86hcz)としてデプロイ済み。デバッグ用にauth-redirect.apps.next-hd.netでも単体公開している(認証ミドルウェアなし)。
Dokploy CLI(claude code for vscode からのデプロイ用)
- インストール:
npm install -g @dokploy/cli - 認証:
dokploy auth -u https://dokploy45.next-hd.net -t <APIトークン>(トークン値はAUTH_SECRETS.mdまたは発行時にコピーしたクリップボードを参照。チャットには貼らない) - Compose作成・デプロイの具体的なコマンド手順は .claude/skills/dokploy-webapp/SKILL.md 参照(新規Compose作成含め実地検証済み)。CLIのGET系コマンドは実装バグにより全滅するため、状態確認はSSH直接調査に頼る(同SKILL.md参照)。
アプリポータル(apps/app-portal)
webapps project配下の複数アプリを横断して起動/停止/再起動/バッチ手動実行/ログ確認を行う集中管理ポータル。設計の経緯・アーキテクチャは docs/superpowers/specs/2026-07-25-app-portal-design.md、実装計画は docs/superpowers/plans/2026-07-25-app-portal.md 参照。
- 公開ドメイン:
https://portal.apps.next-hd.net(認証ゲートウェイ必須 + アプリ層allowlist二段防御) - 各アプリをポータルに登録するには、
.env.exampleのPORTAL_*変数(apps/_template/README.md参照)をDokploy Environment画面で設定する - Dokploy tRPC APIを自前クライアント(
apps/app-portal/src/dokployClient.js)で直接呼び出している。CLIのGET系コマンドが実装バグで全滅する問題(上記「Dokploy CLI」章参照)の回避策の実例でもある
参考情報
- 認証ゲートウェイ:
https://gate66.next-hd.net(Dokployapp-gatewayプロジェクト、oauth2-proxyサービス) - Keycloak管理コンソール:
https://auth91.next-hd.net/admin/master/console/(realm:nexthd) - Keycloakクライアント:
app-gateway(Client Credentials方式、Standard flowのみ有効) - Dokploy管理画面:
https://dokploy45.next-hd.net