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 |
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 Ent ORM manages a connection pool internally.
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 health check at /api/health that verifies:
- The HTTP server is accepting connections
- The database connection is alive
This endpoint does not require authentication and returns a JSON response:
{
"status": "ok",
"database": "connected",
"version": "1.0.0"
}Use this for load balancer health checks, Docker health checks, and uptime monitoring.