Disable password on GUI

I don’t think this can be done securely. One nasty case the password prevents is privilege escalation, where an attacker has managed to get execute access in a sandbox.

If there was a magic header to set, the attacker would be able to use this header and bypass the security.

Wish granted :smiley:

Let me know if there are considerations to include before we merge this.

I’m a bit confused, as you said it can’t be done securely and yet you enable basically the same thing insecurely. As I see it, the https request from the proxy should be secure, and if you stored the defined “tokens” in the database along with trusted IPs, rather than in plain-text of the Duplicati server service that would be better. I suppose the token may not be secure on the proxy config and that I’m not sure how to make better but at least the connections can only come from the trusted IPs.

I misunderstood. From your text, I read that this was a proposed static header value, like:

X-From: HA-Proxy

That would not be secure, as the value is documented, so an attacker can send the same value.

Re-reading your post, I see I mentally skipped the part where you mention “secure token” which is exactly what I also suggested.

For the IP restriction, would it be sufficient to add this to a firewall or sorts?

The PR I have was based on the request from @felixilgatto where the need was to not invoke a tool as part of the spin-up. For that reason, the solution does not store any values in the database, but requires a value to be passed at startup, and is only kept in memory.

Do you have additional needs for your setup? Does it need to be persisted and IP locked?

1 Like

Personally I would rather Duplicati controlled this, in my case the firewall would only be protecting from external access and I don’t have any exposed this way.

I feel there should still be a secure way to store these settings and still keep someway to override them via command-line which can also be beneficial for troubleshooting.

I have no real needs myself, I was mostly interested in this thread and wanted to add the extra information regarding HAProxy options. I don’t think there needs to be any kind of persistence.

Thank you for the solution to my issue—it’s much appreciated.

I don’t think a flawless solution is possible in this case, and it’s important to remember that Duplicati is not primarily a security tool. It’s understandable that experienced users may not trust the security layer implemented in it. I do respect the intention to protect casual users by default, as a minimum level of protection is definitely important.

However, I also believe it’s equally important to provide an option to disable such features for more experienced users who want to tailor their experience or improve usability.

Thanks again for your help.

1 Like

I see how this could be done. It would be something like:

TOKENS=10.0.0.1:my-secret-token1;192.168.0.7:my-other-secret-token

This would then add the additional check of IPs. We could choose to store the string in the database, and then use commandline options (or server-util) to set/reset them.

Ok, then I suggest anyone who does need it, can create an issue and we can look at it then.

While Duplicati is not a security tool as such, any backup tool will have access to a lot of information and should be guarded.

And my goal is to make it “secure by default”, but this should not prevent using it differently by people who understand the consequences.

The pre-auth headers are part of the 2.1.0.113 release that will be up soon.

1 Like

Hi,
I am on a reverse proxy too and I am trying to understand how to login with a token that is passed as a header by the reverse proxy.

I have correctly set the env variable DUPLICATI__WEBSERVICE_PRE_AUTH_TOKENS: ${DUPLICATI_TOKEN}.

But now, what is the name of the token to be set ? Add support for pre-authenticated headers by kenkendk · Pull Request #6097 · duplicati/duplicati · GitHub seems to suggest that it would be PreAuth, but I also see Bearer in this discussion.

Can you provide an example with nginx that shows how the token is supposed to be configured ?

Thanks in advance for your help,
Have a nice day.

Hi @LeVraiRoiDHyrule, welcome to the forum :waving_hand:

The implementation uses PreAuth to avoid breaking anything with the regular Bearer token. If there is no preauth configured, this part of the authorization code is never loaded by the server, so for most users, preauth is not possible.

The Bearer is for the regular tokens, including the forever-token option.

Something like this:

server {
    listen 80;
    server_name example.com;

    location /api/v1/ {
        proxy_pass http://localhost:8200/api/v1/;
        proxy_set_header Authorization "PreAuth 1234";        
    }
}

Thank you for your answer.
I have applied the header in Nginx.
Now, I am having the following error in the WebUI:
The connection to the server is lost, attempting again in 0:10 …
There is no error appearing in Duplicati console itself.

My reverse proxy returns the following error:
duplicati.mydomain.com 874.457.563.87- - [02/May/2025:15:58:00 +0200] "POST /api/v1/auth/refresh HTTP/2.0" 404 0 "https://duplicati.mydomain.com/ngax/index.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0"

My reverse proxy configuration is the following:

location / {
        etag off;
        set $backend0 "http://duplicati:8200";
        proxy_pass $backend0;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Protocol $scheme;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Prefix "/";
        proxy_buffering on;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        auth_request /outpost.goauthentik.io/auth/nginx;
        auth_request_set $auth_cookie $upstream_http_set_cookie;
        auth_request_set $authentik_username $upstream_http_x_authentik_username;
        auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
        auth_request_set $authentik_entitlements $upstream_http_x_authentik_entitlements;
        auth_request_set $authentik_email $upstream_http_x_authentik_email;
        auth_request_set $authentik_name $upstream_http_x_authentik_name;
        auth_request_set $authentik_uid $upstream_http_x_authentik_uid;
        add_header Set-Cookie $auth_cookie;
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
}

location /api/v1/ {
        etag off;
        set $backend2 "http://duplicati:8200/api/v1/";
        proxy_pass $backend2;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Protocol $scheme;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Prefix "/api/v1/";
        proxy_buffering on;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Authorization "PreAuth XXX";
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
}

My duplicati config is the following:

  duplicati:
    image: duplicati/duplicati:latest
    container_name: duplicati
    environment:
      SETTINGS_ENCRYPTION_KEY: ${DUPLICATI_ENCRYPTION}
      DUPLICATI__WEBSERVICE_PRE_AUTH_TOKENS: XXX
    networks:
      services:
    restart: unless-stopped
    volumes:
      - ${CONFIG_FOLDER}/duplicati/config:/config
      - ${CONFIG_FOLDER}/duplicati/backups:/backups
      - ${CONFIG_FOLDER}:/dockercontainers:ro

Would you have an idea of what could be wrong ?
Thanks in advance for any answer, have a nice day.

Not sure why that is. The 404 should not be from Duplicati, as it will return 403 if the token is invalid, so I am guessing that the routing is somehow not hitting the right path?