Files
TX/.env.example
T
riyadhafraa 77f8096deb Improve security and deployment flexibility for external access
Update README and application configurations to support reverse proxy setups, including TLS termination and proper cookie handling, and add an option to seed demo meetings.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: c15da2be-cee7-4cbb-8d58-f9fcc3c38ed7
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/FvHcc7z
Replit-Helium-Checkpoint-Created: true
2026-05-15 10:38:44 +00:00

164 lines
8.0 KiB
Bash

# ============================================================================
# Tx OS — environment configuration. Copy to `.env` and edit before deploying.
# Everything in this file is read either by docker-compose.yml at `up` time
# or directly by the application processes (`api-server`, `tx-os`, scripts).
# NEVER commit `.env` — it is gitignored. `.env.example` is the public template.
# ============================================================================
# -----------------------------------------------------------------------------
# Host ports (compose only)
# -----------------------------------------------------------------------------
# Port the SPA (nginx) is reachable on. Front with TLS in production.
WEB_PORT=3000
# Port the API container is reachable on. In public deployments, bind this
# to 127.0.0.1 only so the edge proxy is the sole external entry point.
API_PORT=8080
# Component preview server port (dev profile only).
MOCKUP_PORT=8081
# -----------------------------------------------------------------------------
# API server runtime
# -----------------------------------------------------------------------------
# In compose this is set automatically; required when running natively.
PORT=8080
# Public base URL the SPA + API are reachable at. Used to build absolute
# upload URLs for the local-FS storage driver and to derive whether the
# session cookie should be marked `secure`. Match the URL operators
# actually open in the browser (e.g. https://tx.example.com).
PUBLIC_BASE_URL=http://localhost:3000
# Comma-separated list of origins allowed by the API server's CORS layer.
# MUST include every URL the SPA can be reached at — the public domain,
# any reverse-proxy hostnames, the LAN IP for tablets/phones, and any
# tunneled URL (Tailscale `*.ts.net`, ngrok, Cloudflare Tunnel, etc).
# Examples:
# ALLOWED_ORIGINS=http://localhost:3000
# ALLOWED_ORIGINS=https://tx.example.com,https://it-demo.tail70b2bc.ts.net
# ALLOWED_ORIGINS=http://localhost:3000,http://192.168.1.42:3000
ALLOWED_ORIGINS=http://localhost:3000
# Set to `true` when Tx OS sits behind a TLS-terminating proxy that
# does NOT forward `X-Forwarded-Proto: https` (notably `tailscale serve`,
# the ngrok free tier, and some Cloudflare Tunnel setups). Without this,
# the session cookie is silently dropped and login bounces back to the
# login screen even on a successful POST /auth/login. Leave unset for
# direct localhost access or when your proxy forwards the header.
# SECURITY: only enable when the API is not reachable directly over plain
# HTTP from outside — i.e. only your TLS edge proxy can hit it. Otherwise
# anyone on the same network can submit plain-HTTP requests that the app
# trusts as HTTPS.
TRUST_PROXY_HTTPS=false
# pino log level: trace | debug | info | warn | error | fatal
LOG_LEVEL=info
# 32+ random bytes. Generate with `openssl rand -hex 32`. REQUIRED.
SESSION_SECRET=change-me-session-secret-min-32-chars-please
# -----------------------------------------------------------------------------
# Local hostname / TLS (used by Caddy + the Setup Wizard)
# -----------------------------------------------------------------------------
# Hostname operators reach the system at on the LAN. The Caddy edge
# binds this name and serves the mkcert-issued certificate.
LOCAL_DOMAIN=tx.local
# Auto-detected by scripts/local-setup.sh — the host's LAN IP. Used as
# an additional SAN on the local certificate so phones / tablets that
# can't resolve mDNS can still reach the system at https://<ip>/.
LOCAL_IP=
# Canonical public URL the SPA + API are reachable at. Setup Wizard
# stores this in system_settings.base_url at install time.
BASE_URL=https://tx.local
# Edge ports (Caddy). Set HTTP_PORT=8080 / HTTPS_PORT=8443 if you
# can't bind privileged ports.
HTTP_PORT=80
HTTPS_PORT=443
# TLS strategy:
# local — local-setup.sh provisions ./certs/local-{cert,key}.pem via mkcert
# byo — operator drops their own cert/key into ./certs/ with the same names
# skip — DEVELOPER ONLY: serve plaintext on :80, no HTTPS. Never use
# outside trusted local development networks.
HTTPS_MODE=local
# -----------------------------------------------------------------------------
# SPA build (tx-os) — read by Vite at build time AND `pnpm --filter tx-os dev`
# -----------------------------------------------------------------------------
# Path the SPA is mounted at. Use "/" when serving from the domain root.
BASE_PATH=/
# -----------------------------------------------------------------------------
# Database
# -----------------------------------------------------------------------------
POSTGRES_USER=tx
POSTGRES_PASSWORD=change-me-postgres
POSTGRES_DB=tx_os
# Composed automatically by docker-compose; set explicitly when running natively.
# DATABASE_URL=postgres://tx:change-me-postgres@localhost:5432/tx_os
DATABASE_URL=postgres://tx:change-me-postgres@db:5432/tx_os
# -----------------------------------------------------------------------------
# Object storage
# -----------------------------------------------------------------------------
# Driver selection. Set to "s3" for production (MinIO/S3); "local" persists
# uploads on the API container's filesystem (single-host, dev-only).
# If unset, the driver auto-detects: "s3" when S3_ENDPOINT is set, else "local".
STORAGE_DRIVER=s3
# Bucket-level paths used by the API. Format: /<bucket>/<prefix>
PRIVATE_OBJECT_DIR=/tx-private/private
PUBLIC_OBJECT_SEARCH_PATHS=/tx-public/public
# Bucket names — created on first boot by the minio-init container.
S3_BUCKET_PRIVATE=tx-private
S3_BUCKET_PUBLIC=tx-public
# S3-compatible endpoint URL. For MinIO running in compose this is the
# in-network DNS name. For AWS S3 leave blank (the SDK uses the default
# regional endpoint). For Cloudflare R2 / Backblaze B2, set the vendor URL.
S3_ENDPOINT=http://minio:9000
# MinIO root credentials. Used both as MINIO_ROOT_USER/PASSWORD and as the
# API server's S3 access key. Change before first boot.
S3_ACCESS_KEY_ID=tx-minio-admin
S3_SECRET_ACCESS_KEY=change-me-minio-secret-min-20-chars
# Region label is cosmetic for MinIO but @aws-sdk requires one.
S3_REGION=us-east-1
# Path-style addressing is required by MinIO and most non-AWS S3 backends.
# Set to "false" only when targeting real AWS S3 (which prefers virtual-host
# style). Defaults to "true" inside the API server.
S3_FORCE_PATH_STYLE=true
# Local-FS driver settings (only consulted when STORAGE_DRIVER=local).
# Filesystem root for uploaded objects. Defaults to ./storage relative to
# the API server's working directory.
LOCAL_STORAGE_ROOT=./storage
# HMAC key used to sign + verify upload URLs for the local driver. If
# unset, the driver falls back to SESSION_SECRET. Set explicitly to rotate
# upload-URL trust independently of session trust.
LOCAL_STORAGE_SIGNING_SECRET=
# -----------------------------------------------------------------------------
# Seeded demo accounts (OPTIONAL since the Setup Wizard exists)
# -----------------------------------------------------------------------------
# When BOTH variables are set, the migrate container creates an `admin`
# and `ahmed` user with these passwords on first boot and immediately
# marks the install complete (skipping the wizard). When EITHER is unset,
# the seed creates only roles/permissions and leaves admin creation to
# the first-run wizard at /setup.
SEED_ADMIN_PASSWORD=
SEED_USER_PASSWORD=
# Set to `true` to populate the Executive Meetings module with a full
# day of realistic-looking demo meetings on first boot (useful for
# screenshots, sales demos, and UI walkthroughs). Leave unset on real
# self-hosted installs — the module should start empty.
SEED_DEMO_MEETINGS=false
# -----------------------------------------------------------------------------
# Email (optional)
# -----------------------------------------------------------------------------
# Leave SMTP_HOST blank to disable outbound mail. The Executive Meetings
# notifier no-ops when no SMTP config is present.
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_SECURE=false
SMTP_FROM=Tx OS <noreply@example.com>