Configuration Reference
The server reads its configuration from config.yaml in the working directory.
Override the path with --config /path/to/config.yaml.
Full example
# The base domain. Sites are served at <slug>.domain
domain: hostedat.ditto.moe
# Address to listen on
# :443 for production (HTTPS via CertMagic)
# :8080 for development (no TLS)
listen: ":443"
# Directory where uploaded site files are stored
storage_path: ./data/sites
# Secret used to sign JWT tokens
# Generate with: openssl rand -hex 32
jwt_secret: "change-me-to-a-random-secret"
# Database configuration
database:
driver: sqlite # sqlite | postgres | mysql
dsn: ./data/hostedat.db
# Minimum CLI version required to use the API.
# Clients with older versions receive HTTP 426 Upgrade Required.
# Leave empty to allow all versions.
min_cli_version: ""
# Registration settings (initial seed — managed at runtime via admin API)
# On first run, registration is temporarily allowed to create the superadmin
# account regardless of this setting.
registration:
enabled: false # Allow new user signups (disabled by default)
invite_required: false # Require invite code to register
# Cloudflare DNS for Let's Encrypt wildcard cert
# Leave api_token empty to disable TLS (dev mode)
cloudflare:
api_token: ""
# Worker runtime settings
worker:
pool_size: 4 # Pre-warmed JS runtimes per site
memory_limit_mb: 128 # Max memory per runtime
execution_timeout: 30000 # Max execution time in ms
max_fetch_requests: 50 # Max outbound fetch() calls per invocation
fetch_timeout_sec: 10 # Timeout per fetch() call
max_response_bytes: 10485760 # 10 MB max response body
max_log_retention: 7 # Days to keep worker logs
max_script_size_kb: 1024 # Max _worker.js file size
data_dir: ./data # Storage for D1 databases, Durable Objects, Queues
# S3-compatible object storage (backed by SeaweedFS)
object_storage:
enabled: false
managed: true # hostedat manages SeaweedFS lifecycle
data_dir: ./data/seaweedfs # SeaweedFS data directory
binary_path: ./weed # SeaweedFS binary path (managed mode)
region: us-east-1
# s3_endpoint: http://127.0.0.1:8333 # Override for external SeaweedFS (managed: false)
auth:
require_sigv4: true # Reject unsigned proxy requests
access_key_id: "" # Optional static S3 credentials
secret_access_key: "" # Optional static S3 credentials Options
domain
| Type | Default | Required |
|---|---|---|
string | — | Yes |
The base domain for the instance. Sites are served at <slug>.<domain>. The main application (dashboard, API) is served at the bare domain.
listen
| Type | Default | Required |
|---|---|---|
string | :8080 | No |
The address and port to listen on. Use :443 for production with TLS.
storage_path
| Type | Default | Required |
|---|---|---|
string | ./data/sites | No |
Directory where uploaded site files are extracted and served from. Created automatically if it doesn't exist.
jwt_secret
| Type | Default | Required |
|---|---|---|
string | — | Yes |
Secret key for signing JWT authentication tokens. Should be a long random string. Generate one with:
openssl rand -hex 32 database.driver
| Type | Default | Values |
|---|---|---|
string | sqlite | sqlite, postgres, mysql |
The database driver. SQLite requires no external setup. Postgres and MySQL require a running database server.
database.dsn
| Type | Default | Required |
|---|---|---|
string | — | Yes |
Data source name. Format depends on the driver:
- SQLite: file path (e.g.,
./data/hostedat.db) - Postgres:
host=localhost port=5432 user=hostedat dbname=hostedat sslmode=disable - MySQL:
user:password@tcp(localhost:3306)/hostedat?parseTime=true
min_cli_version
| Type | Default | Required |
|---|---|---|
string | "" | No |
Minimum CLI version required to interact with the API. Clients running an older version receive HTTP 426 Upgrade Required. Leave empty to allow all versions.
registration.enabled
| Type | Default |
|---|---|
bool | false |
Whether new user registration is allowed. When false, only admins can create new users. On first run with an empty database, registration is temporarily allowed regardless of this setting so the initial superadmin account can be created.
registration.invite_required
| Type | Default |
|---|---|
bool | false |
Whether a valid invite code is required to register. Only applies when registration.enabled is true.
Registration behavior matrix
| enabled | invite_required | Behavior |
|---|---|---|
true | false | Open registration — anyone can sign up |
true | true | Invite-only — registration requires a valid invite code |
false | any | Closed — no new registrations (admins can still create users) |
cloudflare.api_token
| Type | Default | Required |
|---|---|---|
string | "" | Only for HTTPS |
Cloudflare API token with Zone:DNS:Edit permission. Used for DNS-01 challenge to obtain wildcard TLS certificates from Let's Encrypt. Leave empty to run without TLS (development mode).
worker.pool_size
| Type | Default | Required |
|---|---|---|
int | 4 | No |
Number of pre-warmed JavaScript runtimes to maintain per site with a worker. Higher values reduce cold start latency but consume more memory.
worker.memory_limit_mb
| Type | Default | Required |
|---|---|---|
int | 128 | No |
Maximum memory per JavaScript runtime in megabytes. Workers exceeding this limit will be terminated.
worker.execution_timeout
| Type | Default | Required |
|---|---|---|
int | 30000 | No |
Maximum execution time for a single worker invocation in milliseconds. Requests exceeding this limit will be terminated with a timeout error.
worker.max_fetch_requests
| Type | Default | Required |
|---|---|---|
int | 50 | No |
Maximum number of outbound fetch() calls allowed per worker invocation. Prevents runaway request loops.
worker.fetch_timeout_sec
| Type | Default | Required |
|---|---|---|
int | 10 | No |
Timeout for individual outbound fetch() calls in seconds. Requests taking longer will be aborted.
worker.max_response_bytes
| Type | Default | Required |
|---|---|---|
int | 10485760 | No |
Maximum response body size in bytes (default: 10 MB). Workers returning larger responses will be terminated.
worker.max_log_retention
| Type | Default | Required |
|---|---|---|
int | 7 | No |
Number of days to retain worker console logs. Older logs are automatically pruned.
worker.max_script_size_kb
| Type | Default | Required |
|---|---|---|
int | 1024 | No |
Maximum _worker.js file size in kilobytes. Deployments with larger worker scripts will be rejected.
worker.data_dir
| Type | Default | Required |
|---|---|---|
string | ./data | No |
Directory for worker data storage, including D1 database files, Durable Object state, and Queue data. D1 databases are stored at <data_dir>/d1/<siteID>_<databaseID>.sqlite3.
object_storage.enabled
| Type | Default |
|---|---|
bool | false |
Enable S3-compatible object storage backed by SeaweedFS. Provides an S3 API at storage.<domain> and R2-compatible env.BUCKET_NAME bindings in workers.
object_storage.managed
| Type | Default |
|---|---|
bool | true |
When true, hostedat manages the SeaweedFS process lifecycle automatically. Set to false to connect to an external SeaweedFS instance via s3_endpoint.
object_storage.data_dir
| Type | Default |
|---|---|
string | ./data/seaweedfs |
Directory for SeaweedFS data storage. Only used in managed mode.
object_storage.binary_path
| Type | Default |
|---|---|
string | ./weed |
Path to the SeaweedFS binary. Only used in managed mode. Use ./weed.exe on Windows.
object_storage.s3_endpoint
| Type | Default | Required |
|---|---|---|
string | http://127.0.0.1:8333 | No |
S3 endpoint URL for the SeaweedFS instance. Only relevant when managed is false — use this to point hostedat at an external SeaweedFS S3 gateway.
object_storage.region
| Type | Default |
|---|---|
string | us-east-1 |
S3 region string used in SigV4 signing. Must match the region configured in S3 clients.
object_storage.auth.require_sigv4
| Type | Default |
|---|---|
bool | true |
When true, the storage proxy rejects unsigned requests. Only SigV4-signed requests from authenticated S3 clients are accepted.
object_storage.auth.access_key_id / secret_access_key
| Type | Default |
|---|---|
string | "" |
Optional static S3 credentials for the storage proxy. When empty, credentials are managed per-user via the API.
Environment variables
The server does not read environment variables directly — all configuration is via the YAML file. However, the CLI supports these environment variables:
| Variable | Description |
|---|---|
HOSTEDAT_SERVER | Server URL for the CLI |
HOSTEDAT_API_KEY | API key for the CLI |