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

config.yaml
# 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

TypeDefaultRequired
stringYes

The base domain for the instance. Sites are served at <slug>.<domain>. The main application (dashboard, API) is served at the bare domain.

listen

TypeDefaultRequired
string:8080No

The address and port to listen on. Use :443 for production with TLS.

storage_path

TypeDefaultRequired
string./data/sitesNo

Directory where uploaded site files are extracted and served from. Created automatically if it doesn't exist.

jwt_secret

TypeDefaultRequired
stringYes

Secret key for signing JWT authentication tokens. Should be a long random string. Generate one with:

openssl rand -hex 32

database.driver

TypeDefaultValues
stringsqlitesqlite, postgres, mysql

The database driver. SQLite requires no external setup. Postgres and MySQL require a running database server.

database.dsn

TypeDefaultRequired
stringYes

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

TypeDefaultRequired
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

TypeDefault
boolfalse

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

TypeDefault
boolfalse

Whether a valid invite code is required to register. Only applies when registration.enabled is true.

Registration behavior matrix

enabledinvite_requiredBehavior
truefalseOpen registration — anyone can sign up
truetrueInvite-only — registration requires a valid invite code
falseanyClosed — no new registrations (admins can still create users)

cloudflare.api_token

TypeDefaultRequired
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

TypeDefaultRequired
int4No

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

TypeDefaultRequired
int128No

Maximum memory per JavaScript runtime in megabytes. Workers exceeding this limit will be terminated.

worker.execution_timeout

TypeDefaultRequired
int30000No

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

TypeDefaultRequired
int50No

Maximum number of outbound fetch() calls allowed per worker invocation. Prevents runaway request loops.

worker.fetch_timeout_sec

TypeDefaultRequired
int10No

Timeout for individual outbound fetch() calls in seconds. Requests taking longer will be aborted.

worker.max_response_bytes

TypeDefaultRequired
int10485760No

Maximum response body size in bytes (default: 10 MB). Workers returning larger responses will be terminated.

worker.max_log_retention

TypeDefaultRequired
int7No

Number of days to retain worker console logs. Older logs are automatically pruned.

worker.max_script_size_kb

TypeDefaultRequired
int1024No

Maximum _worker.js file size in kilobytes. Deployments with larger worker scripts will be rejected.

worker.data_dir

TypeDefaultRequired
string./dataNo

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

TypeDefault
boolfalse

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

TypeDefault
booltrue

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

TypeDefault
string./data/seaweedfs

Directory for SeaweedFS data storage. Only used in managed mode.

object_storage.binary_path

TypeDefault
string./weed

Path to the SeaweedFS binary. Only used in managed mode. Use ./weed.exe on Windows.

object_storage.s3_endpoint

TypeDefaultRequired
stringhttp://127.0.0.1:8333No

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

TypeDefault
stringus-east-1

S3 region string used in SigV4 signing. Must match the region configured in S3 clients.

object_storage.auth.require_sigv4

TypeDefault
booltrue

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

TypeDefault
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:

VariableDescription
HOSTEDAT_SERVERServer URL for the CLI
HOSTEDAT_API_KEYAPI key for the CLI