Apache Proxy Pass / Setting the Context Path


#1

I am trying to setup Scipio to run behind Apache on a CentOS 7 server.

I added a proxy pass to my Apache config, and that nearly works. The issue I still see is in the base urls. I found that in the framework/webapps/config/url.properties file I was able to fix this to some extent by changing content.url.prefix.secure and/or content.url.prefix.standard, but that doesn’t apply universally, but rather to static resources only. I’ve found a few other settings I thought my change this, but none of them have worked for me yet.

My goal is to have apps run on a url like : https://mydomain.com/staff/scipio/...

Ideally, I’d also like to have the shop url resolve to simply https://mydomain.com/shop.


#2

Ok,

not a big deal. You have to do the two things:

  1. On the server side:
    a) Tell the system to properly generate the urls, by setting the WebSite config
    by setting the defaults in /framework/webapp/config/url.properties (this allows you to set a domain for the entire system):

     # HTTPS Port (Secure port)
     port.https.enabled=Y
     port.https=
     force.https.host=https://mydomain.com/
    
     # HTTP Port (Not Secure port) -> can be mostly ignored nowadays
     port.http=8080
     force.http.host=
    

Alternatively you can set the same values per Website:

    <WebSite productStoreId="ScipioShop" siteName="SCIPIO Shop Web Site" visualThemeSelectorScript="component://common/webcommon/WEB-INF/actions/includes/GetWebSiteStoreVisualThemeId.groovy" visualThemeSetId="ECOMMERCE" webSiteId="ScipioWebStore"
             httpHost=""
             httpPort=""
             httpsHost=""
             httpsPort=""
             enableHttps=""
             standardContentPrefix="" 
             secureContentPrefix=""
             cookieDomain=""
    />

All of this is also described in https://www.scipioerp.com/community/developer/installation-configuration/configuration/

  1. Configure your webserver to forward all requests to the scipio erp server

a) nginx

    location / {
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $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 https;
        proxy_cookie_path ~*^/.* /;
        add_header Front-End-Https   on;

        proxy_pass  http://localhost:8080/shop/;
     }

    location /solr/ {
           auth_basic "Restricted";
           auth_basic_user_file /var/www/.../private/.htpasswd;
            proxy_set_header Host $host;
            proxy_pass  http://localhost:8080/solr/;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-for $remote_addr;
            port_in_redirect off;
            proxy_connect_timeout 300;
            proxy_pass_header Set-Cookie;
    }

    location /base-theme/ {
                    proxy_set_header Host $host;
                    proxy_pass  http://localhost:8080/base-theme/;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-for $remote_addr;
                    port_in_redirect off;
                    proxy_connect_timeout 300;
                    proxy_pass_header Set-Cookie;
    }

    location /images/ {
                    proxy_set_header Host $host;
                    proxy_pass  http://localhost:8080/images/;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-for $remote_addr;
                    port_in_redirect off;
                    proxy_connect_timeout 300;
                    proxy_pass_header Set-Cookie;
    }

    location /foundation-shop-theme/ {
                    proxy_set_header Host $host;
                    proxy_pass  http://localhost:8080/foundation-shop-theme/;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-for $remote_addr;
                    port_in_redirect off;
                    proxy_connect_timeout 300;
                    proxy_pass_header Set-Cookie;
    }

    location /ordermgr-js/ {
                    proxy_set_header Host $host;
                    proxy_pass  http://localhost:8080/ordermgr-js/;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-for $remote_addr;
                    port_in_redirect off;
                    proxy_connect_timeout 300;
                    proxy_pass_header Set-Cookie;
    }

You will have to modify the above to fit your own needs - in this case to make it work for Apache.


#3

I will post a tutorial on this topic on the website soon. We have been asked about this several times in the past…


#4

Thanks, @madppiper. I tried the force.https.host= and force.http.host= settings inside the /framework/webapp/config/url.properties file right off the bat, but those had no effect, where content.url.prefix.secure and/or content.url.prefix.standard had a partial effect.

