Skip to content

Configuring MolnOS

MolnOS is designed to be straightforward to configure while giving you control when you need it. This guide covers everything from the bare minimum to advanced configuration scenarios.

MolnOS can be configured in three ways, with priorities from highest to lowest:

  1. CLI flags (e.g., molnos start --port 8080)
  2. Environment variables (e.g., PORT=8080)
  3. Configuration file (molnos.config.json)

This flexibility means you can choose the approach that fits your deployment:

  • Use config files for local development or VMs where you manage files directly
  • Use environment variables for cloud platforms, containers, or CI/CD pipelines
  • Use CLI flags for quick overrides during testing

To run MolnOS, you must provide these values:

MolnOS supports two authentication methods. Choose one or use both:

Section titled “Option 1: Email-Based Magic Links (Passwordless)”
  • email.host - Your SMTP server hostname
  • email.user - SMTP username (typically your email address)
  • email.password - SMTP password or app-specific password

Configure OAuth to eliminate SMTP dependencies:

  • oauth.presets - Quick setup for Google, GitHub, Microsoft, GitLab
  • oauth.custom - Self-hosted providers (Keycloak, Authentik, etc.)

See OAuth Authentication below for full details.

  • molnos.dataPath - The path to application data (default: data)
  • molnos.initialUser.userName - The initial user’s name
  • molnos.initialUser.email - The email address to the initial user (receives first sign-in link)

The configuration file is the most common way to set up MolnOS, especially for local development and self-hosted deployments.

Terminal window
molnos init

This creates molnos.config.json in your current directory with a template similar to this:

{
"$schema": "https://schemas.molnos.cloud/schema-config-v1.json",
"email": {
"emailSubject": "Sign In To MolnOS",
"user": "my_user@my_domain.net",
"password": "my_password",
"host": "smtp.my_host.net",
"port": 465,
"secure": true
},
"molnos": {
"dataPath": "data",
"initialUser": {
"userName": "User",
"email": "me@my_domain.net"
}
},
"auth": {
"jwtSecret": "your-jwt-secret",
"consoleUrl": "https://localhost:8000"
},
"server": {
"allowedDomains": ["*"]
}
}

Add the $schema property to get autocomplete and validation in VSCode and other editors:

{
"$schema": "https://schemas.molnos.cloud/schema-config-v1.json",
"molnos": { ... }
}

This gives you:

  • Autocomplete for all configuration options
  • Inline documentation when hovering over properties
  • Validation errors for invalid values before you run MolnOS

Environment variables are ideal for cloud deployments, containers, and CI/CD pipelines where you don’t want to manage configuration files.

Environment VariableDescriptionDefault
EMAIL_HOSTSMTP server hostname-
EMAIL_USERSMTP username-
EMAIL_PASSWORDSMTP password-
EMAIL_PORTSMTP port465
EMAIL_SECUREUse SSL/TLS (true/false)true
EMAIL_SUBJECTSubject line for sign-in emails"Sign In To MolnOS"
Environment VariableDescriptionDefault
AUTH_JWT_SECRETSecret key for JWT signing"your-jwt-secret"
CONSOLE_URLURL where users complete sign-in"http://127.0.0.1:8000"
Environment VariableDescriptionDefault
PORTPort to listen on3000
HOSTHost to bind to"localhost"
ALLOWED_DOMAINSComma-separated list of allowed CORS origins"http://127.0.0.1:8080"
Environment VariableDescriptionDefault
DATA_PATHDirectory for application data"data"
STORAGE_KEYEncryption key for sensitive data-
Environment VariableDescriptionDefault
INITIAL_USER_NAMEOrganization name for initial setup-
INITIAL_USER_EMAILAdmin email for initial setup-
SIGNED_URL_SECRETCustom secret value for signed URLsWithheld

Example: Cloud Deployment with Environment Variables

Section titled “Example: Cloud Deployment with Environment Variables”

In your App Platform configuration, add these environment variables:

CONSOLE_URL=https://molnos.yourcompany.com
ALLOWED_DOMAINS=https://molnos.yourcompany.com
INITIAL_USER_NAME=Your Company
EMAIL_HOST=smtp.gmail.com
EMAIL_PASSWORD=your-app-password
EMAIL_PORT=465
EMAIL_SECURE=true
AUTH_JWT_SECRET=your-secure-random-string

