> 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.md).

# Deploy Devolutions Server with Docker

Deploy Devolutions Server with Docker on SQL Server or PostgreSQL: first-time initialization, encryption configuration, custom ports and TLS certificates.

This article shows how to deploy Devolutions Server using Docker with a SQL Server or PostgreSQL database. The Devolutions Server Docker image is a Linux image available for the `linux/amd64` and `linux/arm64` platforms.

{% hint style="info" %}
For the sake of simplicity, Devolutions Server's Docker image version is written `20XX.X` in the code blocks of this article. Change this variable to the version you wish to use.
{% endhint %}

### Prerequisites

* Docker version `20.10.X` or later.
* A database instance:
  * A SQL Server instance, including Azure SQL Database, properly [set up for Devolutions Server](/server/getting-started/installation/database-setup.md).
  * Or a [PostgreSQL](/server/getting-started/installation/database-setup/database-instance/postgresql.md) 14 or later instance, self-hosted or managed, with a role that has the `SUPERUSER` attribute.
* The minimum [system requirements](/server/overview-of-devolutions-server/system-requirements.md) to run Devolutions Server.

### Prepare the database

The container connects to the database with a single account, used for the initialization, the schema upgrades and normal operation. Create a dedicated account for Devolutions Server instead of using an administrator account such as `sa` or `postgres`.

#### SQL Server

Using an administrator account (for example, `sa` or an Azure SQL administrator), create a dedicated login and the Devolutions Server database, then add the login to the `db_owner` role of that database.

If the database does not exist, the initialization creates it with the `Latin1_General_CS_AS` collation, which requires the login to have the permission to create databases.

#### PostgreSQL

Using an administrator account, create a dedicated login role for Devolutions Server. Initialization connects to the `postgres` maintenance database to check whether the Devolutions Server database exists, so the role needs the `CONNECT` privilege on `postgres` (PostgreSQL grants it to all roles by default).

{% hint style="warning" %}
The role must have the `SUPERUSER` attribute to create the database schema during the initialization. The schema creation modifies PostgreSQL type casts, which only a superuser can do.
{% endhint %}

```sql
CREATE ROLE dvls_user WITH LOGIN SUPERUSER PASSWORD 'YourSecurePassword!';
```

After the initialization, the schema upgrades and the normal operation of Devolutions Server do not require the `SUPERUSER` attribute. To limit the privileges of the role, remove the attribute. The role remains the owner of the database:

```sql
ALTER ROLE dvls_user NOSUPERUSER;
```

### Database connection variables

The examples in this article connect to SQL Server. To connect to PostgreSQL, add `-e DATABASE_TYPE=PostgreSQL` and `-e DATABASE_ENCRYPT=true` to the initialization and runtime commands, and set `DATABASE_HOST` to the name of the PostgreSQL server. The other variables are the same for both database engines.

| Variable                            | SQL Server                                                                    | PostgreSQL                                                                                                             |
| ----------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `DATABASE_TYPE`                     | `SqlServer` (default).                                                        | `PostgreSQL`.                                                                                                          |
| `DATABASE_HOST`                     | Server name. A port can be added in the `host,port` format.                   | Server name. A port can be added in the `host:port` format, which takes precedence over `DATABASE_PORT`.               |
| `DATABASE_PORT`                     | `1433` (default).                                                             | `5432` (default).                                                                                                      |
| `DATABASE_ENCRYPT`                  | `true` encrypts the connection. Default: `false`.                             | `true` encrypts the connection and validates the server certificate. Default: `false` (not encrypted).                 |
| `DATABASE_TRUST_SERVER_CERTIFICATE` | `true` trusts the server certificate without validating it. Default: `false`. | With `DATABASE_ENCRYPT=true`, `true` keeps the encryption without validating the server certificate. Default: `false`. |

{% hint style="warning" %}
With PostgreSQL, the default `DATABASE_ENCRYPT=false` value disables SSL: the connection to the database is not encrypted. With `DATABASE_ENCRYPT=true`, the certificate of the PostgreSQL server must be issued by a certificate authority trusted in the container and match the `DATABASE_HOST` name. Otherwise, also set `DATABASE_TRUST_SERVER_CERTIFICATE=true`.
{% endhint %}

The complete list of variables is in [Advanced Docker configuration for Devolutions Server](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/advanced-docker-configuration-for-devolutions-server.md).

### Devolutions Server first time setup

{% tabs %}
{% tab title="Windows" %}