I am not sure where the “Website” section(s) are found that you mention? I thought perhaps those could be in conflict or maybe it’s overriding this other value?

Note that the basic proxy pass works fine for me. It’s not an Apache issue. I’ve setup proxy passes like this many times, including on this same server for other Tomcat servlets. My scipio login pages appear at the proxyed urls, they just have broken links and an html source inspection shows they are pointing at the domain root.

In case it’s useful, I’ll post my Apache config. I just want to get both sides working first, so I can confirm the settings changes work as desired.


#5

Hi Buvinj,

if the defaults in your general.properties does not have an effect, then most likely you are overriding the settings with your database entries (that is where the “Website” entry is taken from.) You can set them through the interface also, go to:

Catalog Manager > Shops > Select your Shop > select “Websites” from the context menu > Check all entries

The following is a direct link https://localhost:8443/catalog/control/EditWebSite?webSiteId=ScipioWebStore

Make sure you restart the system after changing it here.

You can post your apache config, sure. It would allow me to check this briefly and also perhaps help others with similar issues.


#6

At this point, I can’t use the gui / web interface because this is broken. I don’t have the scipio ports accessible, and my host os has no gui. I mean, I could play with the firewalls and take down my proxy pass, etc. but that’s sort of pain.

If this a database value issue, I’d rather just directly modify the database. Can you point me to the table / columns?

Or, maybe I should run the installation again after changing the force host value? I wouldn’t object even to wiping out the database first, since it has no custom content yet. Would that perhaps write the correct db values implicitly?


#7

Resetting the database may be the easiest option you got.

Otherwise you can also just check the Scipio DB for a table called “WebSite” -> then check all entries listed there…


#8

I’ll try that and post my results. Thanks!


#9

Using your nginx example, I managed to get Apache to do the same thing, i.e. run out in front of the Scipio embedded Tomcat servlet. This is helpful for me because I can use the same “perfected” ssl configuration a have defined in Apache, and not have to worry about installing and maintaining certs in multiple formats. It also hides the port spec, so I can keep that firewall up.

The problem, however, is that this does not change the context path. And that is a major issue for me. I don’t want Scipio running on the domain root. In this example (and what I had to live with for now), that’s what is still being done.

I have one server running numerous back end tools, in various other Tomcat instances, or custom Python servers, etc. I also have a commercial front end.

Every other back end tool I have running behind “/staff/toolname”. Generally, I just need a one, to maybe a handful of Apache rules to pull this off. I just proxypass to localhost:toolport. Then, that tool always has it’s own internal means of changing the context path.

Likewise, I want the scipio apps running at /staff/sciopio/scipio app (e.g. /staff/sciopio/accounting). Alternatively, as and a secondary related issue, I want the shop to come off the domain root, at just plain /shop. So, there is a bit of a conflict there.

Anyway, I can’t reliably make this work. I’ve tried fiddling with the force.host and static content settings. I’ve tried making tweaks in the Java. I even tried the Apache mod “ProxyHTMLURLMap”, which dynamically rewrites web content. Nothing works perfectly. I get a roughly working system, but with nasty little glitches sprinkled about. There are more significant logic gaps then I can spend the time plugging.

Please test this, and if possible, add this feature in a “perfected” state to a future release.

I now have to make sure, for instance, that my front website, does have not directory conflicts with the Scipio proxypasses. As an example, I can’t have an /images directory off of the natural Apache doc root.


#10

I have Scipio http running on port 8180. I’ve also tried using the ajp port/protocol, but didn’t see any difference, so I stuck with http for now (since I can use this same pattern with various sorts of backend nested servers).

After redirecting all http requests to https, I have this long list of proxy passes in my Apache ssl.conf. Please let me know if this covers all the components that need external entry points:

# Proxy Settings
SSLProxyEngine          On
ProxyRequests           Off
ProxyPreserveHost       On