CLI flags provide the highest priority and are useful for quick overrides during development or testing.

Terminal window
--jwtSecret <secret> JWT secret for token signing
--magicLinkExpirySeconds <seconds> Magic link expiry time
--jwtExpirySeconds <seconds> JWT expiry time
--refreshTokenExpirySeconds <secs> Refresh token expiry time
--maxActiveSessions <number> Max concurrent sessions
--consoleUrl <url> Application URL for sign-in completion
Terminal window
--emailSubject <subject> Email subject line
--emailHost <hostname> SMTP server hostname
--emailUser <username> SMTP username
--emailPassword <password> SMTP password
--emailPort <port> SMTP port number
--emailSecure Use SSL/TLS (flag, no value)
--emailMaxRetries <number> Max retry attempts
Terminal window
--port <port> Port to listen on
--host <hostname> Host to bind to
--allowed <domain1,domain2,...> Comma-separated allowed domains

Examples of allowed domains:

// Allow specific domains (recommended for production)
"allowedDomains": [
"https://molnos.example.com",
"https://app.example.com"
]
// Allow all domains (development only)
"allowedDomains": ["*"]
// Allow localhost for development
"allowedDomains": [
"http://localhost:8000",
"http://localhost:3000"
]
Terminal window
--db <directory> Database directory path (auth)
--encryptionKey <key> Encryption key for storage (auth)
Terminal window
--data-path <path> Path to application data
--initialUserId <id> Initial user ID (auto-generated if not set)
--initialUserName <name> Initial user name
--initialUserEmail <email> Initial user email address
Terminal window
molnos start --port 8080

When the same setting is provided in multiple ways, MolnOS uses this priority order:

  1. CLI flags (highest priority)
  2. Environment variables
  3. Configuration file
  4. Default values (lowest priority)

If you have:

  • Config file: "port": 3000
  • Environment variable: PORT=8080
  • CLI flag: --port 9000

MolnOS will use port 9000 (CLI flag wins).

OAuth support enables authentication without SMTP dependencies, providing autonomy from external email providers. You can use common providers (Google, GitHub) or self-hosted solutions (Keycloak, Authentik) for complete sovereignty.

For Google, GitHub, Microsoft, or GitLab, use the preset configuration in this style:

{
"oauth": {
"presets": {
"google": {
"clientId": "your-google-client-id",
"clientSecret": "your-google-client-secret",
"redirectUri": "https://your-domain.com/auth/oauth/google/callback"
},
"github": {
"clientId": "your-github-client-id",
"clientSecret": "your-github-client-secret",
"redirectUri": "https://your-domain.com/auth/oauth/github/callback"
}
}
}
}

For complete sovereignty, use self-hosted OAuth providers:

{
"oauth": {
"custom": [
{
"id": "keycloak",
"name": "Company SSO",
"authorizationUrl": "https://auth.company.com/realms/main/protocol/openid-connect/auth",
"tokenUrl": "https://auth.company.com/realms/main/protocol/openid-connect/token",
"userInfoUrl": "https://auth.company.com/realms/main/protocol/openid-connect/userinfo",
"clientId": "molnos-core",
"clientSecret": "your-secret",
"redirectUri": "https://your-domain.com/auth/oauth/keycloak/callback",
"scopes": "openid email profile"
}
]
}
}

Combine OAuth and magic links for maximum flexibility:

{
"email": {
"host": "smtp.gmail.com",
"user": "[email protected]",
"password": "app-password"
},
"oauth": {
"presets": {
"google": {
"clientId": "...",
"clientSecret": "...",
"redirectUri": "https://your-domain.com/auth/oauth/google/callback"
}
}
}
}

Control OAuth authentication attempts (optional):

{
"oauth": {
"rateLimiting": {
"maxAttempts": 10,
"windowMs": 900000
}
}
}
  • maxAttempts - Maximum requests per window (default: 10)
  • windowMs - Time window in milliseconds (default: 900000 = 15 minutes)

