Configuration reference
This page lists every configuration key with its type, built-in default and the environment variable that overrides it. It is generated from the code (internal/config and the packages whose settings it embeds), so it cannot drift from what the server reads. For the load order (defaults, then the YAML file, then the environment), validation and how to start the server with a file, see Configuration. Annotated copies of every key are in openartifact.example.yaml and .env.example.
- YAML key: the dotted path in the configuration file;
server.portisportunderserver:. - Env: the environment variable that overrides the key; it takes precedence over the file. When several variables are listed, they are aliases and the first one that is set wins.
- Type:
string,int,bool,float,duration(Go syntax such as5mor90s),list(a YAML sequence; comma-separated in the environment) ormap(a YAML mapping; comma-separatedkey=valuepairs in the environment). - Default: the value used when neither the file nor the environment sets the key;
emptyis an empty string, list or map. - Credentials are marked Secret: keep them in environment variables or in a file only the server can read.
Top level
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
baseUrl | BASE_URL | string | http://localhost:8080 | baseUrl is the public URL of the server; it is used for generated links and SSO callbacks, so set it when the server runs behind a reverse proxy. |
server
server configures the HTTP listener, TLS, timeouts and request limits.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
server.host | SERVER_HOST | string | 0.0.0.0 | host is the listen address. |
server.port | SERVER_PORT | int | 8080 | port is the listen port. |
server.readTimeout | SERVER_READ_TIMEOUT | int | 0 | readTimeout bounds an entire request (headers + body), in seconds. 0 (the default) means no limit so large artifact uploads are never truncated; slowloris protection instead comes from readHeaderTimeout. |
server.writeTimeout | SERVER_WRITE_TIMEOUT | int | 0 | writeTimeout bounds writing the response, in seconds. 0 (the default) means no limit: large artifact downloads and streams rely on per-handler deadlines instead of one server-wide cutoff. |
server.readHeaderTimeout | SERVER_READ_HEADER_TIMEOUT | int | 20 | readHeaderTimeout bounds only the time to read request headers, in seconds. It stays short regardless of readTimeout to still mitigate slowloris-style attacks even when body reads are unbounded. |
server.maxBodyBytes | SERVER_MAX_BODY_BYTES | int | 17179869184 | maxBodyBytes caps the body of every request (http.MaxBytesReader), a last line of defence behind the per-handler limits so no endpoint can be made to spool or buffer an unbounded body. 0 disables the cap. |
server.shutdownTimeout | SERVER_SHUTDOWN_TIMEOUT | int | 30 | shutdownTimeout is how many seconds in-flight requests get to finish during a graceful shutdown. |
server.shutdownDelay | SERVER_SHUTDOWN_DELAY | int | 0 | shutdownDelay is how many seconds the server keeps serving, reporting not ready on /ready, after a shutdown signal and before it stops accepting connections, so load balancers stop routing to it first. A second signal skips the delay. 0 disables it. |
server.tlsEnabled | SERVER_TLS_ENABLED | bool | false | tlsEnabled serves HTTPS and sends HSTS; it requires tlsCert and tlsKey. |
server.tlsCert | SERVER_TLS_CERT | string | empty | tlsCert is the path of the PEM certificate file. |
server.tlsKey | SERVER_TLS_KEY | string | empty | tlsKey is the path of the PEM private key file. |
server.apiKey | API_KEY | string | empty | Secret. apiKey is a deprecated static key accepted on write endpoints while auth.legacyApiKeyEnabled is true. It authenticates as system/legacy-api-key and logs a warning on each use; empty disables it. |
server.corsOrigins | CORS_ORIGINS | list | empty | corsOrigins lists the browser origins allowed by CORS; none by default. |
server.instanceId | OPENARTIFACT_INSTANCE_ID | string | empty | instanceId names this instance in HA deployments; /health reports it (omitted when empty, the hostname is never disclosed). |
server.ipAllowlist | OPENARTIFACT_IP_ALLOWLIST | list | empty | ipAllowlist lists the CIDR blocks allowed to connect; empty allows all. |
server.rateLimitRps | OPENARTIFACT_RATE_LIMIT_RPS | int | 0 | rateLimitRps caps requests per second per client IP; 0 disables the limit. |
server.trustedProxies | OPENARTIFACT_TRUSTED_PROXIES | list | empty | trustedProxies lists CIDR blocks of reverse proxies allowed to set X-Forwarded-For/X-Real-IP. Empty (default) means no proxy is trusted — the immediate TCP peer is always used as the client IP, so a client can never spoof its own IP via those headers. |
server.pprofEnabled | OPENARTIFACT_PPROF_ENABLED | bool | false | pprofEnabled mounts Go's runtime profiler under /api/v1/admin/pprof/ (admin "manage" permission required). Off by default: profiles expose internals and CPU profiling costs cycles. Sets non-zero mutex and block profile rates while enabled. |
database
database configures the PostgreSQL connection and its pool.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
database.driver | DB_DRIVER | string | postgres | driver names the database driver. It must be non-empty; PostgreSQL is the only supported database and the server always connects to it. |
database.host | DB_HOST | string | localhost | host is the database host. |
database.port | DB_PORT | int | 5432 | port is the database port. |
database.user | DB_USER | string | postgres | user is the database user. |
database.password | DB_PASSWORD | string | empty | Secret. password is the database password. The CHANGE_ME placeholder of the example files is rejected at startup. |
database.database | DB_NAME | string | artifact_repo | database is the database name. |
database.sslMode | DB_SSLMODE | string | require | sslMode is the PostgreSQL sslmode; disable only for local development without TLS. |
database.options | DB_OPTIONS | map | empty | options are extra libpq connection parameters. The environment form is comma-separated key=value pairs, merged over the YAML keys. |
database.maxOpenConns | DB_MAX_OPEN_CONNS | int | 25 | maxOpenConns is the size of the connection pool. 0 means the driver default; otherwise at least 2 (a blob-lock transaction pins one connection and its callback needs another), and at least 4 while tiering.enabled is true. |
database.maxIdleConns | DB_MAX_IDLE_CONNS | int | 5 | maxIdleConns is how many idle connections the pool keeps warm. |
database.connMaxLifetimeMinutes | DB_CONN_MAX_LIFETIME_MINUTES | int | 30 | connMaxLifetimeMinutes is the maximum lifetime of a connection, in minutes. |
database.authCacheTtlMs | DB_AUTH_CACHE_TTL_MS | int | 2000 | authCacheTtlMs is how long, in milliseconds, per-request authentication lookups (token, user, groups, permission targets, repository by name) are served from memory. Writes through this process invalidate immediately; other replicas observe a change after at most this long. 0 disables the cache. |
database.connectTimeout | DB_CONNECT_TIMEOUT | duration | 1m | connectTimeout is how long startup keeps retrying the initial database connection (capped exponential backoff) before giving up. 0 fails at the first error. |
storage
storage selects and configures the blob store (see operations/storage.md). Its replica block adds an asynchronous second copy of every blob (see operations/replication.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
storage.type | STORAGE_BACKEND, STORAGE_TYPE | string | filesystem | type selects the storage backend: filesystem, s3, gcs, azure, garage, seaweedfs or oci. garage and seaweedfs reuse the S3 client with path-style addressing forced on. |
storage.endpoint | STORAGE_ENDPOINT | string | empty | endpoint is the endpoint URL of an S3-compatible service (s3, garage, seaweedfs) or the URL of the OCI registry. |
storage.bucket | STORAGE_BUCKET | string | artifacts | bucket is the bucket name (s3, garage, seaweedfs) or the OCI repository prefix. |
storage.region | STORAGE_REGION | string | us-east-1 | region is the AWS region or equivalent. |
storage.accessKey | STORAGE_ACCESS_KEY | string | empty | accessKey is the S3 access key. It is used only when both keys are set, otherwise the AWS credential chain applies. |
storage.secretKey | STORAGE_SECRET_KEY | string | empty | Secret. secretKey is the S3 secret key. |
storage.path | STORAGE_PATH | string | /var/lib/artifacts | path is the directory of the filesystem backend. |
storage.options | STORAGE_OPTIONS | map | empty | options are free-form backend options. The environment form is comma-separated key=value pairs, merged over the YAML keys. None of the built-in backends reads any key yet. |
storage.forcePathStyle | STORAGE_S3_FORCE_PATH_STYLE | bool | false | forcePathStyle uses path-style S3 addressing (required for MinIO, Garage and SeaweedFS). |
storage.presignTtl | STORAGE_S3_PRESIGN_TTL | duration | 5m | presignTtl is the lifetime of presigned download URLs (s3, gcs), clamped to 1m-1h. It only applies while presignDownloads is on. |
storage.presignUploadTtl | STORAGE_PRESIGN_UPLOAD_TTL | duration | 30m | presignUploadTtl is the lifetime of presigned PUT upload URLs, clamped to 1m-12h. |
storage.presignMaxPendingUploads | STORAGE_PRESIGN_MAX_PENDING_UPLOADS | int | 20 | presignMaxPendingUploads is how many outstanding (not completed, not expired) presigned uploads one user may hold; 0 means unlimited. Beyond it, creating an upload answers 429. |
storage.presignDownloads | STORAGE_PRESIGN_DOWNLOADS | bool | false | presignDownloads answers blob downloads with a 307 redirect to a presigned URL (s3 and gcs only) instead of streaming them. A repository can override it with presign_downloads. |
storage.presignMinSize | STORAGE_PRESIGN_MIN_SIZE | int | 1048576 | presignMinSize is the size in bytes below which blobs are always streamed; 0 redirects everything and a negative value is rejected at startup. |
storage.presignEndpoint | STORAGE_PRESIGN_ENDPOINT | string | empty | presignEndpoint is the public base URL (absolute http(s), no query or fragment) that presigned URLs are signed against (S3 family); empty uses the endpoint. Set it when the endpoint is not reachable by clients. |
storage.gcsBucket | OPENARTIFACT_GCS_BUCKET | string | empty | gcsBucket is the GCS bucket (reached through the S3-compatible XML API). |
storage.gcsHmacKey | OPENARTIFACT_GCS_HMAC_KEY | string | empty | gcsHmacKey is the GCS HMAC access key (required for gcs). |
storage.gcsHmacSecret | OPENARTIFACT_GCS_HMAC_SECRET | string | empty | Secret. gcsHmacSecret is the GCS HMAC secret. |
storage.azureAccountName | OPENARTIFACT_AZURE_ACCOUNT_NAME | string | empty | azureAccountName is the Azure storage account name. |
storage.azureAccountKey | OPENARTIFACT_AZURE_ACCOUNT_KEY | string | empty | Secret. azureAccountKey is the Azure storage account key. |
storage.azureContainerName | OPENARTIFACT_AZURE_CONTAINER_NAME | string | empty | azureContainerName is the Azure container name. |
storage.azureEndpoint | OPENARTIFACT_AZURE_ENDPOINT | string | empty | azureEndpoint is the blob service URL, for Azurite or a sovereign cloud; empty uses https://<account>.blob.core.windows.net. |
storage.stagingPath | STORAGE_STAGING_PATH | string | empty | stagingPath is the spool directory for server-relayed presigned uploads on oci storage (filesystem uses <path>/staging); empty means <tmp>/openartifact-staging. |
storage.ociInsecure | STORAGE_OCI_INSECURE | bool | false | ociInsecure allows plain HTTP to the OCI registry (dev and testing only). |
storage.ociUsername | STORAGE_OCI_USERNAME | string | empty | ociUsername is the OCI registry user. |
storage.ociPassword | STORAGE_OCI_PASSWORD | string | empty | Secret. ociPassword is the OCI registry password. |
storage.replica
storage.replica is the optional blob replica: an asynchronous second copy of every blob on another backend (see operations/replication.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
storage.replica.type | OPENARTIFACT_STORAGE_REPLICA_TYPE | string | empty | type selects the storage backend: filesystem, s3, gcs, azure, garage, seaweedfs or oci. garage and seaweedfs reuse the S3 client with path-style addressing forced on. |
storage.replica.endpoint | OPENARTIFACT_STORAGE_REPLICA_ENDPOINT | string | empty | endpoint is the endpoint URL of an S3-compatible service (s3, garage, seaweedfs) or the URL of the OCI registry. |
storage.replica.bucket | OPENARTIFACT_STORAGE_REPLICA_BUCKET | string | empty | bucket is the bucket name (s3, garage, seaweedfs) or the OCI repository prefix. |
storage.replica.region | OPENARTIFACT_STORAGE_REPLICA_REGION | string | us-east-1 | region is the AWS region or equivalent. |
storage.replica.accessKey | OPENARTIFACT_STORAGE_REPLICA_ACCESS_KEY | string | empty | accessKey is the S3 access key. It is used only when both keys are set, otherwise the AWS credential chain applies. |
storage.replica.secretKey | OPENARTIFACT_STORAGE_REPLICA_SECRET_KEY | string | empty | Secret. secretKey is the S3 secret key. |
storage.replica.path | OPENARTIFACT_STORAGE_REPLICA_PATH | string | empty | path is the directory of the filesystem backend. |
storage.replica.options | OPENARTIFACT_STORAGE_REPLICA_OPTIONS | map | empty | options are free-form backend options. The environment form is comma-separated key=value pairs, merged over the YAML keys. None of the built-in backends reads any key yet. |
storage.replica.forcePathStyle | OPENARTIFACT_STORAGE_REPLICA_FORCE_PATH_STYLE | bool | false | forcePathStyle uses path-style S3 addressing (required for MinIO, Garage and SeaweedFS). |
storage.replica.gcsBucket | OPENARTIFACT_STORAGE_REPLICA_GCS_BUCKET | string | empty | gcsBucket is the GCS bucket (reached through the S3-compatible XML API). |
storage.replica.gcsHmacKey | OPENARTIFACT_STORAGE_REPLICA_GCS_HMAC_KEY | string | empty | gcsHmacKey is the GCS HMAC access key (required for gcs). |
storage.replica.gcsHmacSecret | OPENARTIFACT_STORAGE_REPLICA_GCS_HMAC_SECRET | string | empty | Secret. gcsHmacSecret is the GCS HMAC secret. |
storage.replica.azureAccountName | OPENARTIFACT_STORAGE_REPLICA_AZURE_ACCOUNT_NAME | string | empty | azureAccountName is the Azure storage account name. |
storage.replica.azureAccountKey | OPENARTIFACT_STORAGE_REPLICA_AZURE_ACCOUNT_KEY | string | empty | Secret. azureAccountKey is the Azure storage account key. |
storage.replica.azureContainerName | OPENARTIFACT_STORAGE_REPLICA_AZURE_CONTAINER_NAME | string | empty | azureContainerName is the Azure container name. |
storage.replica.azureEndpoint | OPENARTIFACT_STORAGE_REPLICA_AZURE_ENDPOINT | string | empty | azureEndpoint is the blob service URL, for Azurite or a sovereign cloud; empty uses https://<account>.blob.core.windows.net. |
storage.replica.ociInsecure | OPENARTIFACT_STORAGE_REPLICA_OCI_INSECURE | bool | false | ociInsecure allows plain HTTP to the OCI registry (dev and testing only). |
storage.replica.ociUsername | OPENARTIFACT_STORAGE_REPLICA_OCI_USERNAME | string | empty | ociUsername is the OCI registry user. |
storage.replica.ociPassword | OPENARTIFACT_STORAGE_REPLICA_OCI_PASSWORD | string | empty | Secret. ociPassword is the OCI registry password. |
storage.replica.readFallback | OPENARTIFACT_STORAGE_REPLICA_READ_FALLBACK | string | notfound | readFallback is what a read does when the primary cannot answer: notfound (the default: the primary says the blob does not exist), error (also when the primary fails) or off (never read from the replica). |
storage.replica.interval | OPENARTIFACT_STORAGE_REPLICA_INTERVAL | duration | 5s | interval is the pause between replication passes (queued blobs are also picked up as soon as they are enqueued). |
storage.replica.batch | OPENARTIFACT_STORAGE_REPLICA_BATCH | int | 100 | batch is how many queued operations one claim takes. |
storage.replica.concurrency | OPENARTIFACT_STORAGE_REPLICA_CONCURRENCY | int | 4 | concurrency is how many blobs are copied at once. |
storage.replica.verifyInterval | OPENARTIFACT_STORAGE_REPLICA_VERIFY_INTERVAL | duration | 24h | verifyInterval is the pause between verify passes; 0 = only on demand (POST /api/v1/admin/storage/replication/verify). |
storage.replica.verifyDeep | OPENARTIFACT_STORAGE_REPLICA_VERIFY_DEEP | bool | false | verifyDeep also hashes the bytes of both copies during a verify pass, instead of comparing existence and size only. |
storage.replica.maxBackoff | OPENARTIFACT_STORAGE_REPLICA_MAX_BACKOFF | duration | 1h | maxBackoff caps the retry delay of a failing operation. |
log
log configures the log level, format and destination.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
log.level | LOG_LEVEL | string | info | level is the minimum severity logged: debug, info, warn or error. Unknown values fall back to info. |
log.format | LOG_FORMAT | string | json | format is json or text; any other value gives console text. |
log.output | LOG_OUTPUT | string | stdout | output is stdout, stderr or a file path (appended to). |
gpg
gpg configures the key file that signs APT and RPM metadata and release bundle manifests (see security/signing.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
gpg.enabled | GPG_ENABLED | bool | false | enabled loads the file key at keyPath. Keys managed through the admin API sign regardless. |
gpg.keyPath | GPG_KEY_PATH | string | empty | keyPath is the private key file (the read-only fallback key). |
gpg.passphrase | GPG_PASSPHRASE | string | empty | Secret. passphrase unlocks the key at keyPath. |
gpg.autoGenerate | GPG_AUTO_GENERATE | bool | false | autoGenerate generates an RSA-4096 global signing key at startup when no key exists yet. It needs OPENARTIFACT_SECRET_KEY and is replica-safe. |
attestation
attestation configures the signing key of SBOM and VEX attestations (see security/sbom.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
attestation.keyPath | ATTESTATION_KEY_PATH | string | empty | keyPath is an unencrypted PKCS#8 or SEC1 PEM private key (ECDSA or Ed25519). Empty: a P-256 key is generated on first use and stored encrypted in the database. |
auth
auth configures sessions, anonymous reads and the login-state and SAML service provider keys (see security/authentication.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
auth.allowAnonymousRead | ALLOW_ANONYMOUS_READ | bool | false | allowAnonymousRead lets anonymous clients read private repositories (via the "anonymous-read" permission target). Repositories flagged public are always anonymously readable, never writable, whatever this says. |
auth.legacyApiKeyEnabled | LEGACY_API_KEY_ENABLED | bool | false | legacyApiKeyEnabled accepts the deprecated server.apiKey on write endpoints. |
auth.sessionDurationHours | SESSION_DURATION_HOURS | int | 24 | sessionDurationHours is the lifetime of a web session, in hours. |
auth.hmacKey | AUTH_HMAC_KEY | string | empty | Secret. hmacKey signs OIDC and SAML login state. Unset: a random key is generated once and persisted in system_settings (shared by replicas); a configured value wins. |
auth.samlSpCert | OPENARTIFACT_SAML_SP_CERT | string | empty | samlSpCert is the PEM certificate of the SAML service provider. Unset: a self-signed pair is generated once and persisted encrypted in system_settings (shared by replicas); regenerating it means re-registering the certificate at the identity provider. |
auth.samlSpKey | OPENARTIFACT_SAML_SP_KEY | string | empty | Secret. samlSpKey is the PEM private key of the SAML service provider. Unset together with the certificate: a self-signed pair is generated (see samlSpCert). Stored unencrypted while OPENARTIFACT_SECRET_KEY is unset. |
bootstrap
bootstrap configures the first admin account and API token created on an empty instance (see getting-started/installation.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
bootstrap.adminPasswordFile | OPENARTIFACT_BOOTSTRAP_ADMIN_PASSWORD_FILE | string | empty | Secret. adminPasswordFile is a file holding the initial admin password (a trailing newline is trimmed). Preferred over AdminPassword. |
bootstrap.adminPassword | OPENARTIFACT_BOOTSTRAP_ADMIN_PASSWORD | string | empty | Secret. adminPassword is the initial admin password itself (compose convenience; AdminPasswordFile wins when both are set). |
bootstrap.forcePasswordChange | OPENARTIFACT_BOOTSTRAP_FORCE_PASSWORD_CHANGE | bool | false | Secret. forcePasswordChange forces a password change at the first login of a supplied password. A generated password always forces it. |
bootstrap.adminTokenFile | OPENARTIFACT_BOOTSTRAP_ADMIN_TOKEN_FILE | string | empty | adminTokenFile is a file holding an admin API token secret (oa_pat_ followed by 32 to 128 characters from A-Za-z0-9_-), created as the access token "bootstrap" of the admin user. |
bootstrap.adminTokenTtl | OPENARTIFACT_BOOTSTRAP_ADMIN_TOKEN_TTL | duration | 0 | adminTokenTtl is the lifetime of the bootstrap token; 0 means none. |
bootstrap.generatedPasswordTtl | OPENARTIFACT_BOOTSTRAP_GENERATED_PASSWORD_TTL | duration | 24h | Secret. generatedPasswordTtl is how long a generated (printed) admin password stays valid for login; 0 means it never expires. |
backup
backup configures where backups are written and how long a running backup holds back blob deletions (see operations/backup.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
backup.backupDir | OPENARTIFACT_BACKUP_DIR | string | /var/lib/openartifact/backups | backupDir is the directory backup files are written to. |
backup.leaseTtl | OPENARTIFACT_BACKUP_LEASE_TTL | duration | 5m | leaseTtl is how long a running backup's hold on deleted blob bytes survives without a heartbeat. A running backup renews it every third of this; a crashed backup stops holding deletions back once it expires. |
ai
ai configures AI-assisted package analysis (see integrations/ai-analysis.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
ai.enabled | AI_ENABLED | bool | false | enabled turns AI-assisted artifact analysis on (metadata tagging, license check, security notes). |
ai.autoAnalyze | AI_AUTO_ANALYZE | bool | false | autoAnalyze analyses every upload without being asked. Off: analyses start only on request (UI, API or MCP). Needs enabled. |
ai.provider | AI_PROVIDER | string | openai | provider is the LLM backend: openai, azure, ollama or custom (any OpenAI-compatible endpoint; needs baseUrl). |
ai.baseUrl | AI_BASE_URL | string | empty | baseUrl overrides the API base URL (Azure OpenAI, Ollama or a custom endpoint). |
ai.apiKey | AI_API_KEY | string | empty | Secret. apiKey authenticates to the provider; required for openai and azure, leave it empty for a local ollama. |
ai.model | AI_MODEL | string | gpt-4o-mini | model is the model to use, for example gpt-4o-mini or llama3; it must be available on the configured provider. |
ai.maxTokens | AI_MAX_TOKENS | int | 1024 | maxTokens caps the completion tokens of one analysis request. |
ai.timeoutSecs | AI_TIMEOUT_SECS | int | 30 | timeoutSecs is the HTTP timeout of an AI API call, in seconds. |
ai.systemPrompt | AI_SYSTEM_PROMPT | string | empty | systemPrompt overrides the built-in system prompt; empty uses it. |
mcp
mcp configures the embedded Model Context Protocol server (see integrations/mcp.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
mcp.enabled | MCP_ENABLED | bool | false | enabled mounts the MCP server on the main HTTP listener. |
mcp.transport | MCP_TRANSPORT | string | http | transport must be http (the only supported transport; stdio is rejected). The endpoint requires an "Authorization: Bearer" token. |
mcp.httpPath | MCP_HTTP_PATH | string | /mcp | httpPath is the mount path of the HTTP endpoint. |
mcp.allowedOrigins | MCP_ALLOWED_ORIGINS | list | empty | allowedOrigins are the browser origins (scheme://host[:port]) accepted in the Origin header of MCP requests, besides the origin of baseUrl. A request with any other Origin is refused with 403; requests without an Origin header (non-browser clients) are unaffected. |
mcp.maxBodyBytes | MCP_MAX_BODY_BYTES | int | 1048576 | maxBodyBytes caps one MCP request body (default 1 MiB). |
mcp.rateLimitPerMinute | MCP_RATE_LIMIT_PER_MINUTE | int | 600 | rateLimitPerMinute caps MCP requests per authenticated principal per minute (default 600; 0 disables the limit). |
mcp.aiTriggerPerMinute | MCP_AI_TRIGGER_PER_MINUTE | int | 10 | aiTriggerPerMinute caps trigger_ai_analysis calls per principal per minute, since each one can cost an LLM call (default 10; 0 disables). |
workers
workers tunes the background workers: metadata regeneration, Docker registry garbage collection and upload staging, webhook retention.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
workers.metadataRegenConcurrency | OPENARTIFACT_METADATA_REGEN_CONCURRENCY | int | 4 | metadataRegenConcurrency caps how many metadata regenerations (npm, maven, deb, rpm together) run at once. Each pins up to two database connections, so keep it well below database.maxOpenConns. |
workers.dockerGcInterval | OPENARTIFACT_DOCKER_GC_INTERVAL | duration | 1h | dockerGcInterval is the pause between scheduled Docker registry garbage collection passes (untagged manifests and the blobs only they used). Zero or negative disables the schedule; the admin API can still run it. |
workers.dockerGcGracePeriod | OPENARTIFACT_DOCKER_GC_GRACE_PERIOD | duration | 24h | dockerGcGracePeriod is how long an untagged manifest, or an unreferenced blob, must have been idle before registry GC may delete it. It must outlast the slowest push: layers are uploaded before the manifest that references them. |
workers.proxyDockerDigestTtl | OPENARTIFACT_PROXY_DOCKER_DIGEST_TTL | duration | 720h | proxyDockerDigestTtl is how long a docker proxy keeps a manifest or blob addressed by digest after its last pull. Such content never changes, so this only bounds the cache's size: the proxy cache worker evicts what has not been pulled for this long, and the next pull fetches it again. Zero keeps it until an admin purge or the repository's removal. |
workers.proxyUpstreamStallTimeout | OPENARTIFACT_PROXY_UPSTREAM_STALL_TIMEOUT | duration | 1m | proxyUpstreamStallTimeout is how long a proxy upstream response body may deliver no data before the fetch fails and its flight is released. It is reset on every read, so slow but steady downloads are unaffected. Zero disables the check. |
workers.dockerUploadTtl | OPENARTIFACT_DOCKER_UPLOAD_TTL | duration | 24h | dockerUploadTtl is how long a blob upload session may sit idle before the sweeper deletes it and its staged file. Zero or negative disables the sweeper. |
workers.dockerUploadDir | OPENARTIFACT_DOCKER_UPLOAD_DIR | string | empty | dockerUploadDir is where in-progress blob uploads are staged. Empty means /tmp/openartifact/docker-uploads. |
workers.webhookDeliveryRetentionDays | OPENARTIFACT_WEBHOOK_DELIVERY_RETENTION_DAYS | int | 30 | webhookDeliveryRetentionDays is how many days finished (success or failed) webhook delivery records are kept before the hourly purge deletes them. 0 keeps them forever. Pending deliveries are never purged. |
trash
trash tunes soft delete (see operations/trash.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
trash.retentionDays | OPENARTIFACT_TRASH_RETENTION | int | 7 | retentionDays is how many days a deleted artifact, version or repository stays restorable before the purge worker removes it for good. It applies to repositories without their own trash_retention_days; 0 disables the trash (deletes are immediate and permanent). |
trash.purgeInterval | OPENARTIFACT_TRASH_PURGE_INTERVAL | duration | 15m | purgeInterval is the pause between purge passes. Zero or negative disables the schedule: nothing expires until an admin purges by hand. |
audit
audit tunes the retention of the audit log (see operations/audit-retention.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
audit.retentionDays | OPENARTIFACT_AUDIT_RETENTION_DAYS | int | 0 | retentionDays is how many days audit entries are kept before the retention worker deletes them in batches. 0 keeps them forever (the default): export them with oa audit export before enabling a limit. |
audit.purgeInterval | OPENARTIFACT_AUDIT_PURGE_INTERVAL | duration | 1h | purgeInterval is the pause between retention passes. Only used when RetentionDays is positive. |
audit.purgeBatchSize | OPENARTIFACT_AUDIT_PURGE_BATCH_SIZE | int | 5000 | purgeBatchSize is how many entries one delete statement removes; a pass repeats it, paced, until nothing older than the retention is left. |
docs
docs configures the links from the web UI to the published documentation.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
docs.baseUrl | OPENARTIFACT_DOCS_BASE_URL | string | https://openartifact.github.io/ | baseUrl is the root of the published documentation site; the web UI links to the version matching the server (release builds) or to the latest docs (development builds). Point it at an internal mirror for air-gapped installs; empty hides every documentation link. |
api
api configures the REST API explorer (see integrations/api.md).
api.docs
api.docs configures the interactive API reference.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
api.docs.enabled | OPENARTIFACT_API_DOCS_ENABLED | bool | true | enabled serves the interactive API reference at /api/reference (the old /swagger paths redirect to it) and links it from the About dialog. When false both answer 404. The OpenAPI spec at /api/v1/openapi.json and /api/v1/openapi.yaml is always served: the web client and tooling use it. |
branding
branding white-labels the UI: product name, logos, favicon, colour, login message and support/source links (see operations/branding.md). Administrators can override every value at runtime.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
branding.productName | OPENARTIFACT_BRANDING_PRODUCT_NAME | string | empty | productName replaces "OpenArtifact" in the UI (title, sidebar, login). |
branding.logoLight | OPENARTIFACT_BRANDING_LOGO_LIGHT | string | empty | logoLight is the path of a PNG or SVG logo shown on light surfaces; when only one logo is set it is used for both themes. |
branding.logoDark | OPENARTIFACT_BRANDING_LOGO_DARK | string | empty | logoDark is the path of a PNG or SVG logo shown on dark surfaces. |
branding.favicon | OPENARTIFACT_BRANDING_FAVICON | string | empty | favicon is a PNG or SVG file. |
branding.primaryColor | OPENARTIFACT_BRANDING_PRIMARY_COLOR | string | empty | primaryColor is the accent colour as #rrggbb. |
branding.loginMessage | OPENARTIFACT_BRANDING_LOGIN_MESSAGE | string | empty | loginMessage is shown on the login page (plain text with a tiny markdown subset). |
branding.supportUrl | OPENARTIFACT_BRANDING_SUPPORT_URL | string | empty | supportUrl is an http(s) or mailto link shown in the About dialog. |
branding.sourceUrl | OPENARTIFACT_BRANDING_SOURCE_URL | string | empty | sourceUrl is where users can get the source of the running version (AGPL-3.0 section 13); it defaults to the upstream repository and cannot be hidden. |
blobDeletion
blobDeletion tunes the deferred deletion of blob bytes (see operations/storage.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
blobDeletion.grace | OPENARTIFACT_BLOB_DELETION_GRACE | duration | 24h | grace is how long the bytes of a deleted blob are kept before they may be removed. During it a re-upload of the same content reuses them. Zero removes them as soon as no running backup needs them. |
blobDeletion.sweepInterval | OPENARTIFACT_BLOB_DELETION_SWEEP_INTERVAL | duration | 1m | sweepInterval is the pause between sweeper passes. Zero or negative disables the schedule (the queue then only grows). |
blobDeletion.sweepBatch | OPENARTIFACT_BLOB_DELETION_SWEEP_BATCH | int | 200 | sweepBatch is how many queued deletions a sweeper claims at a time. |
tiering
tiering tunes the storage tier mover (see operations/storage-tiering.md). Tiers and policies themselves are managed through the admin API; with no tier besides the primary store configured none of this has any effect.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
tiering.enabled | OPENARTIFACT_TIERING_ENABLED | bool | true | enabled switches the background mover on. Reads from every tier work regardless; only the movement of blobs between tiers depends on it. |
tiering.interval | OPENARTIFACT_TIERING_INTERVAL | duration | 5m | interval is the pause between mover passes. Zero or negative disables the schedule; an admin can still start a pass by hand. |
tiering.batch | OPENARTIFACT_TIERING_BATCH | int | 200 | batch caps how many blobs one pass moves; the rest wait for the next pass. |
tiering.concurrency | OPENARTIFACT_TIERING_CONCURRENCY | int | 2 | concurrency is how many blobs are copied at once. |
tiering.maxBytesPerSecond | OPENARTIFACT_TIERING_MAX_BYTES_PER_SECOND | int | 67108864 | maxBytesPerSecond caps the mover's total copy bandwidth (all concurrent copies together). Zero is unlimited. |
tiering.verifyReadback | OPENARTIFACT_TIERING_VERIFY_READBACK | bool | true | verifyReadback re-reads each copied blob from the target tier and compares its sha256 before the placement flips, on top of the size check. |
tiering.accessFlushInterval | OPENARTIFACT_TIERING_ACCESS_FLUSH_INTERVAL | duration | 30s | accessFlushInterval is how often recorded blob downloads (used by "idle for N days" policies and promote-on-read) are written to the database. |
tiering.refreshInterval | OPENARTIFACT_TIERING_REFRESH_INTERVAL | duration | 30s | refreshInterval is how often each replica reloads the tier list, so a tier created on one replica is used by the others. |
recovery
recovery groups the disaster-recovery settings.
recovery.journal
recovery.journal tunes the row journal that mirrors package metadata as sidecar blobs in the blob store (see operations/rebuild-from-storage.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
recovery.journal.enabled | OPENARTIFACT_RECOVERY_JOURNAL_ENABLED | bool | true | enabled switches the journal on: the database triggers mark changed rows and the worker writes their sidecar blobs. Off, nothing is captured and openartifact rebuild cannot restore rows created while it was off. |
recovery.journal.interval | OPENARTIFACT_RECOVERY_JOURNAL_INTERVAL | duration | 10s | interval is the pause between worker passes that drain the dirty queue. |
recovery.journal.batch | OPENARTIFACT_RECOVERY_JOURNAL_BATCH | int | 200 | batch is how many dirty rows one drain step claims. |
recovery.journal.concurrency | OPENARTIFACT_RECOVERY_JOURNAL_CONCURRENCY | int | 4 | concurrency is how many sidecar blobs are written or deleted at once. |
recovery.journal.reconcileInterval | OPENARTIFACT_RECOVERY_JOURNAL_RECONCILE_INTERVAL | duration | 24h | reconcileInterval is how often every journaled table is re-checked for rows without a sidecar (backfill) and sidecars without a row. Zero disables periodic reconciles after the first complete one. |
projects
projects tunes project self-service (see security/projects.md).
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
projects.selfCreate | OPENARTIFACT_PROJECTS_SELF_CREATE | bool | false | selfCreate lets any authenticated human user create a project and become its owner. Off by default: only global admins create projects. An administrator can change it at runtime (system setting projects.self_create), which then takes precedence over this default. |
federation
federation tunes federated repositories (see operations/federation.md). Repositories are federated individually through the admin API; this only switches the pull workers and the peer endpoints on and tunes them.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
federation.enabled | OPENARTIFACT_FEDERATION_ENABLED | bool | false | enabled starts the pull workers and mounts the /federation/v1 peer endpoints. Off by default. |
federation.pollInterval | OPENARTIFACT_FEDERATION_POLL_INTERVAL | duration | 30s | pollInterval is the pause between pulls of one peer that is caught up. |
federation.batchSize | OPENARTIFACT_FEDERATION_BATCH_SIZE | int | 200 | batchSize is how many log entries one pull page carries. |
federation.maxBackoff | OPENARTIFACT_FEDERATION_MAX_BACKOFF | duration | 15m | maxBackoff caps the retry delay of an unreachable or failing peer. |
federation.requestTimeout | OPENARTIFACT_FEDERATION_REQUEST_TIMEOUT | duration | 30s | requestTimeout bounds one request to a peer (blob transfers are bounded by it per request, not in total). |
federation.tombstoneRetention | OPENARTIFACT_FEDERATION_TOMBSTONE_RETENTION | duration | 720h | tombstoneRetention is how long the tombstone of a deleted unit is kept in the log; a member that stays offline longer must be resynced. |
federation.spoolDir | OPENARTIFACT_FEDERATION_SPOOL_DIR | string | empty | spoolDir is where blobs pulled from peers are downloaded to. An interrupted download stays there and the next pull resumes it with a Range request. Empty uses a directory under the OS temp dir; set it to a persistent volume to resume across restarts, and give every instance its own. |
federation.maxPartialBytes | OPENARTIFACT_FEDERATION_MAX_PARTIAL_BYTES | int | 10737418240 | maxPartialBytes caps the total size of the interrupted downloads kept in the spool; the least recently written are removed first. |
federation.maxPartialAge | OPENARTIFACT_FEDERATION_MAX_PARTIAL_AGE | duration | 24h | maxPartialAge removes an interrupted download that was not written to for this long. |
telemetry
telemetry configures OpenTelemetry export (off by default), see operations/monitoring.md.
telemetry.otlp
telemetry.otlp configures the OTLP exporters. The endpoint, protocol, headers and TLS settings are shared by every signal. The standard OTEL_* environment variables override the file; the signal specific OTEL_EXPORTER_OTLP_TRACES_*, OTEL_EXPORTER_OTLP_METRICS_* and OTEL_EXPORTER_OTLP_LOGS_* variables only apply while endpoint is empty.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
telemetry.otlp.enabled | OPENARTIFACT_OTLP_ENABLED | bool | false | enabled is the master switch: nothing is exported without it, whatever the per-signal switches say. Off by default; OTEL_SDK_DISABLED=true forces it off. |
telemetry.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | string | empty | endpoint is host:port or an http(s) URL of the collector. Empty uses the SDK default (localhost:4317 for grpc, localhost:4318 for http). |
telemetry.otlp.protocol | OTEL_EXPORTER_OTLP_PROTOCOL | string | grpc | protocol is "grpc" (default) or "http" (OTLP/HTTP protobuf). |
telemetry.otlp.headers | OTEL_EXPORTER_OTLP_HEADERS | map | empty | Secret. headers are sent with every export request (collector credentials). Never logged. The environment form is comma-separated key=value pairs with percent-encoded values. |
telemetry.otlp.insecure | OTEL_EXPORTER_OTLP_INSECURE | bool | false | insecure disables TLS towards the collector. An http:// endpoint implies it. |
telemetry.otlp.serviceName | OTEL_SERVICE_NAME | string | openartifact | serviceName is the service.name resource attribute. |
telemetry.otlp.sampleRatio | OTEL_TRACES_SAMPLER_ARG | float | 1 | sampleRatio is the fraction of new traces recorded, in [0,1]. Requests carrying a sampled traceparent are always recorded (parent based). |
telemetry.otlp.traces | OTEL_TRACES_EXPORTER | bool | true | traces exports distributed traces and installs the HTTP server middleware. On by default, so enabled alone keeps tracing. The environment form is OTEL_TRACES_EXPORTER: otlp turns it on, none turns it off. |
telemetry.otlp.metrics | OTEL_METRICS_EXPORTER | bool | false | metrics exports the Prometheus registry (Go runtime and openartifact_* families) over OTLP to the same endpoint. /metrics is unaffected. The environment form is OTEL_METRICS_EXPORTER: otlp turns it on, none turns it off. |
telemetry.otlp.logs | OTEL_LOGS_EXPORTER | bool | false | logs is the switch for application log records over OTLP; with it (or audit) on, an OTLP log provider is started on the same endpoint. Reserved: no records are written to it yet (#192). The environment form is OTEL_LOGS_EXPORTER: otlp turns it on, none turns it off. |
telemetry.otlp.audit | OPENARTIFACT_OTLP_AUDIT | bool | false | audit is the switch for audit events over OTLP (scope openartifact.audit), independent of traces. It shares the log provider with logs. Reserved: no events are written to it yet (#193). The audit_logs table stays the source of truth. |
scanners
scanners configures the external vulnerability scanners (trivy, grype) used by on-demand scans (see security/scanning.md). OSV needs none of it.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
scanners.cacheDir | OPENARTIFACT_SCANNER_CACHE_DIR | string | empty | cacheDir is where the scanners keep their vulnerability databases (<cacheDir>/trivy, <cacheDir>/grype). It must be writable unless offline is set. Empty means a directory under the user cache dir; the container image sets /var/cache/openartifact/scanners. |
scanners.updateInterval | OPENARTIFACT_SCANNER_UPDATE_INTERVAL | duration | 6h | updateInterval is the pause between database refreshes. 0 downloads only when the server starts and never again; otherwise at least 1h. |
scanners.offline | OPENARTIFACT_SCANNER_OFFLINE | bool | false | offline stops the server from downloading databases: scans use what cacheDir already holds and fail while it holds none. |
scanners.downloadBaseUrl | OPENARTIFACT_SCANNER_DOWNLOAD_BASE_URL | string | https://github.com | downloadBaseUrl is the https origin the pinned release archives are downloaded from when a scanner's install mode is "auto". A mirror must serve GitHub's release paths (/<owner>/<repo>/releases/download/<tag>/<file>). |
scanners.trivy
scanners.trivy configures the trivy binary and its database sources.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
scanners.trivy.path | OPENARTIFACT_TRIVY_PATH | string | empty | path is the binary: a command name looked up on PATH, or an absolute path. Empty means "trivy". |
scanners.trivy.install | OPENARTIFACT_TRIVY_INSTALL | string | none | install is "none" (default) or "auto": download the pinned trivy release into the cache directory when path is empty and trivy is not on PATH. |
scanners.trivy.dbRepository | OPENARTIFACT_TRIVY_DB_REPOSITORY | string | empty | dbRepository is an OCI repository mirroring ghcr.io/aquasecurity/trivy-db. Empty is the upstream default. |
scanners.trivy.javaDbRepository | OPENARTIFACT_TRIVY_JAVA_DB_REPOSITORY | string | empty | javaDbRepository is an OCI repository mirroring ghcr.io/aquasecurity/trivy-java-db. Empty does not download the Java database (several hundred MB; only JAR scanning needs it). |
scanners.grype
scanners.grype configures the grype binary and its database source.
| YAML key | Env | Type | Default | Description |
|---|---|---|---|---|
scanners.grype.path | OPENARTIFACT_GRYPE_PATH | string | empty | path is the binary: a command name looked up on PATH, or an absolute path. Empty means "grype". |
scanners.grype.install | OPENARTIFACT_GRYPE_INSTALL | string | none | install is "none" (default) or "auto": download the pinned grype release into the cache directory when path is empty and grype is not on PATH. |
scanners.grype.dbUrl | OPENARTIFACT_GRYPE_DB_URL | string | empty | dbUrl is the database listing URL of a mirror (GRYPE_DB_UPDATE_URL). Empty is the upstream default. |
Environment-only variables
These variables are read by the configuration loader but have no YAML key.
| Variable | Description |
|---|---|
OTEL_SDK_DISABLED | true forces telemetry off, overriding telemetry.otlp.enabled and OPENARTIFACT_OTLP_ENABLED. |
Variables read outside the configuration loader, such as the secret-encryption key, the metrics scrape token and the migration switch, are described in Environment-only variables.