# Scipio resources
ProxyPassReverseCookieDomain http://localhost:8180 https://mydomain.com
ProxyPass /images/ http://localhost:8180/images/
ProxyPass /resources/ http://localhost:8180/resources/
ProxyPass /ordermgr-js/ http://localhost:8180/ordermgr-js/
ProxyPass /base-theme/ http://localhost:8180/base-theme/
ProxyPass /bootstrap-theme/ http://localhost:8180/bootstrap-theme/
ProxyPass /foundation-shop-theme/ http://localhost:8180/foundation-shop-theme/
ProxyPass /foundation6-theme/ http://localhost:8180/foundation6-theme/
ProxyPass /ignite-admin-theme/ http://localhost:8180/ignite-admin-theme/
ProxyPass /ignite-shop-theme/ http://localhost:8180/ignite-shop-theme/
ProxyPass /metro-theme/ http://localhost:8180/metro-theme/
ProxyPassReverse /images/ http://localhost:8180/images/
ProxyPassReverse /resources/ http://localhost:8180/resources/
ProxyPassReverse /ordermgr-js/ http://localhost:8180/ordermgr-js/
ProxyPassReverse /base-theme/ http://localhost:8180/base-theme/
ProxyPassReverse /bootstrap-theme/ http://localhost:8180/bootstrap-theme/
ProxyPassReverse /foundation-shop-theme/ http://localhost:8180/foundation-shop-theme/
ProxyPassReverse /foundation6-theme/ http://localhost:8180/foundation6-theme/
ProxyPassReverse /ignite-admin-theme/ http://localhost:8180/ignite-admin-theme/
ProxyPassReverse /ignite-shop-theme/ http://localhost:8180/ignite-shop-theme/
ProxyPassReverse /metro-theme/ http://localhost:8180/metro-theme/

# Scipio apps
ProxyPass /accounting http://localhost:8180/accounting
ProxyPass /admin http://localhost:8180/admin
ProxyPass /cms http://localhost:8180/cms
ProxyPass /commonext http://localhost:8180/commonext
ProxyPass /content http://localhost:8180/content
ProxyPass /humanres http://localhost:8180/humanres
ProxyPass /manufacturing http://localhost:8180/manufacturing
ProxyPass /marketing http://localhost:8180/marketing
ProxyPass /order http://localhost:8180/order
ProxyPass /party http://localhost:8180/party
ProxyPass /product http://localhost:8180/product
ProxyPass /securityext http://localhost:8180/securityext
ProxyPass /setup http://localhost:8180/setup
ProxyPass /shop http://localhost:8180/shop
ProxyPass /workeffort http://localhost:8180/workeffort
ProxyPassReverse /accounting http://localhost:8180/accounting
ProxyPassReverse /admin http://localhost:8180/admin
ProxyPassReverse /cms http://localhost:8180/cms
ProxyPassReverse /commonext http://localhost:8180/commonext
ProxyPassReverse /content http://localhost:8180/content
ProxyPassReverse /humanres http://localhost:8180/humanres
ProxyPassReverse /manufacturing http://localhost:8180/manufacturing
ProxyPassReverse /marketing http://localhost:8180/marketing
ProxyPassReverse /order http://localhost:8180/order
ProxyPassReverse /party http://localhost:8180/party
ProxyPassReverse /product http://localhost:8180/product
ProxyPassReverse /securityext http://localhost:8180/securityext
ProxyPassReverse /setup http://localhost:8180/setup
ProxyPassReverse /shop http://localhost:8180/shop
ProxyPassReverse /workeffort http://localhost:8180/workeffort

# "Blocked" apps (uncomment to expose)
# ProxyPass /solr http://localhost:8180/solr
# ProxyPassReverse /solr http://localhost:8180/solr

#11

Hey there,

thanks for the update. As a quick feedback, some of our clients do use apache instead of nginx and have had no problem setting it up, so I know it is doable.