Configure CSRF protection token expiry (optional):

{
"oauth": {
"stateExpirySeconds": 600
}
}

Default: 600 seconds (10 minutes)

When OAuth is configured, these endpoints become available:

  • GET /auth/oauth/providers - List available OAuth providers
  • GET /auth/oauth/{provider} - Initiate OAuth flow (e.g., /auth/oauth/google)
  • GET /auth/oauth/{provider}/callback - OAuth callback handler
  1. Go to Google Cloud Console
  2. Create or select a project
  3. Enable Google+ API
  4. Create OAuth 2.0 credentials for a web application
  5. Add authorized JavaScript origin: http://localhost:8000 (for local)
  6. Add authorized redirect URI: http://localhost:3000/auth/oauth/google/callback (for local)
  7. Copy Client ID and Client Secret to your MolnOS config

All OAuth flows include:

  • CSRF Protection: State parameter validation with IP binding
  • Rate Limiting: Per-IP request throttling (10 req/15min default)
  • HTTPS Enforcement: OAuth endpoints require HTTPS in production
  • Token Security: OAuth tokens never stored, only user info extracted
  • Automatic Cleanup: Expired state tokens removed automatically

Here’s a fully documented configuration file showing all available options:

{
"email": {
"emailSubject": "Sign In To MolnOS",
"user": "[email protected]",
"password": "your-smtp-password",
"host": "smtp.gmail.com",
"port": 465,
"secure": true
},
"oauth": {
"presets": {
"google": {
"clientId": "your-google-client-id",
"clientSecret": "your-google-client-secret",
"redirectUri": "https://molnos.yourcompany.com/auth/oauth/google/callback"
}
},
"custom": [
{
"id": "keycloak",
"name": "Company SSO",
"authorizationUrl": "https://auth.company.com/auth",
"tokenUrl": "https://auth.company.com/token",
"userInfoUrl": "https://auth.company.com/userinfo",
"clientId": "molnos",
"clientSecret": "your-secret",
"redirectUri": "https://molnos.yourcompany.com/auth/oauth/keycloak/callback",
"scopes": "openid email profile"
}
],
"stateExpirySeconds": 600,
"rateLimiting": {
"maxAttempts": 10,
"windowMs": 900000
}
},
"molnos": {
"dataPath": "data",
"initialUser": {
"userName": "User Name",
"email": "[email protected]"
},
"rateLimit": {
"global": {
"enabled": false,
"requestsPerMinute": 0
}
},
"signedUrlSecret": "my-signed-url-secret-value-here"
},
"auth": {
"jwtSecret": "your-secret-key-change-this",
"magicLinkExpirySeconds": 900,
"jwtExpirySeconds": 900,
"refreshTokenExpirySeconds": 604800,
"maxActiveSessions": 3,
"consoleUrl": "https://molnos.yourcompany.com"
},
"server": {
"port": 3000,
"host": "localhost",
"allowedDomains": [
"https://molnos.yourcompany.com"
]
},
"storage": {
"databaseDirectory": "molnosdb",
"encryptionKey": ""
}
}

When you start MolnOS, it validates your configuration and provides helpful error messages if required fields are missing:

Terminal window
$ molnos start
Error: Missing email.host value
Error: Missing email.user value
Error: Missing email.password value
Error: Missing molnos.initialUser.userName value
Error: Missing molnos.initialUser.email value

This ensures you can’t accidentally start MolnOS with incomplete configuration.

Goal: Quick setup for testing on your laptop using Mailpit as the SMPT server.

{
"email": {
"emailSubject": "Sign In To MolnOS",
"user": "[email protected]",
"password": "your-smtp-password",
"host": "localhost",
"port": 1025,
"secure": false
},
"auth": {
"jwtSecret": "your-secret-key-change-this",
"consoleUrl": "http://localhost:8000"
},
"server": {
"allowedDomains": ["*"]
},
"molnos": {
"dataPath": "data",
"initialUser": {
"userName": "User",
"email": "[email protected]"
}
}
}

Goal: Secure production deployment on your infrastructure

