Skip to main content

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

AreaProvided by Logto_CommonWhere it surfaces
Container imageThin wrapper built FROM svhd/logto:<version> (community core + admin console) via Cloud Build; mirrored into Artifact Registrycontainer_image output of the platform deployment
Cloud entrypointentrypoint.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 commandRuntime behaviour on both platforms
Database engineFixes Cloud SQL for PostgreSQL 15 as the only supported engine§Database in the platform guides
Database bootstrapDefines the first-deploy job (db-init) that creates the database and role with CREATEDB CREATEROLE and grants schema ownershipinitialization_jobs output
Application secretsNone — Logto generates and stores its OIDC signing keys in the database (seeded on first boot), so no external application secret is createdsecret_ids output is empty {}
Object storageDeclares one Cloud Storage bucket (storage)storage_buckets output
Core settingsSets TRUST_PROXY_HEADER = "1" and derives ENDPOINT / ADMIN_ENDPOINT from the injected service URLApplication behaviour in the platform guides
Health checksSupplies 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_Common creates no random_password resources and exposes an empty secret_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_secret in 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:

  1. Connects as the Cloud SQL superuser (postgres) — over the Auth Proxy socket / loopback on GKE, or the private IP on Cloud Run,
  2. Waits for PostgreSQL to accept connections,
  3. Creates (or reconfigures) the application role with LOGIN CREATEDB CREATEROLECREATEROLE is mandatory because Logto's own db seed creates per-tenant Postgres roles for row-level-security tenant isolation; without it seeding fails with permission denied to create role (SQLSTATE 42501),
  4. Creates the application database if it does not exist,
  5. Grants all privileges on the database and the public schema, and transfers public schema ownership to the application role (Postgres 15 no longer grants CREATE on public by default),
  6. 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_URL from the foundation-injected DB_* variables. Logto's driver (@silverhand/slonik) parses DB_URL with the WHATWG new 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 on DB_HOST:
    • a /… socket directory (Cloud Run) → connect over the injected private IP (DB_IP) with sslmode=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.
  • Derives ENDPOINT / ADMIN_ENDPOINT from the injected CLOUDRUN_SERVICE_URL / GKE_SERVICE_URL. Logto builds its OIDC issuer and all absolute URLs from ENDPOINT, so it must match the browser-facing host. Operators can override ENDPOINT for a custom domain.
  • Sets TRUST_PROXY_HEADER = "1" so Logto honours the X-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.
  • PORT is never set. Cloud Run reserves the PORT env var (it auto-injects PORT=3001) and rejects any user-provided value; Logto core defaults to 3001, matching container_port.
  • No Redis. Logto uses PostgreSQL for all persistence, so enable_redis defaults to false and no REDIS_URL is injected.
  • TRUST_PROXY_HEADER = "1" and ENDPOINT / ADMIN_ENDPOINT derived 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-forward on 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.