Skip to content

Environment variables

The compose stack reads .env in the repository root (start from .env.example). Courses are configured in the database via Course settings; see Course configuration. Exercise templates are fetched lazily from course module archives.

Variable Default Meaning
APLUS_BASE_URL https://plus.cs.aalto.fi/api/v2/ The one A+ instance this deployment talks to. For the local A+ profile: http://plus:8000/api/v2/.
APLUS_URL backend-advertised origin Browser-facing A+ origin for links and download-only previews. The local A+ profile uses http://localhost:8000.
APLUS_CONNECT_TIMEOUT_SECONDS 5 A+ TCP connection timeout (1-30).
APLUS_SOCKET_TIMEOUT_SECONDS 60 A+ socket timeout (1-300).
APLUS_REQUEST_TIMEOUT_SECONDS 120 Whole A+ request timeout (1-600).
APLUS_MAX_REDIRECTS 3 Explicit same-origin redirect limit (0-3).
APLUS_ERROR_BODY_BYTES 4096 Maximum A+ write-error diagnostic body retained for server logs (256-65536).
APLUS_RESPONSE_BODY_BYTES 26214400 Maximum decoded JSON bytes accepted from one A+ response (1048576-104857600).
APLUS_PAGINATION_BODY_BYTES 104857600 Maximum decoded JSON bytes accepted across one paginated A+ request (APLUS_RESPONSE_BODY_BYTES-1073741824).
APLUS_EXERCISE_FORM_CONCURRENCY 16 Maximum concurrent exercise-form reads while building a cold course structure snapshot (1-64).
Variable Default Meaning
POSTGRES_USER hanami Database user.
POSTGRES_PASSWORD - Required. No default: docker compose up fails fast while empty, and the backend refuses weak/empty passwords against a real Postgres.
POSTGRES_POOL_SIZE 10 Maximum backend JDBC connection pool size (1-100).
POSTGRES_DB hanami Database name.
POSTGRES_PORT 5432 Loopback-only port for local debugging (psql -h localhost), not a public listener.
POSTGRES_URL set by compose JDBC URL the backend connects to. Required unless native development explicitly enables ephemeral H2.
ALLOW_IN_MEMORY_DATABASE false Set to true only for native development without POSTGRES_URL; data vanishes on restart. It cannot be combined with POSTGRES_URL.
POSTGRES_HEALTHCHECK_INTERVAL 10s Compose interval for the Postgres readiness probe.
Variable Default Meaning
BACKEND_PORT 8088 Published backend port.
FRONTEND_PORT 3000 Published frontend port.
FRONTEND_BIND 127.0.0.1 Host address for the published frontend port. Set 0.0.0.0 only for intentional remote access and protect the port with a firewall.
DOCS_PORT 3001 Published documentation site port.
FRONTEND_ORIGIN http://localhost:3000 Public origin the frontend is served from (SvelteKit CSRF / same-origin checks). Set to the public https:// URL in production.
PROTOCOL_HEADER / HOST_HEADER - Behind a TLS-terminating proxy forwarding plain HTTP, set to x-forwarded-proto / x-forwarded-host so SvelteKit sees the real scheme and host.
ADDRESS_HEADER / XFF_DEPTH - / 1 With the bundled Caddy edge, set these to x-forwarded-for / 1 so SvelteKit uses the client address added by the single trusted proxy.
BACKEND_HEALTHCHECK_INTERVAL 10s Compose interval for the backend readiness probe.

The optional edge Compose profile runs Caddy in front of the frontend.

Variable Default Meaning
HANAMI_HOST - Required for the edge profile. Public DNS hostname served by Caddy.
HTTP_PORT 80 Published TCP port for HTTP and automatic HTTPS redirects.
HTTPS_PORT 443 Published TCP and UDP port for HTTPS over HTTP/2 and HTTP/3.
Variable Default Meaning
GITHUB_URL https://github.com/jaakkonakaza/hanami Source repository linked from the frontend footer.
DOCS_URL unset Deployed documentation origin linked from the frontend footer. Local development uses http://localhost:3001.
LICENSE_URL {GITHUB_URL}/blob/main/LICENSE License page linked from the frontend footer.
HANAMI_VERSION package version Optional deployment override for the application version shown in the footer. Releases normally use the version embedded in the package.

See the security model before changing these values.

