Apache proxyPassReverse and Websockets - apache

I've been working on a Perl Mojolicious project that uses websockets. I'm wanting to launch it on a shared server running apache and use proxyPass and proxyPassReverse to make the url prettier for my Mojolicious code running with Hypnotoad.
I have it set up as follows.
Apache url:
mydomain.com
Hypnotoad url:
mydomain.com:8080
With the following apache entry I can reverse proxy the Hypnotoad server to
project.mydomain.com
apache.conf entry
<VirtualHost *:80>
ServerName project.mydomain.com
DocumentRoot /var/www/project
<Directory /var/www/project/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://mydomain.com:8080/ keepalive=On
ProxyPassReverse / http://mydomain.com:8080/
RequestHeader set X-Forwarded-HTTPS "0"
</VirtualHost>
However my websocket requests give a 404 error when I use:
ws://project.mydomain.com/get-data
and a 302 error when I use:
ws://mydomain.com:8080/get-data
I guess this wouldn't be a problem is the websocket didn't check for authentication, but they use Mojolicious routes to check that you can post via the websocket.
From what I can see Apache doesn't support reverse proxying websockets. In apache/httpd conf files.
Has anyone found a usable solution to this using Apache that is stable for a production environment?

In March a patch was committed to the Apache trunk by Jim Jagielski which allows websockets to be proxied correctly. The patch adds a new submodule called proxy_wstunnel which allows mod_proxy to work with the "ws" and "wss" protocols.
The module is not yet in any official Apache releases (as of June 8th 2013), so you will need to compile it yourself. Voyageur's blog describes the process for Apache 2.2, but it should be easier for Apache 2.4

Apache httpd 2.4.6 includes proxying websocket requests.

Related

What is OrientDB's DocumentRoot? Or, where are OrientDB's web files?

I am attempting to access OrientDB's REST API through a reverse proxy. That is, I have a domain orientdb.mydomain.com that forwards to localhost:2480, where the server is. I have this working on the unsecured website, so I can access http://orientdb.mydomain.com and it brings up the studio site:
http://orientdb.mydomain.com/studio/index.html
However, this does not work through https. I get a 404 error ("The requested URL /studio/index.html was not found on this server")
I have a feeling that I'm not using the correct documentroot or there is something funny about OrientDB that it's generating the path above in another way. I cannot actually find this /studio directory anywhere.
This is from my virtualhost setting in my ssl.conf file.
<VirtualHost _default_:443>
DocumentRoot "/opt/orientdb-3.0.6/www"
<Directory "/opt/orientdb-3.0.6/www">
Require all granted
</Directory>
ServerName orientdb.mydomain.com
#more stuff
</VirtualHost>
By the way, I originally had the following options in my Directory tag, but it gave a forbidden error. I changed it to Require all granted and it now says not found- so I think I'm making progress.
AllowOverride All
Order allow,deny
In summary, is it possible to access the OrientDB server in this way and if so what do I put as DocumentRoot, etc?
I don't think you can do that.
OrientDB has its own HTTP server embedded so the only way it can work is with the reverse proxy configuration.
You can expose your web server (apache HTTP I guess) in https and terminate the "s" there, proxying to orientdb HTTP port (2480).
This turned out not to be an OrientDB issue, but a proxy issue. I had used a virtualhost to set up the proxy on port 80, but I did not do the same for port 443. After adding these settings to my 443 virtualhost on orientdb.mydomain.com, I was able to access the studio and the HTTP REST API through HTTPS.
ProxyPass / http://127.0.0.1:2480/
ProxyPassReverse / http://127.0.0.1:2480/
<Proxy *>
Require all granted
</Proxy>

Reverse proxy for external URL - Apache

