Architecture
LocalCloud packages a Java gateway, the web console, local facades, and external emulator processes in one unified Docker container. “One container” does not mean every service shares the same protocol, process, storage engine, or compatibility level.
Request flow
localcloud start --local-onlyselects a Docker data volume, discovers or creates one compatible runtime that listens only on localhost, and maps published canonical ports in the 5380–5405 range.localcloud envresolves that runtime and returns environment variables and endpoint values for the selected project and caller.- SDK, REST, gRPC, and Terraform requests reach a direct emulator port or the gateway on canonical container port
5380(HTTP) or5381(HTTPS / TLS). - The gateway handles operator routes and routes facade/API traffic to local implementations.
Runtime identity and ownership
The named Docker volume mounted at /var/lib/localcloud is the only durable runtime selector; the default is localcloud-data. The CLI verifies the configured image and selects the unique compatible container using that volume. Immutable container ID is live process identity. A recorded ID is only a revalidated tie-break hint.
CLI-created container, network, and volume resources carry exact ownership labels. Ownership is independent per resource. The CLI can start, stop, restart, inspect, and use an attached compatible container, but it never removes or relabels a Docker resource it does not own. Ambiguous volume use, incompatible images, invalid labels, and shared-volume conflicts fail before mutation. localcloud reset --all-projects prints manual full-recreation steps and deletes nothing.
Root operator routes include /health, /health/{service}, /readiness, /env, /services, /seed, /reseed, /import, /reset, /terraform/readiness, /graphql, /api-docs, and /docs.
Process and storage model
| Component | Current Implementation | Persistence Boundary |
|---|---|---|
| Gateway & Facades | Java / Armeria services | Facade records use internal PostgreSQL beneath /var/lib/localcloud/pgdata; operation-specific limits apply. |
| Cloud Storage | fake-gcs-server process | Object blobs and bucket metadata stored beneath /var/lib/localcloud/gcs-data. |
| Pub/Sub | In-process Java facade | Topics, subscriptions, and queued messages use PostgreSQL under /var/lib/localcloud/pgdata. Delivery workers and connections restart; test exact replay and redelivery behavior. |
| Firestore | External emulator configuration | Documented local document/query workflows; opt-in. Test checkpoint, timestamp, listener, and transaction behavior with the exact image you run. |
| Bigtable | Custom emulator process | Backed by PostgreSQL under the mounted data root. Port 5385. |
| BigQuery | Native GoogleSQL analysis + DuckDB execution | Supervised native in-container process; columnar DuckDB storage beneath /var/lib/localcloud/bigquery-data. Ports 5388 (REST) and 5389 (Storage Read gRPC with TLS). |
| Spanner | Extended Cloud Spanner emulator | LevelDB row data plus JSON metadata beneath /var/lib/localcloud/spanner-data. Ports 5386 (gRPC) and 5387 (REST). |
| Memorystore | Valkey-compatible process | Ports 5390 (plaintext) and 5394 (TLS). Check the documented RESP command and recovery subset. |
| AlloyDB & Cloud SQL | PostgreSQL 16 (5391) + companion MySQL 8.4 (5406) | Native PostgreSQL 16 data plane shared by Cloud SQL and AlloyDB; MySQL 8.4 hosted via companion container. |
A retained volume improves restart/container-replacement behavior only for stores that actually persist. It does not provide production replication, backups, disaster recovery, transaction parity, or durability guarantees.
Canonical container ports
The host CLI may dynamically remap these ports if conflicts arise; generated endpoint output from localcloud env is authoritative for a running runtime.
LocalCloud organizes its network ports into clean, continuous tiers:
- 5380–5405: In-container published range (
5380–5394active services and TLS,5395–5405reserved buffer for future service additions). - 5406 & 5443–5465: External companion & child host processes (
5406Cloud SQL MySQL companion container,5443–5465GKE k3d child clusters with5443as primary). - 5410–5414: Specialized & in-container loopback (
5410/udpDNSmasq scoped DNS,5411Firestore private,5412BigQuery REST private,5413BigQuery Storage gRPC private,5414Supervisor XML-RPC private).
Published TCP Block (5380–5405)
| Port | Protocol / Transport | Purpose / Service | Active When |
|---|---|---|---|
5380 | HTTP/1.1 & HTTP/2 (REST/h2c) | Shared gateway, web console, operator APIs, MCP, and all in-process service facades | Server is ready |
5381 | HTTPS & HTTP/2 gRPC | Secure shared gateway (tls.port, default 5381) | Global TLS enabled |
5382 | HTTP REST | Cloud Storage REST API (fake-gcs-server) | gcs enabled |
5383 | h2c gRPC | Cloud Pub/Sub direct SDK endpoint | pubsub enabled |
5384 | h2c gRPC / HTTP | Cloud Firestore wrapper | firestore enabled |
5385 | h2c gRPC | Cloud Bigtable (little_bigtable) | bigtable enabled |
5386 | h2c gRPC | Cloud Spanner data and admin APIs | spanner enabled |
5387 | HTTP REST / JSON | Cloud Spanner REST endpoint (not PostgreSQL wire) | spanner enabled |
5388 | HTTP REST / JSON | BigQuery query and metadata API | bigquery enabled |
5389 | HTTP/2 gRPC | BigQuery Storage Read/Write API (TLS is always required) | bigquery enabled |
5390 | RESP | Memorystore (Redis / Valkey plaintext) | memorystore enabled |
5391 | PostgreSQL wire protocol | Shared PostgreSQL data plane for Cloud SQL and AlloyDB (and LocalCloud metadata) | PostgreSQL is ready |
5392 | HTTPS REST | Cloud Storage TLS endpoint | Global TLS and gcs enabled |
5393 | HTTP/2 gRPC | Cloud Pub/Sub TLS endpoint | Global TLS and pubsub enabled |
5394 | RESP over TLS | Memorystore (Redis / Valkey TLS) | Global TLS and memorystore enabled |
5395–5405 | TCP | Reserved buffer for future in-container service additions | Reserved |
Shared Gateway Facades (Port 5380 / 5381)
All service control planes and in-process facades connect through the shared gateway on 5380 (HTTP/h2c) or 5381 (HTTPS/TLS) rather than individual dedicated ports. These include:
- Security & Identity: Cloud Secret Manager, Cloud KMS, Cloud IAM
- Messaging & Integration: Cloud Tasks, Cloud Scheduler, Cloud Workflows
- Operations: Cloud Logging, Cloud Monitoring, Cloud Resource Manager, Service Usage, Cloud Billing
- Compute & Serverless: Cloud Functions (2nd Gen), Cloud Run, Dataproc (control plane), GKE (control plane), Compute Engine
- Databases: Cloud SQL (control plane), AlloyDB (control plane)
- Auxiliary Integration APIs: Google Sheets
Companions and Subordinate Workloads
| Port | Protocol | Purpose / Service |
|---|---|---|
5406 | MySQL wire protocol | Cloud SQL MySQL 8.4 companion container (localcloud-mysql) |
5410/udp | DNS | Scoped dnsmasq resolver (mapped to host 53/udp in transparent mode) |
5443–5465 | HTTPS (Kubernetes API) | GKE k3d child control-plane allocations (primary API server on 5443) |
Internal Loopback Listeners (Never Published to Host)
| Listener | Purpose |
|---|---|
127.0.0.1:5411 | Private Firestore backend behind the public 5384 wrapper |
127.0.0.1:5412 | Private native BigQuery REST backend behind public 5388 proxy |
127.0.0.1:5413 | Private native BigQuery Storage backend behind public TLS 5389 proxy |
127.0.0.1:5414 | Supervisor XML-RPC control plane |
Transparent networking and Docker socket
Transparent networking is disabled by default. Docker access defaults to auto; the socket is mounted when selected services declare that dependency. Set host.docker_socket: false to opt out. Unflagged CLI lifecycle commands publish ports on all host interfaces; the example above selects loopback explicitly.
- Transparent networking maps host
53/udpto container5410/udp, host80to gateway5380, and host443to the configured native TLS port (5381). It requires scoped host DNS changes and certificate trust and is used only for clients that ignore custom endpoint variables. - Docker socket access grants the container control over the host Docker daemon. It is required only for runtime workflows that deliberately create subordinate containers or clusters (such as Cloud SQL MySQL or GKE k3d). In-container BigQuery runs natively via Supervisord and does not require Docker socket access.
Outbound behavior
LocalCloud is not categorically offline or zero-egress. Depending on configuration and feature use, the runtime can send telemetry, probe certificate storage, check image updates, validate licenses, validate live IAM bearer tokens, or dispatch scheduled/HTTP work. Core local workflows can continue offline after required images are present, but review Privacy and disable or isolate outbound features according to your environment.
Production boundary
Local emulation does not reproduce Google Cloud IAM enforcement, quotas, managed networking, regional behavior, concurrency, performance, replication, or disaster recovery. Consult each service operation and support level, then run an explicit real-Google-Cloud validation before release.
This comment is sent to PostHog. Do not include secrets, personal data, or customer data. See Privacy.