Variable Meaning
COOKIE_SECURE=true Force the session cookie’s Secure flag even when SvelteKit computed an http:// origin.
ALLOW_INSECURE_HTTP=true Allow non-loopback HTTP session cookies for disposable local development. Never use this in production.
ALLOW_WEAK_DB_PASSWORD=true Throwaway local dev only: let the backend connect to Postgres with a weak/empty password.
ALLOW_PRIVATE_COURSE_CONFIG_URL=true Throwaway local Compose or native-backend dev only: allow a courseConfigUrl on a private/loopback host. Never set in production.
LTI_ALLOW_WEAK_SECRET=true Local A+ dev only: accept LTI launches signed with the well-known dev secret.

FRONTEND_SESSION_ENCRYPTION_KEY and FRONTEND_SERVICE_SECRET are required. Supply both through deployment secrets, not image layers or the database.

Variable Default Meaning
FRONTEND_SESSION_ENCRYPTION_KEY required Base64 encoding of exactly 32 random bytes used for new A+ token ciphertext
FRONTEND_SESSION_KEY_VERSION v1 Version stored with sessions created by the active encryption key
FRONTEND_SESSION_PREVIOUS_ENCRYPTION_KEYS empty Comma-separated version=base64 keys retained while sessions from a routine rotation expire
FRONTEND_SERVICE_SECRET required Shared SvelteKit-to-Ktor credential with at least 32 visible ASCII characters
FRONTEND_SESSION_STUDENT_IDLE_DAYS 7 Student idle timeout, from 1 to 30 days
FRONTEND_SESSION_STUDENT_ABSOLUTE_DAYS 90 Student absolute timeout, from 7 to 365 days
FRONTEND_SESSION_STAFF_IDLE_DAYS 1 Teacher and assistant idle timeout, from 1 to 7 days
FRONTEND_SESSION_STAFF_ABSOLUTE_DAYS 30 Teacher and assistant absolute timeout, from 1 to 90 days
FRONTEND_SESSION_TOUCH_SECONDS 3600 Minimum interval between last-use database writes
FRONTEND_SESSION_CLEANUP_SECONDS 300 Background cleanup interval
FRONTEND_SESSION_CLEANUP_BATCH_SIZE 500 Maximum expired or revoked rows deleted per cleanup pass
FRONTEND_SESSION_MAX_PER_USER 20 Maximum active sessions retained per A+ user
FRONTEND_SESSION_CREATION_ENABLED true Set to false to stop new sign-ins during incident response

Optional; see Sign-in and LTI.

Variable Meaning
LTI_CONSUMER_KEY / LTI_CONSUMER_SECRET Key and secret of the LTI 1.1 service configured in the A+ site admin. Leave empty to disable and keep only the manual token gate.
LTI_LAUNCH_URL Override the launch URL used to verify the OAuth1 signature, only if the origin SvelteKit sees differs from what A+ signs (e.g. behind a proxy).
LTI_MENU_LABEL Backend-side A+ course-menu label used to discover each course’s LTI launch URL. Defaults to Hanami.

Fresh values are returned immediately. Values between their fresh and maximum ages are returned immediately while one deduplicated refresh runs in the background. Values beyond the maximum age are loaded before the request returns.

Variable Default
AUTH_CACHE_FRESH_SECONDS 300
AUTH_CACHE_MAX_AGE_SECONDS 900
AUTH_NEGATIVE_CACHE_TTL_SECONDS 30
AUTH_CACHE_MAX_ENTRIES 10000
SNAPSHOT_CACHE_FRESH_SECONDS 21600
SNAPSHOT_CACHE_MAX_AGE_SECONDS 86400
ROSTER_CACHE_FRESH_SECONDS 900
ROSTER_CACHE_MAX_AGE_SECONDS 3600
PROGRESS_CACHE_FRESH_SECONDS 300
PROGRESS_CACHE_MAX_AGE_SECONDS 1800
METADATA_CACHE_FRESH_SECONDS 3600
METADATA_CACHE_MAX_AGE_SECONDS 86400
COURSE_CACHE_MAX_ENTRIES_PER_KIND 10000
AVAILABILITY_CACHE_FRESH_SECONDS 900
AVAILABILITY_CACHE_MAX_AGE_SECONDS 3600
AVAILABILITY_FAILURE_TTL_SECONDS 15
AVAILABILITY_CACHE_MAX_ENTRIES 10000
SUBMISSION_FILE_CACHE_BYTES 268435456
SUBMISSION_FILE_CACHE_ENTRY_BYTES 2097152
SUBMISSION_FILE_CACHE_TTL_SECONDS 86400
ACTIVE_GRADING_CACHE_FRESH_SECONDS 10
ACTIVE_GRADING_CACHE_MAX_AGE_SECONDS 30
GRADING_SUBMISSION_MAX_COUNT 10000
GRADING_SUBMISSION_CACHE_MAX_RECORDS 20000
SUBMISSION_LOAD_MAX_ACTIVE 8
SUBMISSION_LOAD_MAX_QUEUED 32
SUBMISSION_DOWNLOAD_CONCURRENCY 4
TEMPLATE_CATALOG_FRESH_SECONDS 21600
TEMPLATE_CATALOG_MAX_AGE_SECONDS 86400
TEMPLATE_DOWNLOAD_TIMEOUT_SECONDS 30
TEMPLATE_FAILURE_TTL_SECONDS 300

