1 Configuration
picklemustard edited this page 2026-09-07 15:49:27 -04:00

Configuration

gbb-server -config PATH and gbb build --local --config PATH load YAML; their default is configs/config.yaml. Supported GBB_ environment overrides take precedence over file values. The server's -addr flag overrides its configured listen address.

The example configuration (configs/config.example.yaml in the repo) documents the baseline settings. The exact environment mapping is in internal/config/config.go (internal/config/config.go in the repo); names are explicitly mapped, so do not infer them mechanically from YAML nesting.

Essential settings

Setting Purpose
addr / GBB_ADDR API listen address, normally :8080
data_dir / GBB_DATA_DIR Persistent workspaces, caches, logs, and filesystem artifacts
database.dsn / GBB_DATABASE_DSN PostgreSQL catalog, jobs, and operational state; or describe it in parts (see below)
redis.url / GBB_HUMAN_REDIS_URL Anonymous verification and shared abuse counters; only used in public mode
godot_repo Default engine repository; catalog rows can select a fork
build.image_prefix / GBB_IMAGE_PREFIX Prefix matching the toolchain image tags; registry-qualified to pull them
build.image_tag / GBB_IMAGE_TAG Tag those images carry, latest locally or the vX.Y.Z a release published
build.registry.server / GBB_BUILD_REGISTRY_SERVER Registry the pull credential is for
build.registry.username / GBB_BUILD_REGISTRY_USERNAME Account for that pull; empty pulls anonymously
build.registry.password / GBB_BUILD_REGISTRY_PASSWORD Token for it; prefer password_file
build.registry.password_file / GBB_BUILD_REGISTRY_PASSWORD_FILE Path to a mounted token, which wins over the inline value
build.workspace_mount / GBB_WORKSPACE_MOUNT Workspace mount strategy; use bind with shared absolute paths
artifacts.backend / GBB_ARTIFACT_BACKEND fs for local storage, s3 for object storage
auth.cookie_secure / GBB_COOKIE_SECURE Secure attribute for legacy browser sessions
docker.host / DOCKER_HOST Docker-compatible endpoint; an explicit configured host wins

Toolchain images

build.image_prefix is concatenated with linux:<tag>, windows:<tag> or macos:<tag>, so it ends in the separator: gbb/ names the images a local make images builds, and git.picklemustard.dev/studioteal/gbb- names the ones a release publishes.

build.image_tag is worth pinning rather than leaving on latest. An image is pulled only when it is not already present, so a tag that never changes is fetched once and then kept indefinitely -- a floating latest means a deployed sidecar keeps whichever toolchain it happened to see first. scripts/release.sh rewrites this in deploy/k8s/configmap.yaml on every release.

build.registry is how the Docker daemon authenticates that pull. It is not the cluster's imagePullSecret: that one covers the kubelet fetching the pod's own containers, while this covers a pull the daemon makes on the server's behalf, which travels as a header on the Engine API request. dockerd reads no config.json of its own, so a private registry needs this and is otherwise unreachable from a build. Leave it empty for locally built images or a public registry.

Capacity and leases

build.workers controls concurrent builds. build.jobs controls SCons parallelism per build; zero uses all available cores. build.memory and build.cpus constrain each compiler container. Start with one worker and size memory for linking as well as compilation.

build.timeout bounds a build. build.queue_capacity bounds waiting work in the legacy queue. Anonymous admission has its own durable queue and per-IP limits.

build.lease, heartbeat_interval, poll_interval, and max_attempts control worker ownership and retry after a lost lease. Heartbeats must be shorter than the lease. A lease measures worker liveness, not the maximum compilation duration.

build.ccache_volume names the compiler cache. A Docker named workspace volume does not automatically receive files assembled on the API filesystem. For the deployed dind arrangement, both containers must share /data, with bind mode configured.

Precedence

Four layers, lowest first, applied uniformly to every setting:

built-in defaults  <  the YAML file  <  GBB_ environment  <  a *_file field

