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>
334 lines
27 KiB
Markdown
334 lines
27 KiB
Markdown
# NodeSrv
|
||
|
||
Node.js WEBアプリを個別に開発し、既存の [Dokploy](https://dokploy.com/) 環境(AWS Lightsail上でセルフホスト稼働中)へデプロイ・運用するためのプロジェクト。Synology NASは開発機のローカルストレージ用途であり、アプリの実行基盤ではない。
|
||
|
||
## 構成
|
||
|
||
```
|
||
NodeSrv/
|
||
apps/
|
||
_template/ # 新規アプリのひな形(コピーして使う)
|
||
<app-name>/ # 実際の各アプリ
|
||
deploy/
|
||
dokploy.env.example # Dokploy接続情報のテンプレート(実値はdokploy.envに。gitignore済み)
|
||
lightsail.env.example # AWS Lightsail接続情報のテンプレート(実値はlightsail.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` サブゾーンとは名前空間を分離している。
|
||
|
||
## 新規アプリの作り方
|
||
|
||
1. `apps/_template` を `apps/<新アプリ名>` としてコピー
|
||
2. `package.json` の `name` を変更、必要な依存関係を追加
|
||
3. ローカルで開発(詳細は `apps/_template/README.md` および各アプリの README を参照)
|
||
4. `docker-compose.yml` 内の以下3つを実際の値に置換(テンプレートのままで認証なし公開ができる。下記「ポートを`ports:`で直接ホスト公開しない」ルールのみ厳守)
|
||
- `your-app-name`: Dockerサービス名・Traefikルーター識別子(内部識別子。外部には露出しない)
|
||
- `yourapp.apps.next-hd.net`: 公開ドメイン(先頭ラベルは`your-app-name`と一致させる必要はなく、自由に決めてよい)
|
||
- ポート番号
|
||
5. Giteaへpush → Dokployに登録しデプロイ([.claude/skills/dokploy-webapp/SKILL.md](.claude/skills/dokploy-webapp/SKILL.md) 参照)
|
||
6. 認証が必要な場合のみ、下記「認証ゲートウェイ」章の手順を追加で適用
|
||
|
||
### 共通ルール
|
||
|
||
- **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行を追加するだけでよい。
|
||
|
||
```yaml
|
||
- 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例:**
|
||
|
||
```js
|
||
const userEmail = req.headers['x-auth-request-email'];
|
||
const userName = req.headers['x-auth-request-user'];
|
||
```
|
||
|
||
**Python (Flask) 例:**
|
||
|
||
```python
|
||
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を経由しないため、上記ヘッダーは存在しない。ローカル開発では以下のようなフォールバックを入れておくと開発しやすい。
|
||
|
||
```js
|
||
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`)
|
||
|
||
### インフラ全体サマリー
|
||
|
||
| 項目 | 値 |
|
||
|---|---|
|
||
| クラウド | AWS Lightsail(東京リージョン ap-northeast-1) |
|
||
| インスタンス名 | `nexthd-node-a-keycloak` |
|
||
| インスタンススペック | 4GB RAM/2vCPU/80GB SSD、Ubuntu 24.04 LTS |
|
||
| 静的IP | `52.193.142.134` |
|
||
| デプロイ管理基盤 | Dokploy(Docker Composeベース、Traefikリバースプロキシ内蔵) |
|
||
|
||
サブドメインには推測されにくいランダムな数字を付与する方針(`dokploy45`、`auth91`、`gate66`、`git73`等)。個別アプリ用の`apps.next-hd.net`サブゾーンとは名前空間を分離している。
|
||
|
||
| ドメイン | 用途 |
|
||
|---|---|
|
||
| `dokploy45.next-hd.net` | Dokploy管理画面 |
|
||
| `auth91.next-hd.net` | Keycloak(realm: `nexthd`) |
|
||
| `gate66.next-hd.net` | 個別アプリ用認証ゲートウェイ(oauth2-proxy) |
|
||
| `git73.next-hd.net` | Gitea(Dokployのビルドソース) |
|
||
| `*.apps.next-hd.net` | 個別開発アプリの公開先(ワイルドカードDNS) |
|
||
|
||
| Dokployプロジェクト | environment | サービス |
|
||
|---|---|---|
|
||
| `auth-infra` | production | `keycloak`(内部名 `auth-keycloak-yyjuz6`) |
|
||
| `mail-infra` | production | `postfix-relay` |
|
||
| `app-gateway` | production | `oauth2-proxy`(内部名 `appgateway-oauth2proxy-y7xl6r`) |
|
||
| `git-infra` | production | `gitea`(projectId `VGqtH-ONBrAObGLDANJb1` / environmentId `qdsi2v5W39qWHqYpmT21c`、composeId `jMFGNMUjbwzqanyo58rkD`、Dokploy-Gitea連携giteaId `O5-CqLQwVdlzXw3KfmN-8`) |
|
||
| `webapps` | production | 個別開発アプリ一式(projectId `3T-drY1Q377JcLeTiNTDK` / environmentId `Cm0HjMIFyl11UdIcIGRy8`) |
|
||
|
||
サーバーOS初期設定(スワップ追加、ufw、fail2ban、自動セキュリティアップデート等)とDokployインストール自体は初回構築時に完了済み。再構築が必要な場合の手順は過去の作業ログ(Cowork上の対話記録)を参照すること。
|
||
|
||
### Keycloak
|
||
|
||
- Dokployプロジェクト: `auth-infra` / environment: `production`
|
||
- 管理コンソール: `https://auth91.next-hd.net/admin/master/console/`
|
||
- realm構成: `master`(Keycloak自体の管理者用)、`nexthd`(業務ユーザー・アプリ連携用。LINE WORKS SSO・app-gatewayのOIDCクライアントはすべてこちら)
|
||
- DB: PostgreSQL 16(同一Compose内、ボリューム永続化)
|
||
- 構築時のトラブルと対応: `command: start --optimized`は未ビルドイメージ非対応のため`start`に変更、`KC_DB_PASSWORD`と`POSTGRES_PASSWORD`不一致でクラッシュループ、管理コンソールのmixed content問題は`KC_PROXY: edge`(非推奨)を`KC_PROXY_HEADERS: xforwarded` + `KC_HTTP_ENABLED: true`に変更して解消
|
||
|
||
### 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`
|
||
- `POSTFIX_smtpd_tls_security_level=none`は内部ネットワーク(`dokploy-network`)限定の通信が前提の意図的な設定(自己署名証明書によるTLSエラー回避のため)。外部(さくらVPS等)から使う場合はポート587の外部公開・SASL認証追加・TLS再設計が別途必要(未実施)
|
||
|
||
### 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"`、`OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL="true"`(下記LINE WORKS SSO連携の理由により必須)
|
||
- このComposeは`sourceType: Raw`(GeneralタブのCompose Fileに直接記述)で、`env_file`指定はない。**Dokploy Environment画面(.envファイル)に変数を設定しても一切反映されない**ため、環境変数を変更する場合は必ずCompose本体の`environment:`ブロックを直接編集すること(VSCode拡張`devpanda0.dokploy`等で編集可能)
|
||
|
||
### LINE WORKS SSO連携(Keycloak Identity Provider)
|
||
|
||
「全社システム統合・AI活用基盤構想」(LINE WORKSをIdP、KeycloakをID連携ハブとする構想)の第一段階。LINE WORKS ⇔ Keycloak間の連携は完了・稼働中。
|
||
|
||
**LINE WORKS側(Developer Console > SSO > WORKS as IdP)**: SAML App「Keycloak SSO」を登録・有効化済み。
|
||
|
||
| 項目 | 値 |
|
||
|---|---|
|
||
| ACS URL | `https://auth91.next-hd.net/realms/nexthd/broker/lineworks/endpoint` |
|
||
| SP Issuer(Entity Id) | `https://auth91.next-hd.net/realms/nexthd` |
|
||
| Name ID | EMAIL固定 |
|
||
| SSO URL(LINE WORKS発行) | `https://auth.worksmobile.com/saml2/idp/next-hd.co.jp` |
|
||
| Response Issuer(LINE WORKS発行) | `https://auth.worksmobile.com/saml2/next-hd.co.jp` |
|
||
|
||
**Keycloak側(nexthdレルム、Identity Providers > SAML v2.0)**: Alias `lineworks`。証明書は base64本文のみ貼り付け(`BEGIN/END CERTIFICATE`のヘッダー行を含めると改行崩れでパースエラーになるため含めないこと)。
|
||
|
||
**既知の注意点**:
|
||
|
||
- LINE WORKSはSP-initiated SSOのみ対応(IdP-initiatedは非対応)。必ずKeycloakのログイン画面(「LINE WORKSでログイン」ボタン)からログインを開始する必要がある
|
||
- LINE WORKS側SAML Apps一覧の「TEST」ボタンは有効化後も404になるが、実際のSP-initiatedログインフローには影響しない(LINE WORKS側のテスト機能自体の不具合と推測)
|
||
- LINE WORKS SAMLフェデレーション経由のKeycloakユーザーは`email_verified`クレームがfalse/未設定になる。oauth2-proxyはデフォルトでこれを拒否し`Error redeeming code during OAuth2 callback: email in id_token isn't verified`で500になるため、上記の`OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL=true`が必須(2026-07-26判明)
|
||
- LINE WORKSのSAML応答にはメールアドレス以外の属性(氏名等)が含まれないため、新規ユーザー初回ログイン時に毎回Keycloakの「Update Account Information」画面でプロフィール手動入力が発生する。運用開始前にRealm settings > User profileでEmail/First name/Last nameを必須項目から外すか、LINE WORKS側属性マッピングの可否を確認すること(**未対応**)
|
||
|
||
### Traefikミドルウェア(`/etc/dokploy/traefik/dynamic/middlewares.yml`)
|
||
|
||
既存の `redirect-to-https` に加え、以下を追記済み(他アプリのルーターに `oauth-auth` ミドルウェアを適用することで認証を強制できる)。
|
||
|
||
```yaml
|
||
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"
|
||
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](https://github.com/traefik/traefik/issues/10720))。ブラウザはステータスコードに関わらずHTMLボディをレンダリングするため、代わりに`apps/auth-redirect`(`meta refresh`で`gate66.next-hd.net/oauth2/sign_in`へ自動遷移する薄いページ)を用意し、`oauth-errors`の転送先をここに向けることで自動リダイレクトを実現している。`auth-redirect`自体は`webapps`project配下の通常のCompose(composeId: `2OUXZISkrQ2Wk5uG86hcz`)としてデプロイ済み。デバッグ用に`auth-redirect.apps.next-hd.net`でも単体公開している(認証ミドルウェアなし)。
|
||
|
||
**`status`は`401`のみを対象にする(`401-403`にしない)**(2026-07-26判明)。アプリ側が独自に返す`403`(例: app-portalのallowlist拒否)まで`oauth-errors`が「未ログイン」として拾ってしまうと、ログイン画面へ誘導→セッション有効なので即座に302で戻る→また403→また誘導…という無限リダイレクトループになる。oauth2-proxy自体は`401`か`202`しか返さないため、`403`を対象から外してもoauth2-proxy側の挙動には影響しない。403はアプリ側の権限拒否として、Traefikを素通りしてブラウザにそのまま表示させること。
|
||
|
||
### 認証ゲートウェイPoC関連の識別子
|
||
|
||
`authgw-poc`(PoC用アプリ)と`auth-redirect`のDokploy上の識別子。トラブル調査時の参照用。
|
||
|
||
| 項目 | 値 |
|
||
|---|---|
|
||
| authgw-poc composeId | `VVUKrFGLIWN5NxS-h3Gax` |
|
||
| authgw-poc公開ドメイン | `poc-demo.apps.next-hd.net`(認証ゲートウェイ経由) |
|
||
| auth-redirect composeId | `2OUXZISkrQ2Wk5uG86hcz` |
|
||
| auth-redirect公開ドメイン | `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](.claude/skills/dokploy-webapp/SKILL.md) 参照(新規Compose作成含め実地検証済み)
|
||
- **CLIのGET系コマンドは実装バグにより全滅する**(`@dokploy/cli` 0.29.4、`compose one`・`load-services`・`get-converted-compose`・`deployment all-by-compose`等、パラメータを取るGETコマンド全般。CLI内部の`apiGet`がtRPC入力を`{json: ...}`でラップせず渡しているため、サーバー側で400エラーになる。パラメータなしのコマンド(`project all`等)は影響を受けず、POST系コマンド(`save-environment`等)も正しく動作する)。回避策として、CLIのconfig.json(認証情報)を読み取り、正しい形式でtRPCエンドポイントを直接fetchする一時スクリプトを使う。取得結果に機密情報(gitea clientSecret・APIキー等)が含まれることがあるため、内容は画面に出さずファイル経由で必要な値だけ抽出すること。
|
||
|
||
## アプリポータル(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」章参照)の回避策の実例でもある
|
||
- AWS Lightsailインスタンス操作用に`apps/app-portal/src/lightsailClient.js`と開発者マシン用CLI`apps/app-portal/scripts/lightsail-cli.js`を用意している(list/status/create/delete/start/stop/reboot/snapshot)。認証情報は`deploy/lightsail.env`(gitignore済み)に記入し、`apps/app-portal/`から`npm run lightsail -- <command>`、または`node --env-file=../../deploy/lightsail.env scripts/lightsail-cli.js <command>`で実行する。本番サーバーからは呼び出されない開発用ツールのため、SDK(`@aws-sdk/client-lightsail`)はdevDependencies扱い
|
||
|
||
### allowlist管理画面(`/admin`)
|
||
|
||
`https://portal.apps.next-hd.net/admin` から、ポータル本体へのアクセスを許可するメールアドレス一覧(allowlist)をブラウザ上で追加・削除できる。設計・実装計画は `docs/superpowers/specs/2026-07-26-allowlist-admin-design.md` / `docs/superpowers/plans/2026-07-26-allowlist-admin.md` 参照。
|
||
|
||
- **認証方式が異なる**: `/admin`配下はKeycloak/LINE WORKS SSOを経由せず、Master Key(`PORTAL_MASTER_KEY`環境変数)のみで保護される。Traefikで`/admin`用の専用ルーター(priority高め)を用意し、oauth2-proxy認証をバイパスしている
|
||
- ログイン後はセッションcookie(署名鍵は`PORTAL_MASTER_KEY`を流用、有効期限24時間)で認証状態を保持する
|
||
- allowlistの実データは`apps/app-portal/data/allowlist.json`にファイル永続化され、Dockerボリューム(`app_portal_data`)でコンテナ再作成をまたいで保持される。環境変数`PORTAL_ALLOWED_EMAILS`は、このファイルが存在しない初回起動時のみ使われる初期値
|
||
- `PORTAL_MASTER_KEY`は`AUTH_SECRETS.md`同様の機密情報として扱い、Dokploy Environment画面でのみ設定する(値をチャットやコードに出さない)
|
||
|
||
## 未着手タスク
|
||
|
||
- **LINE WORKS SSO ⇔ プリザンター連携**(「全社システム統合・AI活用基盤構想」の本題): Keycloak(`nexthd`レルム)にプリザンター用SAMLクライアントを作成 → さくらVPS上の既存プリザンター(.NET Core版)の`Implem.Pleasanter/App_Data/Parameters/Authentication.json`にSAML SP設定を追加 → LINE WORKS → Keycloak → プリザンターの一連のSSOフロー動作確認、の3ステップが未着手。SP Entity ID・ACS URL等はプリザンターの実ドメイン確定後に設定すること(現時点で実ドメイン未確定)
|
||
- LINE WORKS新規ユーザー初回ログイン時のプロフィール入力画面の扱い(上記LINE WORKS SSO連携の章参照)を運用開始前に確定させること
|
||
- Keycloakの`nexthd`レルムにパスワードリセット等のメール通知設定(`master`レルムと同様のSMTP設定)が必要かどうか未検証。LINE WORKSフェデレーションユーザーはLINE WORKS側で認証が完結するため優先度は低い
|
||
- 複数アプリで1つのHostを共有し`/<app名>`パスプレフィックスで振り分ける方式(DNS登録の手間を減らす狙い)を検証中。確定したら「認証ゲートウェイ」章に追記する
|
||
- `auth-redirect`のデバッグ用ドメイン公開(`auth-redirect.apps.next-hd.net`、認証なし)を残したままにしている。運用上不要になったら`docker-compose.yml`のラベル削除を検討
|
||
|
||
## 参考情報
|
||
|
||
- 認証ゲートウェイ: `https://gate66.next-hd.net`(Dokploy `app-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`
|
||
|
||
### 外部ドキュメント
|
||
|
||
- [Dokploy公式ドキュメント](https://docs.dokploy.com/)
|
||
- [LINE WORKS Developers - LINE WORKS を IdP とした SSO](https://developers.worksmobile.com/jp/docs/sso-idp)
|
||
- [LINE WORKS Developers - Service Provider 情報の登録](https://developers.worksmobile.com/jp/docs/sso-idp-register)
|
||
- [Keycloak公式ドキュメント(Identity Brokering)](https://www.keycloak.org/docs/latest/server_admin/)
|
||
- [oauth2-proxy公式ドキュメント(Traefik連携)](https://oauth2-proxy.github.io/oauth2-proxy/configuration/integrations/traefik/)
|
||
- [Pleasanterユーザーマニュアル](https://pleasanter.org/en/manual)
|