Server base path - reverse proxy config - redirect URLs

I am deploying the 7.0.1 docker image to Kubernetes. The container starts up without error.
However, I will access the portal behind a reverse proxy. For instance, the public base URL will be something like: https://mydomain.com/openemr/. This gets forwarded then to the internal IP address, something like http://192.168.x.x/.

I can reach the base url, but it then redirects to /setup.php. So the URL is changed to:
https://mydomain.com/setup.php. But I need it to redirect to: https://mydomain.com/openemr/setup.php so my reverse proxy can forward to http://192.168.x.x/setup.php.

Is there a way to set a full public base URL, or a base URL path via environment variable so the redirects will be correct?

@APerez Can you help with this case here? He is speaking your expertise here.

I can’t speak to application-level assistance here, but if you’re willing to tinker with the image, look at the ProxyPassReverse directive for Apache.

(Alternatively, if you front the openemr container(s) with your own load-balancing Apache server you can apply it that way.)

As an alternative, I think I could ā€œtrickā€ it into working if I could make the base paths the same. Is there an option to set a base path in OpenEMR? i.e. So it doesn’t stand up on http://localhost/ but rather http://localhost/{somepath} ?

I’d prefer to not have to manipulate the image if possible. Environment variables are easy to set in a docker container when deploying to kubernetes, so that is preferred.

We’re not exposing any kind of functionality through the Docker envvars, I know that much.

You know what? If you’re not willing to meddle with the image, which is fair, maybe you need to extend it. That would probably work okay and I need to spend more time pushing people about this anyways. Apache’s already installed, after all.

So my advice is:

  • Create a new container FROM openemr:7.0.1
  • Create a script that patches or replaces the Apache configuration file openemr.conf copied into the image by the parent container
  • Inject and run that script in the Dockerfile and then reprise the CMD directive to launch the revised container with openemr.sh
  • Build, tag, and push your revised image to a container repo, public or otherwise
  • Consume your image instead of the stock image for Kubernetes

I appreciate the pointers in the right direction.

I will note, as the Docker image starts to get more interest from users for non-dev deployments, I suspect this will become an issue for more folks. Many deployments I suspect will attempt to run OpenEMR behind a reverse proxy, gateway, WAF, etc. where the public URL path won’t match the internal base path.
I was hoping that there was an ENV var that Apache, or OpenEMR would pick up to modify relative URLs and redirects, but so far coming up short.
If I figure something out I’ll report back.

hi @XcrigX , Looks like @jesdynf was on to something with the ProxyPassReverse directive for Apache:

If I am not mistaken, it looks like this is configured on the reverse proxy server side of things. What reverse proxy server are you using?

It gets confusing to research this, since Apache can also be configured and used as a reverse proxy. But in this case Apache/OpenEMR is running behind a reverse proxy.

Anyway, my reverse proxy is forwarding traffic to OpenEMR. Traffic hits my public URL at something like https://mydomain.com/openemr/*, and the proxy forwards it to the internal instance which would be running on a local address unaware of the rest of the network topology - something like http://192.168.1.100/*
When OpenEMR redirects to a new URL, it is correctly keeping my public hostname - it must be detecting it from one of the headers, but it is not aware that the base path is different. So instead of redirecting (for instance) to the setup at https://mydomain.com/openemr/setup.php, which my proxy would know to route to http://192.168.1.100/setup.php , it is redirecting to https://mydomain.com/setup.php - which my proxy doesn’t know how to handle.
The proxy is handing traffic for many different services, so it needs distinct paths for each to route them.

I believe I can do as suggested and edit the Apache config files to make it aware, but this is not ideal in the container world. You can make a custom image per deployment environment (not ideal), or you can inject the config file at deployment time, which requires some hoops to jump through because mounting a config map directory in Kubernetes doesn’t preserve the existing directory if it exists in the image - so you have to mount it to a different location and use an init container to copy it to the correct location (if there are other files in it you need to preserve).
And in both cases I then have to maintain the file - as OpenEMR changes the Apache configs in future versions I have to keep my custom version up to date.
Whereas with environment variables, it is very easy to set them at deployment time so distinct deployments can have different values and share a common image - like is currently possible with the DB connection settings.

Anyway, if this is all handled on the Apache side there may not be anything you can do about it. I just keep thinking that running a LAMP stack in a container isn’t anything novel, so there must be some easier option I’m missing.

Hi, What software are you using for the reverse proxy?