That said, I will check back with one of our sys admins tomorrow on this to check for aparent issues in the way you set up. Perhaps you can send me your full apache config via email? On a first glance it seems odd that you are neither using RewriteRules or multple VirtualHost entries for any of this. You are also missing some more of the configurations we are using for nginx, some of them are vital for the system to fully work.

@rentonize Perhaps you can also check this out tomorrow?


#12

On this part in particular: you are not really using the regular expressions correctly. Since you are mapping anything /images/ against http://localhost:8180/images/, it will overlap with your other configurations. I think if you pass your larger apache config to us via email, I am sure we are able to help out on this.


#13

Great! Thanks. I’ll send my conf files. Using locations, virtual hosts, etc maybe needed. I have avoided that on this server, and been able to get away with just a few entries to pull this off for other apps, but I’m be happy with whatever works.


#14

Hi @BuvinJ,

received the config files, thanks. Since Apache doesn’t seem to do anything else in your case, I’d deploy a more lightweight solution with HAProxy.

Your instance already listens on localhost:8180, so the following /etc/haproxy/haproxy.cfg should work once you replace $_EXTIFACE with the IP of your external interface.

global
    daemon
    maxconn 2048
    tune.ssl.default-dh-param 2048
    log 127.0.0.1 syslog debug

defaults
    option forwardfor
    option http-server-close

    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms

frontend www-https
    bind $_EXTIFACE:443 ssl crt /etc/haproxy/certs/mydomain.com.pem
    default_backend www-backend

backend www-backend
   server www-1 127.0.0.1:8180 check

You can then rewrite the context path as desired with the reqrep directive, there are some examples over here: http://cbonte.github.io/haproxy-dconv/1.9/configuration.html#4.2-reqrep

If you want to forward http requests to https you basically have to add another frontend but there is a multitude of examples out there, e.g. https://stackoverflow.com/questions/13227544/haproxy-redirecting-http-to-https-ssl

HTH, @rentonize


#15

Thank you @rentonize.

I am not looking to change webservers entirely. You are not quite correct that Apache “does not do anything”. It has precise ciphers defined for the ssl, it has some specific authentication via mysql hooks setup. It has SELinux settings related to it in the background. I have vast custom written documentation on doing many things with it (that I can just reference and drop into place), and a collection of other servers using it as well, which I want to keep in sync. Changing that would represent dramatically more work then it appears on the surface, and not everything is only about myself, but the common skills of other coworkers and/or third parties.

Apache is the basic “standard” web server built-in to most Linux distros. Yes there are better alternatives, but I’d like to stay with most common backbone software until I don’t have much else of a choice. BTW, is “Apache Tomcat” and/or “Apache OfBiz” not cousins with “Apache”?


#16

Hi @BuvinJ,

I misinterpreted “I’m be happy with whatever works.” then obviously and will have another look. I’ll get back to you.

BTW, is “Apache Tomcat” and/or “Apache OfBiz” not cousins with “Apache”?

They are both Apache Software Foundation projects, that is correct.

Best, @rentonize


#17

Sorry! I don’t mean to be a pain.

I wasn’t clear. I meant whatever works within the parameters of still using Apache (i.e. virtual hosts, locations, rewrite rules, etc.).

With OFBiz being directly related to Apache, and Apache being so commonly used in this fashion, I’m really surprised this is not a front and center part of the standard OFbiz design and documentation! They provide and discuss ajp, yet not a context path?


#18

Yeah, you’d think so… But when it comes to the inner workings of the OFBiz community, it is all a mystery sometimes.

Regardless, like I mentioned before, we do have clients working with Apache Webserver. We usually recommend nginx, but Apache also works just fine. It is just that we don’t have a sample template for you ready, since our clients usually leave this part of the configuration to their sys-admins.

Regardless though, I agree that there is no harm in providing others with templates, and I plan on updating the website with it sometime in the near future.

As for you: I am sure we can send you a quick configuration example in the next 24-48 hrs…


#19

