Backend Configuration
Backend configuration details including startup validation, runtime behavior, and environment-specific defaults.
The oCore backend is a Go application that reads all configuration from environment variables at startup. There is no configuration file. This page covers how the backend loads, validates, and applies configuration.
Configuration Loading
At startup, the backend's config.Load() function reads environment variables and applies defaults:
Startup → Read env vars → Apply defaults → Validate → Start serverIf any required variable is missing or invalid, the server exits immediately with a descriptive error message. This fail-fast behavior prevents running with an incomplete or insecure configuration.
Required vs Optional
Strictly Required
These variables must always be set:
| Variable | Validation |
|---|---|
DATABASE_URL | Must be non-empty |
JWT_SECRET | Must be non-empty and at least 32 characters |
Required in Production
These variables are validated only when ENVIRONMENT is not development:
| Variable | Validation |
|---|---|
SSH_ENCRYPTION_KEY | Must be at least 32 characters if set |
In development mode (ENVIRONMENT=development), the SSH encryption key is automatically derived from JWT_SECRET via HKDF key derivation. In production, it must be explicitly provided.
Recommended
These variables have defaults that work for development but should be configured for production:
| Variable | Dev Default | Production Recommendation |
|---|---|---|
APP_URL | http://localhost:3000 | Your public dashboard URL |
SMTP_HOST | localhost | Your SMTP provider |
SMTP_PORT | 1025 | 587 (STARTTLS) or 465 (TLS) |
SMTP_FROM | noreply@ocore.local | Your domain's noreply address |
DB_POOL_MIN_CONNS | 2 | Minimum warm PostgreSQL connections for expected steady-state load |
DB_POOL_MAX_CONNS | 25 | Maximum PostgreSQL connections within database capacity limits |
Environment Modes
The ENVIRONMENT variable controls runtime behavior:
Development Mode (ENVIRONMENT=development)
- SSH encryption key auto-derived from JWT secret
- Relaxed validation for optional security settings
- Default SMTP points to local Mailpit (
localhost:1025) - Default WebAuthn origin is
http://localhost:3000
Production Mode (ENVIRONMENT=production)
- Strict validation of security-related variables
SSH_ENCRYPTION_KEYmust be explicitly set if SSH gateway is enabled- All security headers enabled by default
- Cookie security flags enforced (Secure, HttpOnly, SameSite)
Duration Format
Variables that accept durations (JWT_ACCESS_EXPIRY, JWT_REFRESH_EXPIRY) use Go's time.ParseDuration format:
| Unit | Suffix | Example |
|---|---|---|
| Nanoseconds | ns | 500ns |
| Microseconds | us | 100us |
| Milliseconds | ms | 500ms |
| Seconds | s | 30s |
| Minutes | m | 15m |
| Hours | h | 24h |
Units can be combined: 1h30m for one hour and thirty minutes.
Server Port
The backend listens on the port specified by SERVER_PORT (default 8080). In a Docker Compose deployment, this port is only exposed within the Docker network. The reverse proxy forwards external traffic to this port.
services:
backend:
expose:
- "8080" # Internal only, not published to host
ports:
- "2222:2222" # SSH gateway is published directlyDo not publish port 8080 to the host in production. Always route HTTP traffic through a reverse proxy with TLS termination. See the Reverse Proxy guide.
Database Connection
The backend connects to PostgreSQL using the DATABASE_URL connection string. The server creates a configured pgxpool pool and shares it with Ent, River, and runtime health checks.
Connection Pool Bounds
| Variable | Default | Validation |
|---|---|---|
DB_POOL_MIN_CONNS | 2 | Must be 0 or greater |
DB_POOL_MAX_CONNS | 25 | Must be greater than 0 and greater than or equal to DB_POOL_MIN_CONNS |
Tune these values against PostgreSQL's max_connections and the number of backend replicas. The rich /api/health response includes pgx pool metrics when requested with Authorization: Bearer <HEALTH_CHECK_TOKEN>.
Connection String Format
postgres://user:password@host:port/database?sslmode=mode| Parameter | Description |
|---|---|
user | PostgreSQL username |
password | PostgreSQL password (URL-encode special characters) |
host | Database hostname or IP |
port | Database port (default 5432) |
database | Database name |
sslmode | disable, require, verify-ca, or verify-full |
For Docker Compose deployments where the database runs alongside the backend, use sslmode=disable since traffic stays within the Docker network. For external databases or managed services, use sslmode=require or stricter.
SSH Encryption
oCore encrypts stored SSH credentials (keys and passwords) at rest using AES-256-GCM with a key derived from SSH_ENCRYPTION_KEY. This protects credentials if the database is compromised.
In development, the encryption key is derived from JWT_SECRET using HKDF for convenience. In production, always set a separate SSH_ENCRYPTION_KEY:
# Generate a 64-character encryption key
openssl rand -base64 48Changing SSH_ENCRYPTION_KEY after deployment will make existing stored credentials unreadable. Back up the key securely.
Health Check
The backend exposes a liveness check at /api/health for load balancers, Docker health checks, and uptime monitoring.
Unauthenticated requests return a minimal response:
{
"status": "ok"
}Set HEALTH_CHECK_TOKEN and send Authorization: Bearer <token> to receive the rich health payload with version, commit, database pool metrics, SSH pool status, job queue status, agent status, backup freshness, and SSH gateway status.