Server Configuration
Configuration options for self-hosted Scanopy servers.
Configuration reference for self-hosted Scanopy server deployments.
Configuration Methods
Every setting is an environment variable prefixed with SCANOPY_. That is the primary interface, and it works the same however you run the server. Some settings also accept a command-line flag; the flag wins when both are set.
Sources are layered, later ones overriding earlier:
- Built-in defaults
- A
.envfile in the server's working directory (or any parent directory) SCANOPY_*environment variables- Command-line flags
Docker Compose — set them on the server service, or point it at a .env file:
environment:
- SCANOPY_SERVER_PORT=60072
- SCANOPY_DATABASE_URL=postgresql://postgres:password@db:5432/scanopysystemd (for native installs) — keep them in an EnvironmentFile so secrets stay out of the unit file:
[Service]
WorkingDirectory=/opt/scanopy
EnvironmentFile=/etc/scanopy/server.env
ExecStart=/opt/scanopy/scanopy-server# /etc/scanopy/server.env — chmod 600
SCANOPY_DATABASE_URL=postgresql://scanopy:password@localhost:5432/scanopy
SCANOPY_PUBLIC_URL=http://your-server:60072Reload after editing: sudo systemctl restart scanopy-server.
Command-line (for binary builds):
./scanopy-server --server-port 60072 --database-url postgresql://...Not every setting has a CLI flag — SCANOPY_LICENSE_KEY and SCANOPY_WEB_EXTERNAL_PATH, among others, are environment-only. The table below lists N/A where no flag exists.
Parameter Reference
| Parameter | CLI Flag | Environment Variable | Default | Description |
|---|---|---|---|---|
| Server Public URL | --public-url | SCANOPY_PUBLIC_URL | http://localhost:60072 | Public URL for webhooks, email links, etc |
| Server Port | --server-port | SCANOPY_SERVER_PORT | 60072 | Port for server to listen on |
| Database URL | --database-url | SCANOPY_DATABASE_URL | Required | PostgreSQL connection string |
| Web External Path | N/A | SCANOPY_WEB_EXTERNAL_PATH | Embedded UI | Serve the web UI from this directory instead of the copy compiled into the binary. Set to /app/static in the Docker image; unset elsewhere unless you are replacing the bundled UI |
| Log Level | --log-level | SCANOPY_LOG_LEVEL | info | Logging verbosity: trace, debug, info, warn, error |
| Secure Cookies | --use-secure-session-cookies | SCANOPY_USE_SECURE_SESSION_COOKIES | false | Enable HTTPS-only cookies |
| Integrated Daemon URL | --integrated-daemon-url | SCANOPY_INTEGRATED_DAEMON_URL | http://172.17.0.1:60073 | URL to reach daemon in default docker compose |
| Disable Registration | --disable-registration | SCANOPY_DISABLE_REGISTRATION | false | Disable new user registration |
| SMTP Username | --smtp-username | SCANOPY_SMTP_USERNAME | - | SMTP username for email features |
| SMTP Password | --smtp-password | SCANOPY_SMTP_PASSWORD | - | SMTP password for email authentication |
| SMTP Relay | --smtp-relay | SCANOPY_SMTP_RELAY | - | SMTP server address (e.g., smtp.gmail.com) |
| SMTP Email | --smtp-email | SCANOPY_SMTP_EMAIL | - | Sender email address for outgoing emails |
| SMTP Port | --smtp-port | SCANOPY_SMTP_PORT | 465 | Port for the SMTP relay. Selects the encryption mode: 465 is implicit TLS, any other port uses STARTTLS |
| Client IP Source | --client-ip-source | SCANOPY_CLIENT_IP_SOURCE | - | Source of IP address from request headers for reverse proxy setups |
| Metrics Token | --metrics-token | SCANOPY_METRICS_TOKEN | - | Bearer token for Prometheus metrics endpoint authentication |
| Prometheus Allowed IPs | N/A | SCANOPY_EXTERNAL_SERVICE_PROMETHEUS_ALLOWED_IPS | - | Comma-separated IPs/CIDRs allowed to access metrics endpoint |
| Snapshot Retention | N/A | SCANOPY_SNAPSHOT_RETENTION_DAYS_OVERRIDE | 90 | Days to retain topology snapshots before automatic pruning |
| License Key | N/A | SCANOPY_LICENSE_KEY | - | Signed key that enables the commercial edition. Omit for the free community edition |
Integrated Daemon URL
The integrated daemon runs in a separate container and needs to reach the server. The default assumes Docker's bridge network gateway is 172.17.0.1.
Check your bridge gateway:
docker network inspect bridge | grep GatewayIf different, update in docker-compose.yml:
environment:
- SCANOPY_INTEGRATED_DAEMON_URL=http://YOUR_GATEWAY_IP:60073SMTP Configuration
SMTP settings enable email-based features such as password reset.
All SMTP parameters are optional. If not configured, email features will be disabled. Relay, username, password and email must all be set together — with any of them missing, email stays disabled.
Every SMTP connection is encrypted, and there is no setting to turn encryption on or off. SCANOPY_SMTP_PORT selects which kind: the default of 465 is implicit TLS, and any other port uses STARTTLS, which is what submission ports such as 587 and 25 expect. STARTTLS is required rather than opportunistic — if the upgrade fails, the message is not sent.
Set SCANOPY_SMTP_EMAIL to the same mailbox as SCANOPY_SMTP_USERNAME unless that account has been granted permission to send as another address. Most providers reject a mismatch.
Configuration:
environment:
- SCANOPY_SMTP_RELAY=smtp.gmail.com
- [email protected]
- SCANOPY_SMTP_PASSWORD=your-app-password
- [email protected]
- SCANOPY_SMTP_PORT=587Microsoft 365
Microsoft 365 accepts authenticated SMTP only on port 587 with STARTTLS; it does not listen on 465, so the default port fails to connect.
environment:
- SCANOPY_SMTP_RELAY=smtp.office365.com
- SCANOPY_SMTP_PORT=587
- [email protected]
- SCANOPY_SMTP_PASSWORD=your-password
- [email protected]Microsoft 365 also requires tenant-side configuration that Scanopy cannot perform:
- SMTP AUTH must be enabled for the mailbox. Microsoft disables it by default for organizations created after January 2020.
- Security defaults must be off, and the account must not require multi-factor authentication. Microsoft documents both as incompatible with SMTP AUTH.
- The mailbox needs a Microsoft 365 license.
Microsoft is retiring basic authentication for SMTP AUTH. It is disabled by default for existing tenants from the end of December 2026, though an administrator can re-enable it, and it is unavailable to tenants created after that date. Scanopy authenticates with a username and password; OAuth is not supported.
See Microsoft's SMTP AUTH documentation for the tenant-side steps.
When a message cannot be sent, the mail server's reply is recorded in the server log. It names the specific reason — a rejected password, a tenant policy, or a sender the account may not send as — which the failure alone does not tell you.
UI Configuration
The UI automatically uses the hostname and port from your browser's address bar to reach the API.
No configuration needed for standard deployments where UI and API are on the same domain.
Advanced: API on Different Domain
If your API server is on a different hostname than where the UI is served (uncommon):
Rebuild the Docker image with build arguments:
docker build \
--build-arg PUBLIC_SERVER_HOSTNAME=api.example.com \
--build-arg PUBLIC_SERVER_PORT=8080 \
-f backend/Dockerfile \
-t scanopy-server:custom \
.Then use your custom image in docker-compose:
scanopy-server:
image: scanopy-server:custom
# ... rest of configSession Security
Secure Cookies
Important: Enable secure cookies when running Scanopy behind HTTPS.
environment:
- SCANOPY_USE_SECURE_SESSION_COOKIES=trueWhen to enable:
- Behind a reverse proxy with TLS (Nginx, Traefik, Caddy)
- Using a domain with HTTPS
- Production deployments
When to disable (default):
- Internal networks without HTTPS
- Development environments
- Accessing via IP address without TLS
Effect:
true: Cookies marked as Secure, only sent over HTTPSfalse: Cookies sent over HTTP and HTTPS
Environment Files
For easier management, use .env files:
Create .env:
# Database
SCANOPY_DATABASE_URL=postgresql://postgres:password@db:5432/scanopy
# Server
SCANOPY_SERVER_PORT=60072
SCANOPY_SERVER_PUBLIC_URL=http://your-domain.com:60072
SCANOPY_LOG_LEVEL=info
SCANOPY_USE_SECURE_SESSION_COOKIES=false
# SMTP (optional - for password reset and notifications)
SCANOPY_SMTP_RELAY=smtp.gmail.com
SCANOPY_SMTP_USERNAME=[email protected]
SCANOPY_SMTP_PASSWORD=your-app-password
SCANOPY_SMTP_EMAIL=[email protected]
SCANOPY_SMTP_PORT=587
# Daemon
SCANOPY_INTEGRATED_DAEMON_URL=http://172.17.0.1:60073
# Metrics (optional - for Prometheus scraping)
SCANOPY_METRICS_TOKEN=your-secure-metrics-token
SCANOPY_EXTERNAL_SERVICE_PROMETHEUS_ALLOWED_IPS=192.168.1.0/24Reference in docker-compose.yml:
services:
scanopy-server:
image: ghcr.io/scanopy/scanopy/server:latest
env_file:
- .env
# ... rest of configRunning without Docker: the server loads a .env file from its working directory (or a parent) automatically, so dropping one next to the binary works with no extra wiring. For a systemd service, prefer EnvironmentFile= — it doesn't depend on the working directory and keeps the file's permissions explicit.