# Using Duplicati from Docker

The Duplicati Docker images are available from [DockerHub](https://hub.docker.com/r/duplicati/duplicati) and are released as part of the regular releases. The Docker images provided by Duplicati are quite minimal and includes only the binaries required to run Duplicati. There are also variations of the [Duplicati images provided by third parties](https://hub.docker.com/search?q=duplicati), including the popular [linuxserver/duplicati](https://hub.docker.com/r/linuxserver/duplicati) variant.

## Configure the image

The Duplicati Docker images are using `/data` inside the container to store configurations and any files that should persist between container restarts. Note that other images may choose a different location to store data, so be sure to follow the instructions if using a different image.

You also need a way to sign in to the server after it has started. You can either watch the log output, which will emit a special signin url with a token that expires a few minutes after the server has started, or provide the password from within the configuration file.

To ensure that any secrets configured within the application are not stored in plain text, it is also important to set up the database encryption key.

See also the DockerHub page for details on how to configure the image: <https://hub.docker.com/r/duplicati/duplicati/>

## Hostname access

Duplicati's server allows access from IP-based requests, but disallows access from requests that use a hostname. This is done to prevent certain DNS-based attacks, but will also block attempts to use a correct hostname. To avoid this, set the environment variable:

```yaml
environment:
  DUPLICATI__WEBSERVICE_ALLOWED_HOSTNAMES: <hostname1>;<hostname2>
```

Setting this environment variable will enable using desired hostnames instead of IP addresses only. The special hostname `*` will disable the protection and allow any hostname, but this is not recommended for security reasons.

## Managing secrets in Docker

Ideally, you need at least the settings encryption key provided to the container, but perhaps also the webservice password. You can easily provide this via a regular environment variable:

```yaml
services:
  myapp:
    image: duplicati/duplicati:latest
    volumes:
      - ./data:/data
    environment:
      SETTINGS_ENCRYPTION_KEY: "<real encryption key>"
      DUPLICATI__WEBSERVICE_PASSWORD: "<ui password>"
```

But you can make it a bit more secure by using [Docker secrets](https://docs.docker.com/compose/how-tos/use-secrets/) which are abstracted as files that are mounted under `/run/secrets/`. Since Duplicati does not support reading files in place of the environment variables, you can either use a [preload configuration file](https://docs.duplicati.com/configuration-and-management/preload-settings) or use one of [the secret providers](https://docs.duplicati.com/security-and-secrets/using-the-secret-provider).

### Using a preload file

To use the preload approach, prepare a `preload.json` file with your encryption key:

```json
{
  "env": {
    "server": {
        "SETTINGS_ENCRYPTION_KEY": "<real encryption key>",
        "DUPLICATI__WEBSERVICE_PASSWORD": "<ui password>"
    }
  }
}
```

You can then configure this in the compose file:

```yml
services:
  myapp:
    image: duplicati/duplicati:latest
    volumes:
      - ./data:/data
    environment:
      DUPLICATI_PRELOAD_SETTINGS: /run/secrets/preloadsettings
    secrets:
      - preloadsettings

secrets:
  preloadsettings:
    file: ./preload.json
```

### Using a secret manager <a href="#p-72996-using-a-secret-manager-2" id="p-72996-using-a-secret-manager-2"></a>

Setting up the secret manager is a bit more work, but it has the benefit of being able to configure multiple secrets in a single place. To configure the file-based secret provider, you need to create a `secrets.json` file such as this:

```json
{
  "settings-key": "<real encryption key>",
  "ui-password": "<real UI password>"
}
```

Then set it up in the compose file:

```yml
services:
  myapp:
    image: duplicati/duplicati:latest
    volumes:
      - ./data:/data
    environment:
      SETTINGS_ENCRYPTION_KEY: "$$settings-key"
      DUPLICATI__SECRET_PROVIDER: file-secret:///run/secrets/secretprovider
      DUPLICATI__WEBSERVICE_PASSWORD: "$$ui-password"
    secrets:
      - secretprovider

secrets:
  secretprovider:
    file: ./secrets.json
```

It is also possible to use one of the other secret providers, such as one that fetches secrets from a secure key vault. In this case, you do not need the `secrets.json` file, but can just configure the provider.

## Read locked files

Duplicati has support for LVM-based snapshots which is the recommended way for getting a consistent point-in-time copy of the disk. For some uses, it is not possible to configure LVM snapshots, and this can cause problems due to some files being locked. By default, Duplicati will respect the advisory file locking and fail to open locked files, as the lock is usually an indication that the files are in use, and reading it may not result in a meaningful copy.

If you prefer to make a best-effort backup, which was the default in Duplicati v2.0.8.1 and older, you can disable advisory file locking for individual jobs with the advanced option: `--ignore-advisory-locking=true`. You can also disable file locking support entirely in Duplicati:

```yaml
services:
  myapp:
    image: duplicati/duplicati:latest
    volumes:
      - ./data:/data
    environment:
      SETTINGS_ENCRYPTION_KEY: "<real encryption key>"
      DUPLICATI__WEBSERVICE_PASSWORD: "<ui password>"
      DOTNET_SYSTEM_IO_DISABLEFILELOCKING: true
```

## Running behind a proxy

If you want to run Duplicati behind an nginx proxy, you can use a `docker-compose` configuration like this example

```yaml
services:
  nginx:
    image: nginx:alpine
    ports:
      - "8200:8200"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - duplicati
    restart: unless-stopped

  duplicati:
    image: duplicati/duplicati:latest
    environment:
      - DUPLICATI__WEBSERVICE_PASSWORD: "<ui password>"
    volumes:
      - ./data:/data
    restart: unless-stopped
```

And then use an `nginx.conf` file like this example:

```nginx
events {
  worker_connections 1024;
}

http {
  server {
    listen 8200;
    server_name localhost;

    location / {
      proxy_pass http://duplicati:8200;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }
}
```

### Pre-authenticated with reverse proxy

If your proxy setup already authenticates the user and you prefer not having to use another password to access Duplicati, you can configure the proxy to forward a preconfigured authentication header.

It is not possible to disable authentication for Duplicati, as that would make it possible to accidentially expose the server without access control. To avoid being asked for a password on each accss, you need to generate a random token that you can pass from the nginx server to Duplicati that serves as authentication and grants access to Duplicati.

{% hint style="danger" %}
This setup bypasses the Duplicati authentication so make sure your authentication system is sufficiently secure before deploying it.
{% endhint %}

When you have a secure random token, make Duplicati trust it via the pre-authenticated header:

```yaml
services:
  myapp:
    image: duplicati/duplicati:latest
    volumes:
      - ./data:/data
    environment:
      SETTINGS_ENCRYPTION_KEY: "<real encryption key>"
      DUPLICATI__WEBSERVICE_PRE_AUTH_TOKENS: "<secure random token>"
```

Then make the nginx proxy forward the header on each request:

```nginx
http {
  server {
    listen 8200;
    server_name localhost;

    location / {
      proxy_pass http://duplicati:8200;
      proxy_set_header PreAuth <secure random token>
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }
}
```
