# Architecture

> How LocalCloud works inside one container: the gateway, service processes, persistence, networking, and the settings operators control.
>
> Source: https://local.cloud/docs/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

1. `localcloud start --local-only` selects 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.
2. `localcloud env` resolves that runtime and returns environment variables and endpoint values for the selected project and caller.
3. SDK, REST, gRPC, and Terraform requests reach a direct emulator port or the gateway on canonical container port `5380` (HTTP) or `5381` (HTTPS / TLS).
4. 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–5394` active services and TLS, `5395–5405` reserved buffer for future service additions).
- **5406 & 5443–5465**: External companion & child host processes (`5406` Cloud SQL MySQL companion container, `5443–5465` GKE k3d child clusters with `5443` as primary).
- **5410–5414**: Specialized & in-container loopback (`5410/udp` DNSmasq scoped DNS, `5411` Firestore private, `5412` BigQuery REST private, `5413` BigQuery Storage gRPC private, `5414` Supervisor 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/udp` to container `5410/udp`, host `80` to gateway `5380`, and host `443` to 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](https://local.cloud/docs/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.
