Environment variables
The API reads its configuration from environment variables. Where you set them depends on how you run it:
| Setup | File |
|---|---|
| Your computer | spring-admin/.env (copied from .env.example), read by Docker Compose and run-dev.sh. With mvn spring-boot:run, export them in the shell |
| Your own VPS | /opt/infotech-pos/shared/.env (from deploy/env.production.example), passed to Docker Compose by deploy.sh |
| Buyer release | .env next to docker-compose.yml, written by install.sh |
After changing a value on a VPS, run sudo /opt/infotech-pos/app/deploy/deploy.sh --all. In the buyer release, run docker compose up -d. Keep every .env file out of Git and backed up.
Database
| Variable | Meaning |
|---|---|
DB_URL | JDBC URL, e.g. jdbc:postgresql://localhost:5432/pos_admin. The Compose files set it for you |
DB_USERNAME | Database user |
DB_PASSWORD | Database password. Generated by server-setup.sh and install.sh. Do not change it once the database exists |
DB_POOL_SIZE | Connection pool size (release default 10) |
DEV_DB_PORT | Local only: host port of the dev PostgreSQL container (default 5433) |
The user that runs migrations must be allowed to install the pg_trgm extension. Flyway creates and upgrades the schema on every start.
Addresses
| Variable | Meaning |
|---|---|
APP_URL | Public address of the web app, e.g. https://pos.example.com. Payment gateways return shop owners here after paying. Alternatively set it under Payments › Billing settings › Application URL |
CORS_ORIGINS | Comma-separated web app origins allowed to call the API and open the live-updates WebSocket, e.g. https://pos.example.com. Locally: http://localhost:5173,http://127.0.0.1:5173 |
RESET_URL | Password-reset page of the web app, e.g. https://pos.example.com/reset-password |
API_PORT | VPS only: host port the API container listens on at 127.0.0.1 (default 8091). Must match the nginx site |
VITE_API_URL | Web app build only: address of the API, e.g. https://api.example.com. Baked into the JavaScript at build time, so change it and rebuild. Not needed locally (Vite proxies /api) or in the buyer release (same origin) |
Security and sign-in
| Variable | Meaning |
|---|---|
APP_ENCRYPTION_KEY | Base64 32-byte key (openssl rand -base64 32). Encrypts payment gateway secrets and the mail outbox. Required for email, password recovery and online payments. Keep it permanent and backed up: changing it makes saved secrets unreadable |
BOOTSTRAP_EMAIL, BOOTSTRAP_PASSWORD | Create the first super administrator on start, only while none exists. Never overwrite an existing password. Remove the password after the first start. Without them, the setup wizard creates the administrator |
SETUP_TOKEN | Token the setup wizard asks for. If empty, one is generated and written to the API log at start |
TOKEN_MINUTES | Lifetime of an access token (default 30) |
REFRESH_IDLE_DAYS, REFRESH_MAX_DAYS | How long a sign-in can be refreshed when idle, and at most. env.production.example uses 14 and 60 |
REFRESH_SECURE_COOKIE | true behind HTTPS. install.sh sets false (as SECURE_COOKIE) when you install on a plain-HTTP IP address |
| Variable | Meaning |
|---|---|
MAIL_ENABLED | true to send email. Sign-up codes, password resets and billing reminders need it |
MAIL_FROM | Sender address, e.g. no-reply@example.com |
SMTP_HOST, SMTP_PORT | SMTP server and port (default 587) |
SMTP_USERNAME, SMTP_PASSWORD | SMTP login |
SMTP_AUTH, SMTP_STARTTLS | true by default |
MAIL_POLL_MS | How often the mail outbox is processed, in milliseconds (default 10 seconds) |
Without mail configured, password recovery answers "service unavailable" rather than pretending to send. See Email.
Verification codes and SMS
| Variable | Meaning |
|---|---|
OTP_TTL_SECONDS | How long a sign-up code stays valid (default 600, 10 minutes) |
OTP_LOG_CODES | Development only: true writes codes to the API log when mail is disabled. Keep false in production |
OTP_URL, OTP_USERNAME, OTP_SENDER, OTP_KEY | SMS gateway settings. Currently unused: codes are sent by email |
License
| Variable | Meaning |
|---|---|
LICENSE_SERVER_URL | License server for activation and daily check-in (default https://license.infotech.center) |
APP_VERSION | Release version, used to tag the api and web images. Set by install.sh and update.sh from the VERSION file |
The license public key is built into the API and cannot be set by a variable. See License.
Demo and load-test data
| Variable | Meaning |
|---|---|
DEMO_SEED | true only on a public demo server: on every start the API creates the demo accounts below if missing and fills the demo shop with data and pictures. Never on a server that sells to real shops |
DEMO_SEED_ADMIN_EMAIL, DEMO_SEED_ADMIN_PASSWORD | Demo super administrator |
DEMO_SEED_SHOP_NAME | Demo shop name (example: DEMO Shop) |
DEMO_SEED_OWNER_EMAIL, DEMO_SEED_OWNER_PASSWORD | Demo shop owner |
DEMO_DATA_ENABLED | true adds a Demo data button (Shops page, POS header) that creates large catalogues and up to two million test sales. Leave unset in production |
Existing accounts are never changed by the demo seed.
Buyer release only
Written by install.sh into the release .env:
| Variable | Meaning |
|---|---|
SITE_ADDRESS | Your domain (Caddy gets an HTTPS certificate) or :80 for plain HTTP on an IP address or behind your own proxy |
ACME_EMAIL | Email for Let's Encrypt |
HTTP_PORT, HTTPS_PORT | Host ports of the web container (default 80 and 443). Change them to run behind your own nginx, see Reverse proxy |
SECURE_COOKIE | Passed to the API as REFRESH_SECURE_COOKIE |
JAVA_OPTS | JVM options for the API (default -XX:MaxRAMPercentage=70) |
In the release, CORS_ORIGINS and RESET_URL are derived from APP_URL.
Scripts, tests and builds
| Variable | Where | Meaning |
|---|---|---|
DEPLOY_BRANCH | deploy.sh | Branch to deploy (default main) |
DB_TEST_URL, DB_TEST_USERNAME, DB_TEST_PASSWORD | mvn verify | Disposable test database; its name must end in _test. Without it, integration tests are skipped |
ZATCA_SANDBOX_TEST | mvn verify | true runs the ZATCA sandbox tests (needs internet) |
ALLOW_UNLICENSED_BUILD | build-release.sh | 1 allows a test package while the license public key is still the placeholder |
Print agent
Set on the computer that runs the kitchen print agent, not on the server:
| Variable | Meaning |
|---|---|
POS_SERVER | The POS address, https://… |
POS_AGENT_KEY | The agent key (pa_…) from Kitchen printers › Print agents |
POS_ENCODING | ascii (default) or utf8 for printers set to UTF-8, so Arabic names print |
Related pages
Last updated 17 Oct 2026