1. Pull the latest [Devolutions Server Docker image](https://hub.docker.com/r/devolutions/devolutions-server):

   ```powershell
   docker pull devolutions/devolutions-server:release-20XX.X
   ```
2. Run Devolutions Server in initialization mode to create the database if it does not exist, create its schema and its first administrator, generate the encryption keys, and configure HTTPS with a self-signed certificate. The `dvls-init-data` volume keeps `App_Data` so that the encryption configuration can be extracted afterward. With PostgreSQL, add `-e DATABASE_TYPE=PostgreSQL` and `-e DATABASE_ENCRYPT=true`, and set `DATABASE_HOST` to the PostgreSQL server name.

   ```powershell
   docker volume create dvls-init-data

   docker run --rm `
     -e DATABASE_HOST=your-sql-server.database.windows.net `
     -e DATABASE_NAME=dvls `
     -e DATABASE_USERNAME=dvls_user `
     -e DATABASE_PASSWORD='YourSecurePassword!' `
     -e HOSTNAME=localhost `
     -e WEB_SCHEME=https `
     -e PORT=5000 `
     -e DVLS_INIT=true `
     -v dvls-init-data:/opt/devolutions/dvls/App_Data `
     -p 5000:5000 `
     devolutions/devolutions-server:release-20XX.X
   ```
3. Wait for the `Initialization completed successfully.` message, then press <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop the container. After the initialization, the container keeps running Devolutions Server until it is stopped. The `--rm` option removes the container and keeps the `dvls-init-data` volume.
4. Extract `encryption.config` from the initialization volume and convert it to base64. Store the `encryption.config.b64` file securely: every runtime start needs it.

   ```powershell
   docker run --rm `
     -v dvls-init-data:/data `
     alpine `
     cat /data/encryption.config > $env:TEMP\encryption.config

   $content = Get-Content -Path "$env:TEMP\encryption.config" -Raw
   $bytes = [System.Text.Encoding]::UTF8.GetBytes($content)
   $base64 = [System.Convert]::ToBase64String($bytes)
   $base64 | Out-File -FilePath "$env:TEMP\encryption.config.b64" -NoNewline -Encoding ASCII
   ```
5. Start Devolutions Server in runtime mode with the base64 encryption configuration. With PostgreSQL, add the same `DATABASE_TYPE` and `DATABASE_ENCRYPT` variables as in the initialization command. Once this is done, use the `docker ps` and `docker logs dvls-server` commands to make sure everything is in working order.

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

   docker run -d --name dvls-server `
     -e DATABASE_HOST=your-sql-server.database.windows.net `
     -e DATABASE_NAME=dvls `
     -e DATABASE_USERNAME=dvls_user `
     -e DATABASE_PASSWORD='YourSecurePassword!' `
     -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
   ```
6. Access the web interface by opening `https://localhost:5000` in your browser. Go past the self-signed certificate security warning by clicking ***Advanced*** – ***Proceed***. A custom TLS certificate can be mounted later.
7. Log in by using `dvls-admin` for both the username and password. Devolutions Server then requires a new password for this account.
8. Make sure that Devolutions Server is running with `DVLS_ENCRYPTION_CONFIG_B64`, its web interface is accessible, and `encryption.config.b64` is saved in a secure location (it is needed for every restart and redeployment). Once this is done, remove the temporary initialization volume:

   ```powershell
   docker volume rm dvls-init-data
   ```

{% endtab %}

{% tab title="macOS" %}

1. Pull the latest [Devolutions Server Docker image](https://hub.docker.com/r/devolutions/devolutions-server):

   ```bash
   docker pull devolutions/devolutions-server:release-20XX.X
   ```
2. Run Devolutions Server in initialization mode to create the database if it does not exist, create its schema and its first administrator, generate the encryption keys, and configure HTTPS with a self-signed certificate. The `dvls-init-data` volume keeps `App_Data` so that the encryption configuration can be extracted afterward. With PostgreSQL, add `-e DATABASE_TYPE=PostgreSQL` and `-e DATABASE_ENCRYPT=true`, and set `DATABASE_HOST` to the PostgreSQL server name.

   ```bash
   docker volume create dvls-init-data

   docker run --rm \
     -e DATABASE_HOST=your-sql-server.database.windows.net \
     -e DATABASE_NAME=dvls \
     -e DATABASE_USERNAME=dvls_user \
     -e DATABASE_PASSWORD='YourSecurePassword!' \
     -e HOSTNAME=localhost \
     -e WEB_SCHEME=https \
     -e PORT=5000 \
     -e DVLS_INIT=true \
     -v dvls-init-data:/opt/devolutions/dvls/App_Data \
     -p 5000:5000 \
     devolutions/devolutions-server:release-20XX.X
   ```
3. Wait for the `Initialization completed successfully.` message, then press <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop the container. After the initialization, the container keeps running Devolutions Server until it is stopped. The `--rm` option removes the container and keeps the `dvls-init-data` volume.
4. Extract `encryption.config` from the initialization volume and convert it to base64. Store the `encryption.config.b64` file securely: every runtime start needs it.

   ```bash
   docker run --rm \
     -v dvls-init-data:/data \
     alpine \
     cat /data/encryption.config > /tmp/encryption.config

   base64 -i /tmp/encryption.config -o /tmp/encryption.config.b64
   ```
5. Start Devolutions Server in runtime mode with the base64 encryption configuration. With PostgreSQL, add the same `DATABASE_TYPE` and `DATABASE_ENCRYPT` variables as in the initialization command. Once this is done, use the `docker ps` and `docker logs dvls-server` commands to make sure everything is in working order.

   ```bash
   docker run -d --name dvls-server \
     -e DATABASE_HOST=your-sql-server.database.windows.net \
     -e DATABASE_NAME=dvls \
     -e DATABASE_USERNAME=dvls_user \
     -e DATABASE_PASSWORD='YourSecurePassword!' \
     -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
   ```
6. Access the web interface by opening `https://localhost:5000` in your browser. Go past the self-signed certificate security warning by clicking ***Advanced*** – ***Proceed***. A custom TLS certificate can be mounted later.
7. Log in by using `dvls-admin` for both the username and password. Devolutions Server then requires a new password for this account.
8. Make sure that Devolutions Server is running with `DVLS_ENCRYPTION_CONFIG_B64`, its web interface is accessible, and `encryption.config.b64` is saved in a secure location (it is needed for every restart and redeployment). Once this is done, remove the temporary initialization volume:

   ```bash
   docker volume rm dvls-init-data
   ```

{% endtab %}

{% tab title="Linux" %}

1. Pull the latest [Devolutions Server Docker image](https://hub.docker.com/r/devolutions/devolutions-server):

   ```bash
   docker pull devolutions/devolutions-server:release-20XX.X
   ```
2. Run Devolutions Server in initialization mode to create the database if it does not exist, create its schema and its first administrator, generate the encryption keys, and configure HTTPS with a self-signed certificate. The `dvls-init-data` volume keeps `App_Data` so that the encryption configuration can be extracted afterward. With PostgreSQL, add `-e DATABASE_TYPE=PostgreSQL` and `-e DATABASE_ENCRYPT=true`, and set `DATABASE_HOST` to the PostgreSQL server name.

   ```bash
   docker volume create dvls-init-data

   docker run --rm \
     -e DATABASE_HOST=your-sql-server.database.windows.net \
     -e DATABASE_NAME=dvls \
     -e DATABASE_USERNAME=dvls_user \
     -e DATABASE_PASSWORD='YourSecurePassword!' \
     -e HOSTNAME=localhost \
     -e WEB_SCHEME=https \
     -e PORT=5000 \
     -e DVLS_INIT=true \
     -v dvls-init-data:/opt/devolutions/dvls/App_Data \
     -p 5000:5000 \
     devolutions/devolutions-server:release-20XX.X
   ```
3. Wait for the `Initialization completed successfully.` message, then press <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop the container. After the initialization, the container keeps running Devolutions Server until it is stopped. The `--rm` option removes the container and keeps the `dvls-init-data` volume.
4. Extract `encryption.config` from the initialization volume and convert it to base64. Store the `encryption.config.b64` file securely: every runtime start needs it.

   ```bash
   docker run --rm \
     -v dvls-init-data:/data \
     alpine \
     cat /data/encryption.config > /tmp/encryption.config

   base64 -w 0 /tmp/encryption.config > /tmp/encryption.config.b64
   ```
5. Start Devolutions Server in runtime mode with the base64 encryption configuration. With PostgreSQL, add the same `DATABASE_TYPE` and `DATABASE_ENCRYPT` variables as in the initialization command. Once this is done, use the `docker ps` and `docker logs dvls-server` commands to make sure everything is in working order.

   ```bash
   docker run -d --name dvls-server \
     -e DATABASE_HOST=your-sql-server.database.windows.net \
     -e DATABASE_NAME=dvls \
     -e DATABASE_USERNAME=dvls_user \
     -e DATABASE_PASSWORD='YourSecurePassword!' \
     -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
   ```
6. Access the web interface by opening `https://localhost:5000` in your browser. Go past the self-signed certificate security warning by clicking ***Advanced*** – ***Proceed***. A custom TLS certificate can be mounted later.
7. Log in by using `dvls-admin` for both the username and password. Devolutions Server then requires a new password for this account.
8. Make sure that Devolutions Server is running with `DVLS_ENCRYPTION_CONFIG_B64`, its web interface is accessible, and `encryption.config.b64` is saved in a secure location (it is needed for every restart and redeployment). Once this is done, remove the temporary initialization volume:

   ```bash
   docker volume rm dvls-init-data
   ```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Run the initialization only once per database. Running it again against an initialized database fails, because the administrator account already exists.
{% endhint %}

### Operating modes

The Devolutions Server container operates in three distinct modes:

| Mode                      | Environment Variable    | Purpose          | Behavior                                                                                                                                                |
| ------------------------- | ----------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Runtime** **(default)** | No special variables    | Normal operation | Applies pending database schema upgrades, then starts the web server and keeps running.                                                                 |
| **Initialization**        | `DVLS_INIT=true`        | First-time setup | Creates the database if it does not exist, its schema, the encryption keys and the administrator account, then starts the web server and keeps running. |
| **Update**                | `DVLS_UPDATE_MODE=true` | Database upgrade | Backs up the configuration files and the installation folder, migrates the database, then exits.                                                        |

{% hint style="info" %}
**Initialization** and **Update** modes are mutually exclusive.

To start the runtime mode without applying the pending schema upgrades, set `DVLS_DATABASE_UPGRADE_ON_STARTUP=false`.
{% endhint %}

{% hint style="warning" %}
The update mode does not back up SQL Server or PostgreSQL databases. Back up the database before running it, for example with `BACKUP DATABASE` on SQL Server or `pg_dump` on PostgreSQL.
{% endhint %}

{% hint style="warning" %}
The Devolutions Server image does not include the PostgreSQL client tools `pg_dump` and `pg_restore`, which the built-in backup job uses with PostgreSQL. To use this job, build a derived image that installs the `postgresql-client` package, with a major version equal to or newer than the PostgreSQL server's, or mount the tools in the container and set their full paths in the `DVLS_PG_DUMP_PATH` and `DVLS_PG_RESTORE_PATH` variables.
{% endhint %}

### Custom port

Devolutions Server listens on port `5000` by default. To change it, set the `PORT` environment variable and publish the same port in the `docker run` command. For example, to use the `8080` port, replace `-e PORT=5000` and `-p 5000:5000` with `-e PORT=8080` and `-p 8080:8080`, then open `https://localhost:8080`.

`PORT` takes precedence over `WEB_PORT`. The `ASPNETCORE_URLS` variable has no effect: the container sets the listening address from `WEB_SCHEME` and `PORT`.

### Mount a custom TLS certificate

Mount your own certificate files instead of using the auto-generated self-signed certificate:

1. Copy the certificate and its private key, in PEM format, to a folder of the Docker host, for example `/host/path/certs`.
2. Add these options to the runtime command, with `WEB_SCHEME=https` and `HOSTNAME` set to the name in the certificate (for example, `devolutions-server.company.com`):

   ```bash
   -e TLS_CERTIFICATE_FILE=/opt/devolutions/dvls/certs/server.pem
   -e TLS_PRIVATE_KEY_FILE=/opt/devolutions/dvls/certs/server.key
   -v /host/path/certs:/opt/devolutions/dvls/certs:ro
   ```

{% hint style="info" %}
If neither file is found at these paths, Devolutions Server generates a self-signed certificate instead. If only one of the two files is found, the container stops with an error.
{% endhint %}

### Container management

| Commands                   | Functions              |
| -------------------------- | ---------------------- |
| `docker start dvls-server` | Starts the container.  |
| `docker stop dvls-server`  | Stops the container.   |
| `docker rm dvls-server`    | Removes the container. |

{% hint style="info" %}
Removing the container is safe as long as you have the `encryption.config.b64` file, access to your database, and your environment variables documented.
{% endhint %}

#### See also

* [Security checklist](/server/getting-started/security-checklist.md)
* [PostgreSQL](/server/getting-started/installation/database-setup/database-instance/postgresql.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)
* [Advanced Docker configuration for Devolutions Server](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/advanced-docker-configuration-for-devolutions-server.md)
* [Deploy Devolutions Server and SQL Server with Docker Compose on Windows](/server/knowledge-base/how-to-articles/devolutions-server-docker-deployment/deploy-devolutions-server-and-sql-server-with-docker-compose-on-windows.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.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.
