Docker Configuration
VisionAlert On-premises is defined by two files in the vision-alert folder of the Docker Compose bundle:
docker-compose.ymldefines the services, ports, and volumes..envholds your settings. It is a hidden file next todocker-compose.yml.
Run all docker compose commands from that folder.
Services​
| Service | Image | Purpose |
|---|---|---|
web | platerecognizer/vision-alert | Web dashboard and API on port 8080. |
worker | platerecognizer/vision-alert | Processes uploaded snapshots. |
scheduler | platerecognizer/vision-alert | Runs the anomaly check cycle every CHECK_INTERVAL seconds. |
bridge | platerecognizer/vision-alert | Routes files received by the SFTP server to the right camera. |
sftpgo | drakkan/sftpgo:v2.6.6 | SFTP server on port 2022 that cameras upload snapshots to. |
db | postgres:16 | PostgreSQL database. |
The services start automatically on boot because they use the unless-stopped restart policy. If you stop them with docker compose down, start them again with docker compose up -d.
Changing Settings​
To change a setting, edit .env or docker-compose.yml and apply it:
docker compose up -d
Docker Compose recreates only the services whose settings changed. Your data is kept in Docker volumes, and upgrades keep your edits because docker compose pull only replaces the images.
Replace YOUR_LICENSE_KEY with your License Key and YOUR_API_TOKEN with your API Token. Get your token and license key. Use On-premises Licenses. The downloaded .env file already contains them.
Networking​
- Port 8080 serves the dashboard and API. To use a different port, for example 8888, change the
portsentry of thewebservice indocker-compose.ymlto8888:8080and setSITE_URLto match. - Port 2022 is the SFTP server. Cameras upload snapshots to it, so it must be reachable from the camera network. Plain FTP is not available.
- If you expose VisionAlert on a public IP address, put a reverse proxy in front of port 8080 and serve it over HTTPS. Set
SITE_URL,ALLOWED_HOSTS, andCSRF_TRUSTED_ORIGINSto match the public URL. - The services need outbound access to
api.platerecognizer.comon ports80and443for license activation and periodic validation. See Server Addresses for the IP addresses to whitelist. Offline activation is not available.
Environment Variables​
Set these variables in .env.
LICENSE_KEY​
Your VisionAlert On-premises license key. Get it from the VisionAlert page.
Example:
LICENSE_KEY=YOUR_LICENSE_KEY
This is required.
TOKEN​
Your Plate Recognizer API token. Get it from the VisionAlert page.
Example:
TOKEN=YOUR_API_TOKEN
This is required.
ADMIN_EMAIL​
Email address of the first administrator account. The account is created on first start. It is also the username cameras use to log in to the SFTP server.
Example:
ADMIN_EMAIL=YOUR_ADMIN_EMAIL
This is required.
ADMIN_PASSWORD​
Password of the first administrator account.
Example:
ADMIN_PASSWORD=YOUR_ADMIN_PASSWORD
This is required.
SFTPGO_ADMIN_PASSWORD​
Internal password VisionAlert uses to manage the SFTP server. The downloaded .env file contains a random value. Set it once before the first start and never change it, because the SFTP server only creates its administrator on first start.
Example:
SFTPGO_ADMIN_PASSWORD=YOUR_RANDOM_STRING
This is required.
SFTP_PASSWORD​
Password cameras use to upload snapshots over SFTP. If unset, VisionAlert generates one and shows it on the API Tokens page of the on-premises dashboard. To change it later, edit .env and run docker compose up -d.
Example:
SFTP_PASSWORD=YOUR_SFTP_PASSWORD
Optional Variables​
The variables below are not in the downloaded files. Add them to the environment list of the web service in docker-compose.yml. That list is shared with the worker, scheduler, and bridge services, so one entry applies to all of them.
web:
<<: &app-config
image: platerecognizer/vision-alert
restart: unless-stopped
volumes:
- user_data:/user-data
environment:
- LICENSE_KEY=${LICENSE_KEY:?Set LICENSE_KEY in .env}
# ... existing entries ...
- SITE_URL=http://YOUR_SERVER_IP:8080
- CHECK_INTERVAL=3600
- ANOMALY_CHECKERS=2
Replace YOUR_SERVER_IP with the IP address or hostname that users reach the server on. Only add the variables you want to change, then run docker compose up -d.
SITE_URL​
Public URL of the instance. It is used in dashboard links and webhook payloads, so it must match the address users reach the server on. Defaults to http://localhost:8080.
CHECK_INTERVAL​
Seconds between anomaly check cycles. Each cycle analyzes the snapshots collected since the previous cycle. Defaults to 3600.
ANOMALY_CHECKERS​
Number of inference workers used to analyze snapshots. Defaults to 2. See Speed Optimization.
IO_CONCURRENCY​
Number of snapshots read and written in parallel while analyzing. Defaults to 4.
WEB_WORKERS​
Number of web server workers for the dashboard and API. Defaults to 2.
ALLOWED_HOSTS​
Comma-separated list of host names the web server accepts. By default all hosts are accepted. Set it when serving VisionAlert under a domain name.
Example:
- ALLOWED_HOSTS=visionalert.example.com
CSRF_TRUSTED_ORIGINS​
Comma-separated origins, including the scheme, that are trusted for form submissions. Set it together with ALLOWED_HOSTS when running behind a reverse proxy.
Example:
- CSRF_TRUSTED_ORIGINS=https://visionalert.example.com
GEMINI_API_KEY​
Google Gemini API key that enables the AI glare reviewer. Get a key from Google AI Studio. The services then need outbound HTTPS access to the Gemini API.
Example:
- GEMINI_API_KEY=YOUR_GEMINI_API_KEY
Speed Optimization​
- Snapshot analysis runs in batches every
CHECK_INTERVALseconds. Between cycles the services are close to idle, so a short interval mostly changes how quickly alerts are raised, not the total CPU used. - By default two inference workers analyze snapshots during a cycle. On hosts with 4 or more cores, set
ANOMALY_CHECKERShigher, for exampleANOMALY_CHECKERS=4, to finish each cycle faster. - Increase
WEB_WORKERSonly if the dashboard or API becomes slow under many concurrent users.
Logs​
Each service writes its own log. Follow all of them, or a single service:
docker compose logs -f
docker compose logs -f web
| Service | What to look for |
|---|---|
web | Startup, migrations, license validation, API requests. |
worker | Snapshot processing. |
scheduler | Anomaly check cycles and alerts. |
bridge | Upload routing errors, such as files outside a folder. |
sftpgo | SFTP logins and uploads. |
db | PostgreSQL startup and connection errors. |
Data and Storage​
Everything VisionAlert writes is stored in Docker volumes created by docker-compose.yml:
| Volume | Contents |
|---|---|
postgres_data | The PostgreSQL database. |
user_data | Camera snapshots under media/camera_snapshot, application logs, and cache. |
sftpgo_data | SFTP server state. |
sftp_home | Files received by the SFTP server before they are processed. |
VisionAlert keeps every snapshot it receives. There is currently no automatic cleanup, so size the disk for the retention period you need and monitor free disk space. Plan about 0.3 MB of disk per snapshot.
Back up regularly. Dump the database while the services run, then copy the user_data volume. The database name and user are both visionalert, as defined in docker-compose.yml:
docker compose exec db pg_dump -U visionalert visionalert > vision-alert-backup.sql
docker compose down keeps all volumes. docker compose down -v deletes them.
Summary​
- Set
LICENSE_KEY,TOKEN,ADMIN_EMAIL,ADMIN_PASSWORD, andSFTPGO_ADMIN_PASSWORDin.env. Docker Compose refuses to start without them. The downloaded bundle fills in all butADMIN_PASSWORD. - Never change
SFTPGO_ADMIN_PASSWORDafter the first start. It is internal to VisionAlert. SFTP_PASSWORDis the camera upload password. Leave it empty to have one generated and shown on the API Tokens page.- Port 2022 must be reachable from your cameras. It is the SFTP server. Plain FTP is not available.
- Allow outbound access to
api.platerecognizer.comon ports 80 and 443 for license validation. - Add optional variables such as
SITE_URL,CHECK_INTERVAL, andANOMALY_CHECKERSto thewebservice indocker-compose.yml. - Back up the database and the
user_datavolume regularly. Snapshots are never pruned automatically.