From 76f43cea9b762fb3981aabbc82f7786778774f3f Mon Sep 17 00:00:00 2001 From: gbpark Date: Fri, 24 Apr 2026 19:15:06 +0900 Subject: [PATCH] =?UTF-8?q?DB=20=EC=9D=B4=EB=A6=84=20vexplor=20=E2=86=92?= =?UTF-8?q?=20invyone=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - application.yml, k8s configmap, docker-compose 4종: SPRING_DATASOURCE_URL path - provisioning 코드: {prefix}_vexplor → {prefix}_invyone 테넌트 DB 네이밍 규칙 - 프론트 마법사: Step1Basic, Step4Run 미리보기 라벨 - CompanyAccordionRow: 기본 DB 이름 포맷 - 마이그레이션/멀티테넌시 문서 동기화 - Traefik 와일드카드 설정 산출물 보관 (notes/) 비밀번호(vexplor0909!!) 및 역사 기록 문서(INVYONE_CONCEPT, DDD1542, test-output, dashboard-runtime-fixes) 는 의도적으로 미변경. --- .../CompanyProvisioningService.java | 6 +-- .../provisioning/ProvisioningController.java | 4 +- .../erp/provisioning/ProvisioningStatus.java | 2 +- .../src/main/resources/application.yml | 2 +- db/migrate_company13_export.sh | 2 +- db/migrations/RUN_079_MIGRATION.md | 8 ++-- db/migrations/RUN_080_MIGRATION.md | 4 +- db/migrations/RUN_081_MIGRATION.md | 2 +- docker-compose.backend.win.yml | 2 +- docker/deploy/docker-compose.yml | 2 +- docker/dev/docker-compose.backend.mac.yml | 2 +- docker/prod/docker-compose.backend.prod.yml | 2 +- docs/MULTI_TENANCY_ARCHITECTURE.md | 18 ++++---- .../provisioning/CompanyAccordionRow.tsx | 2 +- .../admin/provisioning/wizard/Step1Basic.tsx | 4 +- .../admin/provisioning/wizard/Step4Run.tsx | 2 +- k8s/configmap.yaml | 4 +- .../2026-04-24-company-mgmt-ui-schema.md | 6 +-- .../docker-compose.yml | 44 +++++++++++++++++++ .../invyone-tenant.yml | 35 +++++++++++++++ 20 files changed, 116 insertions(+), 37 deletions(-) create mode 100644 notes/gbpark/2026-04-24-traefik-wildcard/docker-compose.yml create mode 100644 notes/gbpark/2026-04-24-traefik-wildcard/invyone-tenant.yml diff --git a/backend-spring/src/main/java/com/erp/provisioning/CompanyProvisioningService.java b/backend-spring/src/main/java/com/erp/provisioning/CompanyProvisioningService.java index e03be17a..a55b9a08 100644 --- a/backend-spring/src/main/java/com/erp/provisioning/CompanyProvisioningService.java +++ b/backend-spring/src/main/java/com/erp/provisioning/CompanyProvisioningService.java @@ -24,7 +24,7 @@ import java.util.UUID; * * 6 단계: * 1. REGISTER_META — COMPANY_MNG 에 db_status='provisioning' 으로 row 선반영 (initiate) - * 2. CREATE_DATABASE — CREATE DATABASE "{prefix}_vexplor" + * 2. CREATE_DATABASE — CREATE DATABASE "{prefix}_invyone" * 3. COPY_SCHEMA — pg_dump --schema-only | psql * 4. COPY_DATA — 선택 + 필수 그룹의 테이블들 JDBC 복사 * 5. CREATE_ADMIN — user_info 에 {prefix}_admin INSERT (BCrypt) @@ -53,7 +53,7 @@ public class CompanyProvisioningService { private String metaDbName() { int slash = metaJdbcUrl.lastIndexOf('/'); - if (slash < 0) return "vexplor"; + if (slash < 0) return "invyone"; String tail = metaJdbcUrl.substring(slash + 1); int q = tail.indexOf('?'); return q < 0 ? tail : tail.substring(0, q); @@ -63,7 +63,7 @@ public class CompanyProvisioningService { public ProvisioningStatus initiate(Map req) { String companyCode = (String) req.get("company_code"); String dbPrefix = (String) req.get("db_prefix"); - String dbName = dbPrefix + "_vexplor"; + String dbName = dbPrefix + "_invyone"; String subdomain = (String) req.get("subdomain"); // 템플릿 그룹 수 집계: 필수(3) + 선택된 optional diff --git a/backend-spring/src/main/java/com/erp/provisioning/ProvisioningController.java b/backend-spring/src/main/java/com/erp/provisioning/ProvisioningController.java index abc21851..5dba9ffb 100644 --- a/backend-spring/src/main/java/com/erp/provisioning/ProvisioningController.java +++ b/backend-spring/src/main/java/com/erp/provisioning/ProvisioningController.java @@ -99,7 +99,7 @@ public class ProvisioningController { if (dbPrefix != null) { boolean formatOk = isValidDbPrefix(dbPrefix); - String dbName = dbPrefix + "_vexplor"; + String dbName = dbPrefix + "_invyone"; boolean exists = false; if (formatOk) { Map p = new HashMap<>(); @@ -161,7 +161,7 @@ public class ProvisioningController { "error", "invalid_format", "field", "db_prefix")); } // 중복 - String dbName = dbPrefix + "_vexplor"; + String dbName = dbPrefix + "_invyone"; if (sqlSession.selectOne("provisioning.existsCompanyCode", Map.of("company_code", companyCode)) != null) { return ResponseEntity.status(409).body(Map.of("error", "duplicate", "field", "company_code")); } diff --git a/backend-spring/src/main/java/com/erp/provisioning/ProvisioningStatus.java b/backend-spring/src/main/java/com/erp/provisioning/ProvisioningStatus.java index d1b667ff..e96c3958 100644 --- a/backend-spring/src/main/java/com/erp/provisioning/ProvisioningStatus.java +++ b/backend-spring/src/main/java/com/erp/provisioning/ProvisioningStatus.java @@ -17,7 +17,7 @@ public class ProvisioningStatus { private String id; /** 생성 요청한 회사 코드 */ private String companyCode; - /** 생성 대상 DB 이름 (예: qnc_vexplor) */ + /** 생성 대상 DB 이름 (예: qnc_invyone) */ private String dbName; /** 서브도메인 */ private String subdomain; diff --git a/backend-spring/src/main/resources/application.yml b/backend-spring/src/main/resources/application.yml index f5cad107..8481f00c 100644 --- a/backend-spring/src/main/resources/application.yml +++ b/backend-spring/src/main/resources/application.yml @@ -14,7 +14,7 @@ spring: jackson: default-property-inclusion: always datasource: - url: jdbc:postgresql://183.99.177.40:5432/vexplor + url: jdbc:postgresql://183.99.177.40:5432/invyone username: postgres password: "vexplor0909!!" driver-class-name: org.postgresql.Driver diff --git a/db/migrate_company13_export.sh b/db/migrate_company13_export.sh index fc96f04a..25ee7901 100755 --- a/db/migrate_company13_export.sh +++ b/db/migrate_company13_export.sh @@ -11,7 +11,7 @@ SOURCE_HOST="localhost" SOURCE_PORT="5432" -SOURCE_DB="vexplor" +SOURCE_DB="invyone" SOURCE_USER="postgres" TARGET_HOST="대상_호스트" diff --git a/db/migrations/RUN_079_MIGRATION.md b/db/migrations/RUN_079_MIGRATION.md index 3d398fdc..b0ae393d 100644 --- a/db/migrations/RUN_079_MIGRATION.md +++ b/db/migrations/RUN_079_MIGRATION.md @@ -14,7 +14,7 @@ Phase 1 은 **라우팅 no-op** 단계 — 컬럼만 추가, 실제 라우팅은 | 컬럼 | 타입 | 설명 | |---|---|---| -| `DB_NAME` | VARCHAR(64) | 실제 DB 이름 (예: `qnc_vexplor`). Phase 3 이전엔 NULL 허용 | +| `DB_NAME` | VARCHAR(64) | 실제 DB 이름 (예: `qnc_invyone`). Phase 3 이전엔 NULL 허용 | | `SUBDOMAIN` | VARCHAR(64) | 접속 서브도메인 (예: `qnc`). UNIQUE | | `DB_HOST` | VARCHAR(128) | DB 서버 호스트 (향후 분산 대비). 기본 NULL | | `DB_STATUS` | VARCHAR(20) | `provisioning` / `schema_copied` / `admin_created` / `active` / `failed` / `suspended`. 기본 `active` | @@ -44,13 +44,13 @@ CREATE UNIQUE INDEX IF NOT EXISTS UX_COMPANY_MNG_SUBDOMAIN ## 실행 방법 ### 방법 1: DBeaver / pgAdmin -1. `vexplor` DB 연결 +1. `invyone` DB 연결 2. 위 SQL 블록 복사 & 실행 3. 확인 쿼리 돌려서 컬럼 생성 여부 확인 ### 방법 2: psql ```bash -psql -h 183.99.177.40 -U postgres -d vexplor <<'SQL' +psql -h 183.99.177.40 -U postgres -d invyone <<'SQL' ALTER TABLE COMPANY_MNG ADD COLUMN IF NOT EXISTS DB_NAME VARCHAR(64), ADD COLUMN IF NOT EXISTS SUBDOMAIN VARCHAR(64), @@ -99,6 +99,6 @@ ALTER TABLE COMPANY_MNG ## 체크리스트 -- [ ] `vexplor` DB 에 위 SQL 실행 +- [ ] `invyone` DB 에 위 SQL 실행 - [ ] 확인 쿼리 1, 2, 3 모두 통과 - [ ] `SELECT * FROM COMPANY_MNG LIMIT 1;` 로 기존 데이터 정상 조회 확인 diff --git a/db/migrations/RUN_080_MIGRATION.md b/db/migrations/RUN_080_MIGRATION.md index 8dc2b07a..75653e55 100644 --- a/db/migrations/RUN_080_MIGRATION.md +++ b/db/migrations/RUN_080_MIGRATION.md @@ -26,11 +26,11 @@ CREATE UNIQUE INDEX IF NOT EXISTS UX_COMPANY_MNG_DB_NAME ## 실행 방법 ### DBeaver / pgAdmin -위 SQL 블록을 `vexplor` DB 에 실행. +위 SQL 블록을 `invyone` DB 에 실행. ### psql ```bash -psql -h 183.99.177.40 -U postgres -d vexplor <<'SQL' +psql -h 183.99.177.40 -U postgres -d invyone <<'SQL' CREATE UNIQUE INDEX IF NOT EXISTS UX_COMPANY_MNG_DB_NAME ON COMPANY_MNG (DB_NAME) WHERE DB_NAME IS NOT NULL; diff --git a/db/migrations/RUN_081_MIGRATION.md b/db/migrations/RUN_081_MIGRATION.md index 5c2f2cea..ee463b79 100644 --- a/db/migrations/RUN_081_MIGRATION.md +++ b/db/migrations/RUN_081_MIGRATION.md @@ -39,7 +39,7 @@ ALTER TABLE COMPANY_MNG ## 실행 ```bash -psql -h 183.99.177.40 -U postgres -d vexplor <<'SQL' +psql -h 183.99.177.40 -U postgres -d invyone <<'SQL' ALTER TABLE COMPANY_MNG ADD COLUMN IF NOT EXISTS PLAN VARCHAR(20) DEFAULT 'Starter', ADD COLUMN IF NOT EXISTS INDUSTRY VARCHAR(50), diff --git a/docker-compose.backend.win.yml b/docker-compose.backend.win.yml index 6885abdd..1f51ec05 100644 --- a/docker-compose.backend.win.yml +++ b/docker-compose.backend.win.yml @@ -12,7 +12,7 @@ services: environment: - SPRING_PROFILES_ACTIVE=dev - SERVER_PORT=8081 - - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/vexplor + - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/invyone - SPRING_DATASOURCE_USERNAME=postgres - SPRING_DATASOURCE_PASSWORD=vexplor0909!! - JWT_SECRET=ilshin-plm-super-secret-jwt-key-2024 diff --git a/docker/deploy/docker-compose.yml b/docker/deploy/docker-compose.yml index 0d890d7b..467b06e6 100644 --- a/docker/deploy/docker-compose.yml +++ b/docker/deploy/docker-compose.yml @@ -11,7 +11,7 @@ services: environment: SPRING_PROFILES_ACTIVE: prod SERVER_PORT: "8081" - SPRING_DATASOURCE_URL: jdbc:postgresql://183.99.177.40:5432/vexplor + SPRING_DATASOURCE_URL: jdbc:postgresql://183.99.177.40:5432/invyone SPRING_DATASOURCE_USERNAME: postgres SPRING_DATASOURCE_PASSWORD: "vexplor0909!!" JWT_SECRET: ilshin-plm-super-secret-jwt-key-2024 diff --git a/docker/dev/docker-compose.backend.mac.yml b/docker/dev/docker-compose.backend.mac.yml index 9b418a35..43ed6261 100644 --- a/docker/dev/docker-compose.backend.mac.yml +++ b/docker/dev/docker-compose.backend.mac.yml @@ -12,7 +12,7 @@ services: environment: - SPRING_PROFILES_ACTIVE=dev - SERVER_PORT=8082 - - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/vexplor + - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/invyone - SPRING_DATASOURCE_USERNAME=postgres - SPRING_DATASOURCE_PASSWORD=vexplor0909!! - JWT_SECRET=ilshin-plm-super-secret-jwt-key-2024 diff --git a/docker/prod/docker-compose.backend.prod.yml b/docker/prod/docker-compose.backend.prod.yml index cdfab86b..eccaba28 100644 --- a/docker/prod/docker-compose.backend.prod.yml +++ b/docker/prod/docker-compose.backend.prod.yml @@ -12,7 +12,7 @@ services: environment: - SPRING_PROFILES_ACTIVE=prod - SERVER_PORT=8081 - - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/vexplor + - SPRING_DATASOURCE_URL=jdbc:postgresql://183.99.177.40:5432/invyone - SPRING_DATASOURCE_USERNAME=postgres - SPRING_DATASOURCE_PASSWORD=vexplor0909!! - JWT_SECRET=ilshin-plm-super-secret-jwt-key-2024 diff --git a/docs/MULTI_TENANCY_ARCHITECTURE.md b/docs/MULTI_TENANCY_ARCHITECTURE.md index ee8eada7..76007ce0 100644 --- a/docs/MULTI_TENANCY_ARCHITECTURE.md +++ b/docs/MULTI_TENANCY_ARCHITECTURE.md @@ -11,9 +11,9 @@ INVYONE 은 **회사(=tenant)별로 독립된 PostgreSQL 데이터베이스**를 가진다. 접속한 서브도메인에 따라 요청이 자동으로 해당 회사 DB 로 라우팅된다. ``` -qnc.invyone.com → qnc_vexplor DB -kookje.invyone.com → kookje_vexplor DB -vexplor (메타 DB) → 회사 정보·라우팅 테이블·SUPER_ADMIN 데이터 +qnc.invyone.com → qnc_invyone DB +kookje.invyone.com → kookje_invyone DB +invyone (메타 DB) → 회사 정보·라우팅 테이블·SUPER_ADMIN 데이터 ``` ### 설계 원칙 @@ -46,25 +46,25 @@ vexplor (메타 DB) → 회사 정보·라우팅 테이블·SUPER_ADMIN 데이 ↓ (HTTP Host 헤더) [SubdomainResolverFilter] ↓ subdomain=qnc → CompanyResolver.resolveDbName("qnc") - ↓ DbContextHolder.set("qnc_vexplor") + ↓ DbContextHolder.set("qnc_invyone") [JwtAuthenticationFilter] ↓ [Controller → Service → sqlSession.selectList(...)] ↓ [TenantRoutingDataSource.determineTargetDataSource()] - ↓ DbContextHolder.get() = "qnc_vexplor" -[HikariDataSource for qnc_vexplor] → 실제 SQL 실행 + ↓ DbContextHolder.get() = "qnc_invyone" +[HikariDataSource for qnc_invyone] → 실제 SQL 실행 ``` ### 2.3 메타 DB 의 역할 -`vexplor` DB (COMPANY_MNG 테이블) 는 **라우팅 룩업 테이블**만 담당: +`invyone` DB (COMPANY_MNG 테이블) 는 **라우팅 룩업 테이블**만 담당: | 컬럼 | 용도 | |---|---| | `COMPANY_CODE` | 회사 식별자 (PK) | | `SUBDOMAIN` | 서브도메인 prefix (UNIQUE) | -| `DB_NAME` | 실제 tenant DB 이름 (예: `qnc_vexplor`) (UNIQUE) | +| `DB_NAME` | 실제 tenant DB 이름 (예: `qnc_invyone`) (UNIQUE) | | `DB_HOST` | tenant DB 호스트 (분산 대비, 현재 단일) | | `DB_STATUS` | `provisioning` / `active` / `failed` / `suspended` | | `PLAN`, `INDUSTRY`, `TEMPLATES_COUNT`, `DB_QUOTA_GB` | UI 메타 | @@ -87,7 +87,7 @@ vexplor (메타 DB) → 회사 정보·라우팅 테이블·SUPER_ADMIN 데이 ``` 1. REGISTER_META COMPANY_MNG 에 status='provisioning' 선반영 -2. CREATE_DATABASE CREATE DATABASE "{prefix}_vexplor" (postgres 기본 DB 경유) +2. CREATE_DATABASE CREATE DATABASE "{prefix}_invyone" (postgres 기본 DB 경유) 3. COPY_SCHEMA pg_dump --schema-only | psql (ProcessBuilder 배열 인자) 4. COPY_DATA 선택된 그룹 테이블 JDBC 복사 (company_code 필터) 5. CREATE_ADMIN {prefix}_admin BCrypt 계정 생성 diff --git a/frontend/components/admin/provisioning/CompanyAccordionRow.tsx b/frontend/components/admin/provisioning/CompanyAccordionRow.tsx index 28fc63a4..db0ca4ef 100644 --- a/frontend/components/admin/provisioning/CompanyAccordionRow.tsx +++ b/frontend/components/admin/provisioning/CompanyAccordionRow.tsx @@ -58,7 +58,7 @@ export default function CompanyAccordionRow({ const sub = r.subdomain || ""; const name = r.company_name || r.name || r.company_code; const plan = (r.plan || "Starter").toString(); - const dbName = r.db_name || `${sub}_vexplor`; + const dbName = r.db_name || `${sub}_invyone`; const dbPct = Number(r.db_pct) || 0; const users = Number(r.users) || 0; const active30 = Number(r.active30) || 0; diff --git a/frontend/components/admin/provisioning/wizard/Step1Basic.tsx b/frontend/components/admin/provisioning/wizard/Step1Basic.tsx index 8bd84fc1..814a1854 100644 --- a/frontend/components/admin/provisioning/wizard/Step1Basic.tsx +++ b/frontend/components/admin/provisioning/wizard/Step1Basic.tsx @@ -167,7 +167,7 @@ export default function Step1Basic({ value={state.db_prefix || ""} onChange={onDbPrefixChange} placeholder="영문 소문자 · 숫자 · 밑줄" - suffix="_vexplor" + suffix="_invyone" mono status={availToInputStatus(prefStatus)} /> @@ -289,7 +289,7 @@ export default function Step1Basic({ {state.db_prefix || "___"} - _vexplor + _invyone diff --git a/frontend/components/admin/provisioning/wizard/Step4Run.tsx b/frontend/components/admin/provisioning/wizard/Step4Run.tsx index 394157d8..6af58ecd 100644 --- a/frontend/components/admin/provisioning/wizard/Step4Run.tsx +++ b/frontend/components/admin/provisioning/wizard/Step4Run.tsx @@ -527,7 +527,7 @@ export default function Step4Run({ idx={i} status={rowStatus(s.key)} isLast={i === DISPLAY_STEPS.length - 1} - dbName={`${state.db_prefix || "___"}_vexplor`} + dbName={`${state.db_prefix || "___"}_invyone`} /> ))} diff --git a/k8s/configmap.yaml b/k8s/configmap.yaml index 23b9d5de..1938625c 100644 --- a/k8s/configmap.yaml +++ b/k8s/configmap.yaml @@ -6,13 +6,13 @@ metadata: data: SPRING_PROFILES_ACTIVE: "prod" SERVER_PORT: "8081" - SPRING_DATASOURCE_URL: "jdbc:postgresql://183.99.177.40:5432/vexplor" + SPRING_DATASOURCE_URL: "jdbc:postgresql://183.99.177.40:5432/invyone" SPRING_DATASOURCE_USERNAME: "postgres" JWT_EXPIRATION: "86400000" FILE_UPLOAD_DIR: "./uploads" NODE_ENV: "production" NODE_PORT: "8080" - DATABASE_URL: "postgresql://postgres:vexplor0909!!@183.99.177.40:5432/vexplor" + DATABASE_URL: "postgresql://postgres:vexplor0909!!@183.99.177.40:5432/invyone" CORS_ORIGIN: "https://solution.invyone.com" NEXT_PUBLIC_API_URL: "https://solution.invyone.com/api" NEXT_TELEMETRY_DISABLED: "1" diff --git a/notes/gbpark/2026-04-24-company-mgmt-ui-schema.md b/notes/gbpark/2026-04-24-company-mgmt-ui-schema.md index ea87a961..4a57139d 100644 --- a/notes/gbpark/2026-04-24-company-mgmt-ui-schema.md +++ b/notes/gbpark/2026-04-24-company-mgmt-ui-schema.md @@ -41,7 +41,7 @@ | 목업에 없지만 UI 에서 파생 | 소스 | |---|---| | `{prefix}.invyone.com` 프리뷰 | `SUBDOMAIN` + 하드코딩 도메인 | -| `{prefix}_vexplor` DB 명 | `DB_NAME` | +| `{prefix}_invyone` DB 명 | `DB_NAME` | | 상태 dot | `DB_STATUS` | ### 1.2 런타임 집계 (CompanyStatsService) @@ -67,7 +67,7 @@ | 목업 필드 | 계산 | |---|---| | `url_preview` (`qnc.invyone.com`) | `${subdomain}.invyone.com` | -| `db_name_display` (`qnc_vexplor`) | `db_name` (이미 있음) | +| `db_name_display` (`qnc_invyone`) | `db_name` (이미 있음) | --- @@ -86,7 +86,7 @@ "company_code": "COMPANY_10", "company_name": "큐엔씨", "subdomain": "qnc", - "db_name": "qnc_vexplor", + "db_name": "qnc_invyone", "db_host": "183.99.177.40", "db_status": "active", "status": "active", diff --git a/notes/gbpark/2026-04-24-traefik-wildcard/docker-compose.yml b/notes/gbpark/2026-04-24-traefik-wildcard/docker-compose.yml new file mode 100644 index 00000000..b6542367 --- /dev/null +++ b/notes/gbpark/2026-04-24-traefik-wildcard/docker-compose.yml @@ -0,0 +1,44 @@ +services: + traefik: + image: traefik:v2.11 + container_name: traefik + restart: always + ports: + - "80:80" + - "443:443" + command: + - --api.insecure=false + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --providers.docker.network=traefik-net + - --providers.file.directory=/dynamic + - --providers.file.watch=true + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entrypoints.web.http.redirections.entryPoint.to=websecure + - --entrypoints.web.http.redirections.entryPoint.scheme=https + - --entrypoints.web.http.redirections.entryPoint.permanent=true + - --certificatesresolvers.le.acme.httpchallenge=true + - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web + - --certificatesresolvers.le.acme.email=admin@junggomoa.com + - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json + - --certificatesresolvers.ledns.acme.dnschallenge=true + - --certificatesresolvers.ledns.acme.dnschallenge.provider=porkbun + - --certificatesresolvers.ledns.acme.email=admin@junggomoa.com + - --certificatesresolvers.ledns.acme.storage=/letsencrypt/acme-dns.json + - --log.level=INFO + environment: + - PORKBUN_API_KEY=${PORKBUN_API_KEY} + - PORKBUN_SECRET_API_KEY=${PORKBUN_SECRET_API_KEY} + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /opt/docker/traefik/letsencrypt:/letsencrypt + - /opt/docker/traefik/dynamic:/dynamic:ro + networks: + - traefik-net + +networks: + traefik-net: + external: true diff --git a/notes/gbpark/2026-04-24-traefik-wildcard/invyone-tenant.yml b/notes/gbpark/2026-04-24-traefik-wildcard/invyone-tenant.yml new file mode 100644 index 00000000..3111a2c7 --- /dev/null +++ b/notes/gbpark/2026-04-24-traefik-wildcard/invyone-tenant.yml @@ -0,0 +1,35 @@ +http: + routers: + invyone-tenant-frontend: + rule: "HostRegexp(`{sub:[a-z0-9-]+}.invyone.com`)" + entryPoints: + - web + - websecure + service: invyone-tenant-frontend + tls: + certResolver: ledns + domains: + - main: invyone.com + sans: + - "*.invyone.com" + + invyone-tenant-api: + rule: "HostRegexp(`{sub:[a-z0-9-]+}.invyone.com`) && PathPrefix(`/api`)" + entryPoints: + - web + - websecure + service: invyone-tenant-api + tls: + certResolver: ledns + priority: 100 + + services: + invyone-tenant-frontend: + loadBalancer: + servers: + - url: "http://host.docker.internal:30000" + + invyone-tenant-api: + loadBalancer: + servers: + - url: "http://host.docker.internal:30081"