The environment sits above the file because it is the last thing a deployment can change without editing a ConfigMap. A *_file field sits above the environment because the path is normally written in the YAML while the contents come from a volume the YAML cannot see: a mounted secret that lost to an inline value would be pointless. The two are different keys, so there is no circularity — GBB_DATABASE_PASSWORD_FILE sets the path, and the file's contents then win over GBB_DATABASE_PASSWORD.

Unknown keys are rejected. A misspelled setting fails at startup rather than being silently ignored.

Connections: one string, or parts

database and redis each accept either a whole connection string (dsn, url) or discrete fields (host, port, user, name/db, password, sslmode). Setting both forms is refused rather than silently resolved, because a connection string is used whole and its parts cannot be overridden individually.

Prefer the discrete form when a password contains @ / ? # : or %. Those are percent-escaped for you, where a hand-written string quietly parses as a different host. database.params carries any libpq keyword the schema does not name, so nothing is lost by not writing the string yourself.

A composed database connection defaults to port 5432 and sslmode: require. A local instance with no certificate needs sslmode: disable, or connecting fails with an error about TLS rather than about the setting.

Secrets from files

Every credential has a *_file sibling that reads it from a mounted path: database.dsn_file, database.password_file, redis.url_file, redis.password_file, and access_key_id_file / secret_access_key_file / session_token_file under the S3 blocks. Trailing newlines are trimmed, so both echo secret > file and a projected Kubernetes Secret work. A file that cannot be read is fatal at startup: continuing with an empty credential produces an authentication failure against the right host with the wrong secret, which is the least diagnosable outcome available.

Inline password: values in the file are accepted for development. The deployed config is a ConfigMap, so do not use them there.

Storage and credentials

For S3, configure endpoint, bucket, region, prefix, and path-style addressing as required by your store. Create the bucket before starting the server. Supply GBB_S3_ACCESS_KEY_ID and GBB_S3_SECRET_ACCESS_KEY through the environment or deployment secrets, or mount them and set secret_access_key_file.

Temporary credentials add session_token. A deployment that already mounts ~/.aws can set profile (with credentials_files / config_files to override the search paths) instead of static keys; static keys win where both are given, so setting both is refused. signing_region signs as a region other than the bucket's own, for a store that demands a particular one. A store on a private certificate authority sets tls.ca_bundle_path, which is added to the system roots rather than replacing them; tls.cert_file and tls.key_file supply a client certificate for mTLS.

Legacy delivery can redirect to presigned URLs or proxy through the API. Anonymous delivery streams privately; the separate gateway uses its own read-only S3 credential and database role. See gateway configuration; it accepts the same database, redis, and s3 blocks through its own -config file, and still reads its historical environment variables.

Private module cloning uses modules.ssh_key_path and modules.known_hosts_path. Keep the private key readable only by the intended identity and verify host keys. Compiler containers do not perform repository authentication themselves.

Public service settings

Anonymous mode requires GBB_HUMAN_ENABLED=true, GBB_PUBLIC_ORIGIN, GBB_TURNSTILE_SITE_KEY, GBB_TURNSTILE_SECRET, a configured Redis, explicit GBB_HUMAN_TRUSTED_PROXIES, and GBB_ADMIN_GROUP.

Redis is the redis: block. GBB_HUMAN_REDIS_URL remains the supported way to supply it and is what existing deployments use; GBB_REDIS_URL is the same setting under the block's own name and wins if both are set. The discrete fields (redis.host, redis.user, redis.password_file, redis.db, redis.tls.*) are the alternative, and redis.db is how two deployments share one instance, since the key prefixes are fixed.

The origin must be HTTPS with no path, query, or fragment. Trusted proxy entries are whitespace-separated CIDRs for immediate ingress peers. Redis must support the shared verification and enforcement scripts. Public request settings must agree across API and gateway replicas.

GBB_DOWNLOAD_GATEWAY_ENABLED=true disables the API's old download delivery path at gateway cutover. Set it only with ingress routing configured. See Security and Deployment and operations.

Retention

retention.artifacts: "0s" keeps artifacts indefinitely. Nonzero retention stamps a deadline when a build succeeds; shortening the configuration does not retroactively shorten existing deadlines. Log retention is separate and uses file modification time. Audit retention, collector interval, and batch size are independently configurable.

Keep real configuration and credentials out of version control. Commit example values only.