> For the complete documentation index, see [llms.txt](https://docs.devolutions.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.devolutions.net/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/advanced-docker-configuration-for-devolutions-server.md).

# Advanced Docker configuration for Devolutions Server

Configure Devolutions Server in Docker with SQL Server, PostgreSQL or SQLite, and set up TLS certificates, reverse proxies, secrets and version updates.

This article covers advanced configuration options for the Devolutions Server Docker image: the complete environment variable reference, database configuration for SQL Server, PostgreSQL and SQLite, TLS certificates, reverse proxy settings, security hardening and version updates.

The Devolutions Server image is published on Docker Hub as [`devolutions/devolutions-server`](https://hub.docker.com/r/devolutions/devolutions-server). It is a Linux image (Debian) built for `linux/amd64` and `linux/arm64`.

The image supports the following database engines:

| Engine     | `DATABASE_TYPE` value | Notes                                                                                                                                                                                                                                   |
| ---------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQL Server | `SqlServer` (default) | On-premises SQL Server or a managed service such as Azure SQL Database.                                                                                                                                                                 |
| PostgreSQL | `PostgreSQL`          | PostgreSQL 14 or later, self-hosted or managed, with a role that has the `SUPERUSER` attribute. For the server-side preparation, see [PostgreSQL](/server/getting-started/installation/database-setup/database-instance/postgresql.md). |
| SQLite     | `SQLite`              | Experimental. One active Devolutions Server node on local storage only.                                                                                                                                                                 |

{% hint style="info" %}
Most short examples in this article use Bash line continuation (`\`). In PowerShell, end each continued line with a backtick (`` ` ``) instead.
{% endhint %}

### Environment variables reference

#### Database connection variables

Each variable in the *Alias* column is an alternative name for the same setting (Azure-specific naming). Set either the standard name or its alias, not both: when both are set, the standard name is used.

| Variable                            | Alias                     | Required               | Default                                  | Description                                                                                                                                                                                                                                                                                                                          |
| ----------------------------------- | ------------------------- | ---------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DATABASE_TYPE`                     | —                         | No                     | `SqlServer`                              | Database engine: `SqlServer`, `PostgreSQL` or `SQLite`. The value is not case-sensitive, and `MSSQL` and `Postgres` are accepted as aliases. Any other value stops the container at startup.                                                                                                                                         |
| `DATABASE_HOST`                     | `AZURE_SQL_HOST`          | SQL Server, PostgreSQL | —                                        | Database server host name or IP address. SQL Server accepts the `host,port` format (for example `sql.example.com,1435`). PostgreSQL accepts the `host:port` format (for example `postgres.example.com:5433`), which overrides `DATABASE_PORT`; the `host,port` format does not work with PostgreSQL.                                 |
| `DATABASE_NAME`                     | `AZURE_SQL_DATABASE`      | SQL Server, PostgreSQL | —                                        | Name of the Devolutions Server database.                                                                                                                                                                                                                                                                                             |
| `DATABASE_USERNAME`                 | `AZURE_SQL_USERNAME`      | SQL Server, PostgreSQL | —                                        | Database account used by Devolutions Server. SQL Server: a SQL Server login that is a member of `db_owner` on the Devolutions Server database. PostgreSQL: a dedicated role that owns the Devolutions Server database, with the `SUPERUSER` attribute to create the database schema.                                                 |
| `DATABASE_PASSWORD`                 | `AZURE_SQL_PASSWORD`      | SQL Server, PostgreSQL | —                                        | Password of the database account. Treat it as a secret: use `DATABASE_PASSWORD_FILE` with Docker secrets, or a secret store such as Azure Key Vault.                                                                                                                                                                                 |
| `DATABASE_PASSWORD_FILE`            | `AZURE_SQL_PASSWORD_FILE` | No                     | —                                        | Path of a file that contains the database password, such as a Docker secret mounted at `/run/secrets/dvls_db_password`. Used only when neither `DATABASE_PASSWORD` nor `AZURE_SQL_PASSWORD` is set. The file must not be empty; trailing line breaks are removed.                                                                    |
| `DATABASE_PORT`                     | `AZURE_SQL_PORT`          | No                     | `1433` (SQL Server), `5432` (PostgreSQL) | Database server port. SQL Server: appended to `DATABASE_HOST` as `host,port` when it differs from `1433` and `DATABASE_HOST` does not already contain a port. PostgreSQL: must be an integer between 1 and 65535.                                                                                                                    |
| `DATABASE_ENCRYPT`                  | —                         | No                     | `false`                                  | Set to `true` to encrypt the database connection with TLS. SQL Server: sets `Encrypt`. PostgreSQL: `false` sets `SSL Mode=Disable` (connection not encrypted); `true` sets `SSL Mode=VerifyFull`, or `SSL Mode=Require` when `DATABASE_TRUST_SERVER_CERTIFICATE=true`. Read on every container start: pass it on every `docker run`. |
| `DATABASE_TRUST_SERVER_CERTIFICATE` | —                         | No                     | `false`                                  | Set to `true`, with `DATABASE_ENCRYPT=true`, to accept the database server certificate without validating it (for example a self-signed certificate). SQL Server: sets `TrustServerCertificate`. PostgreSQL: selects `SSL Mode=Require` instead of `VerifyFull`. Read on every container start.                                      |
| `DATABASE_PATH`                     | —                         | SQLite                 | —                                        | Absolute path of the SQLite database file, inside `$DVLS_PATH/App_Data` (for example `/opt/devolutions/dvls/App_Data/dvls.sqlite`). Used only with `DATABASE_TYPE=SQLite`.                                                                                                                                                           |

{% hint style="info" %}
With `DATABASE_TYPE=SQLite`, the container refuses to start when `DATABASE_HOST`, `DATABASE_NAME`, `DATABASE_USERNAME`, `DATABASE_PASSWORD`, `DATABASE_PASSWORD_FILE`, `DATABASE_PORT` or one of their aliases is set.
{% endhint %}

#### Web server configuration

| Variable                | Required | Default                                             | Description                                                                                                                                                                                                                                                                        |
| ----------------------- | -------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `HOSTNAME`              | No       | Host name of the container (`localhost` when empty) | Server host name, used for the access URI, the server name and the self-signed certificate. Docker sets `HOSTNAME` to the container host name (the container ID unless `--hostname` is used), so pass `-e HOSTNAME=<public host name>`. Overridden by `WEBSITE_HOSTNAME` on Azure. |
| `WEB_SCHEME`            | No       | `http`                                              | Protocol the container listens on: `http` or `https`. Set to `https` to enable TLS.                                                                                                                                                                                                |
| `PORT` / `WEB_PORT`     | No       | `5000`                                              | Port the container listens on, on all interfaces. When both are set, `PORT` is used. `ASPNETCORE_URLS` has no effect: the container writes the listening address itself.                                                                                                           |
| `EXTERNAL_WEB_SCHEME`   | No       | Value of `WEB_SCHEME`                               | Public protocol when Devolutions Server runs behind a reverse proxy (for example `https` when the proxy handles TLS).                                                                                                                                                              |
| `EXTERNAL_WEB_PORT`     | No       | Value of `PORT` / `WEB_PORT`                        | Public port when Devolutions Server runs behind a reverse proxy (for example `443`). Ports `443` (HTTPS) and `80` (HTTP) are omitted from the access URI.                                                                                                                          |
| `EXTERNAL_WEB_HOSTNAME` | No       | Value of `HOSTNAME`                                 | Public host name used in the access URI, for example a custom domain when `WEBSITE_HOSTNAME` is the `azurewebsites.net` address. When this variable is set, each normal start (not initialization or update mode) rewrites the access URI stored in the database to match it.      |

#### TLS certificate configuration

| Variable               | Required | Default | Description                                                                                                                                |
| ---------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `TLS_CERTIFICATE_FILE` | No       | —       | Path of a mounted PEM certificate file (for example `/opt/devolutions/dvls/certs/server.pem`). Used when the file exists.                  |
| `TLS_PRIVATE_KEY_FILE` | No       | —       | Path of a mounted PEM private key file (for example `/opt/devolutions/dvls/certs/server.key`). Used when the file exists.                  |
| `TLS_CERTIFICATE_B64`  | No       | —       | Base64-encoded certificate content, written to `App_Data/server.pem`. Used when `TLS_CERTIFICATE_FILE` does not point to an existing file. |
| `TLS_PRIVATE_KEY_B64`  | No       | —       | Base64-encoded private key content, written to `App_Data/server.key`. Used when `TLS_PRIVATE_KEY_FILE` does not point to an existing file. |

{% hint style="info" %}
If `WEB_SCHEME=https` and neither a certificate nor a private key is provided, the container generates a self-signed certificate (valid 5 years, 2048-bit RSA). If only one of the two is provided, the container stops at startup. Use file mounts or base64 variables for production certificates.
{% endhint %}

#### Operating mode configuration

The container runs in one of three modes:

| Mode              | Condition                                           | Behavior                                                                                                                                                                               |
| ----------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Runtime (default) | `DVLS_INIT` and `DVLS_UPDATE_MODE` unset or `false` | Applies pending database schema upgrades (when `DVLS_DATABASE_UPGRADE_ON_STARTUP=true`), then starts Devolutions Server and keeps running.                                             |
| Initialization    | `DVLS_INIT=true`                                    | Prepares a new database and its first administrator, then starts Devolutions Server and keeps running.                                                                                 |
| Update            | `DVLS_UPDATE_MODE=true`                             | Backs up the configuration and installation files, takes a database snapshot for SQLite only, upgrades the database schema, restores the configuration and custom folders, then exits. |

{% hint style="info" %}
`DVLS_INIT` and `DVLS_UPDATE_MODE` are mutually exclusive. Setting both to `true` stops the container with an error.
{% endhint %}

| Variable                             | Required | Default                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ------------------------------------ | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DVLS_INIT`                          | No       | `false`                   | Set to `true` for the first start against a new database. The container creates the database if it does not exist (SQL Server and PostgreSQL), creates or upgrades the schema, writes the default settings, encryption keys and gateway key pair, creates the administrator, then starts Devolutions Server. After `Initialization completed successfully.` appears in the logs, stop the container and start it again without `DVLS_INIT`: a second initialization fails because the administrator already exists. |
| `DVLS_UPDATE_MODE`                   | No       | `false`                   | Set to `true` to run update mode, then exit. Update mode does not back up SQL Server or PostgreSQL databases: back them up before running it.                                                                                                                                                                                                                                                                                                                                                                       |
| `DVLS_BACKUP_PATH`                   | No       | `/tmp/dvls-backup`        | Folder where update mode copies the configuration files (`config`) and the installation folder (`installation`). The default folder is inside the container: mount a volume to keep the backup. When this variable is set, SQLite pre-update snapshots are also stored there (in `database`); otherwise they are stored in `App_Data/Backups/database`.                                                                                                                                                             |
| `DVLS_DATABASE_UPGRADE_ON_STARTUP`   | No       | `true` (set in the image) | Applies pending database schema upgrades during a normal start, before Devolutions Server accepts requests. If the upgrade fails, the container does not start. Accepts only `true` or `false`.                                                                                                                                                                                                                                                                                                                     |
| `DVLS_DATABASE_UPGRADE_LOCK_TIMEOUT` | No       | `300` (set in the image)  | Maximum number of seconds a starting container waits for the schema upgrade lock held by another container on the same database. When the wait expires, the container does not start. Integer between 1 and 2147483.                                                                                                                                                                                                                                                                                                |
| `DVLS_SKIP_ACCESS_URI_UPDATE`        | No       | `false`                   | Set to `true` to keep the access URI stored in the database unchanged when `EXTERNAL_WEB_HOSTNAME` is set.                                                                                                                                                                                                                                                                                                                                                                                                          |

#### Initialization mode variables

These variables are only used during initialization (`DVLS_INIT=true`):

| Variable              | Required | Default            | Description                                                                                                            |
| --------------------- | -------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `DVLS_ADMIN_USERNAME` | No       | `dvls-admin`       | User name of the administrator account created during initialization.                                                  |
| `DVLS_ADMIN_PASSWORD` | No       | `dvls-admin`       | Initial password of the administrator account. Set a different value: the administrator must change it at first logon. |
| `DVLS_ADMIN_EMAIL`    | No       | `admin@<HOSTNAME>` | Email address of the administrator account.                                                                            |

#### System configuration

| Variable                     | Required | Default                                    | Description                                                                                                                                                                                    |
| ---------------------------- | -------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DVLS_PATH`                  | No       | `/opt/devolutions/dvls`                    | Installation root path (location of `appsettings.json` and `App_Data`).                                                                                                                        |
| `DVLS_EXECUTABLE_PATH`       | No       | `/opt/devolutions/dvls/Devolutions.Server` | Devolutions Server executable started by the image entry point.                                                                                                                                |
| `DVLS_TELEMETRY`             | No       | `true`                                     | Enables or disables telemetry collection.                                                                                                                                                      |
| `DVLS_ENCRYPTION_CONFIG_B64` | No       | —                                          | Base64-encoded encryption configuration, written to `App_Data/encryption.config` at each start. Required to keep the same encryption keys across restarts, redeployments and scaled instances. |
| `DVLS_PG_DUMP_PATH`          | No       | `pg_dump` on the `PATH`                    | Full path of the `pg_dump` executable used by the built-in backup job with PostgreSQL. The image does not include it.                                                                          |
| `DVLS_PG_RESTORE_PATH`       | No       | `pg_restore` on the `PATH`                 | Full path of the `pg_restore` executable used to validate backups with PostgreSQL. The image does not include it.                                                                              |

#### SSH access configuration

| Variable       | Required                     | Default   | Description                                                                                                                      |
| -------------- | ---------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `SSH_ENABLED`  | No                           | `false`   | Enables the SSH daemon for debugging. Enabled automatically on Azure App Service unless set explicitly.                          |
| `SSH_PORT`     | No                           | `2222`    | SSH listening port (publish it with `-p 2222:2222`).                                                                             |
| `SSH_PASSWORD` | Yes, when `SSH_ENABLED=true` | `Docker!` | Root password for SSH. The default value applies only when SSH is enabled automatically on Azure. Must not contain a line break. |

{% hint style="info" %}
If `SSH_ENABLED=true` is set without `SSH_PASSWORD`, the container refuses to start.
{% endhint %}

#### Azure Web App variables

These variables are set automatically by Azure App Service:

| Variable              | Set by | Description                                                                                                                       |
| --------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `WEBSITE_HOSTNAME`    | Azure  | Overrides `HOSTNAME` (for example `dvls-prod.azurewebsites.net`).                                                                 |
| `WEBSITE_INSTANCE_ID` | Azure  | Enables SSH unless `SSH_ENABLED` is set. With `WEBSITE_HOSTNAME`, forces `EXTERNAL_WEB_SCHEME=https` and `EXTERNAL_WEB_PORT=443`. |

### TLS certificate configuration

#### Auto-generated self-signed certificate

When `WEB_SCHEME=https` is set without certificate variables, the container generates a self-signed certificate (valid 5 years, 2048-bit RSA, `CN` and subject alternative name set to `HOSTNAME`):

**Windows (PowerShell):**

```powershell
docker run -d --name dvls-server `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e HOSTNAME=localhost `
  -e WEB_SCHEME=https `
  -e PORT=5000 `
  -p 5000:5000 `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
docker run -d --name dvls-server \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e HOSTNAME=localhost \
  -e WEB_SCHEME=https \
  -e PORT=5000 \
  -p 5000:5000 \
  devolutions/devolutions-server:release-20XX.X
```

{% hint style="warning" %}
Use the self-signed certificate for development and testing only. Browsers show a security warning for it.
{% endhint %}

#### Certificate files via volume mount

Mount certificate files from the host:

**Windows (PowerShell):**

```powershell
New-Item -ItemType Directory -Force -Path C:\dvls\certs
Copy-Item C:\path\to\server.pem, C:\path\to\server.key -Destination C:\dvls\certs\

docker run -d --name dvls-server `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e HOSTNAME=devolutions-server.company.com `
  -e WEB_SCHEME=https `
  -e PORT=5000 `
  -e TLS_CERTIFICATE_FILE=/opt/devolutions/dvls/certs/server.pem `
  -e TLS_PRIVATE_KEY_FILE=/opt/devolutions/dvls/certs/server.key `
  -p 5000:5000 `
  -v C:\dvls\certs:/opt/devolutions/dvls/certs:ro `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
mkdir -p /host/certs
cp /path/to/server.pem /host/certs/
cp /path/to/server.key /host/certs/
chmod 600 /host/certs/server.key

docker run -d --name dvls-server \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e HOSTNAME=devolutions-server.company.com \
  -e WEB_SCHEME=https \
  -e PORT=5000 \
  -e TLS_CERTIFICATE_FILE=/opt/devolutions/dvls/certs/server.pem \
  -e TLS_PRIVATE_KEY_FILE=/opt/devolutions/dvls/certs/server.key \
  -p 5000:5000 \
  -v /host/certs:/opt/devolutions/dvls/certs:ro \
  devolutions/devolutions-server:release-20XX.X
```

Certificate format requirements:

* Certificate: PEM format (`.pem`, `.crt`).
* Private key: PEM format (`.key`, `.pem`).
* Chain: include the intermediate certificates in the certificate file.

Example certificate file with chain:

```
-----BEGIN CERTIFICATE-----
<Your certificate>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Intermediate CA certificate>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Root CA certificate>
-----END CERTIFICATE-----
```

#### Base64-encoded certificates

Use base64-encoded certificates when working with secrets management systems (Azure Key Vault, Kubernetes Secrets):

**Windows (PowerShell):**

```powershell
$certificate = [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\path\to\server.pem"))
$privateKey = [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\path\to\server.key"))

docker run -d --name dvls-server `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e HOSTNAME=devolutions-server.company.com `
  -e WEB_SCHEME=https `
  -e PORT=5000 `
  -e TLS_CERTIFICATE_B64="$certificate" `
  -e TLS_PRIVATE_KEY_B64="$privateKey" `
  -p 5000:5000 `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
base64 -w 0 server.pem > server.pem.b64
base64 -w 0 server.key > server.key.b64

docker run -d --name dvls-server \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e HOSTNAME=devolutions-server.company.com \
  -e WEB_SCHEME=https \
  -e PORT=5000 \
  -e TLS_CERTIFICATE_B64="$(cat server.pem.b64)" \
  -e TLS_PRIVATE_KEY_B64="$(cat server.key.b64)" \
  -p 5000:5000 \
  devolutions/devolutions-server:release-20XX.X
```

On macOS, use `base64 -i server.pem -o server.pem.b64` instead of `base64 -w 0`.

The certificate and private key are written to `/opt/devolutions/dvls/App_Data/` and referenced in the Devolutions Server configuration.

### Database configuration

#### Connection string format

At every start, the container builds the database connection string from the environment variables and writes it to `appsettings.json` (`ConnectionStrings` section). The connection string contains the following keys:

| Connection string key (SQL Server) | Connection string key (PostgreSQL) | Source variable                                 |
| ---------------------------------- | ---------------------------------- | ----------------------------------------------- |
| `Data Source`                      | `Host` and `Port`                  | `DATABASE_HOST`, `DATABASE_PORT`                |
| `Initial Catalog`                  | `Database`                         | `DATABASE_NAME`                                 |
| `User ID`                          | `Username`                         | `DATABASE_USERNAME`                             |
| `Password`                         | `Password`                         | `DATABASE_PASSWORD` or `DATABASE_PASSWORD_FILE` |
| `Encrypt`                          | `SSL Mode`                         | `DATABASE_ENCRYPT`                              |
| `TrustServerCertificate`           | `SSL Mode`                         | `DATABASE_TRUST_SERVER_CERTIFICATE`             |

Because the connection string is rebuilt at every start, pass the same database variables on every `docker run`: initialization, runtime and update.

#### SQL Server

Default port (`1433`), with `DATABASE_PORT` omitted:

```bash
-e DATABASE_HOST=sql.example.com
```

Non-standard port, either in the host name or in a separate variable:

```bash
-e DATABASE_HOST=sql.example.com,1435
```

```bash
-e DATABASE_HOST=sql.example.com \
-e DATABASE_PORT=1435
```

Azure SQL Database, with the Azure-specific aliases:

```bash
-e AZURE_SQL_HOST=dvls-sql-server.database.windows.net \
-e AZURE_SQL_DATABASE=dvls \
-e AZURE_SQL_USERNAME=dvls_user@dvls-sql-server \
-e AZURE_SQL_PASSWORD='YourPassword!'
```

With `DVLS_INIT=true`, a database that does not exist is created with the `Latin1_General_CS_AS` collation. The login then needs permission to create databases; otherwise, create the database beforehand.

#### PostgreSQL

Set `DATABASE_TYPE=PostgreSQL`. The default port becomes `5432`. Minimal example:

```bash
-e DATABASE_TYPE=PostgreSQL \
-e DATABASE_HOST=postgres.example.com \
-e DATABASE_NAME=dvls \
-e DATABASE_USERNAME=dvls_owner \
-e DATABASE_PASSWORD='YourPassword!' \
-e DATABASE_ENCRYPT=true
```

For a non-standard port, use `DATABASE_PORT=5433` or `DATABASE_HOST=postgres.example.com:5433`. With an IP address, set the port with `DATABASE_PORT`. The SQL Server `host,port` format does not work with PostgreSQL.

The PostgreSQL connection string contains the `Host`, `Port`, `Username`, `Password`, `Database` and `SSL Mode` keys. At run time, Devolutions Server also adds `Search Path=dbo,public` and `Keep Alive=30` when they are missing. In `psql`, Devolutions Server tables are lowercase in the `dbo` schema (for example `dbo.connections`).

`DATABASE_ENCRYPT` and `DATABASE_TRUST_SERVER_CERTIFICATE` set the `SSL Mode`:

| `DATABASE_ENCRYPT` | `DATABASE_TRUST_SERVER_CERTIFICATE` | Resulting `SSL Mode` | Result                                                                          |
| ------------------ | ----------------------------------- | -------------------- | ------------------------------------------------------------------------------- |
| `false` (default)  | Any value                           | `Disable`            | The connection is not encrypted.                                                |
| `true`             | `true`                              | `Require`            | The connection is encrypted; the server certificate is not validated.           |
| `true`             | `false` (default)                   | `VerifyFull`         | The connection is encrypted; the certificate chain and host name are validated. |

{% hint style="warning" %}
With the default values, the PostgreSQL connection is not encrypted. Set `DATABASE_ENCRYPT=true` when the database is reached over a network.
{% endhint %}

**Database account and creation**

* Use a dedicated role that owns the Devolutions Server database. Devolutions Server uses this single owner role for schema creation, schema upgrades and run time: the least-privilege runner roles available with SQL Server do not apply to PostgreSQL.
* The role must have the `SUPERUSER` attribute to create the database schema, because the schema creation modifies PostgreSQL type casts. The schema is created by `DVLS_INIT=true`, or at startup when the database is empty. Once the schema exists, the role does not require the attribute: remove it with `ALTER ROLE <role> NOSUPERUSER;`.
* With `DVLS_INIT=true`, a database that does not exist is created through the `postgres` maintenance database. The role then needs `CONNECT` on the `postgres` database.

**Backups**

* The built-in backup job runs `pg_dump --format=custom` and validates the result with `pg_restore --list`. The image does not include these tools: build a derived image that installs the PostgreSQL client package, or mount the binaries and set `DVLS_PG_DUMP_PATH` and `DVLS_PG_RESTORE_PATH`.
* The major version of `pg_dump` must be equal to or newer than the major version of the PostgreSQL server; otherwise, the backup fails.
* A database backup does not contain the encryption keys. Keep `encryption.config` (or the `DVLS_ENCRYPTION_CONFIG_B64` value) backed up separately.

#### SQLite

SQLite support is experimental. It runs one active Devolutions Server node against a database file on local storage, and is not suitable for high availability, several replicas, or network or distributed file systems (SMB, NFS).

```bash
-e DATABASE_TYPE=SQLite \
-e DATABASE_PATH=/opt/devolutions/dvls/App_Data/dvls.sqlite \
-v dvls-sqlite-data:/opt/devolutions/dvls/App_Data
```

`DATABASE_PATH` must be an absolute file path inside `App_Data`. Persist the whole `App_Data` folder on a volume: it contains the database file and the encryption configuration. A lock prevents a second container from using the same database file while the first one is running.

#### Encrypted database connection (TLS) <a href="#encrypted-database-connection-tls" id="encrypted-database-connection-tls"></a>

By default, Devolutions Server connects to the database without TLS. If SQL Server enforces encryption (for example an instance with ***Force Encryption*** enabled), the connection fails until encryption is enabled on the client side. If the PostgreSQL server requires SSL, the default `SSL Mode=Disable` connection is refused. With PostgreSQL, `DATABASE_ENCRYPT=true` selects `SSL Mode=VerifyFull`, or `SSL Mode=Require` when `DATABASE_TRUST_SERVER_CERTIFICATE=true` is also set.

{% hint style="warning" %}
These variables are read on every container start, not only during initialization. The connection string is regenerated from them on each start, so pass them on every `docker run`: initialization, runtime and update. Omitting them at runtime rewrites the connection string with encryption disabled.
{% endhint %}

| Scenario                                                | Required variables                                                   |
| ------------------------------------------------------- | -------------------------------------------------------------------- |
| SQL Server or PostgreSQL with a CA-trusted certificate  | `DATABASE_ENCRYPT=true`                                              |
| SQL Server or PostgreSQL with a self-signed certificate | `DATABASE_ENCRYPT=true` and `DATABASE_TRUST_SERVER_CERTIFICATE=true` |

**Windows (PowerShell):**

```powershell
$encryptionConfig = Get-Content "$env:TEMP\encryption.config.b64" -Raw

docker run -d --name dvls-server `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e DATABASE_ENCRYPT=true `
  -e DATABASE_TRUST_SERVER_CERTIFICATE=true `
  -e HOSTNAME=localhost `
  -e WEB_SCHEME=https `
  -e PORT=5000 `
  -e DVLS_ENCRYPTION_CONFIG_B64="$encryptionConfig" `
  -p 5000:5000 `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
docker run -d --name dvls-server \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e DATABASE_ENCRYPT=true \
  -e DATABASE_TRUST_SERVER_CERTIFICATE=true \
  -e HOSTNAME=localhost \
  -e WEB_SCHEME=https \
  -e PORT=5000 \
  -e DVLS_ENCRYPTION_CONFIG_B64="$(cat /tmp/encryption.config.b64)" \
  -p 5000:5000 \
  devolutions/devolutions-server:release-20XX.X
```

{% hint style="warning" %}
Setting `DATABASE_TRUST_SERVER_CERTIFICATE=true` disables certificate validation. Use it only with self-signed certificates in trusted networks. For production, install a CA-trusted certificate on the database server and set only `DATABASE_ENCRYPT=true`.
{% endhint %}

#### Database authentication

Docker containers support username and password authentication only: SQL Server authentication, or a PostgreSQL role with a password. Windows authentication (integrated security) and Microsoft Entra authentication are not supported. SQLite uses no database authentication; protect access to its volume instead.

### Reverse proxy configuration

When Devolutions Server runs behind a reverse proxy, an nginx ingress or Azure App Service, configure the external URL settings:

**Windows (PowerShell):**

```powershell
docker run -d --name dvls-server `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e HOSTNAME=devolutions-server.company.com `
  -e WEB_SCHEME=http `
  -e PORT=5000 `
  -e EXTERNAL_WEB_SCHEME=https `
  -e EXTERNAL_WEB_PORT=443 `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
docker run -d --name dvls-server \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e HOSTNAME=devolutions-server.company.com \
  -e WEB_SCHEME=http \
  -e PORT=5000 \
  -e EXTERNAL_WEB_SCHEME=https \
  -e EXTERNAL_WEB_PORT=443 \
  devolutions/devolutions-server:release-20XX.X
```

Key settings:

* `WEB_SCHEME=http`: the container uses HTTP.
* `EXTERNAL_WEB_SCHEME=https`: the public URL uses HTTPS.
* `EXTERNAL_WEB_PORT=443`: standard HTTPS port, omitted from the URL.
* `HOSTNAME=devolutions-server.company.com`: public host name.

With these values, the access URI is `https://devolutions-server.company.com/`. The access URI is stored in the database during initialization. To change it on an existing deployment, set `EXTERNAL_WEB_HOSTNAME`: each normal start then rewrites the stored access URI from `EXTERNAL_WEB_SCHEME`, `EXTERNAL_WEB_HOSTNAME` and `EXTERNAL_WEB_PORT`. Set `DVLS_SKIP_ACCESS_URI_UPDATE=true` to prevent this rewrite.

### Security hardening

#### Secrets management

{% hint style="danger" %}
Do not write passwords in `docker run` commands or compose files that are stored or shared. Use Docker secrets, environment files kept out of version control, or a secret store.
{% endhint %}

**Docker secrets (Swarm mode)**

`DATABASE_PASSWORD_FILE` reads the password from the secret file. It is used only when `DATABASE_PASSWORD` is not set.

**Windows (PowerShell):**

```powershell
"YourPassword!" | docker secret create dvls_db_password -

docker service create `
  --name dvls-server `
  --secret dvls_db_password `
  -e DATABASE_PASSWORD_FILE=/run/secrets/dvls_db_password `
  ...
```

**macOS/Linux (Bash):**

```bash
echo 'YourPassword!' | docker secret create dvls_db_password -

docker service create \
  --name dvls-server \
  --secret dvls_db_password \
  -e DATABASE_PASSWORD_FILE=/run/secrets/dvls_db_password \
  ...
```

**Environment files**

Create a `.env` file and keep it out of version control:

```bash
DATABASE_PASSWORD=YourPassword!
DVLS_ADMIN_PASSWORD=AdminPassword!
```

Pass it to the container:

**Windows (PowerShell):**

```powershell
docker run -d --name dvls-server `
  --env-file .env `
  -e DATABASE_HOST=your-sql-server `
  ...
```

**macOS/Linux (Bash):**

```bash
docker run -d --name dvls-server \
  --env-file .env \
  -e DATABASE_HOST=your-sql-server \
  ...
```

**Azure Key Vault**

Use ***Managed Identity*** to retrieve secrets from Key Vault at runtime. See [Devolutions Server deployment to Azure App Service using a container](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/devolutions-server-deployment-to-azure-app-service-using-a-container.md) for more details.

#### Network isolation

Use Docker networks to isolate Devolutions Server:

**Windows (PowerShell):**

```powershell
docker network create dvls-network

docker run -d --name dvls-server `
  --network dvls-network `
  -p 127.0.0.1:5000:5000 `
  -e DATABASE_HOST=sql-server `
  ...
```

**macOS/Linux (Bash):**

```bash
docker network create dvls-network

docker run -d --name dvls-server \
  --network dvls-network \
  -p 127.0.0.1:5000:5000 \
  -e DATABASE_HOST=sql-server \
  ...
```

#### SSH access

Disable SSH in production unless it is required for debugging:

```bash
-e SSH_ENABLED=false
```

If SSH is enabled:

* Use a long, unique password.
* Change the default password.
* Restrict access with firewall rules.
* Consider SSH key authentication (requires a custom image).

#### Version updates

**Version tagging**

* The image `devolutions/devolutions-server` is tagged by release (for example `release-20XX.X`) and by build (for example `20XX.X.X.0`). Tags ending in `-beta` are beta builds.
* A release tag always points to the latest build of that release: pulling it again brings the newer builds of the same release. A build tag pins an exact build.
* There is no `latest` tag: always specify a tag.
* At every normal start, the container applies the pending database schema upgrades before it accepts requests (`DVLS_DATABASE_UPGRADE_ON_STARTUP=true` in the image). Update mode is not required to change versions.

**Update to a new version**

1. Back up the database: `BACKUP DATABASE` for SQL Server, `pg_dump --format=custom` for PostgreSQL. For SQLite, run update mode with the new tag first: it takes an integrity-checked snapshot of the database file.
2. Pull the new image tag:

   ```bash
   docker pull devolutions/devolutions-server:release-20XX.X
   ```
3. Stop and remove the current container:

   ```bash
   docker stop dvls-server
   docker rm dvls-server
   ```
4. Start a container from the new tag with the same environment variables:

   ```bash
   docker run -d --name dvls-server \
     -e DATABASE_HOST=your-sql-server \
     -e DATABASE_NAME=dvls \
     -e DATABASE_USERNAME=dvls_user \
     -e DATABASE_PASSWORD='YourPassword!' \
     -e HOSTNAME=localhost \
     -e WEB_SCHEME=https \
     -e PORT=5000 \
     -e DVLS_ENCRYPTION_CONFIG_B64="$(cat /tmp/encryption.config.b64)" \
     -p 5000:5000 \
     devolutions/devolutions-server:release-20XX.X
   ```

   ```powershell
   $encryptionConfig = Get-Content "$env:TEMP\encryption.config.b64" -Raw
   docker run -d --name dvls-server `
     -e DATABASE_HOST=your-sql-server `
     -e DATABASE_NAME=dvls `
     -e DATABASE_USERNAME=dvls_user `
     -e DATABASE_PASSWORD='YourPassword!' `
     -e HOSTNAME=localhost `
     -e WEB_SCHEME=https `
     -e PORT=5000 `
     -e DVLS_ENCRYPTION_CONFIG_B64="$encryptionConfig" `
     -p 5000:5000 `
     devolutions/devolutions-server:release-20XX.X
   ```
5. Check the startup logs with `docker logs dvls-server`. If the schema upgrade fails, the container stops before it accepts requests.

When several containers share the same database, one container applies the schema upgrade while the others wait for it, up to `DVLS_DATABASE_UPGRADE_LOCK_TIMEOUT` seconds. To control when the schema changes, start one container with the new tag first, then the other replicas.

**Update mode (optional)**

Update mode (`DVLS_UPDATE_MODE=true`) upgrades the database schema and exits, without starting Devolutions Server. It copies the configuration files (`appsettings.json`, `web.config`, `encryption.config`) and the installation folder to `DVLS_BACKUP_PATH`, and takes a database snapshot for SQLite only. For SQL Server and PostgreSQL, back up the database before running it. Mount a volume on `DVLS_BACKUP_PATH` to keep the backup after the container exits.

**Windows (PowerShell):**

```powershell
$encryptionConfig = Get-Content "$env:TEMP\encryption.config.b64" -Raw

docker run --rm `
  -e DATABASE_HOST=your-sql-server `
  -e DATABASE_NAME=dvls `
  -e DATABASE_USERNAME=dvls_user `
  -e DATABASE_PASSWORD='YourPassword!' `
  -e DVLS_UPDATE_MODE=true `
  -e DVLS_BACKUP_PATH=/backup `
  -e DVLS_ENCRYPTION_CONFIG_B64="$encryptionConfig" `
  -v dvls-backups:/backup `
  devolutions/devolutions-server:release-20XX.X
```

**macOS/Linux (Bash):**

```bash
docker run --rm \
  -e DATABASE_HOST=your-sql-server \
  -e DATABASE_NAME=dvls \
  -e DATABASE_USERNAME=dvls_user \
  -e DATABASE_PASSWORD='YourPassword!' \
  -e DVLS_UPDATE_MODE=true \
  -e DVLS_BACKUP_PATH=/backup \
  -e DVLS_ENCRYPTION_CONFIG_B64="$(cat /tmp/encryption.config.b64)" \
  -v dvls-backups:/backup \
  devolutions/devolutions-server:release-20XX.X
```

After update mode exits, start the runtime container from the same tag.

### Security checklist

Consult [Devolutions Server security hardening](/server/getting-started/security-checklist/devolutions-server-security-hardening.md) for:

* Administration accounts settings
* Password policies
* Multifactor authentication
* IP restrictions
* Audit logging
* Encryption settings

#### See also

* [Deploy Devolutions Server with Docker](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment.md)
* [Devolutions Server deployment to Azure App Service using a container](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/devolutions-server-deployment-to-azure-app-service-using-a-container.md)
* [PostgreSQL](/server/getting-started/installation/database-setup/database-instance/postgresql.md)
* [Install Devolutions Server for Linux](/server/knowledge-base/how-to-articles/install-devolutions-server-for-linux.md)
* [System requirements](/server/overview-of-devolutions-server/system-requirements.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.devolutions.net/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/advanced-docker-configuration-for-devolutions-server.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
