Skip to main content

Environment Variables & Secrets

All configuration is injected via environment variables. No secrets are committed to git.


File Locations

FileLocationPurpose
.env/opt/rcb/.env on VPS onlyProduction runtime config
.env.exampleinfra/local/.env.example (git)Template — copy to .env
alertmanager.yml/opt/rcb/infra/local/observability/alertmanager/alertmanager.ymlGenerated from template, gitignored
alertmanager.yml.templateinfra/local/observability/alertmanager/alertmanager.yml.template (git)Committed template with ${VAR} placeholders

Production .env — Full Reference

# ──────────────────────────────────────────────────────────────────
# Domain
# ──────────────────────────────────────────────────────────────────
DOMAIN=rcb.bg
ACME_EMAIL=admin@rcb.bg

# ──────────────────────────────────────────────────────────────────
# PostgreSQL
# ──────────────────────────────────────────────────────────────────
DB_PASSWORD=<strong-random-password>

# ──────────────────────────────────────────────────────────────────
# Spring Boot / JASYPT encryption master password
# Decrypts ENC(...) values in application.yaml
# ──────────────────────────────────────────────────────────────────
JASYPT_PASSWORD=<jasypt-encryptor-master-password>

# ──────────────────────────────────────────────────────────────────
# Keycloak admin credentials (production)
# ──────────────────────────────────────────────────────────────────
KC_ADMIN_USER=admin
KC_ADMIN_PASSWORD=<strong-keycloak-admin-password>

# ──────────────────────────────────────────────────────────────────
# Grafana admin password
# ──────────────────────────────────────────────────────────────────
GRAFANA_ADMIN_PASSWORD=<strong-grafana-password>

# ──────────────────────────────────────────────────────────────────
# Traefik BasicAuth — generate with: htpasswd -nb admin yourpassword
# Note: $$ escapes $ in docker-compose
# ──────────────────────────────────────────────────────────────────
TRAEFIK_BASICAUTH=admin:$$apr1$$...

# ──────────────────────────────────────────────────────────────────
# GHCR (GitHub Container Registry) — read:packages PAT
# Used by deploy.sh to pull Docker images
# ──────────────────────────────────────────────────────────────────
GHCR_TOKEN=<github-personal-access-token>

# ──────────────────────────────────────────────────────────────────
# Docker image tags — updated automatically by CI/CD on each deploy
# Format: sha-XXXXXXX (short git SHA)
# ──────────────────────────────────────────────────────────────────
BACKEND_TAG=sha-abc1234
FRONTEND_TAG=sha-def5678

# ──────────────────────────────────────────────────────────────────
# Ghost CMS
# ──────────────────────────────────────────────────────────────────
GHOST_DB_PASSWORD=<strong-random>
GHOST_MAIL_FROM=noreply@rcb.bg
SENDGRID_API_KEY=<sendgrid-api-key>

# ──────────────────────────────────────────────────────────────────
# Alertmanager — Slack webhook
# Used by alertmanager.yml (generated via envsubst from .template)
# Also used directly by GitHub Actions for deploy notifications
# ──────────────────────────────────────────────────────────────────
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../...

Variable Reference Table

Infrastructure

VariableUsed ByDescription
DOMAINTraefik, Keycloak, GhostRoot domain — rcb.bg
ACME_EMAILTraefikLet's Encrypt certificate email
TRAEFIK_BASICAUTHTraefik labelsBasicAuth for dashboard at traefik.${DOMAIN}

Database

VariableUsed ByDescription
DB_PASSWORDPostgreSQL, Spring Boot, KeycloakShared DB password for rcb_db
GHOST_DB_PASSWORDGhost, ghost-dbIsolated Ghost database password

Application

VariableUsed ByDescription
JASYPT_PASSWORDSpring Boot (rcb-backend)Master key to decrypt ENC(...) properties
KC_ADMIN_USERKeycloakAdmin console username
KC_ADMIN_PASSWORDKeycloakAdmin console password
GRAFANA_ADMIN_PASSWORDGrafanaDashboard admin password

CI/CD & Deployment

VariableUsed ByDescription
GHCR_TOKENdeploy.sh, GitHub ActionsPAT with read:packages — pulls Docker images
BACKEND_TAGdocker-compose.prod.ymlActive backend image tag (updated by deploy.sh)
FRONTEND_TAGdocker-compose.prod.ymlActive frontend image tag (updated by deploy.sh)

Notifications

VariableUsed ByDescription
SLACK_WEBHOOK_URLAlertmanager, GitHub ActionsSlack incoming webhook — used for both Prometheus alerts and CI/CD deploy notifications

Email / External

VariableUsed ByDescription
SENDGRID_API_KEYGhost CMSSMTP relay via SendGrid for Ghost emails
GHOST_MAIL_FROMGhost CMSSender address for Ghost notifications

GitHub Actions Secrets

Set these in each repo under Settings → Secrets and variables → Actions:

Backend repo (ivelin1936/Renault-Club-Bulgaria)

SecretValue
VPS_HOSTVPS IP or hostname
VPS_USERSSH deploy user (e.g. deploy)
VPS_SSH_KEYSSH private key (Ed25519 or RSA)
GHCR_TOKENGitHub PAT — read:packages scope
SLACK_WEBHOOK_URLSlack webhook URL