Also, in kubernetes, there is a neat workaround to not bash the entire directory when mounting a config map (this is also an issue I ran into on the Kubernetes stuff for OpenEMR and can see the workaround here: https://github.com/openemr/openemr-devops/blob/master/kubernetes/phpmyadmin/deployment.yaml#L29-L31). That being said, the goal is that the reverse proxy should be able to manage this, which is why curious what you are using as the reverse proxy.

I’m using Azure API Manager currently in a reverse-proxy role here. But it could be any kind of gateway in this scenario that is routing traffic from the outside to the inside.
I’m not clear how the reverse proxy would mange this scenario, but my understanding may be incomplete.
My understanding is that a reverse proxy only handles traffic in one direction - traffic hits the proxy, and based on rules (usually the URL paths), it routes it to where it needs to go. If the service that it routes to re-directs to a new URL, the proxy is not aware of this unless the redirect is to a URL that also hits the proxy - at which point it uses it’s rules to again route it to the proper place.

Herein lies my problem, the redirected URL doesn’t contain the path that my proxy needs to route it - back to my OpenEMR instance.

Unless you are thinking that the reverse proxy should be setting some headers that Apache/OpenEMR would utilize to properly construct the URL paths? That could be the case - the Forwarded, and X-Forwarded headers, etc.

Just as an example from another project - Keycloak has various options to handle this scenario, if you scroll down to the ā€œDifferent context-path on reverse proxyā€ section here:

That’s essentially what I was hoping to find, either a way to set the context path of OpenEMR so it would match the path exposed by my reverse-proxy, or a way to explicitly tell it that path so it uses it to construct the urls as you navigate around.

Check out the answer on this thread:

My take on that is that the reverse proxy (which apache reverse proxy would do via the ProxyPassReverse Directive setting) can be set to manage this situation (ie. then nothing would need to be done on the docker itself). Let me know if my assumption is incorrect.

Also, pretty sure a reverse proxy is 2 way (ie. both the request and response pass through it). I just read through following article to review reverse proxy mechanism (this article also posted quick example of setting up reverse proxy in apache and it seems like Azure API manager should also be able to so something like ProxyPassReverse setting when in reverse proxy role).

You may be correct Brady, I’m not 100% certain. I’ve worked with several components that allow you to hardcode the public base URL or path to achieve a similar result - but perhaps this is because it’s simpler than trying to get a reverse-proxy to rewrite the headers (and potentially in-page links) generated by a site.

I played around today with getting the Apache server in the OpenEMR docker container to do this, but no luck so far. So far I was trying to use the existing OpenEMR image and simply inject a custom openemr.conf file with the ā€˜ProxyPassReverse’ directive . But I haven’t been able to get it to work yet. ProxyPassReverse requires some modules to be loaded, and when I try to do so Apache fails saying it can’t find them.
i.e. I’m trying to add:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyPassReverse ā€œ/ā€ ā€œhttps://mydomain.com/openemrā€

Which results in this error:

Starting apache!
httpd: Syntax error on line 482 of /etc/apache2/httpd.conf: Syntax error on line 3 of /etc/apache2/conf.d/openemr.conf:
Cannot load modules/mod_proxy.so into server: Error loading shared library /var/www/modules/mod_proxy.so: No such file or directory

And indeed if I inspect the container there are many modules in the /modules directory, but not this one. (I’m an Apache novice).

So maybe I’d need to rebuild a custom OpenEMR image as was suggested earlier so I can install those modules.
Or try to get my reverse proxy to do this work, rewriting the Location header, page links?, etc on the outbound responses.

Pretty sure those directives are for the reverse proxy (when using apache as a reverse proxy).

I think most straightforward way to get what you want in the apache openemr.conf in the openemr docker (in kubernetes could overwrite that file with config map if don’t want to build a separate docker) is to change the:
DocumentRoot /var/www/localhost/htdocs/openemr
to
DocumentRoot /var/www/localhost/htdocs

If do above, just make sure there are no ā€œbadā€ scripts in /var/www/localhost/htdocs that may cause security vulnerabilities. Another way that may work (that would not allow public web access to /var/www/localhost/htdocs) would be to use an alias in apache:
Alias "/openemr" "/var/www/localhost/htdocs/openemr"

I tried setting the Alias option and re-mapping my proxy.
So now I’d be routing:

https://mydomain.com/openemr/*

to

http://192.168.x.x/openemr/*

The effect is the same - I can reach the initial page, but then OpenEMR redirects to setup without using the alias context path. So it redirects to:

https://mydomain.com/setup.php

Which of course my proxy can’t route.
I suppose I could take the other suggestion, or insert another directory into the structure:

/var/www/localhost/htdocs/openemr/openemr/

The OpenEMR demo appears to use a base/context paths, i.e.

https://demo.openemr.io/openemr/
https://demo.openemr.io/a/openemr/
https://demo.openemr.io/b/openemr/

How is it configured?