Logto Common — Shared Application Configuration
Logto_Common is the shared application layer for Logto. It is not deployed on
its own; instead it supplies the Logto-specific configuration that both
Logto_GKE and Logto_CloudRun build on, so the
two platform variants behave identically where it matters. End users never configure
this layer directly — it has no deployment UI inputs of its own — but understanding
what it provides explains the defaults you see in the platform docs.
For the infrastructure that actually provisions and runs Logto, see the platform guides (Logto_GKE, Logto_CloudRun) and the foundation guides (App_GKE, App_CloudRun, App_Common).
1. What this layer provides
| Area | Provided by Logto_Common | Where it surfaces |
|---|---|---|
| Container image | Thin wrapper built FROM svhd/logto:<version> (community core + admin console) via Cloud Build; mirrored into Artifact Registry | container_image output of the platform deployment |
| Cloud entrypoint | entrypoint.sh composes DB_URL from the injected DB_* vars and derives ENDPOINT / ADMIN_ENDPOINT from the service URL before handing off to the image's seed-then-start command | Runtime behaviour on both platforms |
| Database engine | Fixes Cloud SQL for PostgreSQL 15 as the only supported engine | §Database in the platform guides |
| Database bootstrap | Defines the first-deploy job (db-init) that creates the database and role with CREATEDB CREATEROLE and grants schema ownership | initialization_jobs output |
| Application secrets | None — Logto generates and stores its OIDC signing keys in the database (seeded on first boot), so no external application secret is created | secret_ids output is empty {} |
| Object storage | Declares one Cloud Storage bucket (storage) | storage_buckets output |
| Core settings | Sets TRUST_PROXY_HEADER = "1" and derives ENDPOINT / ADMIN_ENDPOINT from the injected service URL | Application behaviour in the platform guides |
| Health checks | Supplies the default startup / liveness / readiness probes targeting /api/status | §Observability in the platform guides |
2. Application secrets — there are none to manage
Unlike most identity products, Logto needs no external application secret. Its
OIDC private signing keys are generated by the db seed step on first boot and stored
inside the PostgreSQL database. Consequently:
Logto_Commoncreates norandom_passwordresources and exposes an emptysecret_ids = {}map. There is no encryption key or JWT secret to protect or rotate.- The only secret in play is the database password, which is generated and managed
by the foundation (its Secret Manager name is reported as
database_password_secretin the platform outputs).
Because the signing keys live in the database, the database itself is the sole custodian of Logto's cryptographic material — protecting and backing up Cloud SQL is what protects Logto's identity keys. Retrieve the DB password secret with:
gcloud secrets list --project "$PROJECT" --filter="name~logto"
gcloud secrets versions access latest --secret=<database_password_secret> --project "$PROJECT"
See App_Common for the shared secret and Workload Identity model.
3. Database engine and bootstrap
Logto requires PostgreSQL (the module fixes POSTGRES_15); MySQL and other
engines are rejected by a plan-time validation guard. On the first deployment a
one-shot job (db-init) runs using postgres:15-alpine and idempotently:
- Connects as the Cloud SQL superuser (
postgres) — over the Auth Proxy socket / loopback on GKE, or the private IP on Cloud Run, - Waits for PostgreSQL to accept connections,
- Creates (or reconfigures) the application role with
LOGIN CREATEDB CREATEROLE—CREATEROLEis mandatory because Logto's owndb seedcreates per-tenant Postgres roles for row-level-security tenant isolation; without it seeding fails withpermission denied to create role(SQLSTATE 42501), - Creates the application database if it does not exist,
- Grants all privileges on the database and the
publicschema, and transferspublicschema ownership to the application role (Postgres 15 no longer grantsCREATEonpublicby default), - Signals the Cloud SQL Auth Proxy sidecar to shut down (
/quitquitquit) so the GKE Job pod can complete.
Logto then seeds its own schema and OIDC signing keys on boot via
npm run cli db seed -- --swe (--swe = seed-when-empty — idempotent; it only writes
when the database has no Logto tables). The db-init job is safe to re-run. Inspect
the database directly with:
gcloud sql connect <instance-name> --user=<db-user> --database=<db-name> --project "$PROJECT"
The instance, database (logto), and user (logto) names are in the platform
deployment outputs.
4. Container image and entrypoint
The custom image is a thin wrapper built FROM svhd/logto:<version> (the community
Logto image bundling the core + admin console) with a cloud entrypoint
(entrypoint.sh) layered on top. The base-image tag is driven by an app-specific
LOGTO_VERSION build ARG — not the generic APP_VERSION, which the foundation
injects into build_args and would otherwise clobber the FROM tag. The image is
built via Cloud Build and mirrored into Artifact Registry (enable_image_mirroring = true).
The entrypoint runs before Logto starts and:
- Composes
DB_URLfrom the foundation-injectedDB_*variables. Logto's driver (@silverhand/slonik) parsesDB_URLwith the WHATWGnew URL(), which rejects the libpq Unix-socket form (empty authority host →Invalid URL). Logto is therefore a URL-authority DSN app that cannot use the Cloud SQL socket — the entrypoint branches onDB_HOST:- a
/…socket directory (Cloud Run) → connect over the injected private IP (DB_IP) withsslmode=no-verify(encrypted; CA verification skipped for the DB hop only, because Cloud SQL presents a self-signed cert not in Node's CA bundle); 127.0.0.1/localhost(GKE Auth Proxy sidecar) → plain TCP, no SSL (the proxy terminates TLS);- a private IP → TCP with
sslmode=no-verify.
- a
- Derives
ENDPOINT/ADMIN_ENDPOINTfrom the injectedCLOUDRUN_SERVICE_URL/GKE_SERVICE_URL. Logto builds its OIDC issuer and all absolute URLs fromENDPOINT, so it must match the browser-facing host. Operators can overrideENDPOINTfor a custom domain. - Sets
TRUST_PROXY_HEADER = "1"so Logto honours theX-Forwarded-*headers behind the Cloud Run / GKE HTTPS front end. - Hands off to the image's own boot command
(
npm run cli db seed -- --swe && npm start).
The wrapper is a POSIX-sh script (the svhd/logto base is Node/Alpine with no
python3), so URL-encoding of the DB credentials is done in pure shell.
5. Core application settings and ports
Logto_Common establishes the baseline environment so Logto comes up correctly:
- Ports. Logto core (the API / OIDC endpoint) listens on 3001 and is the port
published on both platforms (
container_port = 3001). The admin console listens on 3002 and is not reachable through the single Cloud Run port / single GKE Service port — see the caveat below. PORTis never set. Cloud Run reserves thePORTenv var (it auto-injectsPORT=3001) and rejects any user-provided value; Logto core defaults to 3001, matchingcontainer_port.- No Redis. Logto uses PostgreSQL for all persistence, so
enable_redisdefaults tofalseand noREDIS_URLis injected. TRUST_PROXY_HEADER = "1"andENDPOINT/ADMIN_ENDPOINTderived at runtime (see §4).
Admin console caveat. Because Cloud Run and a single GKE Service publish only one port, only the core (3001) is reachable. The admin console (3002) — where the first administrator account and application registrations are created — is not exposed through the published port. To complete first-run setup, reach the console on 3002 directly (for example
kubectl port-forwardon GKE, or a second exposure), or front Logto with a proxy that routes to both ports. See the platform guides for details.
6. Health probe behaviour
The default probes target /api/status — an unauthenticated endpoint on the Logto
core that returns 200 once the server is up. A generous startup window accommodates
the one-time schema + OIDC-key seed that runs on first boot.
- Startup probe — HTTP
GET /api/status, 60-second initial delay, 15-second period, 30-failure threshold (a wide first-boot window for the seed step). - Liveness probe — HTTP
GET /api/status, 30-second period. - Readiness probe — HTTP
GET /api/status, 30-second initial delay, 10-second period.
All three are unauthenticated 200s, so they never trip the auth gate that guards
/api/* mutating routes.
7. Object storage
A single Cloud Storage bucket (suffix storage, STANDARD class, public access
prevention enforced, no object versioning) is declared here and provisioned by the
foundation, which grants the workload service account access. Logto keeps all core
state in PostgreSQL, so this bucket is available for optional assets rather than
required runtime storage. List it with:
gcloud storage buckets list --project "$PROJECT"
For the Logto-specific, user-facing configuration (variables by group, outputs, and how to explore each service from the Console and CLI), see the platform guides: Logto_GKE and Logto_CloudRun.