Issue with accessing Passbolt from different network ports due to the hardcoded APP_FULL_BASE_URL

I identified that the issue on my setup is related to having the APP_FULL_BASE_URL configured in the docker-compose file with an hardcoded value (“https://passbolt.domain.com/”).

I have external collaborators accessing the passbolt server, but since this is a segregated environment, I have the upper-level firewall ports being filtered, and each of the collaborators have a different dedicated open port in the firewall, from where they can access Passbolt server.

Given this context, their HOST header include that port, which is also included in the full URL of the requests as well

e.g. “https://passbolt.domain.com:8443/js/app/api-vendors.js?v=4.2.0”

Traefik is doing its job nicely to reverse-proxy the requests coming from the firewall, and these are arriving successfully to the passbolt web server in the backend with the correct Host and X-Forwarded-For headers including the port.

This issue is that, since cake PHP is configured to use the hardcoded value from fullbaseUrl, and the links in the webserver pages are included by calling the Router::url function (which contains the hardcoded value in fullBaseUrl), thee responses to their requests don’t have the port included in the webpages responded to their clients:
The links in the pages returned are something like:

https://passbolt.domain.com/js/app/api-vendors.js

Instead of the original requested and expected

https://passbolt.domain.com:8443/js/app/api-vendors.js

.
.
This also causes their requests to fail, and to not even leave their browsers, because the resources included in the web page fail the CSP (content security policy), since the page is trying to fetch resources from a host different than https://passbolt.domain.com:8443.

Althouh it is not ideal, I could have this solved by going directly to the passbolt server itself, and replacing, in /etc/passbolt/app.php:

    'fullBaseUrl' => env('APP_FULL_BASE_URL', false),

with

    ‘fullBaseUrl’ => “https://” . $_SERVER[‘HTTP_HOST’],

After this (and nginx restart on Passbolt container level), the webserver started to reply correctly, including the links in the pages replied to their requests, including the port associated in the hyperlinks written in the html body of the page.

Question

Do you know how can I configure the docker-compose file itself to have this issue fixed diretcly there, instead of passing the hardcoded “https://passbolt.domain.com” and having the change things directly in the container after creation?

P.S.: This is just a temporary fix, because everytime I docker-compose stop/start the containers, the server is unavailable an returns 502. I have to jump into the passbolt container, uncomment the default one ('fullBaseUrl' => env('APP_FULL_BASE_URL', false)), restart nginx, comment the default one and uncomment the lat one I mentioned ('fullBaseUrl' => env('APP_FULL_BASE_URL_NON_EXISTENT', false)) and restart nginx again for it to become available.

To survive restarts you could mount your app.php with your custom configuration.

1 Like

Hi there @diego , and thanks for the suggestion, and the time taken.
I will implement that, but I think the issue is in other place.

The app.php doesn’t get changed/reset with start/stop. It stays the same, with the same line in the code. But the app seems to be expecting the fullBaseUrl passed in the docker-compose, or other, because it returns 502 Bad Gateway on the backend passbolt webserver level.

It only starts working again when I:

  1. uncomment the default one ('fullBaseUrl' => env('APP_FULL_BASE_URL', false)),
  2. restart nginx,
  3. comment the default one and uncomment the lat one I mentioned ('fullBaseUrl' => env('APP_FULL_BASE_URL_NON_EXISTENT', false)), and
  4. restart nginx again for it to become available.

I didn’t find the cause of this yet.

If you set this env variable in your docker-compose.yaml works as you expect?
APP_FULL_BASE_URL: https://passbolt.$domain.tld
If you are using a different port than 443, specify it on after the domain
APP_FULL_BASE_URL: https://passbolt.$domain.tld:4433

Hi ther @Termindiego25 , and thanks for passing by.

Different people use different network ports.

So, some have https://passbolt.$domain.tld:8443, while other have https://passbolt.$domain.tld:8444 (because they come from a different network port).

That’s why I wanted to know how to change the docker-compose file in order to have this dynamically configured there, instead of a hardcoded URL with only one of the network ports as you suggested.

Okay, I see. Unfortunately, this is not possible because when you start a docker container, the config is copied from the docker-compose and changing docker ports will require you to delete and create again the container.

You can try to map all the ports you use to the same internal one configured on Passbolt, but I don’t know if this will work.

For your use case, it is better to use just one port and leave the work to the reverse proxy.

Just out of curiosity, why do you use this approach instead of using just one port for everyone?

1 Like

Hi tere @Termindiego25 ,

That is exactly how I set it up in the first place.

The backend passbolt webserver only listens on one port, and reverse proxy is doing the work for the different network ports used to access passbolt from ‘outside’.

The issue is that when the correct requests reach the backend server level, they lose the notwork port from the HOST, because passbolt is configured to use an hardcoded value as URL (without any network port in it).

I’ve already confirmed that the integral HOST header value (including the network port used at reverse proxy level) is included in the requests sent from traefik reverse proxy to the backend passbolt webserver.

If the headers lose the port, it’s a reverse proxy misconfiguration, because is the reverse proxy that changes the ports when it receives the request and the response.
I do not use Traefik, so I can’t help you. I was trying to use Apache and it doesn’t work properly, but you can see my configuration here in case it is useful to you:

Sorry @p1d630n

Did have time to try it yet, and without FullBaseUrl set how it is behaving?

Its gray water here I never saw it worked in that configuration

1 Like

@Termindiego25 I totally understand your pois, and I also assumed that, but after tcpdumping things in both traefik and passbolt webserver , I can see that all headers are included.

Also, the part where the networks ports are missing is on the hyperlinks included in the body of the web page responses (the other pages and .js loaded, referenced in the html - I left a screenshot in the original post). So, the proper network level headers are not missing or failing, since the response itself reaches the client host that requested it from that other network port. Only the links included it the HTML body are not, because they force the browser to fetch the resources from the default url (https == port 443).

That’s when I tried to change things at the passbolt webserver container level, changing

'fullBaseUrl' => env('APP_FULL_BASE_URL', false)

to

‘fullBaseUrl’ => “https://” . $_SERVER[‘HTTP_HOST’]

And with this hotfix, it works.

spot on @p1d630n, well done, did you try sharing, recovering and bending a little the app to see if all the scenario are working.
Oh yeah make a try with MFA as well just to be sure.

Yes @max , I checked on that and seems to be working. Even removed MFA and set up a new one, thanks.

The issue, which is also the orignal question, is that when I do a docker-compose start/stop, the app.php remains the same, with my new line there, but the webserver is unavailable an returns 502.

I then have to jump into the passbolt container and:

  1. Uncomment the default one (‘fullBaseUrl’ => env(‘APP_FULL_BASE_URL’, false)),
  2. restart nginx,
  3. comment the default one,
  4. Uncomment the lat one I mentioned (‘fullBaseUrl’ => env(‘APP_FULL_BASE_URL_NON_EXISTENT’, false)), and
  5. restart nginx again, and
  6. it then becomes available for every collaborator coming through different ports.

did you try to set the env var APP_FULL_BASE_URL to “https://” . $_SERVER[‘HTTP_HOST’] ?

1 Like

I tried, but was stuck precisely around that level (changing docker-compose like that) to make it work.
However, it didn’t seem to be fruitful.

Would it be because of the additional double quotes?
Do you know how should the syntax of that go exactly?

Ok, did you tried to mount passbolt.php inside your docker (path is /etc/passbolt/passbolt.php)

where you just add:

<?php
return [
    'App' => [
        'fullBaseUrl' => “https://” . $_SERVER[‘HTTP_HOST’] 
    ]
];
1 Like

Hi there everyone.

Unfortunately, @max suggestion also didn’t work out.

After long time, and several attempts, I was able to solve this issue by basically ignoring the instructions to include the hostname as the APP_FULL_BASE_URL environment variable, by commenting that line on the docker-compose file.

As stated in the documentation of the app.default.php of passbolt_api Github reporsotory:

fullBaseUrl - A base URL to use for absolute links. When set to false (default) CakePHP generates required value based on HTTP_HOST environment variable.

This means that by keeping that variable commented in the docker-compose file, results in its default value (false), making the server use the HTTP_HOST variable instead.

Besides this, I had to configure Nginx Proxy Manager in front of it, and set up an advanced configuration location that forwards the requests to the Passbolt server, replacing the HOST header with $http_host.

location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass https://:4433;
}

Thank you once more for the help, and specially for creating and mantaining Passbolt! :slightly_smiling_face: