Installation
Eviworx is deployed via Docker Compose. This guide walks you through the installation step-by-step. The architecture is based on 12 containers with Traefik as API gateway for TLS termination, routing and security headers.
Prerequisites
- Docker: Version 24.0+ (
docker --version) - Docker Compose: Version 2.20+ (
docker compose version) - Free disk space: Min. 20 GB
- RAM: Min. 8 GB (recommended: 16 GB)
- Operating system: Linux (Ubuntu 22.04+, Debian 11+, RHEL 8+)
- Network: Ports 80 and 443 available (Traefik)
- SSL/TLS: Certificate (cert.pem + cert.key) for Traefik
Step-by-Step Installation
Step 1: Clone Deployment Repository & Registry Login
# Clone deployment repository (contains docker-compose.yaml + Traefik configuration)
git clone https://github.com/eviworx/eviworx-deploy.git eviworx
cd eviworx
# Registry login (for private container images)
# Registry host is provided by Eviworx
docker login <your-registry>
Note: The repository and registry are private. Contact info@eviworx.com for credentials.
After cloning you have the following directory structure:
eviworx/
docker-compose.yaml # Compose file (from the repo)
.env.example # Template for secrets & configuration
certs/ # Directory for TLS certificates (empty)
traefik/
traefik.yml # Traefik Static Config
dynamic.yml # Traefik Routing Config
Step 2: Provide SSL Certificate
Traefik requires a TLS certificate (PEM format). Place your certificate in the certs directory:
# Provide certificate files:
cp /path/to/your/cert.pem ./certs/cert.pem
cp /path/to/your/cert.key ./certs/cert.key
# Or self-signed certificate for development:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ./certs/cert.key \
-out ./certs/cert.pem \
-subj "/CN=localhost"
Step 3: Configure Environment Variables
All secrets and configuration values are managed via a .env file. Create this from the included template:
Create .env file
# Create .env from template and adjust
cp .env.example .env
nano .env
Generate Secure Passwords/Keys
# All secrets as hex strings (no special characters, URL-safe)
openssl rand -hex 32 # for POSTGRES_PASSWORD, REDIS_PASSWORD, SHARE_SECRET, INTERNAL_API_KEY
openssl rand -hex 48 # for JWT_SECRET (slightly longer recommended)
openssl rand -hex 32 # for LICENSE_ENCRYPTION_KEY
openssl rand -hex 32 # for TWO_FACTOR_ENCRYPTION_KEY
openssl rand -hex 32 # for JOBWORKER_DB_PASSWORD
openssl rand -hex 32 # for READONLY_DB_PASSWORD
.env File Contents
# =============================================
# Eviworx — Environment Configuration (.env)
# =============================================
# --- Domain / Frontend URL ---
FRONTEND_URL=https://helpdesk.example.com
# --- Database ---
POSTGRES_USER=helpdesk_user
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD
POSTGRES_DB=helpdesk_db
JOBWORKER_DB_PASSWORD=YOUR_STRONG_PASSWORD
READONLY_DB_PASSWORD=YOUR_STRONG_PASSWORD
# --- Redis ---
REDIS_PASSWORD=YOUR_STRONG_PASSWORD
# --- JWT (session token) ---
JWT_SECRET=YOUR_STRONG_PASSWORD
# --- Share token (time-limited public share links) ---
# REQUIRED — backend starts with a fatal error if not set!
SHARE_SECRET=YOUR_STRONG_PASSWORD
# --- Internal API Key (service-to-service) ---
INTERNAL_API_KEY=YOUR_64_HEX_CHARS
# --- Encryption Keys ---
LICENSE_ENCRYPTION_KEY=YOUR_64_HEX_CHARS
TWO_FACTOR_ENCRYPTION_KEY=YOUR_64_HEX_CHARS
# --- Web Push (VAPID, optional) ---
# Generate once: npx web-push generate-vapid-keys
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
VAPID_SUBJECT=mailto:admin@example.com
# --- Admin (only on the very first start) ---
ADMIN_INITIAL_PASSWORD=StrongPassword123!
# --- Licensing ---
# Without an entry: trial mode (30 days, max. 3 agents)
# LICENSE_KEY=EVI-XXXX-XXXX-XXXX
# LICENSE_SECRET=your-license-secret-from-vendor
# --- Optional: Reverse Proxy / Load Balancer ---
# If Eviworx runs behind an external reverse proxy:
# TRUSTED_PROXIES=217.89.98.0/24,203.0.113.0/24
# --- Optional: Cloudflare Turnstile CAPTCHA ---
# TURNSTILE_SITE_KEY=
# TURNSTILE_SECRET_KEY=
# --- Optional: Email branding ---
# EMAIL_ACCENT_COLOR=#3b8f93
# EMAIL_APP_NAME=Eviworx
# EMAIL_APP_URL=https://helpdesk.example.com
# EMAIL_FOOTER_TEXT=Eviworx 2026
# --- Optional: Report generator ---
# COMPANY_NAME=Company Inc.
# CSV_DELIMITER=;
Security: The .env file is listed in .gitignore and is NOT committed to the repository. Never commit secrets to Git!
Step 4: Start Containers
# Pull images from the registry
docker compose pull
# Start the stack
docker compose up -d
On first start, automatically:
- Database initialized (PostgreSQL)
- Restricted DB users created (helpdesk_jobworker, helpdesk_readonly)
- Database schema created via migrations
- System roles created (Admin, Agent, Approver, End User, Data Protection Officer)
- Default admin user created (if SEED_DATABASE=true)
- ClamAV virus signatures downloaded (~3 minutes)
- Traefik initialized (TLS, routing, security headers)
Important: First start takes 3-5 minutes (ClamAV must load virus signatures). Wait until all containers are "healthy".
Step 5: Verify Installation
# Check container status
docker compose ps
# Expected output: All containers "healthy" or "running"
# NAME STATUS
# eviworx-traefik Up (healthy)
# eviworx-frontend Up (healthy)
# eviworx-backend Up (healthy)
# eviworx-job-worker Up (healthy)
# eviworx-email-worker Up (healthy)
# eviworx-notification-worker Up (healthy)
# eviworx-workflow-engine Up (healthy)
# eviworx-report-generator Up (healthy)
# eviworx-av-worker Up (healthy)
# eviworx-db Up (healthy)
# eviworx-redis Up (healthy)
# eviworx-clamav Up (healthy)
# Check backend health
curl -k https://localhost/api/health/live
# Expected: {"status":"alive"}
# Check logs (if issues)
docker compose logs -f backend
docker compose logs -f traefik
docker compose logs -f clamav # ClamAV takes longest to start
First Login
After successful installation (all containers "healthy"), open your browser:
https://your-domain.com
# Traefik automatically redirects HTTP to HTTPS
Default Credentials (SEED_DATABASE=true)
| Role | Password | Permissions | |
|---|---|---|---|
| Admin | admin@company.com |
ADMIN_INITIAL_PASSWORD |
Full admin rights |
The password is set via the ADMIN_INITIAL_PASSWORD environment variable (default: ChangeMeNowXx). This is ONLY used on first start with an empty database.
CRITICAL: Change the admin password immediately after first login! Create additional users via the invitation function or user management.
Post-Installation: Change Secrets
1. Change Admin Password & Enable MFA
Log in as admin:
- Change password: User menu → Settings → Security
- Enable MFA: User menu → Settings → Security → Two-Factor Authentication
2. SEED_DATABASE disable
After first successful start, disable re-seeding:
# Edit .env
nano .env
# Set:
SEED_DATABASE=false
# Restart container
docker compose up -d backend
3. Activate License
Eviworx starts automatically in trial mode (30 days, max. 3 agents). For production use, add your license key to .env:
# In .env:
LICENSE_KEY=EVI-XXXX-XXXX-XXXX
LICENSE_SECRET=your-license-secret-from-vendor
# Restart backend
docker compose up -d backend
Alternatively directly in the UI: Admin Center → System → Product License → Online Activation — Full license documentation →
4. Configure General Settings
Company name and application URL are configured in the UI:
- Admin Center → System → General → Company Name
- Admin Center → System → General → Application URL
These values are used dynamically for QR codes, PDF labels, email templates and other features. The company name in report exports is set by the report generator via its own COMPANY_NAME variable, see Environment Variables Reference.
Traefik API Gateway
Traefik v3 serves as the central API gateway and handles:
- TLS-Termination: HTTPS with configurable cipher suites (TLS 1.2+)
- Routing:
/api/*→ Backend,/socket.io→ Backend (WebSocket),/*→ Frontend - Security: HSTS, CSP, X-Frame-Options, rate limiting (100 req/s, burst 200)
- Internal service endpoints: are blocked externally (only reachable within the container network)
- HTTP → HTTPS: Automatic redirect
- Compression: Gzip compression for API and frontend
External Reverse Proxy / Load Balancer
If Eviworx runs behind an external reverse proxy (e.g. Nginx, HAProxy), two things need to be configured so that logs and IP-based rate limits see the real client IP rather than the proxy's:
1. Backend — TRUSTED_PROXIES in .env
# In .env:
TRUSTED_PROXIES=217.89.98.0/24,203.0.113.0/24
Comma-separated CIDR ranges. Docker-internal and private networks (172.16.0.0/12, 10.0.0.0/8, 192.168.0.0/16) are always trusted by default.
2. Traefik — forwardedHeaders.trustedIPs in traefik.yml
Add your external proxy CIDR to the trustedIPs list in both entrypoints (web + websecure) so Traefik does not overwrite the X-Forwarded-For header:
# traefik/traefik.yml
entryPoints:
web:
forwardedHeaders:
trustedIPs:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "217.89.98.0/24" # ← your proxy CIDR websecure:
forwardedHeaders:
trustedIPs:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "217.89.98.0/24" # ← your proxy CIDR
After editing, restart Traefik: docker compose restart traefik
Traefik Configuration
The configuration consists of two files:
traefik/traefik.yml– Static configuration (entrypoints, logging)traefik/dynamic.yml– Dynamic configuration (routers, services, middlewares, TLS)
# Check Traefik logs
docker compose logs -f traefik
# Access log format: JSON (machine-readable)
# Fields: X-Request-ID, User-Agent (other headers dropped)
Volumes & Persistence
Eviworx uses 6 Docker volumes for persistent data:
| Volume | Purpose | Importance |
|---|---|---|
postgres_data |
Database (all tickets, assets, etc.) | CRITICAL - Backup required! |
redis_data |
Job queue & cache | Important - AOF persistence |
uploads |
Uploaded files (attachments) | CRITICAL - Backup required! |
quarantine |
Infected files (7 days retention) | Optional - can be deleted |
clamav_data |
Virus signatures (~1 GB) | Can be reloaded |
sourcemaps |
JS source maps of the five newest releases (frontend writes, backend reads read-only for error tracking) | Repopulated on start, approx. 100-500 MB |
Volume Backup
# Backup PostgreSQL
docker compose exec db pg_dump -U helpdesk_user helpdesk_db > backup_$(date +%Y%m%d).sql
# Backup uploads (attachments)
docker run --rm -v eviworx_uploads:/data -v $(pwd):/backup alpine tar czf /backup/uploads_$(date +%Y%m%d).tar.gz -C /data .
Environment Variables Reference
All environment variables with default values and descriptions are listed in the Environment Variables Reference.
Generate Secrets
All secrets are generated as hex strings (no special characters, URL-safe), usually 64 characters long:
# Generate a dedicated key for EACH secret:
openssl rand -hex 48 # → JWT_SECRET
openssl rand -hex 32 # → SHARE_SECRET (REQUIRED!)
openssl rand -hex 32 # → INTERNAL_API_KEY
openssl rand -hex 32 # → LICENSE_ENCRYPTION_KEY (exactly 32 bytes!)
openssl rand -hex 32 # → TWO_FACTOR_ENCRYPTION_KEY (exactly 32 bytes!)
openssl rand -hex 32 # → POSTGRES_PASSWORD
openssl rand -hex 32 # → JOBWORKER_DB_PASSWORD
openssl rand -hex 32 # → READONLY_DB_PASSWORD
openssl rand -hex 32 # → REDIS_PASSWORD
# Enter all generated values into .env
Troubleshooting
Traefik won't start / SSL error
# Check Traefik logs
docker compose logs traefik
# Most common cause: certificate files missing
ls -la ./certs/cert.pem ./certs/cert.key
# Check whether ports 80/443 are already in use
sudo lsof -i :80
sudo lsof -i :443
ClamAV won't start / stays unhealthy
# Check ClamAV logs
docker compose logs clamav
# Most common cause: not enough RAM
# Solution: increase Docker RAM to at least 4 GB
# ClamAV needs 3-5 minutes on first start
# Wait until Freshclam has loaded the signatures:
docker compose logs clamav | grep -i "Database updated"
Backend won't start (Migration error)
# Check backend logs
docker compose logs backend
# Common errors:
# 1. Database not ready yet
# → Wait 30s and check: docker compose ps db
# 2. DATABASE_URL wrong
# → Check password in .env (must match POSTGRES_PASSWORD)
# 3. Prisma migration failed
# → Run manually:
docker compose exec backend npx prisma migrate deploy
Workers can't connect to backend
# Check backend is reachable
docker compose exec job-worker curl http://backend:3000/api/health/live
# Check INTERNAL_API_KEY in all worker services
# MUST be identical everywhere:
docker compose config | grep INTERNAL_API_KEY
# Most common error: backend not healthy yet
docker compose ps backend
# STATUS should be "Up (healthy)"
Redis connection error
# Check whether Redis is running and the password is correct
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD --no-auth-warning ping
# Expected: PONG
# Check REDIS_URL in all services (must contain the password!)
docker compose config | grep REDIS_URL
Advanced Configuration
FIPS 140-2 Mode
Eviworx uses FIPS 140-2 compatible algorithms (no official certification). In standard mode, FIPS-compatible algorithms are already used (PBKDF2-SHA512, AES-256-GCM, HMAC-SHA256). In the optional FIPS mode, the backend checks at startup that Node.js runs in FIPS mode (OpenSSL FIPS provider) and does not start otherwise:
# Enable FIPS mode (set in .env):
ENABLE_FIPS=true
# Restart container
docker compose up -d backend
Multiple Worker Instances (HA)
Worker services can be scaled to multiple instances. Requirements and limits: Scaling & High Availability →
- ☐
JWT_SECRETchanged (min. 32 bytes) - ☐
SHARE_SECRETset (REQUIRED — backend won't start otherwise!) - ☐
INTERNAL_API_KEYchanged (min. 32 bytes) - ☐
LICENSE_ENCRYPTION_KEYchanged (exactly 32 bytes!) - ☐
TWO_FACTOR_ENCRYPTION_KEYchanged (exactly 32 bytes!) - ☐
REDIS_PASSWORDchanged (in all services!) - ☐ All database passwords changed
- ☐
ADMIN_INITIAL_PASSWORDset (secure password!) - ☐
SEED_DATABASE=falseafter first start - ☐
FRONTEND_URLset to real domain - ☐ SSL/TLS certificate configured (Traefik)
- ☐ Admin password changed after login + MFA enabled
- ☐ Company name & application URL configured in settings
Useful Commands
Container Management
# Start all containers
docker compose up -d
# Restart a single container
docker compose restart backend
# Pull new version (after update notification)
docker compose pull && docker compose up -d
# Stop containers
docker compose stop
# Stop AND remove containers (volumes remain!)
docker compose down
# WARNING: Delete all volumes (DATA LOSS!)
docker compose down -v # ONLY for a full reset!
# View logs (all containers log in JSON format)
docker compose logs -f backend
docker compose logs --tail=100 traefik
docker compose logs --tail=100 clamav
# Open a shell in a container
docker compose exec backend sh
docker compose exec db psql -U helpdesk_user helpdesk_db
Database Management
# PostgreSQL Shell
docker compose exec db psql -U helpdesk_user helpdesk_db
# Apply migrations (manually)
docker compose exec backend npx prisma migrate deploy
# Prisma Studio (DB admin UI)
docker compose exec backend npx prisma studio
# Database Backup
docker compose exec db pg_dump -U helpdesk_user helpdesk_db > backup.sql
# Database Restore
cat backup.sql | docker compose exec -T db psql -U helpdesk_user helpdesk_db
Redis Management
# Redis CLI (with password!)
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD --no-auth-warning
# Check queue sizes (BullMQ)
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD --no-auth-warning keys "bull:*"
# Check Locks
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD --no-auth-warning keys "lock:*"
First steps after installation
Complete reference of all variables