I configured my apache so that it can forward my requests to external URL like google.com, but the reverse proxy doesn't work.
<VirtualHost *:443>
ServerName authtest.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
<LocationMatch "/google">
ProxyPass https://www.google.com/
ProxyPassReverse https://www.google.com/
</LocationMatch>
</VirtualHost>
Is it possible for me to reverse proxy external websites?
Is it possible for me to reverse proxy external websites?
Yes but with significant downsides.
Note: when I tried your configuration, I got SSL Proxy requested for [...] but not enabled [Hint: SSLProxyEngine] in the logs so I added SSLProxyEngine on.
Host issue
When you make a HTTP/1.1 request to a server, you automatically add the hostname in the request. When you proxy them, you have two possibilites:
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: authtest.com)--> Google
or
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: google.com)--> Google
The first one is what you get with ProxyPreserveHost On. Google servers won't handle requests for authtest.com, you should remove this line.
Even in the second case, you can have issues. ProxyPassReverse will handle redirects but only for the given domain: I'm in France, google.com redirects me to google.fr (a different domain) and the reverse proxy doesn't rewrite the redirect.
An other issue is the referer: if a service sees requests for images/css/js coming from a different web site it may consider it as bandwidth leeching and block them. Now, you need to rewrite the html of the response too (mod_proxy_html will help but it's not a silver bullet).
Path issue
In your example, you proxy <authtest>/google to <google>/. Like above, you need to rewrite the html: absolute links/resources won't work unless your server adds /google everywhere. Same for relative links/resources (but with more edge cases). If you owned the backend server, you could have checked urls in html/css/js files. Here, if the url is built dynamically in the browser using js you can't do anything.
If you can proxy / to / (or /whatever to /whatever) you will avoid a lot of issues here.
Chech this GIT Repo
I forked a GIT Repo and customized it to work with scenario:
[browser] --(Host: google.local)--> [apache proxy] --(Host: google.nl)--> Google
The Apache config as follows:
<VirtualHost *:80>
ServerName google.local
SSLProxyEngine on
ProxyRequests Off
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
ProxyPass / https://www.google.nl/
ProxyPassReverse / https://www.google.nl/
ErrorLog /var/log/apache2/google.local-error.log
CustomLog /var/log/apache2/google.local-access.log combined
</VirtualHost>

How to run IPython behind an Apache proxy

I would like to run an IPython notebook web server behind an Apache (reverse) proxy so that instead of the URL
https://my.server:XXXX
(where XXXX is some port number) I could use
https://my.server/py0
I am aware that IPython uses websockets and I suspect this is the part that is missing from my setup, but I simply could not find a suitably detailed description on how to configure this. Unfortunately the IPython webserver setup docs don't have much to say regarding proxies apart from this:
When behind a proxy, especially if your system or browser is set to
autodetect the proxy, the notebook web application might fail to
connect to the server’s websockets[...]
So I decided to try it on my own and put the following in /etc/apache2/sites-enabled/default-ssl.conf :
SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
ProxyPass /py0/ https://localhost:10000/
ProxyPassReverse /py0/ https://localhost:10000/
Accessing IPython "directly" over the URL https://my.server:10000 works perfectly as advertised.
The URL https://my.server/py0 (without a trailing slash) returns "404 Not found".
The same with a trailing slash https://my.server/py0/ does "work" in that it forwards to https://my.server/login?next=%2F, which is then "Not found" in its own right -- obviously because the /py0/ part got lost. Maybe I should tell IPython about it but how ??
Perhaps relevant version numbers: Ubuntu 14.04 LTS, Apache 2.4.7.
Perhaps relevant SO question: IPython behind nginx. However, since everything else in my setup is handled by Apache to my full satisfaction, I do not want to run Nginx in addition.
Is there any good soul out there who has successfully configured IPython notebook web servers behind Apache? If yes, then please step forward and share your knowledge :-) Many thanks!
I got this working using the following setup.
IPython
IPython Notebook is listening at http://localhost:8888/ipython. It was necessary to add the /ipython prefix, because IPython uses absolute paths, so it must be the same as the reverse proxied path.
The ipython_notebook_config.py
c = get_config()
c.NotebookApp.ip = 'localhost'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8888
c.NotebookApp.base_url = '/ipython'
Apache
I enabled
mod_proxy
mod_proxy_http
mod_proxy_wstunnel
In the apache config I added
<Location /ipython>
ProxyPass http://localhost:8888/ipython
ProxyPassReverse http://localhost:8888/ipython
ProxyPassReverseCookieDomain localhost my.server.com
RequestHeader set Origin "http://localhost:8888"
</Location>
<Location /ipython/api/kernels/>
ProxyPass ws://localhost:8888/ipython/api/kernels/
ProxyPassReverse ws://localhost:8888/ipython/api/kernels/
</Location>
to an SSL enabled virtual host definition.
The RequestHeader set Origin "http://localhost:8888" was necessary for the websockets, otherwise you get a 403 Forbidden.
Now IPython is reachable at https://my.server.com/ipython (no trailing /!).
WARNING: This is rather verbose, as I gather you have figured much of this, but for documentation purposes, I laid out enough detail here for someone else to follow.
I put this answer together after implementing this myself with the help from various links. The first from here Websocket origin check fails when used with Apache WS proxy #5525. I repeat much of it here with some changes. Other links are referenced below.
1. Set up iPython:
This is in the post, but rather than do it as the original post suggested, I just followed the general instructions for Running a notebook server. With this done you should be able to test the setup, which will require enabling the port you have this configured for. If this does not work, then any Apache set up will not work.
2. Configure Apache:
Make sure you have the following mods available and enabled.
./configure --enable-proxy --enable-ssl --enable-deflate --enable-proxy-http --enable-proxy-wstunnel --enable-info --enable-rewrite --enable-headers
Added --enable-headers here as they were not installed on mine. Also I used the Apache2 a2enmod command. So sudo a2enmod headers, sudo a2enmod proxy, etc.
If you're running a version of Apache prior to 2.4, you do not have the proxy_wstunnel mod. You can either a patch your version or upgrade. To patch your version, you can follow these instructions. Be sure to copy over both mod_proxy.so and mod_proxy_wstunnel.so. To get the configure script, you need to run ./buildconfig, which has its own dependencies. This is noted in a comment therein.
Within Apache, create a "sites-available/iPython.conf" file. Originally I said to either add to httpd.conf or ports.conf. Adding your own site file is much cleaner and will allow you to enable/disable the configuration when desired.
Listen [ANY PORT HERE] # post has port 8999 here...
...
<VirtualHost *:[ANY PORT HERE]>
SSLProxyEngine On # post did not have this...
ProxyPass / http://127.0.0.1:8888/
ProxyPassReverse / http://127.0.0.1:8888/
# spoof headers to make notepad accept the request as coming from the same origin
Header set Origin "http://127.0.0.1:8888/"
RequestHeader set Origin "http://127.0.0.1:8888/"
LogLevel debug
</VirtualHost>
NOTE 1: The post uses port 8999, but it can be any port you want. You want port 80 here, but you do not need to specify it, so, modifying the above would yield:
<VirtualHost *:80>
... # Everything is the same here...
</VirtualHost>
NOTE 2: Since you are using SSL, you need to add SSLProxyEngine On within the body of the VirtualHost definition. As noted above, the post did not have this specifically.
NOTE 3: Port 8888 is whatever port ipython is running on. Change this based on your configuration.
NOTE 4: If you want to host multiple applications, and this is one of them, rather than having / and :8888/, you will want /ipython and :8888/ipython or whatever you want this to be named. In order to support this, see Running with a different URL prefix.
Enable the new configuration:
sudo a2ensite iPython
If you need to disable:
sudo a2dissite iPython
Reload Apache:
sudo service apache2 reload
My Environment:
Ubuntu 14.04.1
Apache 2.4.7
ipython 2.3.0
EDIT: Updated to reflect the final changes I made to get this working. I also changed the instruction order to what I think makes more sense.
Based on Apache's config of #adam, I'm putting here a full SSL-aware <VirualHost> sections but without the /ipython prefix, and i'm giving also the SSL-options for anyone interested:
<VirtualHost *:80>
ServerAdmin myname#my.place.com
ServerName some.server.com
SSLEngine off
Redirect permanent / https://some.server.com
</VirtualHost>
## From http://stackoverflow.com/questions/23890386/how-to-run-ipython-behind-an-apache-proxy
#
<VirtualHost *:443>
ServerAdmin myname#my.place.com
ServerName some.server.com
SSLEngine on
SSLCertificateFile some_server_com.crt
SSLCertificateKeyFile some_server_com.key
<Location />
ProxyPass http://localhost:8888/
ProxyPassReverse http://localhost:8888/
ProxyPassReverseCookieDomain localhost some.server.com
RequestHeader set Origin "http://localhost:8888"
</Location>
<Location /api/kernels/>
ProxyPass ws://localhost:8888/api/kernels/
ProxyPassReverse ws://localhost:8888/api/kernels/
</Location>
Redirect permanent / https://some.server.com
</VirtualHost>
This works for jupyter and password hash:
<VirtualHost *:443>
ServerName default
ProxyPreserveHost On
ProxyRequests off
SSLProxyEngine on
SSLEngine on
SSLProtocol TLSv1
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLCertificateFile /home/ubuntu/.certs/mycert.pem
ProxyPass /notebook/terminals/websocket/ wss://localhost:9999/notebook/terminals/websocket/
ProxyPassReverse /notebook/terminals/websocket/ wss://localhost:9999/notebook/terminals/websocket/
ProxyPass /notebook/api/kernels/ wss://127.0.0.1:9999/notebook/api/kernels/
ProxyPassReverse /notebook/api/kernels/ wss://127.0.0.1:9999/notebook/api/kernels/
ProxyPass /notebook https://127.0.0.1:9999/notebook
ProxyPassReverse /notebook https://127.0.0.1:9999/notebook
</VirtualHost>
On newer versions of IPython/Jupyter that have a terminal you also need to add entries for terminals.
<Location /ipython/terminals/websocket/>
ProxyPass ws://localhost:8888/ipython/terminals/websocket/
ProxyPassReverse ws://localhost:8888/ipython/terminals/websocket/
</Location>
I'm using apache version 2.4.18 in a server running Ubuntu 16.04.1 LTS(xenial)
and finally I have my jupyter notebook running through ssl.
I had already configured the standard SSL on my server, so https:// was working. I had also followed this instructions: Running a notebook server to get my cert file and my password in the jupyter_notebook_config.py configuration file. What I was missing was:
c.NotebookApp.allow_origin = '*'
c.NotebookApp.base_url = '/SomeName'
The apache configuration file that worked for me using solutions from several places and part of the answers here was:
SSLProxyEngine on
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
<Location "/SomeName">
ProxyPass https://localhost:XXXX/SomeName
ProxyPassReverse https://localhost:XXXX/SomeName
</Location>
<Location "/SomeName/api/kernels">
ProxyPass wss://localhost:XXXX/SomeName/api/kernels
ProxyPassReverse wss://localhost:XXXX/SomeName/api/kernels
</Location>
<Location "/SomeName/terminals/websocket">
ProxyPass wss://localhost:XXXX/SomeName/terminals/websocket
ProxyPassReverse wss://localhost:XXXX/SomeName/terminals/websocket
</Location>
where XXXX is the port you are using, e.g. 8888, and SomeName could be any name you want.
I hope this can help.