Unset SMTP_HOST disables sending. Local dev with the aplus profile: SMTP_HOST=mailpit, SMTP_PORT=1025, then read mail at http://localhost:8025.

Variable Default
SMTP_HOST - (disabled)
SMTP_PORT 25
SMTP_FROM hanami@localhost
SMTP_USER / SMTP_PASSWORD -
SMTP_STARTTLS false

Leave both secrets unset to disable deferred manual grading. Use independent, random values in a deployment; both secrets must contain at least 32 UTF-8 bytes.

Variable Default Meaning
MANUAL_GRADING_ENCRYPTION_KEY - Encrypts A+ callback capabilities at rest.
MANUAL_GRADING_REGISTRATION_SECRET - Authenticates intake-grader registration and fixture reset requests.
MANUAL_GRADING_CALLBACK_ORIGINS http://grader:8080,http://plus:8000 Comma-separated callback origins accepted during registration.
MANUAL_GRADING_CONNECT_TIMEOUT_SECONDS 5 Callback connection timeout (1-30).
MANUAL_GRADING_REQUEST_TIMEOUT_SECONDS 30 Whole callback request timeout (1-120).
MANUAL_GRADING_SOCKET_TIMEOUT_SECONDS 30 Callback socket timeout (1-120).
MANUAL_GRADING_ERROR_BODY_BYTES 4096 Maximum callback error response read before it is discarded (256-65536).
MANUAL_GRADING_COMPLETED_RETENTION_DAYS 90 Days to retain completed capability rows before deleting their encrypted callback credential (1-3650).
Variable Default Meaning
APLUS_PORT 8000 Published A+ front port.
GRADER_PORT 8080 Published grader port.
APLUS_COURSE_DIR ./aplus/aplus-manual Host course directory mounted into the local A+ and grader containers.
APLUS_LOCAL_SETTINGS - Optional settings module mounted into the local A+ container.
COMPOSE_NETWORK_NAME hanami_default Concrete Compose network name used by services.
GRADER_RUNNER_MODULE_NETWORK hanami_default Network attached to grader-runner containers; set it to the same value as COMPOSE_NETWORK_NAME.
GRADER_RUNNER_NAMESPACE hanami Namespace for staged grader-runner copies under /tmp/aplus.
MAILPIT_UI_PORT 8025 Published Mailpit web UI port.
MAILPIT_SMTP_PORT 1025 Published Mailpit SMTP port.

Read from frontend/.env.local (start from frontend/.env.example), or set by scripts/dev-frontend.sh; see Getting started.

Variable Meaning
BACKEND_URL Backend to proxy API calls to (default http://localhost:8088).
APLUS_URL Browser-facing A+ origin for external links and runtime LTI origin validation. Native development uses the published port, such as http://localhost:8000.
DOCS_URL Documentation origin for the footer (default http://localhost:3001 in the development helpers).
GITHUB_URL Source repository for the footer.
FRONTEND_SERVICE_SECRET Must match the Ktor service secret. Native scripts provide a local development value.

These are set by repository scripts and test tooling rather than by a normal deployment:

Variable Purpose
DOCKER_DEV Enables Vite’s Docker HMR settings in docker-compose.dev.yml.
SVELTE_KIT_OUT_DIR Keeps svelte-check output separate from the live development build.
VITEST Selects the isolated SvelteKit output directory used by Vitest.
HANAMI_FIXTURE_BACKEND_ORIGINS Exact comma-separated origins that local fixture provisioning may contact in addition to loopback development URLs.