Thanks Paul! That time frame is plenty soon enough for me.

I wish I had nginx as my default, go to. Instead, I have myself bound up in further complexities using typical LAMP stacks.

I’m sure providing a template like this for Apache will be helpful for you in the long term. Documentation is almost on par with the quality of the software for some sales prospects.


#20

Ok, so by using a Subdirectory structure, the case becomes a lot trickier than initially expected. Since our internal macros to generate urls can sometimes generate relative urls (even when a static domain is set) there is the possibility of urls not being generated correctly. That is a common problem with applications like this, but admittedly it would be better if we took care of this internally. I will create an internal ticket for this and we will provide an update on this soon.

As a workaround, you can rely on mod_proxy_html to fix this on the apache side (there is a downside, as you won’t be able to gzip compress html pages from within scipioerp, but hey at least it works).

So give the following config a try in your SSL config:

<VirtualHost localhost:443>
	ErrorLog "${INSTALL_DIR}/logs/apache_error.log"
	CustomLog "${INSTALL_DIR}/logs/access.log" common
	
	SSLEngine on
	SSLProxyEngine on
	ServerName localhost
	SSLCertificateFile "C:/wamp64/bin/apache/apache2.4.33/certificate.crt"
	SSLCertificateKeyFile "C:/wamp64/bin/apache/apache2.4.33/private.key"
	
	# Redirect to trailing slash urls
	RewriteEngine On
	RewriteCond %{REQUEST_URI} ^/(staff/scipio)$
	RewriteRule ^(.*)$ https://%{HTTP_HOST}$1/ [R=301,L]

	# Settings for Apache Reverse Proxying
	ProxyRequests Off	  
	ProxyPreserveHost On
	# Set RequestHeader to always transport as https - we will terminate ssl for the actual proxy
	RequestHeader set X-Forwarded-Proto "https" early 
	
	# Proxy from subdirectory https://localhost/staff/scipio/ to scipio server 
	# Replace /staff/scipio/ with own path
	<LocationMatch ^/staff/scipio/(.*)$>
	  # Proxy pass to scipioserver - replace localhost with scipio instance
	  ProxyPassMatch  http://127.0.0.1:8080/$1
	  ProxyPassReverse http://127.0.0.1:8080/$1
	  
	  # Set cookies for proper session handling
	  ProxyPassReverseCookiePath / /
	  ProxyPassReverseCookieDomain / /
	  
	  # Fix relative urls - replace https://localhost/staff/scipio/ with proper path
	  SetOutputFilter proxy-content
	  RequestHeader unset Accept-Encoding
	  ProxyHTMLEnable On
	  ProxyHTMLExtended On
	  ProxyHTMLURLMap ^(?!//.*)/(.*)$ https://localhost/staff/scipio/$1 R
	</LocationMatch>
 
</VirtualHost>

You will have to enable mod_ssl, mod_proxy, mod_proxy_html, mod_rewrite for this to work. Adapt to your own configuration.

In addition: Inside of your framework/webapp/config/url.properties you should set the following:

	# HTTPS Port (Secure port)
port.https.enabled=Y
port.https=443
force.https.host=localhost/staff/scipio/

# HTTP Port (Not Secure port)
port.http=8080
force.http.host=localhost/staff/scipio/

# SCIPIO: if set to Y, the ports and hosts above have priority over the information in the current request when building links.
# Otherwise, they are only used as defaults/fallbacks, if request values not present/applicable.
# Default: N (current request values have priority)
# NOTE: the scipio default ("N") is different from the implicit stock Ofbiz default ("Y").
# NOTE: this does not control values from WebSite entity; currently WebSite entity always override values above AND from request.
override.request.host.port=Y

There may still be a few issues - in particular with relative urls used inside of the themes, so if you find any issues there, you may have to recompile or string replace the /base-theme/ or /metro-theme/ paths in there and replace with your own paths.

I will update this thread once we implemented a fix for relative urls in general, it will simply the above configuration significantly.