Frontend repo (ivelin1936/renault-club-bulgaria-fe)

Same secrets as BE — the FE workflow uses the same VPS and Slack channel.


Frontend Environment Variables (Vite)

The FE uses VITE_ prefixed variables, baked into the JS bundle at build time:

VITE_KEYCLOAK_URL=https://auth.rcb.bg    # Keycloak server URL
VITE_KEYCLOAK_REALM=rcb # Keycloak realm name
VITE_KEYCLOAK_CLIENT_ID=rcb-frontend # Keycloak public client ID
VITE_API_BASE_URL=https://api.rcb.bg # Backend API base URL

In GitHub Actions CI, these are passed as env: in the Build step. They do not need to be secrets (they are public URLs).

No VITE_ in .env

VITE_ variables are compile-time constants baked into the React bundle. They are not read from the VPS .env file at runtime.


Generating Secure Passwords

# Random 32-char password (good for DB_PASSWORD, KC_ADMIN_PASSWORD, etc.)
openssl rand -base64 32

# Traefik BasicAuth hash
htpasswd -nb admin yourpassword
# Output: admin:$apr1$...
# In docker-compose use $$ to escape $ signs

E2E Test Environment Variables

These variables are used by the Playwright E2E test suite. They are set as GitHub Actions secrets in the FE repository and passed to the e2e job in ci.yml.

# ──────────────────────────────────────────────────────────────────
# Playwright E2E
# ──────────────────────────────────────────────────────────────────

# If set, Playwright skips starting the dev server and connects to this URL.
# Leave unset for local development (dev server auto-starts).
# Set to remote URL for staging/production smoke tests.
PLAYWRIGHT_BASE_URL=https://staging.rcb.bg

# ──────────────────────────────────────────────────────────────────
# Keycloak — used by auth.fixture.ts (ROPC token exchange)
# ──────────────────────────────────────────────────────────────────
KEYCLOAK_URL=http://localhost:8180 # Keycloak base URL
KEYCLOAK_REALM=rcb # Keycloak realm
KEYCLOAK_CLIENT_ID=rcb-frontend-test # Test-only client (ROPC must be enabled)

# ──────────────────────────────────────────────────────────────────
# Test user credentials
# These users must exist in the Keycloak realm with appropriate roles.
# Store passwords as GitHub Actions secrets — never commit them.
# ──────────────────────────────────────────────────────────────────
TEST_USER_USERNAME=testuser@rcb.bg
TEST_USER_PASSWORD=<secret> # GitHub secret: TEST_USER_PASSWORD

TEST_ADMIN_USERNAME=testadmin@rcb.bg
TEST_ADMIN_PASSWORD=<secret> # GitHub secret: TEST_ADMIN_PASSWORD

TEST_MOD_USERNAME=testmod@rcb.bg
TEST_MOD_PASSWORD=<secret> # GitHub secret: TEST_MOD_PASSWORD

E2E Variable Reference Table

VariableUsed ByDescription
PLAYWRIGHT_BASE_URLPlaywright config (playwright.config.ts)Override base URL; if unset, dev server starts automatically
KEYCLOAK_URLe2e/fixtures/auth.fixture.tsKeycloak server base URL for ROPC token exchange
KEYCLOAK_REALMe2e/fixtures/auth.fixture.tsKeycloak realm name
KEYCLOAK_CLIENT_IDe2e/fixtures/auth.fixture.tsTest client ID — must have Direct Access Grants enabled
TEST_USER_PASSWORDe2e/fixtures/auth.fixture.tsPassword for regular member test user
TEST_ADMIN_PASSWORDe2e/fixtures/auth.fixture.tsPassword for admin test user
TEST_MOD_PASSWORDe2e/fixtures/auth.fixture.tsPassword for moderator test user

Keycloak ROPC Setup

The auth fixture uses the ROPC (Resource Owner Password Credentials) grant. This must be enabled on a dedicated test client only:

  1. Keycloak Admin Console → Realm rcb → Clients → rcb-frontend-test
  2. Settings → Direct Access Grants → Enabled: ON
  3. The production client rcb-frontend must have Direct Access Grants disabled

NVD API Key (OWASP Dependency Check)

The optional NVD_API_KEY speeds up the OWASP Dependency Check's NVD database download from 5–10 minutes to under 30 seconds in CI.

# ──────────────────────────────────────────────────────────────────
# OWASP NVD API Key (optional)
# Speeds up NVD database updates for dependency-check -Powasp
# Register at: https://nvd.nist.gov/developers/request-an-api-key
# ──────────────────────────────────────────────────────────────────
NVD_API_KEY=<nvd-api-key>

Set this as a GitHub Actions secret (NVD_API_KEY) in the BE repository. Local development works without it — the first run will be slow while the NVD database is downloaded, but subsequent runs use the Maven local repository cache.


Secret Rotation

When rotating a secret:

  1. Update the value in /opt/rcb/.env on the VPS
  2. If rotating SLACK_WEBHOOK_URL, regenerate alertmanager.yml:
    envsubst < infra/local/observability/alertmanager/alertmanager.yml.template \
    > infra/local/observability/alertmanager/alertmanager.yml
    docker compose -f docker-compose.prod.yml restart alertmanager
  3. Update the corresponding GitHub Actions secret in both repos
  4. Restart affected services: docker compose -f docker-compose.prod.yml restart <service>