What are my options to deploy Go applications alongside PHP applications?

What I'm basically trying to accomplish is having my main website running a CMS written in Go. This will be located at www.example.com.
I also have applications written in PHP located in directories, such as www.example.com/clients/
How can I serve example.com/clients using Apache/PHP while serving example.com using Go built-in web server?
Via mod_proxy in Apache2, you can proxy different paths into different destinations at localhost or anywhere else accessible by your server, including within your local network (if your server can access it).
For this you would use ProxyPass (Apache2 Docs for ProxyPass, which is very useful reading) like the example below:
<VirtualHost *:80>
ServerName some.example.host.xyz
DocumentRoot /var/www/your-document-root
Alias /clients/ /var/www/clients/
ProxyPass /clients/ !
ScriptAlias /something-using-cgi/ /var/www/cgi-stuff/
ProxyPass /something-using-cgi/ !
ProxyPreserveHost On
ProxyPass / http://localhost:9876/
ProxyPassReverse / http://localhost:9876/
ProxyPass /elsewhere/ http://elsewhere.example.host.xyz:1234/
ProxyPassReverse /elsewhere/ http://elsewhere.example.host.xyz:1234/
</VirtualHost>
You'll want to be sure that you set your proxy security such that external users can't use your reverse proxy as a forward proxy, too. You can do that via ProxyRequests as described in the official Apache2 docs. The way I did this on a server is to put this in your server-wide config (you should verify on your own that this is secure enough):
# disables forward proxy
ProxyRequests Off
Andrew Gerrand has a good blog post about this for nginx but the principle is the same for Apache.
You want to set up Apache as a reverse proxy for requests coming in for the Go application.
For Apache you want to look at mod_proxy

Apache VirtualHost with mod-proxy and SSL

I am trying to setup a server with multiple web applications which will all be served through apache VirtualHost (apache running on the same server). My main constrain is that each web application must use SSL encryption. After googling for a while and looking other questions on stackoverflow, I wrote the following configuration for the VirtualHost:
<VirtualHost 1.2.3.4:443>
ServerName host.domain.org
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
SSLProxyEngine On
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / https://localhost:8443/
ProxyPassReverse / https://localhost:8443/
</VirtualHost>
Even though https://host.domain.org:8443 is accessible, https://host.domain.org is not, which defeats the purpose of my virtual host configuration. Firefox complains that even though it successfully connected to the server, the connection was interrupted. Chrome return an error 107: net::ERR_SSL_PROTOCOL_ERROR.
Finally I should also mention that the virtual host works perfectly fine when I do not use SSL.
How can I make this work ?
Thanks
You don't need to configure SSL in both Apache and Tomcat.
The easiest way to accomplish that is configure SSL just on Apache and proxy to tomcat using http.