Ganek reads its settings from environment variables, in the compose stack via the .env file next to docker-compose.yml. .env.example in the repository is the source of truth; this page groups the same settings with their defaults. Commented-out lines in the example are optional.
| Variable |
Default |
What it does |
GANEK_MODE |
single |
single for a self-hosted instance with one company; multi for the hosted product (public signup, quotas, captcha). |
GANEK_SECRET_KEY |
change it |
Signs session tokens and the capability links in candidate emails. openssl rand -hex 32. Rotating it signs everyone out. |
GANEK_ENCRYPTION_KEY |
derived from the secret key |
Encrypts stored Google refresh tokens and 2FA secrets. Set it separately (openssl rand -hex 32) so the two keys rotate independently; rotating this one only means recruiters reconnect their calendars. |
POSTGRES_PASSWORD |
ganek |
Password of the bundled Postgres. Change it before exposing anything. |
GANEK_DATABASE_URL |
bundled Postgres |
postgresql+asyncpg://user:pass@host:5432/ganek for an external server. Use a database dedicated to Ganek. |
| Variable |
Default |
What it does |
GANEK_S3_BUCKET |
ganek-cvs |
Bucket for uploaded CVs. |
GANEK_S3_ACCESS_KEY, GANEK_S3_SECRET_KEY |
minioadmin |
Credentials the backend uses. Change both. |
MINIO_ROOT_USER, MINIO_ROOT_PASSWORD |
minioadmin |
Root credentials of the bundled MinIO. Change both. |
GANEK_S3_PUBLIC_ENDPOINT_URL |
unset |
Public origin candidates upload to (presigned POST). Must be reachable from the browser. It is baked into the frontend’s Content Security Policy at build time, so rebuild the frontend image after changing it. |
GANEK_CV_MAX_SIZE_MB |
10 |
Upload size limit; type is restricted to PDF and common document formats. |
| Variable |
Default |
What it does |
GANEK_PUBLIC_BASE_URL |
unset |
The candidate-facing origin, for example https://jobs.example.com. Quiz, status and interview links in emails use it; the frontend builds the sitemap and Open Graph URLs from it. Set it as soon as the instance has a hostname. |
GANEK_GOOGLE_CLIENT_ID, GANEK_GOOGLE_CLIENT_SECRET |
unset |
Google sign-in and Google Calendar scheduling. Create an OAuth web client in Google Cloud Console. |
GANEK_GOOGLE_REDIRECT_URL |
${GANEK_PUBLIC_BASE_URL}/api/v1/auth/google/callback |
Override the redirect URI registered with Google. |
Emails are skipped with a warning while no provider is configured. The recruiter checklist shows the state.
| Variable |
Default |
What it does |
GANEK_EMAIL_PROVIDER |
smtp |
smtp for any relay, or mailjet for the HTTPS API (EU-hosted; its bounce and complaint events feed the suppression list). |
GANEK_SMTP_HOST, GANEK_SMTP_PORT, GANEK_SMTP_USER, GANEK_SMTP_PASSWORD |
unset, port 587 |
The SMTP relay. |
GANEK_SMTP_STARTTLS |
true |
Disable only for a local plaintext catcher such as Mailhog. |
GANEK_EMAIL_FROM |
unset |
Sender address, for example jobs@example.com. Set up SPF, DKIM and DMARC for its domain (see Self-hosting). |
GANEK_MAILJET_API_KEY, GANEK_MAILJET_SECRET_KEY |
unset |
Mailjet only: the REST API key pair. |
GANEK_EMAIL_WEBHOOK_SECRET |
unset |
Basic-auth password the provider presents on its bounce and complaint webhook (https://ganek:<secret>@host/api/v1/email/webhooks/mailjet). Unset means webhooks are off. |
| Variable |
Default |
What it does |
GANEK_CAPTCHA_ENABLED |
false |
Self-hosted proof-of-work challenge (ALTCHA, no third party) on signup, apply and request-new-link. Only shown in multi mode. |
GANEK_CAPTCHA_SECRET |
unset |
HMAC key for the challenge; any long random string. Required when enabled. |
| Variable |
Default |
Meaning |
GANEK_SSR_SECRET |
unset |
Optional. Page views are counted when the frontend’s server render says a load is one (no cookie, no script, no identifier; see the GDPR guide). Those headers can be sent by anyone who calls the API directly, so the counters are advisory. Set the same long random string on the backend and the frontend and only loads that carry it count; anything else is served as usual and not counted. |
| Variable |
Default |
What it does |
GANEK_LOG_FORMAT |
text |
json writes one object per line for log shippers. Every line carries the request id, also returned as the X-Request-ID header (an inbound one is honoured). |
GANEK_LOG_LEVEL |
INFO |
Standard Python levels. |
GANEK_SENTRY_DSN |
unset |
Optional error reporting to Sentry or a self-hosted Sentry/GlitchTip. Unset means nothing leaves the box. Events are scrubbed (emails, capability tokens, CV file names, cookies). Setting this makes your Sentry host a processor: list it in your records (see the GDPR guide). |
GANEK_SENTRY_ENVIRONMENT |
production |
Environment tag. |
GANEK_SENTRY_TRACES_SAMPLE_RATE |
0 |
Performance tracing stays off by default. |
| Variable |
Default |
What it does |
GANEK_COOKIE_SECURE |
true |
Session cookies are sent over HTTPS only. Leave it on in production; turn it off only for plain-HTTP local development. |
GANEK_TRUST_PROXY_HEADERS |
true |
Read the client IP from X-Forwarded-For. Keep the backend behind a trusted proxy, or clients can spoof their IP and dodge the rate limits. |
Per-IP, per-minute limits are Redis-backed with an in-memory fallback.
| Variable |
Default |
GANEK_RATE_LIMIT_ENABLED |
true |
GANEK_RATE_LIMIT_AUTH_PER_MINUTE |
10 |
GANEK_RATE_LIMIT_APPLY_PER_MINUTE |
5 |
GANEK_RATE_LIMIT_UPLOAD_PER_MINUTE |
10 |
GANEK_RATE_LIMIT_QUIZ_PER_MINUTE |
60 |
GANEK_RATE_LIMIT_PUBLIC_PER_MINUTE |
120 |
Per-tenant abuse guards (0 turns one off). Admins see the counters on the usage endpoint and as a banner from 80% of a limit.
| Variable |
Default |
What it limits |
GANEK_QUOTA_EMAILS_PER_DAY |
500 |
Emails queued per day. |
GANEK_QUOTA_APPLICATIONS_PER_HOUR |
100 |
Application attempts per hour; the public apply endpoint answers 429 past it. |
GANEK_QUOTA_ACTIVE_JOBS |
50 |
Jobs published at once; publishing past it answers 409. |