Getting started
Configuration
Every setting comes from an environment variable, and an empty variable counts as unset. A secret can instead be read from a file: set <NAME>_FILE to its path.
Process
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_MODE | all | Modules this process runs; all runs every module in one process. The --mode flag of vws serve takes precedence. One of: all, world, content, control. | |
VWS_ENV | production | Deployment environment. development relaxes the production requirements and generates a local signing key. One of: development, production. | |
VWS_DATA_DIR | .vws | Directory for local state: the development signing key and the disk object store. | |
VWS_HTTP_ADDR | :8080 | Address of the public HTTP listener. | |
VWS_TLS_CERT_FILE | with VWS_TLS_KEY_FILE | PEM file with the certificate chain the public listener serves over HTTPS; leave it empty behind a load balancer that terminates TLS. The Vite dev server uses it too. | |
VWS_TLS_KEY_FILE | with VWS_TLS_CERT_FILE | PEM file with the private key of VWS_TLS_CERT_FILE. | |
VWS_PUBLIC_URL | in development, VWS_NGROK_URL, else localhost with the port of VWS_HTTP_ADDR | in production | Public base URL of the platform host. Tenant custom domains are configured in the database. |
VWS_OPS_ADDR | 127.0.0.1:9091 | Address of the operations listener for metrics and health checks; off disables it. Use :9091 inside containers. | |
VWS_SHUTDOWN_TIMEOUT | 20s | Time in-flight requests get during a graceful shutdown. Keep it below the stop timeout of the process manager. | |
VWS_TRUSTED_PROXIES | Comma-separated IP addresses or CIDR prefixes of load balancers whose X-Forwarded-For header is trusted, such as the VPC CIDR behind an ALB. |
Tenancy
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_TENANCY | multi in development | in production | single serves one tenant on every host the platform is reached at, with no subdomains or domain verification; multi finds the tenant of each request by its host. One of: single, multi. |
VWS_TENANT | Slug of the tenant a single-tenant platform serves. Empty serves the only tenant there is, or creates main on the first start; a database with several tenants needs it. | ||
VWS_TENANT_DOMAIN | Domain under which every new tenant gets its platform subdomain, <slug>.<domain>, such as tenants.example.com. It needs a wildcard DNS record and certificate. Empty gives new tenants no platform subdomain. | ||
VWS_OPERATOR_HOST | console.localhost in development | in production with VWS_TENANCY=multi | Host of the central admin of a multi-tenant platform, such as console.example.com, where operators sign in with the platform identity provider. In development the central admin also answers at /operator on every host. |
Database
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_DATABASE_URL | always | Postgres URL of the application role, which row-level security applies to. Secret. | |
VWS_DATABASE_MIGRATION_URL | VWS_DATABASE_URL | Postgres URL of the role that owns the schema, used by vws migrate and VWS_MIGRATE_ON_START. Secret. | |
VWS_DATABASE_MAX_CONNS | 10 | Maximum pool size of each process. | |
VWS_MIGRATE_ON_START | false | Apply pending migrations when the server starts. |
Redis
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_REDIS_URL | in modes all, world and control | Redis URL. rediss:// enables TLS, which ElastiCache with in-transit encryption requires. Secret. |
Cluster
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_CLUSTER_ADDR | off | Address of the listener on which the world processes of a platform reach each other's rooms and spaces, such as :9090, on a private network only. off runs every room on the process its visitors reach, which needs one process in modes all and world. | |
VWS_CLUSTER_ADVERTISE | the host of VWS_CLUSTER_ADDR, or the first private IPv4 address of the machine, with its port | Address at which the other processes reach this one's cluster listener: a private IP address and the port of VWS_CLUSTER_ADDR. | |
VWS_CLUSTER_SECRET | with VWS_CLUSTER_ADDR | Secret that every call between the world processes carries, at least 32 characters long; openssl rand -base64 32 makes one. Secret. |
Object storage
Credentials come from the standard AWS chain, such as AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for S3-compatible services.
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_STORAGE_BACKEND | disk | Where maps, assets, uploads and recordings are stored. One of: disk, s3. | |
VWS_STORAGE_DISK_PATH | $VWS_DATA_DIR/objects | Directory of the disk backend. | |
VWS_S3_BUCKET | when VWS_STORAGE_BACKEND is s3 | Bucket of the s3 backend. | |
VWS_S3_REGION | Bucket region. Empty uses the AWS SDK default (AWS_REGION). | ||
VWS_S3_ENDPOINT | Endpoint of an S3-compatible service. Empty uses AWS. | ||
VWS_S3_FORCE_PATH_STYLE | false | Address buckets by path instead of by subdomain, as most S3-compatible services require. |
Media
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_LIVEKIT_URL | LiveKit server URL. Media features stay disabled when it is empty. | ||
VWS_LIVEKIT_API_URL | Address at which the server calls LiveKit's API when it differs from VWS_LIVEKIT_URL, the one browsers connect to, as inside a container network. Empty uses VWS_LIVEKIT_URL. | ||
VWS_LIVEKIT_API_KEY | with VWS_LIVEKIT_URL | LiveKit API key. | |
VWS_LIVEKIT_API_SECRET | with VWS_LIVEKIT_URL | LiveKit API secret, at least 32 characters long, because a shorter one could be guessed from any token it signs. Secret. |
Authentication
To rotate keys, add the new key second and deploy, move it first and deploy, then remove the old key once VWS_ACCESS_TOKEN_TTL has passed.
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_SIGNING_KEYS | a key generated in $VWS_DATA_DIR/signing-key.pem, in development | in production | PEM-encoded Ed25519 private keys in PKCS #8 form that sign access tokens. The first key signs and every key verifies, which allows rotation. A single-line value may use literal \n sequences. Secret. |
VWS_ACCESS_TOKEN_TTL | 15m | Lifetime of access tokens. | |
VWS_REFRESH_TOKEN_TTL_WEB | 720h | Lifetime of browser refresh tokens. | |
VWS_REFRESH_TOKEN_TTL_NATIVE | 2160h | Lifetime of mobile app refresh tokens. | |
VWS_ENCRYPTION_KEY | in production | 32 random bytes in base64 that seal identity providers' client secrets and the tokens of connected calendars in the database; openssl rand -base64 32 makes one. Without it, neither identity providers other than the built-in ones nor calendars can be used. Secret. |
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_EMAIL_BACKEND | log in development, otherwise off | How sign-in links and invites are sent: off, written to the log in development, through Amazon SES with the AWS SDK's default credentials, or through Mailgun's API. Sign-in by email is offered only when email is not off. One of: off, log, ses, mailgun. | |
VWS_EMAIL_FROM | with VWS_EMAIL_BACKEND=ses or mailgun | Sender address of the email the server sends. | |
VWS_MAILGUN_DOMAIN | with VWS_EMAIL_BACKEND=mailgun | Sending domain of the Mailgun account, such as mg.example.com. | |
VWS_MAILGUN_API_KEY | with VWS_EMAIL_BACKEND=mailgun | Mailgun API key that may send from VWS_MAILGUN_DOMAIN, such as a sending key of that domain. Secret. | |
VWS_MAILGUN_REGION | us | Region of the Mailgun account, which decides the API host: api.mailgun.net for us, api.eu.mailgun.net for eu. One of: us, eu. |
Platform sign-in
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_OIDC_ISSUER | OpenID Connect issuer of the platform identity provider, for the operator console and development. Tenant providers are configured in the database. | ||
VWS_OIDC_CLIENT_ID | with VWS_OIDC_ISSUER | Client ID at the platform identity provider. | |
VWS_OIDC_CLIENT_SECRET | with VWS_OIDC_ISSUER | Client secret at the platform identity provider. Secret. | |
VWS_OIDC_SCOPES | openid,email,profile | Comma-separated scopes requested from the platform identity provider. |
Calendars
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_GOOGLE_CLIENT_ID | OAuth client ID of the platform at Google, which reads the calendars and tasks that people connect; its redirect URI is $VWS_PUBLIC_URL/api/v1/calendars/callback. Empty offers no Google calendars. | ||
VWS_GOOGLE_CLIENT_SECRET | with VWS_GOOGLE_CLIENT_ID | Client secret of VWS_GOOGLE_CLIENT_ID. Secret. | |
VWS_MICROSOFT_CLIENT_ID | Application ID of the platform at Microsoft Entra, for work, school and personal accounts, which reads the calendars and To Do tasks that people connect; its redirect URI is $VWS_PUBLIC_URL/api/v1/calendars/callback. Empty offers no Microsoft calendars. | ||
VWS_MICROSOFT_CLIENT_SECRET | with VWS_MICROSOFT_CLIENT_ID | Client secret of VWS_MICROSOFT_CLIENT_ID. Secret. |
Logging and telemetry
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_LOG_LEVEL | info | Minimum level of log records. One of: debug, info, warn, error. | |
VWS_LOG_FORMAT | json | Log encoding: json for CloudWatch and other collectors, text for terminals. One of: json, text. | |
VWS_SENTRY_DSN | Sentry DSN. Error reporting is disabled when it is empty. Secret. | ||
VWS_SENTRY_ENVIRONMENT | $VWS_ENV | Environment tag on Sentry events. | |
OTEL_EXPORTER_OTLP_ENDPOINT | Standard OpenTelemetry variable. Tracing is enabled when this or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is set; the SDK honours every other OTEL_* variable. | ||
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | Standard OpenTelemetry variable for the traces endpoint alone. | ||
OTEL_SDK_DISABLED | false | Standard OpenTelemetry variable that disables tracing. |
Limits
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_ROOM_CAPACITY | 200 | Capacity of rooms that do not set their own. | |
VWS_ZONE_SIZE | 320 | Side, in map pixels, of the square zones that scope movement updates. | |
VWS_POSITION_INTERVAL | 200ms | Minimum interval between position updates a moving client sends. | |
VWS_MAX_FRAME_BYTES | 1048576 | Largest WebSocket frame accepted from a client, in bytes. | |
VWS_CHAT_MAX_CHARS | 4000 | Longest chat message, in characters. |
Features
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_FEATURES | chat,editor,media,scripting | Comma-separated features the platform allows. Tenant, world and room settings can only narrow this list. Known features: chat, editor, media, recording, scripting, modules. |
Development
| Variable | Default | Required | Description |
|---|---|---|---|
VWS_NGROK_URL | ngrok endpoint URL, such as a static domain, that vws serve opens to this server in development; empty opens none. Needs the ngrok agent on PATH. | ||
VWS_NGROK_CONFIG | ngrok agent configuration file holding the authtoken. Empty uses the agent's default location. | ||
VWS_NGROK_UPSTREAM | the public listener, on localhost | Address ngrok forwards to, such as the Vite dev server at https://localhost:5173 to serve the client with hot reload. | |
VWS_DEV_TENANT | Slug of the tenant that serves hosts no domain names, such as a LAN address or a tunnel, in development only. |
Found a mistake? Tell us.