# Install Devolutions Server for Linux

Devolutions Server is available for Linux with Microsoft Kestrel as the built-in web server and Microsoft PowerShell 7 for command-line installation. The present topic shows how to manually install Devolutions Server for Linux using Bash prompts and PowerShell scripts, as well as how to access and remove it.

Alternatively, Devolutions Server can be installed automatically using the scripts found on the [Devolutions GitHub ScriptLibrary repository](https://github.com/Devolutions/ScriptLibrary/tree/main/DVLSForLinux).

### Installing prerequisites <a href="#installing-prerequisites" id="installing-prerequisites"></a>

1. If Microsoft SQL Server is not already installed, run the following Bash prompt with the `MSSQL_SA_PASSWORD` variable changed to a strong password:

   ```bash
   source /etc/os-release
   curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor --batch --yes -o /usr/share/keyrings/microsoft-prod.gpg
   curl -fsSL https://packages.microsoft.com/config/ubuntu/$VERSION_ID/mssql-server-2022.list | sudo tee /etc/apt/sources.list.d/mssql-server-2022.list
   sudo apt-get update
   sudo apt-get install -y mssql-server
   sudo MSSQL_SA_PASSWORD="mystrongpassword" MSSQL_PID="evaluation" /opt/mssql/bin/mssql-conf -n setup accept-eula
   sudo /opt/mssql/bin/mssql-conf set sqlagent.enabled true
   sudo systemctl restart mssql-server
   ```

   `MSSQL_PID` is set to ***evaluation*** in this example, but a product key can be entered here instead.

{% hint style="warning" %}
Microsoft only supports [certain SQL versions](https://docs.devolutions.net/server/overview/system-requirements/#software-dependencies). Refer to Microsoft's documentation to make sure your version of SQL is officially supported for your distribution.
{% endhint %}

2. Run this Bash prompt to install PowerShell 7:

   ```bash
   sudo apt-get update
   sudo apt-get install -y wget apt-transport-https software-properties-common
   source /etc/os-release
   wget -q https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb
   sudo dpkg -i packages-microsoft-prod.deb
   rm packages-microsoft-prod.deb
   sudo apt-get update
   sudo apt-get install -y powershell
   ```

Ensure that the installation takes place in a directory that is accessible for the current user as the command line `wget` downloads a `.deb` package to said directory.

3. Choose whether to install the [Devolutions.PowerShell module](https://www.powershellgallery.com/packages/Devolutions.PowerShell/) for the current user or all users.

   * **For current user** (location: `/.local/share/powershell/Modules`), run:

     ```powershell
     Install-Module -Name 'Devolutions.PowerShell' -Confirm:$False
     ```
   * **For all users** (location: `/opt/microsoft/powershell/7/Modules`), run:

     ```powershell
     & sudo pwsh -Command { Install-Module -Name 'Devolutions.PowerShell' -Confirm:$False -Scope 'AllUsers' -Force }
     ```

   A warning is likely to appear stating that the installation comes from an untrusted repository. The module is hosted on PowerShell Gallery, the official location for hosting PowerShell modules managed by Microsoft. To avoid seeing this warning in the future, run:

   ```powershell
   Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
   ```

   Although not required, provisioning separate users and groups for Devolutions Server is highly recommended. Here is a Bash prompt to create a user and a group both named ***dvls*** with the installation directory set to `/opt/devolutions/dvls`:

   ```bash
   sudo useradd -N dvls
   sudo groupadd dvls
   sudo usermod -a -G dvls dvls
   # optional, add current user to dvls group
   sudo usermod -a -G dvls $(id -un)
   sudo mkdir -p /opt/devolutions/dvls
   sudo chown -R dvls:dvls /opt/devolutions/dvls
   sudo chmod 550 /opt/devolutions/dvls
   ```

### Downloading and installing Devolutions Server for Linux <a href="#downloading-and-installing-dvls-for-linux" id="downloading-and-installing-dvls-for-linux"></a>

1. Run the PowerShell script below to download the latest version of Devolutions Server for Linux and extract the `.tar.gz` file into the `/opt/devolutions/dvls` location:

   ```powershell
   $DVLSPath = "/opt/devolutions/dvls"
   $DVLSProductURL = "https://devolutions.net/productinfo.htm"

   $Result = (Invoke-RestMethod -Method 'GET' -Uri $DVLSProductURL) -Split "`r"

   $DVLSLinux = [PSCustomObject]@{
       "Version" = (($Result | Select-String DPSLinuxX64bin.Version) -Split "=")[-1].Trim()
       "URL"     = (($Result | Select-String DPSLinuxX64bin.Url) -Split "=")[-1].Trim()
       "Hash"    = (($Result | Select-String DPSLinuxX64bin.hash) -Split "=")[-1].Trim()
   }

   $DVLSDownloadPath = Join-Path -Path "/tmp" -ChildPath (([URI]$DVLSLinux.URL).Segments)[-1]

   Invoke-RestMethod -Method 'GET' -Uri $DVLSLinux.URL -OutFile $DVLSDownloadPath

   & tar -xzf $DVLSDownloadPath -C $DVLSPath --strip-components=1

   Remove-Item -Path $DVLSDownloadPath

   & sudo pwsh -Command {
     Param(
         $DVLSPath
     )

     chown -R dvls:dvls $DVLSPath
     chmod -R o-rwx $DVLSPath
     chmod 660 (Join-Path -Path $DVLSPath -ChildPath 'appsettings.json')
     chmod 770 (Join-Path -Path $DVLSPath -ChildPath 'App_Data')
     chown -R dvls:dvls $DVLSPath
   } -Args $DVLSPath

   Set-Location -Path $DVLSPath
   ```

   It is best for Devolutions Server to be able to respond over TLS. If a certificate does not exist already, one can be quickly generated using this Bash prompt:

   ```bash
   cd /opt/devolutions/dvls

   openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout cert.key -out cert.crt -subj "/CN=MYHOST" -addext "subjectAltName=DNS:MYHOST"
   openssl pkcs12 -export -out cert.pfx -inkey cert.key -in cert.crt -passout pass:
   ```

   In the example above, the `subjectAltName` uses `DNS:.` To respond on an IP only, use `IP:` instead.

Note that the generated `.pfx` certificate does not have a password.

2. Using the Devolutions.PowerShell module, run installation for Devolutions Server via PowerShell. Make sure to customize the values listed here:

   * `MYHOST`
   * `MSSQLHOST`
   * `DBUSERNAME`
   * `YOURSTRONGPASSWORD`
   * `MYEMAIL`

   ```powershell
   Import-Module -Name 'Devolutions.PowerShell'

   $DVLSPath = "/opt/devolutions/dvls"
   # Modify the $DVLSURI to use 'https' if using SSL
   $DVLSURI  = "http://MYHOST:5000/"

   $DVLSAdminUsername = 'dvls-admin'
   $DVLSAdminPassword = 'dvls-admin'
   $DVLSAdminEmail    = 'MYEMAIL'

   $Params = @{
       "DatabaseHost"           = "MSSQLHOST"
       "DatabaseName"           = "DSERVER"
       "DatabaseUserName"       = "DBUSERNAME"
       "DatabasePassword"       = "YOURSTRONGPASSWORD"
       "ServerName"             = "DSERVER"
       "AccessUri"              = $DVLSURI
       "HttpListenerUri"        = $DVLSURI
       "DPSPath"                = $DVLSPath
       "UseEncryptedconnection" = $False # Modify as needed
       "TrustServerCertificate" = $False # Modify as needed
       "EnableTelemetry"        = $True # Modify as needed
       "DisableEncryptConfig"   = $True
   }

   $Configuration = New-DPSInstallConfiguration @Params
   New-DPSAppsettings -Configuration $Configuration

   $Settings = Get-DPSAppSettings -ApplicationPath $DVLSPath

   New-DPSDatabase -ConnectionString $Settings.ConnectionStrings.LocalSqlServer
   Update-DPSDatabase -ConnectionString $Settings.ConnectionStrings.LocalSqlServer -InstallationPath $DVLSPath
   New-DPSDataSourceSettings -ConnectionString $Settings.ConnectionStrings.LocalSqlServer

   New-DPSEncryptConfiguration -ApplicationPath $DVLSPath
   New-DPSDatabaseAppSettings -Configuration $Configuration

   New-DPSAdministrator -ConnectionString $Settings.ConnectionStrings.LocalSqlServer -Name $DVLSAdminUsername -Password $DVLSAdminPassword -Email $DVLSAdminEmail
   ```

   If a certificate has already been generated, proceed to modify the `appsettings.json` file to allow Kestrel to respond over TLS using this PowerShell script:

   ```powershell
   Import-Module -Name 'Devolutions.PowerShell'

   $DVLSPath = '/opt/devolutions/dvls'

   $JSON = Get-Content -Path (Join-Path -Path $DVLSPath -ChildPath 'appsettings.json') | ConvertFrom-JSON -Depth 100

   $JSON.Kestrel.Endpoints.Http | Add-Member -MemberType NoteProperty -Name 'Certificate' -Value @{
       'Path'     = (Join-Path -Path $DVLSPath -ChildPath 'cert.pfx')
       'Password' = ''
   }

   $JSON | ConvertTo-JSON -Depth 100 | Set-Content -Path (Join-Path -Path $DVLSPath -ChildPath 'appsettings.json')

   $Settings = Get-DPSAppSettings -ApplicationPath $DVLSPath

   $AccessUri = (Get-DPSAccessUri -ConnectionString $Settings.ConnectionStrings.LocalSqlServer).AccessUri
   Set-DPSAccessUri -ApplicationPath $DVLSPath -ConnectionString $Settings.ConnectionStrings.LocalSqlServer -AccessURI ($AccessUri -Replace "http","https")

   & sudo pwsh -Command {
     Param(
         $DVLSPath
     )

     & chown dvls:dvls (Join-Path -Path $DVLSPath -ChildPath 'cert.pfx')
   } -Args $DVLSPath
   ```

   To offer background running of Devolutions Server for Linux, it is recommended to create a unit file for systemd via this Bash prompt:

   ```bash
   sudo tee /etc/systemd/system/dvls.service > /dev/null <<EOT
   [Unit]
   Description=DVLS

   [Service]
   Type=simple
   Restart=always
   RestartSec=10
   User=dvls
   ExecStart=/opt/devolutions/dvls/Devolutions.Server
   WorkingDirectory=/opt/devolutions/dvls
   KillSignal=SIGINT
   SyslogIdentifier=dvls
   Environment="SCHEDULER_EMBEDDED=true"

   [Install]
   WantedBy=multi-user.target
   Alias=dvls.service
   EOT

   sudo systemctl daemon-reload
   ```
3. To start Devolutions Server, run:

   ```bash
   sudo systemctl start dvls

   # View status
   sudo systemctl status dvls
   ```

### Accessing Devolutions Server for Linux <a href="#accessing-dvls-linux" id="accessing-dvls-linux"></a>

By default, Devolutions Server for Linux listens on port 5000 on the IP or hostname of the installation system, which most commonly looks like: `http://MYHOST:5000`. Be aware that OAuth errors may occur upon first launch when trying to access Devolutions Server from a unconfigured URL. If this is the case, add additional URIs to listen on, or modify the primary one by running the following script in PowerShell:

```powershell
Import-Module -Name 'Devolutions.PowerShell'

$DVLSPath = "/opt/devolutions/dvls"

$Settings = Get-DPSAppSettings -ApplicationPath $DVLSPath
$ConnectionString = $Settings.ConnectionStrings.LocalSqlServer

Get-DPSAccessUri -ConnectionString $ConnectionString

Set-DPSAccessUri -ConnectionString $ConnectionString -ApplicationPath $DVLSPath -AccessURI 'http://10.10.0.20:5000/' -AdditionalAccessURIs @('http://ubuntu-2204:5000/')
```

If Devolutions Server remains inaccessible outside of the installed system, check if the requisite firewall ports are opened, by adding Uncomplicated Firewall to the prompt, for example: `sudo ufw allow 5000`.

### Importing Devolutions Server encryption key <a href="#importing-devolutions-server-encryption-key" id="importing-devolutions-server-encryption-key"></a>

**Export from an existing Windows installation**

```powershell
Import-Module -Name 'Devolutions.PowerShell
$existingDVLSInstance = 'C:\my\path\dvlsInstance\'
$destination = 'C:\other\path\encryption.config'
Export-DPSEncryptionKeys -ApplicationPath $existingDVLSInstance -Destination $destination
```

**Import to new Linux installation**

```powershell
Import-Module -Name 'Devolutions.PowerShell
$newDvlsInstance = '/home/user/linuxDlvsInstance'
$keysToImport = '/path/to/encryption.config'
Import-DPSEncryptionKeys -ApplicationPath $newDvlsInstance -Filename $keysToImport
```

### Updating Devolutions Server for Linux <a href="#updating-devolutions-server-for-linux" id="updating-devolutions-server-for-linux"></a>

Do not extract the new `.tar.gz` archive directly over `/opt/devolutions/dvls.` Doing so overwrites `appsettings.json` and `encryption.config`, which leaves the service unable to start and may make existing data undecryptable. Always follow the update method detailed on this page.

1. Backup the database. Here's how to do so for Microsoft SQL Server (Linux or remote):

   ```
   /opt/mssql-tools18/bin/sqlcmd -S <MSSQLHOST> -U <DBUSERNAME> -P '<PASSWORD>' -C \
     -Q "BACKUP DATABASE [DSERVER] TO DISK = N'/var/opt/mssql/data/DSERVER-$(date +%F-%H%M).bak' WITH INIT, COMPRESSION;"
   ```

   Full path to `sqlcmd` avoids **"**&#x63;ommand not found" error in non-login shells where `/etc/profile.d/mssql-tools.sh` has not been sourced.

   `-C` trusts the server certificate (required for local SQL Server installs that use a self-signed certificate).

   Backup to a directory writable by the MSSQL user. `/var/opt/mssql/data/` works out of the box.
2. Make sure the `.bak` file exists and is not empty before proceeding to the next step.
3. Stop the Devolutions Server service using the following script:

   ```bash
   sudo systemctl stop dvls.service
   sudo systemctl status dvls.service   # confirm inactive (dead)
   ```
4. Back up the installation and configuration files. Keep in mind that `/opt/devolutions/dvls` is in mode 550 and is owned by `dvls:dvls`, therefore the backup cmdlets must run as root. Start PowerShell with `sudo pwsh`, then paste this script:

   ```powershell
   Import-Module Devolutions.PowerShell
   $DVLSPath        = '/opt/devolutions/dvls'
   $BackupBase      = "/var/backups/dvls/$(Get-Date -Format 'yyyy-MM-dd-HHmm')"
   $BackupConfig    = Join-Path $BackupBase 'config'
   $BackupInstall   = Join-Path $BackupBase 'installation'
   mkdir -p $BackupConfig $BackupInstall
   Backup-DPSConfigurationFiles -ApplicationPath $DVLSPath -BackupConfigurationPath $BackupConfig
   Backup-DPSInstallationFiles  -ApplicationPath $DVLSPath -BackupPath              $BackupInstall
   ```

   * `Backup-DPSConfigurationFiles` preserves: `appsettings.json`, `web.config`, and `encryption.config`.
   * `Backup-DPSInstallationFiles` preserves custom folders, anomaly detection folder, and any user-added assets.
5. Empty the install directory except for `App_data`, as it contains runtime state that survives upgrades. Use this script to do so:

   ```bash
   sudo find /opt/devolutions/dvls -mindepth 1 -maxdepth 1 ! -name 'App_Data' -exec rm -rf {} +
   sudo tar -xzf /tmp/DVLS.<version>.linux-x64.tar.gz -C /opt/devolutions/dvls --strip-components=1
   ```

   Use `--strip-components` only if the archive has a top-level folder.
6. Restore configuration and custom data. In this step, `appsettings.json` (DB connection string) and `web.config` are put back into the new installation. Since `encryption.config` was already preserved inside `App_Data/` by step #5, `Restore-DPSConfigurationFiles` will not put it at the install root because that is not where it lives on Linux. Here is the restoration script:

   ```
   Restore-DPSCustomFolders            -BackupPath              $BackupInstall -ApplicationPath $DVLSPath
   Restore-DPSAnomalyDetectionFolder   -BackupPath              $BackupInstall -ApplicationPath $DVLSPath
   Restore-DPSConfigurationFiles       -BackupConfigurationPath $BackupConfig  -ApplicationPath $DVLSPath
   ```
7. Pull the connection strings from the restored `appsettings.json`:

   ```
   $ConnectionString = (Get-DPSAppSettings -ApplicationPath $DVLSPath).ConnectionStrings.LocalSqlServer
   Update-DPSDatabase -ConnectionString $ConnectionString -InstallationPath $DVLSPath
   ```

   `Update-DPSDatabase` prints no output on success. Verify that it worked by checking that the command returned exit code 0 and that, after starting the service in step #9, the journal shows ***Migration done with status Done*** entries with no `[ERR]` lines.
8. Re-apply ownership and permissions:

   ```
   sudo chown -R dvls:dvls /opt/devolutions/dvls
   sudo chmod 550 /opt/devolutions/dvls
   sudo chmod 660 /opt/devolutions/dvls/appsettings.json
   sudo chmod 770 /opt/devolutions/dvls/App_Data
   # If a certs/ directory is in use:
   [ -d /opt/devolutions/dvls/certs ] && sudo chmod 750 /opt/devolutions/dvls/certs
   ```
9. Start the service and check if it works correctly:

   ```
   sudo systemctl start dvls.service
   sudo systemctl status dvls.service
   sudo journalctl -u dvls.service -n 100 --no-pager
   ```

#### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

* **Service won't start, `appsettings.json` missing or empty:** restore from `$BackupConfig/appsettings.json`, repeat steps #8 and 9.
* **Login works but entries fail to decrypt:** `encryption.config` was not restored. Copy `$BackupConfig/encryption.config` into `$DVLSPath/App_Data/`, fix permissions (`chown dvls:dvls` and `chmod 660`), then restart.
* **DB schema errors at runtime:** `Update-DPSDatabase` was skipped or failed. Repeat step #7.
* **Full rollback:** stop the service (see step #3), empty `/opt/devolutions/dvls` except `App_Data/` (step #5), copy the contents of `$BackupInstall` back into `/opt/devolutions/dvls`, restore `appsettings.json` from `$BackupConfig`, re-apply ownership and permissions from step #8, restore the DB from the `.bak` produced in step #1, then restart.

### Removing Devolutions Server <a href="#removing-dvls" id="removing-dvls"></a>

To remove Devolutions Server, run the Bash prompt below and customize it for the system. This script relies on the [DbaTools PowerShell module](https://dbatools.io/) to facilitate the removal of the MSSQL database. It assumes `localhost` is the MSSQL installation and `dvls` the database name.

```
# Remove DVLS on Linux, adjust as necessary
& sudo systemctl stop dvls.service
& sudo rm /etc/systemd/system/dvls.service
& sudo rm -rf /opt/devolutions/dvls
& sudo userdel -r dvls
& sudo groupdel dvls

Import-Module dbatools
$Credential = Get-Credential

Set-DbaToolsInsecureConnection

Remove-DbaDatabase -SqlInstance localhost -SqlCredential $Credential -Database 'dvls' -Confirm:$False
```


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.devolutions.net/server/knowledge-base/how-to-articles/install-devolutions-server-for-linux.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