{
"email": {
"user": "[email protected]",
"password": "secure-app-password",
"host": "smtp.gmail.com",
"port": 465,
"secure": true
},
"auth": {
"jwtSecret": "generated-with-openssl-rand-base64-32",
"consoleUrl": "https://molnos.yourcompany.com",
"jwtExpirySeconds": 3600,
"refreshTokenExpirySeconds": 2592000
},
"server": {
"allowedDomains": [
"https://molnos.yourcompany.com"
]
},
"molnos": {
"dataPath": "data",
"initialUser": {
"userName": "User Name",
"email": "[email protected]"
}
}
}

Cloud Platform (Using Environment Variables)

Section titled “Cloud Platform (Using Environment Variables)”

Goal: Deploy on DigitalOcean, AWS, or similar without managing config files

Set these environment variables in your platform’s dashboard:

Terminal window
# Required
EMAIL_HOST=smtp.sendgrid.net
EMAIL_USER=apikey
EMAIL_PASSWORD=your-sendgrid-api-key
INITIAL_USER_NAME="Your Company"
INITIAL_USER_EMAIL=[email protected]
# Important
AUTH_JWT_SECRET=your-secure-random-string
CONSOLE_URL=https://molnos.yourcompany.com
ALLOWED_DOMAINS=https://molnos.yourcompany.com
# Optional
EMAIL_PORT=465
EMAIL_SECURE=true
PORT=3000

Goal: Eliminate SMTP dependency using self-hosted OAuth

{
"oauth": {
"custom": [
{
"id": "keycloak",
"name": "Internal SSO",
"authorizationUrl": "https://sso.company.internal/realms/main/protocol/openid-connect/auth",
"tokenUrl": "https://sso.company.internal/realms/main/protocol/openid-connect/token",
"userInfoUrl": "https://sso.company.internal/realms/main/protocol/openid-connect/userinfo",
"clientId": "molnos-core",
"clientSecret": "your-keycloak-secret",
"redirectUri": "https://molnos.company.internal/auth/oauth/keycloak/callback",
"scopes": "openid email profile"
}
]
},
"auth": {
"jwtSecret": "generated-with-openssl-rand-base64-32",
"consoleUrl": "https://molnos.company.internal"
},
"molnos": {
"dataPath": "data",
"initialUser": {
"userName": "Admin",
"email": "[email protected]"
}
}
}

Note: Email configuration is completely optional when OAuth is configured.

Always generate a strong, random JWT secret:

Terminal window
openssl rand -base64 32

Never commit secrets to version control. Use environment variables or secret management tools.

If you provide a storage.encryptionKey, MolnOS encrypts sensitive data at rest. Generate it the same way:

Terminal window
openssl rand -base64 32

In production, never use "allowedDomains": ["*"]. Always specify exact domains:

"allowedDomains": [
"https://molnos.yourcompany.com"
]

Configure rate limiting to protect your services from abuse. Rate limits can be set globally for all services or individually per service.

Apply the same rate limit to all services:

{
"molnos": {
"dataPath": "data",
"rateLimit": {
"global": {
"enabled": true,
"requestsPerMinute": 60
}
}
}
}

Override global settings for individual services (Functions, Databases, Storage, Sites, Observability):

{
"molnos": {
"dataPath": "data",
"rateLimit": {
"global": {
"enabled": true,
"requestsPerMinute": 60
},
"services": {
"functions": {
"enabled": true,
"requestsPerMinute": 120
},
"databases": {
"enabled": true,
"requestsPerMinute": 100
},
"storage": {
"enabled": false,
"requestsPerMinute": 0
}
}
}
}
}

Service-specific settings always override global settings. If a service doesn’t have specific settings, it inherits from the global configuration.

By default, MolnOS services run on localhost with predefined ports:

ServiceDefault Port
Storage3001
Functions3002
Sites3003
Databases3004
Observability3005

You can customize these endpoints for distributed deployments or to avoid port conflicts.

Override default ports for individual services:

{
"molnos": {
"dataPath": "data",
"services": {
"databases": {
"port": 5004
},
"storage": {
"port": 5001
}
}
}
}

Run services on different hosts for microservices-style deployments:

