Installing the Server
Overview
DeskAlerts 12 is delivered for on-premises use as a set of Docker images that run on a Linux host with Docker Compose. The stack contains the DeskAlerts application services, an nginx reverse proxy that publishes them on port 443, and — optionally — Microsoft SQL Server 2022 and RabbitMQ. The package is self-contained: the server needs no access to Docker Hub, npm, or the public internet, so it can be installed on an isolated network.
This page takes a system administrator from a clean Linux server to the first sign-in, one step at a time: each step says what it does and gives the commands to run. The commands are written for Ubuntu Server 24.04 LTS and were run in this order on a clean server. On other distributions only the Docker installation (Step 3) differs.
According to DeskAlerts distribution policy, server packages are not published for public download. Request the package for the current version from the DeskAlerts Support team.
Before You Begin
| You need | Details |
|---|---|
| A Linux server | x86_64, 4 vCPU, 16 GB RAM, and 50 GB SSD at minimum (8 vCPU, 32 GB, 100 GB recommended) — see System Requirements |
An account with sudo | The commands run as a regular user; sudo is used where root is required |
| The server name | The final host name, for example alerts.company.local, with a DNS record that points to the server |
| The package | deskalerts-docker-images-<VERSION>.tar.gz and its SHA-256 checksum from DeskAlerts Support |
| A TLS certificate | For the server name, in PEM format (fullchain.pem, privkey.pem) — see Step 11 |
| A database | The in-stack SQL Server container from the package, or an external SQL Server 2019+ with a login for DeskAlerts |
| The license file | The .txt license issued for this server |
The examples use version 12.1.0.3 and the server name alerts.company.local. Replace both with your values everywhere on this page. Every command after Step 6 is run from the package folder unless the step says otherwise.
What You Receive
The package is a tar.gz archive named after the version, for example deskalerts-docker-images-12.1.0.3.tar.gz (about 3 GB). Unpacked, it looks like this:
deskalerts-docker-images-12.1.0.3/
├── README.txt
├── QUICKSTART.txt
├── MANIFEST.txt
├── CHECKSUMS.sha256
├── images/
│ ├── deskalerts-app.tar.gz # all DeskAlerts services
│ ├── mssql-2022.tar.gz # in-stack SQL Server
│ └── rabbitmq-4.1.tar.gz # in-stack RabbitMQ
├── deploy/
│ ├── compose.yml # DeskAlerts services and nginx
│ ├── compose.mssql.yml # overlay: SQL Server 2022 container
│ ├── compose.rabbitmq.yml # overlay: RabbitMQ container
│ └── .env.example # configuration template
├── scripts/
│ ├── import-images.sh # loads the images into Docker
│ ├── init-env.sh # creates deploy/.env and generates the secrets
│ ├── prepare-data-dirs.sh # creates the data folders on the host
│ ├── start.sh / stop.sh # starts and stops the stack
│ └── verify.sh # checks the running stack
└── docs/
└── ON_PREM_DOCKER_DEPLOYMENT_ADMIN.md
MANIFEST.txt lists the version, the images in the package, and whether it contains the in-stack SQL Server and RabbitMQ. The SSO Gateway MSI for Active Directory SSO is delivered separately — see SSO Gateway and Companion.
Step 1. Check the Server
Confirm the operating system, the number of CPUs, the memory, and the free disk space:
grep PRETTY_NAME /etc/os-release
nproc
free -h
df -h /opt /var/lib
The images take about 14 GB once loaded into Docker, and the archive with its unpacked copy takes another 6 GB during the installation. Keep at least 25 GB free on the file system that holds /opt and /var/lib/docker before you start.
Step 2. Check the Server Name
The DeskAlerts services call the server by its own URL, so the server name must resolve on the server itself — not only on the workstations:
getent hosts alerts.company.local
The output must show the IP address of this server. If the DNS record does not exist yet, add the name to /etc/hosts until it does:
echo "192.168.10.20 alerts.company.local" | sudo tee -a /etc/hosts
Step 3. Install Docker
Install Docker Engine with the Docker Compose plugin. Choose the variant that matches your network.
With internet access
Add the Docker repository and install the packages (the official procedure for Ubuntu):
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
For other distributions follow the Docker Engine installation guide.
Without internet access
On a machine with internet access, download these five packages for your Ubuntu release from https://download.docker.com/linux/ubuntu/dists/<codename>/pool/stable/amd64/ (noble for 24.04): containerd.io, docker-ce, docker-ce-cli, docker-buildx-plugin, docker-compose-plugin. Copy them to the server into one folder, for example ~/docker-offline, and install them together:
cd ~/docker-offline
sudo apt-get install -y --no-install-recommends ./*.deb
Important: Keep
--no-install-recommends. Without itaptalso tries to download the recommended packages (pigz,docker-ce-rootless-extras) from the internet and the whole installation stops withTemporary failure resolving. Docker does not need them.
Start Docker and allow your account to use it
Enable the Docker service at boot, add your account to the docker group, and apply the group to the current session:
sudo systemctl enable --now docker
sudo usermod -aG docker "$USER"
newgrp docker
Check the result:
docker version --format '{{.Server.Version}}'
docker compose version
Both commands must print a version number. If docker version reports permission denied, sign out and sign in again so that the new group membership applies.
Step 4. Limit the Size of the Container Logs
Docker keeps the console output of every container in a file that grows without limit by default, and the DeskAlerts services write a lot of output. Set a size limit for all containers before the stack is created:
echo '{ "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "5" } }' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
The limit applies to containers created after the restart. The DeskAlerts file logs are kept separately — see Logs and Diagnostics.
Note: If
/etc/docker/daemon.jsonalready exists, add thelog-driverandlog-optskeys to it instead of overwriting the file.
Step 5. Copy the Package to the Server
Copy the archive to the server, for example with scp from the computer where you downloaded it:
scp deskalerts-docker-images-12.1.0.3.tar.gz admin@alerts.company.local:/tmp/
On the server, compare the checksum of the archive with the value you received from DeskAlerts Support:
sha256sum /tmp/deskalerts-docker-images-12.1.0.3.tar.gz
Step 6. Unpack the Package
Create the working folder, move the archive into it, and unpack it:
sudo mkdir -p /opt/deskalerts
sudo chown "$USER":"$USER" /opt/deskalerts
mv /tmp/deskalerts-docker-images-12.1.0.3.tar.gz /opt/deskalerts/
cd /opt/deskalerts
tar -xzf deskalerts-docker-images-12.1.0.3.tar.gz
Go to the package folder and check every file against the list of checksums:
cd /opt/deskalerts/deskalerts-docker-images-12.1.0.3
sha256sum --quiet -c CHECKSUMS.sha256 && echo "All files OK"
The output must end with All files OK. Read MANIFEST.txt to confirm the version and the included images:
cat MANIFEST.txt
Step 7. Load the Docker Images
Load all images from the images/ folder into Docker:
bash scripts/import-images.sh
The script takes several minutes (about 4.5 minutes on 4 vCPU). Check that every DeskAlerts image carries the version of the package:
docker images --format '{{.Repository}}:{{.Tag}}' | sort
Expected: eleven deskalerts/*:12.1.0.3 images (ai, auth, connection, db-manager, main, nginx, pwa, reports, settings, smtp, workflows), plus alpine:3.20, mcr.microsoft.com/mssql/server:2022-latest, and rabbitmq:4.1-management.
Once the images are loaded, the archive is no longer needed on this server. Keep a copy elsewhere and delete it here to free 3 GB:
rm /opt/deskalerts/deskalerts-docker-images-12.1.0.3.tar.gz
Step 8. Create the Configuration File
All settings of the stack are in one file, deploy/.env. Create it from the template:
bash scripts/init-env.sh
The script copies deploy/.env.example to deploy/.env, restricts the file to its owner, and generates the secrets that must be unique for every installation: the token-signing keys, the Settings API key, the SSO internal secret, the AI encryption key, and the RabbitMQ password with its connection strings.
Warning: Run
init-env.shonly on a new installation, and never with--force-secretson a server that already has DeskAlerts data. A new AI encryption key makes the stored AI provider keys unreadable, a new SSO secret breaks Active Directory SSO, and a new RabbitMQ password locks the services out of the existing broker.
Step 9. Set the Server URL and the Data Folder
Go to the deploy folder:
cd /opt/deskalerts/deskalerts-docker-images-12.1.0.3/deploy
Set the public URL of the server. It must be the https:// address users will open, with the host name from the TLS certificate:
sed -i 's|^DESKALERTS_SERVER_URL=.*|DESKALERTS_SERVER_URL=https://alerts.company.local|' .env
Set the host folder for media and uploads. The template contains a Windows path (C:/media) that does not work on Linux:
sed -i 's|^DESKALERTS_MS_MOUNT_FOLDER_SOURCE=.*|DESKALERTS_MS_MOUNT_FOLDER_SOURCE=/opt/deskalerts/data/media|' .env
Step 10. Configure the Database
Choose one of the two variants.
Variant A: SQL Server in the stack
The package runs SQL Server 2022 as a container and keeps its data in a folder on the host.
Enter the password for the SQL Server sa account. Use at least 12 characters with upper-case letters, lower-case letters, and digits; avoid symbols, which need quoting in .env. The password is not echoed and does not end up in the shell history:
read -rs -p "SQL Server sa password: " DA_DB_PASS; echo
Write the password to .env in both forms — plain for the SQL Server container and Base64-encoded for the DeskAlerts services:
sed -i "s|^DESKALERTS_DB_PASSWORD_RAW=.*|DESKALERTS_DB_PASSWORD_RAW=${DA_DB_PASS}|" .env
sed -i "s|^DESKALERTS_DB_PASSWORD_64=.*|DESKALERTS_DB_PASSWORD_64=$(printf '%s' "$DA_DB_PASS" | base64 -w0)|" .env
unset DA_DB_PASS
Enable the host folder for the database files (the line is commented out in the template):
sed -i 's|^# *DESKALERTS_DB_MOUNT_FOLDER=.*|DESKALERTS_DB_MOUNT_FOLDER=/opt/deskalerts/data/mssql|' .env
Keep DESKALERTS_DB_SERVER=mssql, DESKALERTS_DB_USER=sa, and DESKALERTS_DB_NAME=DeskAlerts from the template.
Variant B: External SQL Server
Prepare a SQL Server login for DeskAlerts with SQL Server authentication. The dbcreator server role is enough: the database is created by the installation and the login becomes its owner. The SQL Server must accept connections on port 1433 from this server.
Set the SQL Server host, the login, and the database name:
sed -i 's|^DESKALERTS_DB_SERVER=.*|DESKALERTS_DB_SERVER=sql01.company.local|' .env
sed -i 's|^DESKALERTS_DB_USER=.*|DESKALERTS_DB_USER=deskalerts|' .env
sed -i 's|^DESKALERTS_DB_NAME=.*|DESKALERTS_DB_NAME=DeskAlerts|' .env
Enter the password of the login and write it Base64-encoded:
read -rs -p "SQL login password: " DA_DB_PASS; echo
sed -i "s|^DESKALERTS_DB_PASSWORD_64=.*|DESKALERTS_DB_PASSWORD_64=$(printf '%s' "$DA_DB_PASS" | base64 -w0)|" .env
unset DA_DB_PASS
Comment out the plain password line. It is used only by the in-stack SQL Server, but start.sh refuses to start while it still holds the placeholder from the template:
sed -i 's|^DESKALERTS_DB_PASSWORD_RAW=|# DESKALERTS_DB_PASSWORD_RAW=|' .env
For Azure SQL Database also set DESKALERTS_DB_AZURE_SQL=true.
Check the values
Print the values you have set, without the passwords:
grep -E '^(DESKALERTS_VERSION|DESKALERTS_SERVER_URL|DESKALERTS_DB_SERVER|DESKALERTS_DB_USER|DESKALERTS_DB_NAME|DESKALERTS_DB_MOUNT_FOLDER|DESKALERTS_MS_MOUNT_FOLDER_SOURCE|DESKALERTS_DB_DROP_DATABASE)=' .env
DESKALERTS_DB_DROP_DATABASE must stay false. The optional settings — SMTP, Active Directory SSO — can be added to .env now or later; see Optional Settings in .env.
Step 11. Install the TLS Certificate
Without a certificate of its own, nginx generates a self-signed certificate on start. That is enough to open the portal for a test, but agents and browsers will not trust it. For production, install a certificate for the server name from your corporate CA or Let's Encrypt.
Create the certificate folders on the host:
sudo mkdir -p /opt/deskalerts/ssl/live/alerts.company.local /opt/deskalerts/ssl/archive/alerts.company.local
Copy the certificate with its intermediate chain as fullchain.pem and the unencrypted private key as privkey.pem into the live folder and protect the key:
sudo cp fullchain.pem privkey.pem /opt/deskalerts/ssl/live/alerts.company.local/
sudo chmod 600 /opt/deskalerts/ssl/live/alerts.company.local/privkey.pem
A certificate exported from Windows as a .pfx file is converted to these two files with OpenSSL — see HTTPS and Certificates.
Open deploy/compose.yml:
nano /opt/deskalerts/deskalerts-docker-images-12.1.0.3/deploy/compose.yml
Find the nginx: service and add a volumes: section directly above its ports: line, with the same indentation as ports::
volumes:
- type: bind
source: /opt/deskalerts/ssl/live/alerts.company.local
target: /opt/letsencrypt/live/alerts.company.local
- type: bind
source: /opt/deskalerts/ssl/archive/alerts.company.local
target: /opt/letsencrypt/archive/alerts.company.local
ports:
- "443:443"
Save a copy of the edited file next to the certificates:
cp /opt/deskalerts/deskalerts-docker-images-12.1.0.3/deploy/compose.yml /opt/deskalerts/ssl/compose.yml.custom
Important: An update brings a new
compose.ymlwithout this section. Add it again in every new package folder before the first start — otherwise nginx silently falls back to a self-signed certificate and the agents stop connecting.
Step 12. Create the Data Folders
Create the folders for media, uploads, directory-synchronization logs, and the in-stack database, with the owners the containers expect:
cd /opt/deskalerts/deskalerts-docker-images-12.1.0.3
bash scripts/prepare-data-dirs.sh
The script reads the paths from deploy/.env and stops with a clear message if a path is still the Windows path from the template.
Step 13. Start the Stack
Start the stack with the overlays your deployment uses:
In-stack SQL Server and RabbitMQ (Variant A):
bash scripts/start.sh --mssql --rabbitmq
External SQL Server and in-stack RabbitMQ (Variant B):
bash scripts/start.sh --rabbitmq
start.sh checks that all images are loaded, writes the chosen overlays to deploy/.env (COMPOSE_FILE), and starts the containers in a fixed order:
logs-initprepares the shared log volume anddb-managercreates or upgrades the database; both exit with code 0.main,auth,connection,workflows,settings,smtp,reports, andaistart after both have finished.nginxstarts when the services it proxies are healthy.
The first start takes from under a minute to several minutes, depending on the hardware and the database. The script ends with Stack is up.
Later start.sh, stop.sh, and verify.sh calls need no flags: they reuse the overlays saved in .env. Pass the flags again only to change the set of overlays.
Step 14. Verify the Installation
Run the check script:
bash scripts/verify.sh
The script lists the containers and checks the login page, /auth/health, and /api/health. Expected result:
OK https://alerts.company.local/
OK https://alerts.company.local/auth/health
OK https://alerts.company.local/api/health
✅ Verification passed. Open https://alerts.company.local/ and change the admin password.
In the container list, db-manager and logs-init must have exited with code 0, and every other container must be Up … (healthy). Confirm that the database step succeeded:
docker logs deskalerts-db-manager-1 2>&1 | tail -3
The last line must be Database setup completed successfully!.
Check which certificate nginx uses:
docker logs deskalerts-nginx-1 2>&1 | grep -E 'Using SSL|self-signed'
With your certificate installed the output names /opt/letsencrypt/live/alerts.company.local/fullchain.pem. A line about a self-signed certificate means the mount from Step 11 is missing or the files are not named fullchain.pem and privkey.pem.
Step 15. Restrict Network Access
Users and agents need only TCP 443. The stack also publishes, on all interfaces of the server, the ports of the individual services (40004–40012) and — with the in-stack database — SQL Server on 1433. List them:
sudo ss -ltnp | grep docker-proxy
Allow only port 443 to this server in the network firewall in front of it. Docker inserts its own firewall rules for published ports, so a host firewall such as ufw does not block them.
Step 16. Sign In and Change the Administrator Password
Open https://alerts.company.local/ in a browser on a workstation. The login page shows the version in its top-right corner.

Sign in with the built-in account admin and the password admin. The portal opens the Dashboard without asking for a new password, so change it yourself right away:
- Click admin at the bottom of the left menu and choose Profile settings.
- In the Security section, click Change password. Enter
adminin Current password, the new strong password in New password and Confirm new password, and click Update password. - Sign out and sign in again with the new password. Store it safely.

Until the license is uploaded the left menu shows only some sections (Dashboard, Create alert, Alerts, Audience explorer, Shared assets, Settings); the others appear with the licensed modules. The password policy for all portal accounts is set under Settings → Users & access → Web-portal password policy.
Note: A browser that still holds a session for the same URL from an earlier installation can show the portal shell without a sign-in; the server refuses its requests. Sign out, or clear the site data in the browser, after reinstalling a server.
Step 17. Upload the License
- Open Settings → License.
- Scroll down to Activate new license and drag the
.txtlicense file onto the upload area, or click Browse files and select it.

- Check the License summary at the top of the page: the status must be Active, with your organization name, the number of web-portal users and recipients, and the expiration date. The licensed modules are listed below the summary.

If the portal shows Failed to apply license, reload the page and check the License summary before you upload the file again: in version 12.1.0.3 the message can appear although the license was applied.
Step 18. Check Automatic Start After a Reboot
The containers come back with the Docker service. Make sure it is enabled at boot and test a reboot before the server goes into production:
systemctl is-enabled docker
sudo reboot
After the server is back, wait one or two minutes and run the check again:
cd /opt/deskalerts/deskalerts-docker-images-12.1.0.3
bash scripts/verify.sh
A few services may restart once while SQL Server is still starting; the result counts only when verify.sh passes.
Step 19. Back Up the Configuration
deploy/.env holds the generated secrets that the database depends on. Without it the installation cannot be updated or restored with the existing data. Copy it, together with the customized compose.yml, to a protected location outside the server:
mkdir -p ~/deskalerts-config
cp /opt/deskalerts/deskalerts-docker-images-12.1.0.3/deploy/.env ~/deskalerts-config/env-12.1.0.3
cp /opt/deskalerts/deskalerts-docker-images-12.1.0.3/deploy/compose.yml ~/deskalerts-config/compose-12.1.0.3.yml
chmod 600 ~/deskalerts-config/*
Then set up regular backups of the database and the media folder — see Database and Backup.
Optional Settings in .env
Edit deploy/.env with nano and restart the stack with bash scripts/start.sh to apply a change.
SMTP
DESKALERTS_SMTP_SERVER=smtp.company.local
DESKALERTS_SMTP_PORT=587
DESKALERTS_SMTP_SSL=true
DESKALERTS_SMTP_AUTH=true
DESKALERTS_SMTP_USER=alerts@company.local
DESKALERTS_SMTP_PASSWORD=...
The SMTP server can also be set later in the portal under Settings → Delivery channels → SMTP server (emails) — see Auxiliary Delivery Channels.
Active Directory SSO
- Install the SSO Gateway MSI on a domain-joined Windows Server (see SSO Gateway and Companion).
- Point the stack at the gateway:
DESKALERTS_SSO_GATEWAY_URL=http://<sso-host>:58009
- Enter the value of
DESKALERTS_SSO_INTERNAL_SECRETfrom.envas the Internal secret (INTERNAL_SECRET) of the gateway MSI. Both must be identical.
AI features
AI features are not configured in .env. After the installation, open Settings → Integrations → AI integrations, turn the feature on, and enter the provider key. The server needs outbound HTTPS to the provider; on an isolated network leave AI off — the rest of the product works without it. See AI Providers.
Troubleshooting the Installation
| Symptom | Likely cause | Action |
|---|---|---|
apt-get install ./*.deb stops with Temporary failure resolving | apt tries to download recommended packages | Add --no-install-recommends (Step 3) |
prepare-data-dirs.sh refuses C:/media | The media path from the template was not changed | Set DESKALERTS_MS_MOUNT_FOLDER_SOURCE (Step 9) |
start.sh: DESKALERTS_DB_PASSWORD_64 / _RAW still hold the .env.example placeholder | A password line still has the template value; with an external SQL Server, usually DESKALERTS_DB_PASSWORD_RAW | Set the passwords, or comment out DESKALERTS_DB_PASSWORD_RAW for an external SQL Server (Step 10) |
start.sh: DESKALERTS_VERSION / DESKALERTS_DB_VERSION does not match the package | .env was copied from another version | Set both to the values in deploy/.env.example of this package |
db-manager exited with a non-zero code | Wrong database password, SQL Server unreachable, or the login cannot create the database | docker logs deskalerts-db-manager-1; check the DESKALERTS_DB_* values and port 1433 |
pull access denied or Compose tries to download an image | An image is not loaded (often a full disk during the import) | Free disk space and run bash scripts/import-images.sh again |
/api/health returns Degraded | The services cannot log in to RabbitMQ — the password in .env differs from the existing broker volume | Restore the .env the broker was created with |
502 from nginx | A service is still starting | Wait for the health checks; docker ps |
| Browser or agent rejects the certificate | nginx uses the self-signed certificate | Step 11; check with docker logs deskalerts-nginx-1 (Step 14) |
| Failed to apply license | Known message in 12.1.0.3; the license is often applied anyway | Reload Settings → License and check the summary (Step 17) |
/api/health reports the state of the services, not of the database: it can show Healthy while SQL Server is unreachable. When the portal misbehaves, check the database container or server directly. More symptoms and fixes are listed in Services and Health.
Initial Configuration in the Portal
| Step | Where |
|---|---|
| Connect the directory and import the audience | Settings → Users & access → IAM sync (AD/EntraID) — see Users & Access |
| Decide which devices may register | Settings → Users & access → Audience access level — see Audience and Identity |
| Configure SSO for administrators | Settings → Users & access → SSO settings — for Active Directory SSO see SSO Gateway and Companion |
| Configure email, SMS, Teams | Settings → Delivery channels — see Auxiliary Delivery Channels |
| Create web-portal roles and users | Settings → Users & access → Web-portal roles, Web-portal users |
| Set defaults for new alerts | Settings → Alerts → New popup and ticker defaults |
| Install the first agents | The Desktop agent section |
Related
docs/ON_PREM_DOCKER_DEPLOYMENT_ADMIN.md— the deployment guide shipped in the package- Preparing the Server, HTTPS and Certificates
- Updating the Server, Database and Backup, Logs and Diagnostics