Access web based applications using an alias instead of a port



  • Currently, I have a number of applications that run on a server on the LAN that are accessed by typing the IP of the server and the associated port of the application. So if application 1 has port 8080 and application 2 has port 9090, I would access them by typing <ip of="" server="">:8080 for app 1 and <ip of="" server="">:9090 for app 2.

    My question is, is it possible to create an alias for an application that takes into account the port number, so that the users can just enter <app alias="">or <app alias="">.mydomain.net into the browser and be redirected into that app? I've search online and it looks like HAProxy, Apache and maybe eve Squid can do that, but I'm not sure which one I should use and which package I should install (there are numerous packages for each of those apps on the pfSense package list>.</app></app></ip></ip>



  • Are all the 'applications' http/https websites?
    Or are there also other kind of services involved.? (that would probably make it impossible.)
    In case your going with haproxy, i advice to use the 1.5 version.
    As for the first part getting the name yourapp.domain.net to resolve to an ip you would need to configure the dns-forwarder host overrides.



  • All the applications are HTTP web apps that are running on different ports. No services involved.

    Are there any instructions as to how I would use HAProxy to achieve that?

    All the devices are already under domain.net since pfSense is sending out DHCP leases with that info. So I can go to <server name="">: <app port="">or <server name="">.domain.net: <app port="">and I'll achieve the same result.</app></server></app></server>



  • No ready to use instructions that i know off..

    probably this could work:
    1-add a vip - ipalias on pfsense to give it a second ip on the lan (not absolutely required, but making it listen on lan might hinder webgui access..)
    2-configure dnsforwarder with hostoverides for all applications to point names to the ip(1)
    3-in haproxy configure backends for each application configure the server on the ip:port they use
    4-in haproxy configure 1 frontend that listens on the ip (1) and on port 80
    5-in haproxy configure additional 'shared' frontends and add a acl that checks the hostname(2) and the sends traffic to the right backend(3)



  • I followed what you said and setup a Backend with all the apps and their associated ports (I've left the rest black/defaults since I wasn't sure what to put in there). I've setup a Frontend with External Port 80 and ACL with "Path contains" with the application port (the rest is black/defaults). It doesn't allow me to select a Shared Frontend (it just says "At least 1 primary frontend is needed.), and when I try to start HAProxy, it says that it can't bind to address 0.0.0.0:80.

    What am I doing wrong?



  • As the webgui (lighttpd process) is probably also bound to 0.0.0.0:80 it wont work when two processes are trying to bind the same ip:port combination.

    In the haproxy frontend configuration you can select the ipalias from (1) in the 'External address' field. That should allow you to start haproxy.

    Then add a 'second' frontend, but select the 'Shared Frontend' checkbox, select the primary frontend to use. (there is probably only 1)
    Select the backendserverpool for app2, and add a acl with name:MyACL Expression:HostMatches value: <appalias2>.mydomain.net</appalias2>



  • So this is what I have so far, and I still can't get it to work (I get a 503 error):







    ![Shared Frontend.png](/public/imported_attachments/1/Shared Frontend.png)
    ![Shared Frontend.png_thumb](/public/imported_attachments/1/Shared Frontend.png_thumb)
    ![All frontends.png](/public/imported_attachments/1/All frontends.png)
    ![All frontends.png_thumb](/public/imported_attachments/1/All frontends.png_thumb)



  • Check on the stats tab if the backend servers are reported as 'up' (you might also want to configure the 'Health check method' on the backend to perform a HTTP check), also a weight of 1 on the server might help though should not be needed. Other than that the config looks good i think. That port 8081 is correct i presume.? (as you mentioned 8080 before)



  • So I figured out what the problem is. To login to the different applications, you must enter a username and a password (it's a popup box that comes up in the browser as soon as you load the page). Is there a way to pass the credentials to the application?

    Also, once I start adding more apps, what do I select for the "Backend server pool" for the main and shared frontends, if each app is a different backend/backend pool?



  • So the server is in 'red' on the stats page right?  What value does the LastChk column in the stats show?
    And what does it say when you hover over the text with your mouse.?

    When using healthcheck method 'HTTP' you can use something like this in the field "Http check version":

    HTTP/1.1\r\nHost:\ app1.mydomain.local\r\nAccept:\ */*\r\nAuthorization:Basic\ YWRtaW46cGFzcw==
    

    Check what parts are needed and what can be skipped..

    Also you might want to set the http check method to GET, if your server doesnt respond to OPTIONS.

    For that last part use check what headers your browser sends when you login, or encode it with other means to Base64. If you decode the above it will say "admin:pass"



  • Your "Http check version" advice got everything to be green!  Everything works correctly and I can type "app1" in the browser and it brings me to app1.  ;D

    I have a few questions:

    1. The apps that have a username/password pop work great. But apps that ask you to login inside a webpage, do not (they're green in the stats window, but I had to change the check method to GET). When I type that app's name in the browser, it doesn't find it. I even tried to disable the login requirement.

    2. Is there any way to pass credentials into the browser (so that when I type "app1", it already passes the credentials in and doesn't ask me for them)?

    3. Some of the apps are located in <server ip="">/app. Is there a way to specify the folder location in HAProxy (not just the server IP) and do the same thing?</server>



    1. i dont fully understand what the problem is, basically the browser requests should just get forwarded to the webserver if all conditions are met.
      -you have configured a dns hostoverride for the name in dnsforwarder?
      -you have a acl that uses hostmatches with the same name as what you type in the browser?
      -does haproxy return a error page?
      -what does the browser say exactly? that it cant connect to the webserver or that it didnt get a reply? or what?

    2. you might be able to add a header with credentials, though basically defeats the purpose of having a login at all doesn't it?
      Place this into the 'Backend pass thru':

    http-request add-header Authorization:Basic YWRtaW46cGFzcw==
    
    1. you might be able to rewrite the requests, however make sure that links generated in the body of reply's are returned to the client 'correctly'. So they must either be 'relative links', or must take into account the user will be using a different url. HAProxy will not change the body contents of a reply..
    reqirep  ^([^\ :]*)\ /(.*) \1\ /app1/\2
    

    If the reply url's dont work anymore you might have some luck with this, as it allows the app1 path to be requested directly by the browsers:

    acl    no_redir url_beg   /app1/
    reqirep  ^([^\ :]*)\ /(.*) \1\ /app1/\2 if !no_redir
    


  • Where do I add the lines for #2 and #3?

    I've added the applications that are in a directory and one has a LastChk "Layer 7 wrong status: ERROR" and the other has  "Layer 7 wrong status: Not Found". Both of them give a 503 error when I type them into the web browser.



    1. Define what "applications" we are talking about. Simple websites? Tied to a database?

    2. Why is everything listening on a different port?



  • These are applications that are used through a web UI (you access them through the website. They do have databases, but those are internal ones (they store everything in internal .db files and config files).

    They have different ports because everything is running on one server. None of this would have been an issue if I had multiple servers, but unfortunately, I do not.



  • Tear everything down, and I do mean everything. From the servers, to haproxy. I can't believe no one asked these questions before diving into haproxy. haproxy is for failover/loadbalancing multi-thousand visitors per second, not this use case.

    Start from the start using virtual hosts for the websites, all running on the same port. Both apache and nginx can do this easily. duckduckgo (or google) for virtual hosts.

    Unless running XP <sp3, use="" sni="" for="" ssl="" (don't="" be="" scared,="" it's="" just="" an="" extra="" line="" in="" the="" config="" each="" website).="" you="" don't="" need="" a="" different="" ip="" every="" site.="" again,="" duckduckgo="" is="" your="" friend.<br="">When you are done with setting up the server, (and did I mention uninstall haproxy?) go into the DNS forwarder and set up the forwards:

    domain          IP
    subdomain1.domain.com    192.168.1.10
    subdomain2.domain.com    192.168.1.10
    etc…etc... replacing subdomains, domains and IPs with your needed configurations.

    That should give you what you are looking for, with a lot less time spent on your part, time which was spent learning something new, as opposed to figuring how stuff works.</sp3,>



  • In my opinion Haproxy is a perfectly valid option for small sites needing some 'smart' switching to different webservers even with only small amounts of visitors, and has very little overhead. Though i agree, if everything is running on 1 webserver, and you have good control over that 'virtual hosts' does sound good. However if your running some other 'websites' like Outlook Web Access, together with some other applications integrated websites, together with a normal iis website, together with a apache website. It might not be easy to put it all together using virtual hosts.. I dont know what and why its running the way it currently is.. I assumed there was a good reason for it, maybe i was wrong..

    As my response for getting it to work in haproxy, all the 'code' can be put into the 'Backend pass thru'.

    For the layer7 errors, what happens if you directly visit those servers with a browser "http://<server>:8081/" ? Do you also get an error? What do you need to do to resolve that issue ? If http://<server>:8081/app1/ does 'work' then you must make sure that the httpchk also uses that url to perform the checks fill in the 'Http check URI' with '/app1/'

    Those 'errors' are returned by the webserver, so make sure you know what is needed in the request to get a valid response.. Try with curl to query the website yourself and find what is needed to get a '200' response.

    As long as the health checks say the server is 'down' haproxy wont allow any clients to connect so the 503 response is valid for those situations..

    As a workaround you might set for example "http-check expect status 404". Though that increases the risk of haproxy falsely identifying the backend as 'up'.. Or you might go back to healthcheck method 'basic' which only does a TCP connect&disconnect..</server></server>


  • Netgate Administrator

    Using a reverse proxy that can read host-headers is a common solution to this problem. Not the only one though.

    Steve



  • @jflsakfja:

    Tear everything down, and I do mean everything. From the servers, to haproxy. I can't believe no one asked these questions before diving into haproxy. haproxy is for failover/loadbalancing multi-thousand visitors per second, not this use case.

    Start from the start using virtual hosts for the websites, all running on the same port. Both apache and nginx can do this easily. duckduckgo (or google) for virtual hosts.

    Unless running XP <sp3, use="" sni="" for="" ssl="" (don't="" be="" scared,="" it's="" just="" an="" extra="" line="" in="" the="" config="" each="" website).="" you="" don't="" need="" a="" different="" ip="" every="" site.="" again,="" duckduckgo="" is="" your="" friend.<br="">When you are done with setting up the server, (and did I mention uninstall haproxy?) go into the DNS forwarder and set up the forwards:

    domain          IP
    subdomain1.domain.com    192.168.1.10
    subdomain2.domain.com    192.168.1.10
    etc…etc... replacing subdomains, domains and IPs with your needed configurations.

    That should give you what you are looking for, with a lot less time spent on your part, time which was spent learning something new, as opposed to figuring how stuff works.</sp3,>

    Using VirtualHosts was actually my first choice. The issue was that I wasn't able to find a way to just forward ports on an application. All the documentation that I've found kept asking me for the directory where the website is. Since this is an application with a web frontend, I was never able to get it to work (I WAS able to get it to work when I had multiple websites in different directories running on Apache). If you know of a way of getting around that (I'm sure that I'm just missing something), I'd be more than happy for any guidance.

    As my response for getting it to work in haproxy, all the 'code' can be put into the 'Backend pass thru'.

    For the layer7 errors, what happens if you directly visit those servers with a browser "http://<server>:8081/" ? Do you also get an error? What do you need to do to resolve that issue ? If http://<server>:8081/app1/ does 'work' then you must make sure that the httpchk also uses that url to perform the checks fill in the 'Http check URI' with '/app1/'

    Those 'errors' are returned by the webserver, so make sure you know what is needed in the request to get a valid response.. Try with curl to query the website yourself and find what is needed to get a '200' response.

    As long as the health checks say the server is 'down' haproxy wont allow any clients to connect so the 503 response is valid for those situations..

    As a workaround you might set for example "http-check expect status 404". Though that increases the risk of haproxy falsely identifying the backend as 'up'.. Or you might go back to healthcheck method 'basic' which only does a TCP connect&disconnect..</server></server>

    So for all apps that are just http://<server>:<port>, everything works great once I've implemented your advice. However, websites that are http://<server>:<port>/app, do not work. Those are the ones that are giving me the errors. When I just go to http://<server>: <port>for the corresponding app, I get either a 404 error or an "invalid request". The issue is that I can't figure out how to add the path to HAProxy to tell it where the app is.

    Using a reverse proxy that can read host-headers is a common solution to this problem. Not the only one though.

    Is that something that pfSense has built in?</port></server></port></server></port></server>



  • @Heli0s:

    Using VirtualHosts was actually my first choice. The issue was that I wasn't able to find a way to just forward ports on an application. All the documentation that I've found kept asking me for the directory where the website is. Since this is an application with a web frontend, I was never able to get it to work (I WAS able to get it to work when I had multiple websites in different directories running on Apache). If you know of a way of getting around that (I'm sure that I'm just missing something), I'd be more than happy for any guidance.

    Please define what you mean by "application". A php script can be considered an application. Without knowing more details about what you are trying to do, I can't exactly give sane advice. Not that I do at other times, but I digress  ;D



  • I have a few apps, some are python based, while other are .NET based. They all start by running an executable. They simply have a web frontend as opposed to a "regular" application GUI. Since they're running as a Windows process, I can't really point to a web directory (/www/htdocs/).



  • How are the web front ends rendered? They have to be somewhere that's accessing by the webserver, unless they do their own serving outside the webserver. In that case, put all the frontends in separate directories using virtual hosts, and point them to their required executables. Which is bad, but that's another story. If they do their own serving then this rules out my suggestions.



  • @PiBa:

    If http://<server>:8081/app1/ does 'work' then you must make sure that the httpchk also uses that url to perform the checks fill in the 'Http check URI' with '/app1/'</server>



  • Oops I missed that sentence :) So everything works now! I'm getting a good health check. The issue though is that when I go to http://app1, it takes me to http://<server>:<port>, instead of http://<server>:<port>/app1. Where can I add the /app1 part?</port></server></port></server>



  • Hope this helps, put the code in the 'Backend pass thru':

    Code to change a request from / to /app1/

    reqirep  ^([^\ :]*)\ /(.*) \1\ /app1/\2
    

    If urls in the response contain absolute urls it might be required to use this:

    acl    no_redir url_beg   /app1/
    reqirep  ^([^\ :]*)\ /(.*) \1\ /app1/\2 if !no_redir
    

    The code makes sure that the method and url-path behind the / stays the same. Which method you need exactly might depend on the application thats running.
    For readability of the above how change a request from /app1/ to /app1/app1redir/

    reqirep  ^([^\ :]*)\ /app1/(.*) \1\ /app1/app1redir/\2
    

    If those above dont work you might still be able to get a acceptable workaround by using a redirect:

    acl    no_redir url_beg   /app1/
    http-request redirect location http://%[req.hdr(Host)]/app1/ if !no_redir
    
    

    Actually most of this info can be found in the manual, have you seen it?: http://cbonte.github.io/haproxy-dconv/configuration-1.5.html



  • Everything works great! Thank you so much for all your help!


Log in to reply