ScanopyScanopy

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:

  1. Built-in defaults
  2. A .env file in the server's working directory (or any parent directory)
  3. SCANOPY_* environment variables
  4. 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/scanopy

systemd (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:60072

Reload 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

ParameterCLI FlagEnvironment VariableDefaultDescription
Server Public URL--public-urlSCANOPY_PUBLIC_URLhttp://localhost:60072Public URL for webhooks, email links, etc
Server Port--server-portSCANOPY_SERVER_PORT60072Port for server to listen on
Database URL--database-urlSCANOPY_DATABASE_URLRequiredPostgreSQL connection string
Web External PathN/ASCANOPY_WEB_EXTERNAL_PATHEmbedded UIServe 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-levelSCANOPY_LOG_LEVELinfoLogging verbosity: trace, debug, info, warn, error
Secure Cookies--use-secure-session-cookiesSCANOPY_USE_SECURE_SESSION_COOKIESfalseEnable HTTPS-only cookies
Integrated Daemon URL--integrated-daemon-urlSCANOPY_INTEGRATED_DAEMON_URLhttp://172.17.0.1:60073URL to reach daemon in default docker compose
Disable Registration--disable-registrationSCANOPY_DISABLE_REGISTRATIONfalseDisable new user registration
SMTP Username--smtp-usernameSCANOPY_SMTP_USERNAME-SMTP username for email features
SMTP Password--smtp-passwordSCANOPY_SMTP_PASSWORD-SMTP password for email authentication
SMTP Relay--smtp-relaySCANOPY_SMTP_RELAY-SMTP server address (e.g., smtp.gmail.com)
SMTP Email--smtp-emailSCANOPY_SMTP_EMAIL-Sender email address for outgoing emails
SMTP Port--smtp-portSCANOPY_SMTP_PORT465Port for the SMTP relay. Selects the encryption mode: 465 is implicit TLS, any other port uses STARTTLS
Client IP Source--client-ip-sourceSCANOPY_CLIENT_IP_SOURCE-Source of IP address from request headers for reverse proxy setups
Metrics Token--metrics-tokenSCANOPY_METRICS_TOKEN-Bearer token for Prometheus metrics endpoint authentication
Prometheus Allowed IPsN/ASCANOPY_EXTERNAL_SERVICE_PROMETHEUS_ALLOWED_IPS-Comma-separated IPs/CIDRs allowed to access metrics endpoint
Snapshot RetentionN/ASCANOPY_SNAPSHOT_RETENTION_DAYS_OVERRIDE90Days to retain topology snapshots before automatic pruning
License KeyN/ASCANOPY_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 Gateway

If different, update in docker-compose.yml:

environment:
  - SCANOPY_INTEGRATED_DAEMON_URL=http://YOUR_GATEWAY_IP:60073

SMTP 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=587

Microsoft 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 config

Session Security

Secure Cookies

Important: Enable secure cookies when running Scanopy behind HTTPS.

environment:
  - SCANOPY_USE_SECURE_SESSION_COOKIES=true

When 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 HTTPS
  • false: 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/24

Reference in docker-compose.yml:

services:
  scanopy-server:
    image: ghcr.io/scanopy/scanopy/server:latest
    env_file:
      - .env
    # ... rest of config

Running 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.

On this page