{
"molnos": {
"dataPath": "data",
"services": {
"databases": {
"host": "db.internal",
"port": 3004
},
"storage": {
"host": "storage.internal",
"port": 3001
},
"functions": {
"host": "compute.internal",
"port": 3002
}
}
}
}

Services without explicit configuration inherit server.host (or 127.0.0.1) and use their default ports.

For distributed deployments where services communicate over a network, you can enable HTTPS for individual services using the secure property:

{
"molnos": {
"dataPath": "data",
"services": {
"databases": {
"host": "db.example.com",
"port": 443,
"secure": true
},
"storage": {
"host": "storage.example.com",
"port": 443,
"secure": true
},
"functions": {
"host": "localhost",
"port": 3002
}
}
}
}

In this example, the databases and storage services use HTTPS (https://db.example.com:443), while the functions service uses HTTP (http://localhost:3002). This is useful when some services are deployed behind a TLS-terminating load balancer or reverse proxy.

PropertyDescriptionDefault
services.<service>.hostService host addressserver.host
services.<service>.portService port numberSee table below
services.<service>.secureUse HTTPS instead of HTTPfalse

Where <service> is one of: storage, functions, sites, databases, or observability.

Default ports:

ServiceDefault Port
Storage3001
Functions3002
Sites3003
Databases3004
Observability3005

MolnOS supports distributing capabilities across multiple hosts using cluster mode. A core node handles routing and management while worker nodes run specific capabilities like Functions or Storage.

ModeDescription
standaloneDefault. All capabilities run locally on a single host.
coreRoutes requests to configured remote workers. Runs Identity, Management, and non-delegated capabilities locally.
workerRuns only the specified capabilities. Validates cluster secret on incoming requests.

The core node routes requests to worker nodes based on capability:

{
"molnos": {
"dataPath": "data",
"cluster": {
"mode": "core",
"secret": "your-shared-cluster-secret",
"workers": {
"functions": {
"url": "http://functions-worker:3002",
"timeoutMs": 5000,
"healthCheckPath": "/health",
"healthCheckIntervalMs": 30000
},
"storage": {
"url": "http://storage-worker:3001"
}
}
}
}
}

Worker nodes only start the capabilities they’re assigned. They don’t need email, OAuth, initial user, or even dataPath configuration since they don’t handle identity—the core node manages authentication:

{
"molnos": {
"cluster": {
"mode": "worker",
"secret": "your-shared-cluster-secret",
"capabilities": ["functions"]
}
}
}
PropertyDescriptionDefault
cluster.modeNode mode: standalone, core, or workerstandalone
cluster.secretShared secret for inter-node authentication
cluster.capabilitiesCapabilities this worker handles (worker mode only)
cluster.workersWorker registry mapping capabilities to endpoints (core mode only)

Worker endpoint options:

PropertyDescriptionDefault
urlWorker base URL (required)
timeoutMsRequest timeout in milliseconds5000
healthCheckPathHealth check endpoint path/health
healthCheckIntervalMsHealth check interval30000

The core and workers authenticate using a shared secret passed via the X-MolnOS-Cluster-Secret header. Always use a strong, randomly generated secret. For production deployments, use HTTPS between nodes.

The core node monitors worker health automatically. After 3 consecutive health check failures, a worker is marked unhealthy and requests return 503 Service Unavailable. Workers recover automatically when health checks succeed again.

Core node (main.example.com):

{
"molnos": {
"dataPath": "data",
"cluster": {
"mode": "core",
"secret": "s3cr3t-k3y",
"workers": {
"functions": { "url": "http://compute.example.com:3000" }
}
}
}
}

Worker node (compute.example.com):

{
"molnos": {
"cluster": {
"mode": "worker",
"secret": "s3cr3t-k3y",
"capabilities": ["functions"]
}
}
}

Requests to /functions/* on the core are proxied to the worker. The worker validates the cluster secret and processes the request.

Service management (start/stop/restart) works transparently across the cluster. When you manage a service assigned to a remote worker, the core automatically forwards the command to the appropriate worker node.

Console → Core management API → Core forwards to Worker
  • The same API endpoints work regardless of where the service runs
  • Workers validate the cluster secret before accepting management commands
  • If a worker is unreachable, the management operation returns an error