Docs
Configuration
What the installer writes to deploy/.env, and the few settings you might change.
The installer writes your whole configuration for you, so on most installs you never touch it. This page explains what's in it, the few settings you might change, and how to apply a change.
Almost everything else is configured in the admin, not in a file: your email (Resend), payment gateways, file storage, Turnstile, branding and the rest live under Settings, stored in the database and encrypted. See First run and the Settings reference.
Where it lives#
Your configuration is one file, deploy/.env, in the folder you installed from. To find it:
sudo clientos env
The installer writes it once, on the first install, and never overwrites it. Updates leave it alone too.
Keep
deploy/.envprivate, and keep a copy somewhere safe.CREDENTIAL_SECRETin it encrypts every key you save in Settings. Lose it and those keys can't be read back, so you'd have to paste them all again. Everyclientos backupincludes a copy.
Applying a change#
Edit the file as root, then run:
sudo clientos start
That recreates whatever the change affects. clientos restart is not enough: it restarts the containers with the configuration they already had.
The API checks its configuration when it starts. If a value is missing or unsafe, it refuses to start and its log, sudo clientos logs api, begins with Invalid environment: and names each problem.
Settings you might change#
| Variable | What it does |
|---|---|
MAIL_POSTAL_ADDRESS | Your agency's postal address, added to commercial email. US CAN-SPAM rules require one, and its absence is a spam signal. Set it before you launch. |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | Google sign-in for clients. Both or neither. See below. |
EXTRA_TRUSTED_PROXIES | Only if you put Cloudflare's proxy (orange cloud) in front: Cloudflare's address ranges, separated by spaces. See Cloudflare's proxy. Empty otherwise. |
SUBNET | The private network the containers share. The installer picks one that clashes with nothing on the server. Change it only if you add a VPN or network that overlaps it, then run sudo clientos stop and sudo clientos start. |
SETUP_KEY | The key the setup page asks for. Meaningless once setup is done. |
Settings written for you#
Leave these as the installer wrote them unless a page in these docs tells you otherwise.
| Variable | What it is |
|---|---|
PORTAL_DOMAIN | Your client portal's address. The API and your files are served on it too. |
ADMIN_DOMAIN | Your team's address. |
DOMAIN | The domain both addresses are under. Sign-in covers it, and your license is bound to it. Don't change these three on a running install; see Moving to another domain. (A server installed before addresses were chosen in the browser has only DOMAIN, and answers on portal., admin., api. and files. under it.) |
ACME_EMAIL | Where Let's Encrypt writes if a certificate renewal fails. |
CLIENTOS_VERSION | The release this server runs. clientos update and clientos rollback change it. |
CLIENTOS_VERSION_PREVIOUS | The release before the last update, kept for clientos rollback. |
CLIENTOS_LICENSE_KEY | Your license key. ClientOS is downloaded with it, and the setup page activates it. |
POSTGRES_PASSWORD | The database owner's password. Only the migration step uses it. |
APP_DB_PASSWORD | The API's own, more limited database login. The migration step sets it on every start. |
REDIS_PASSWORD | Redis. |
MINIO_PASSWORD | The file store's root password. The API never receives it. |
STORAGE_SECRET | The API's own key to the file store, limited to its one bucket. |
SESSION_SECRET | Signs every session and sign-in code. Changing it signs everybody out. |
CREDENTIAL_SECRET | Encrypts every key saved in Settings. To change it, follow Rotating the credential secret. |
CREDENTIAL_SECRET_PREVIOUS | Empty, except during a rotation of CREDENTIAL_SECRET. |
FORWARDED_IP_SECRET | Lets the apps pass each visitor's real address to the API for rate limiting. |
Everything else, such as the public addresses, the cookie domain and the allowed origins, is worked out from these three, so there's nothing to keep in step.
Google sign-in for clients#
Optional. Lets clients sign in with a Google account that matches the email address you invited. Clients can't sign up through Google. The Google button appears only when both values are set.
-
In Google Cloud Console, create an OAuth client of type Web application.
-
Add this as an authorized redirect URI, with your own domain:
https://YOUR_PORTAL/v1/auth/callback/google -
Put the client ID and secret in
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETindeploy/.env. -
Run
sudo clientos start.
What isn't set here#
Some things look like they belong in deploy/.env but don't:
- Email. There's no mail setting in the file. Mail goes out only through the Resend account you connect at Settings → Integrations → Resend.
- Cloudflare R2. Files go to the server's own storage until you save a bucket at Settings → Storage.
NODE_ENV. ClientOS always runs in production mode. If you addNODE_ENVwith any other value, the API refuses to start.
The API also refuses to start if any of these are set: RESEND_API_KEY, R2_ACCOUNT_ID, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_PUBLIC_BASE_URL, S3_ENDPOINT, LICENSE_SERVER_URL, LICENSE_PUBLIC_KEY, DEMO_ROLE=on, E2E_JOBS=on, or DATABASE_ROLE_CHECK set to anything but strict. Remove the line and run sudo clientos start.
Example#
What the installer writes, for clients.youragency.com and team.youragency.com. Your secrets are long random strings.
DOMAIN='youragency.com'
PORTAL_DOMAIN='clients.youragency.com'
ADMIN_DOMAIN='team.youragency.com'
ACME_EMAIL='[email protected]'
POSTGRES_PASSWORD=...
APP_DB_PASSWORD=...
REDIS_PASSWORD=...
MINIO_PASSWORD=...
STORAGE_SECRET=...
SESSION_SECRET=...
CREDENTIAL_SECRET=...
CREDENTIAL_SECRET_PREVIOUS=
FORWARDED_IP_SECRET=...
SETUP_KEY=...
CLIENTOS_VERSION=1.4.0
CLIENTOS_LICENSE_KEY=CLOS-XXXX-XXXX-XXXX-XXXX
SUBNET=10.213.0.0/24
EXTRA_TRUSTED_PROXIES=
MAIL_POSTAL_ADDRESS=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=