Apache ProxyPass with dynamic hostname - linux

I'm trying to use Apache as a gateway to reverse proxy to a backend server with the same name as the requested http_host.
ex:
ProxyPass / https://%{HTTP_HOST}/
ProxyPassReverse / https://%{HTTP_HOST}/
I'm getting an error when I use this setup. Suggestions?

There's no way to dynamically reverse proxy like that using proxy pass. However, you can do it using mod_rewrite's P flag. The same thing with ProxyPassReverse, you can't use the %{HTTP_HOST}, however, since the hostnames are the same as the same, you don't need it at all. Just need:
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [L,P]
One issue you may run into is that since DNS resolves proxying server to some IP, the proxying server must know that the same DNS hostname does not resolve to itself and actually resolves to a backend server (the server to proxy to), otherwise it will cause a loop.

To use Apache ProxyPass directives with dynamic hostnames you will need to also use ModRewrite.
Objective
All requests to the virtualhost will ProxyPass and ProxyPassReverse (also known as an "Apache Gateway") to the %{HTTP_HOST}
The only reason this would make sense to do is if you have localhost entries on the apache server for specfic host names
Examples
Localhost File
10.0.0.2 foo.bar.com
10.0.0.3 bar.bar.com
How it works
The client makes a request to foo.bar.com (dnslookup is a public IP... YOUR APACHE SERVER)
Your apache server has a localhost entry of 10.0.0.2 for foo.bar.com (some other server on your network)
The request goes through ModRewrite and /path1 is appended, then handed off to ProxyPass and ProxyPassReverse
ProxyPass and ProxyPassReverse hand the call off to foo.bar.com at ip 10.0.0.2
Client requests foo.bar.com ---reverse proxies to----> foo.bar.com/path1 (on some OTHER internal server)
Apache Configuration
<VirtualHost *:443>
Servername *
# Must not contain /path1 in path (will add /path1)
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/path1/.*
RewriteRule ^/(.*) https://%{HTTP_HOST}/path1$1 [NC,R=302,L]
# Must contain /path1 in path (will send request to the proxy)
RewriteEngine On
RewriteOptions Inherit
RewriteCond %{REQUEST_URI} ^/path1/.*
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [NC,P]
SSLEngine on
SSLProxyEngine On
ProxyRequests Off
ProxyPass / https://$1/
ProxyPassReverse / https://$1/
ProxyPreserveHost On
###################
# SSL Constraints #
###################
SSLProtocol -ALL +SSLv3 +TLSv1
# Choose cipher suites
SSLHonorCipherOrder On
SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:!LOW:!SSLv2:!EXPORT
# SameOrigin The page can only be displayed in a frame on the same origin as the page itself
Header set X-Frame-Options SAMEORIGIN
SSLCertificateFile /etc/apache2/example.crt
SSLCertificateKeyFile /etc/apache2/example.key
SSLCertificateChainFile /etc/apache2/gd_bundle.crt
SetOutputFilter INFLATE;proxy-html;DEFLATE
</VirtualHost>
source: http://brakertech.com/apache-proxypass-with-dynamic-hostname/

Related

ProxyPass custom port Redirect to https

I would like to grand access to certain IP's to mysite.com:1234 but deny that port to other users and redirect them to port 80 or 443, the first part is working with my vhosts file but I can't seem to get the redirection part working, other IP's get 403 error
<VirtualHost 12.123.123.123:443>
<Directory "/home/mysite/public_html">
Options -Indexes -FollowSymLinks +SymLinksIfOwnerMatch
AllowOverride All
SSLRequireSSL
</Directory>
<IfModule mod_proxy.c>
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
ProxyPass / http://127.0.0.1:1234/
ProxyPassReverse / http://127.0.0.1:1234/
<Proxy "http://127.0.0.1:1234/">
Deny from all
allow from 1.1.1.1
allow from 1.1.1.2
allow from 1.1.1.3
allow from 1.1.1.4
</Proxy>
</IfModule>
One solution would be to implement your proxy rule with mod_rewrite. Rewrite rules have a [P] flag which means "reverse proxy". You could have a rewrite condition that checks for the correct IP addresses before a rule that does the proxy. Then all other requests would fall through to a second rule that does the redirect.
RewriteEngine On
# Reverse proxy for allowed remote addresses
RewriteCond %{REMOTE_ADDR} ^1.1.1.[1234]$
RewriteRule ^/?(.*)$ http://127.0.0.1:1234/$1 [P,L]
# Redirect everything else to the main site
RewriteRule ^/?(.*)$ https://mysite.example/$1 [R=301,L]

Proxyreverse in Apache2 with wordpress

I have installed and configured Wordpress on my server using also apach2 virtualhosts.
I made a virtualhost with this config
<VirtualHost *:80 *:443>
ServerAdmin yourluxuryroad#gmail.com
ServerName yourluxuryroad.com
ServerAlias www.yourluxuryroad.com
DocumentRoot /var/www/yourluxuryroad
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.yourluxuryroad.com [OR]
RewriteCond %{SERVER_NAME} =yourluxuryroad.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
ProxyPreserveHost On
ProxyRequests Off
ProxyPass /node-yrl-book http://localhost:5000
ProxyPassReverse /node-yrl-book http://localhost:5000
</VirtualHost>
<Directory /var/www/yourluxuryroad/>
AllowOverride All
</Directory>
As you can see from the config i'm trying to set the ProxyPass directive for redirect the requests recived on the path /node-yrl-book to a nodejs service ( made using expressjs ) at port 5000 but this is not working, instead of getting a redirect to that service i get the 404 Page not found wordpress page.
If I make a request at my_ip/node-yrl-book instead it works correctly and i am redirected to the service at port :5000
I suppose that i'm missing something in my configuration but i'm not understanding what..
Maybe is something in wordpress that has to be changed?
You have way too much going on.
ProxyPass -or- DocumentRoot, not both.
You can either serve the page from apache (by using DocumentRoot), or you can serve the page from nodejs (by using ProxyPass).
Finally i solved this, I made an SSL certificate for my website using let's encrypt certbot, This script created a new virtualhost in another file for the https requests ( called /etc/apache2/sites-available/myDomain-le-ssl.conf ) That virtualhost was overriding my proxypass directive, editing also this virtualhost made all work

Block other domains pointing to yours

I have domain abc.com and I noticed another domain not owned by me pointing to the same IP address as mine. It is ghosting mine, so when you visit that website it looks exactly as if you were on mine.
Any ideas of how to prevent that?
my vhost looks like:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /path/to/site
<Directory /path/to/site/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteCond %{HTTP_REFERER} .
RewriteCond %{HTTP_REFERER} !example\.com [NC]
RewriteCond %{HTTP_HOST} !example.com [NC]
RewriteRule .? - [F]
ServerName example.com
ServerAlias www.example.com
</VirtualHost>
</IfModule>
Apache uses the Host field from the HTTP requests headers to know which vhost is requested (Host corresponds to apache ServerName or ServerAlias).
Try apache2ctl -S, it will give you an ouput containing something like:
VirtualHost configuration:
*:80 is a NameVirtualHost
default server ip (/etc/apache2/sites-enabled/000-default.conf:1)
port 80 namevhost ip (/etc/apache2/sites-enabled/000-default.conf:1)
port 80 namevhost www.example1.com (/etc/apache2/sites-enabled/001-vhost.conf:1)
port 80 namevhost www.example2.com (/etc/apache2/sites-enabled/002-vhost.conf:1)
*:443 is a NameVirtualHost
default server 127.0.1.1 (/etc/apache2/sites-enabled/default-ssl.conf:2)
port 443 namevhost 127.0.1.1 (/etc/apache2/sites-enabled/default-ssl.conf:2)
port 443 namevhost www.example1.com (/etc/apache2/sites-enabled/non-default-ssl.conf:2)
Now imagine my ip is 1.1.1.1:
Given those three curl commands:
1. curl http://1.1.1.1 -H 'Host: www.example1.com'
1. curl http://1.1.1.1 -H 'Host: www.example2.com'
1. curl http://1.1.1.1 -H 'Host: www.spoofexample.com'
First one, apache finds the corresponding ServerName in a vhost file and uses /etc/apache2/sites-enabled/001-vhost.conf to satisfy request
Second one, apache finds the corresponding ServerName in a vhost file and uses /etc/apache2/sites-enabled/002-vhost.conf to satisfy request
Third one (your undesired mapped DNS), apache doesn't find the corresponding ServerName into any of its vhosts file, and uses /etc/apache2/sites-enabled/000-default.conf to satisfy request
The same logic applies to SSL vhosts.
PS1: ServerName for the default HTTP vhost has a value of ip, and there is no ServerName in the default SSL vhost. Apache just assumes a 127.0.1.1, which is not the IP address it listens on (just telling so it's not more confusing).
PS2: To make a vhost the default one it must be the first by names sorted (000 -> 001 -> 002).
It is not possible somebody can ghost your account.
Suppose I am domain owner of abc.com from hostgator. In order to host it on godaddy.com I have to go to domain controller put the godaddy nameservers there. Then on hosting i create a website with same name.
You should not hosting a real domain with ipaddress also. always use name servers which will prevent all those configuration.
Please check this page for redirects
https://www.namecheap.com/support/knowledgebase/article.aspx/385/2237/how-to-redirect-a-url-for-a-domain
Are you hosting a domain from your local computer ?

Apache2 Websocket Proxy for Mattermost from dynamic dns host

i'm using mattermost locally at home in a Vagrant Virtual Machine. With Port Forwarding on my DSL Router, i map the web frontend on a subomain on my WAN vHost with fixed IP.
<VirtualHost *:80>
ServerName chat.domain.tld
ServerSignature Off
ProxyPreserveHost On
<Location />
Order deny,allow
Allow from all
ProxyPassReverse http://chat.domain.tld/
</Location>
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule .* http://mappedsubdomain.somedyndns.tld:8090%{REQUEST_URI} [P,QSA]
DocumentRoot /somewhere/on/my/disk
</VirtualHost>
And that works fine! In this case i'm mapped the Web Frontend from Port 8090 to the port 80 on the vHost Subdomain. And the Web-Frontend is reachable.
But.
mattermost is using another Port to communicate with the Web-Frontend over Websockets. For that i also forwarded the Websocket Port from my local Machine. If i'm accessing the Dynamic DNS Host Url: http://mappedsubdomain.somedyndns.tld:8090 the Web-Fontend works well WITH the second opened Port for Websockets. Mattermost is usable on the Dynamic DNS Host Url.
As Default Mattermost is using Port 80 for the Websockets. But in my case, i'm using port 890 for the Websockets in Mattermost. It works locally, inside the LAN and over the Dynamic DNS Host.
Now, i want to make a ProxyReverse withe the Websocket Protocol.
The WAN-Host is a Debian with Apache2.2 and the loaded mod_proxy_wstunnel Module.
At first, i tried simply to map the second Port:
Listen 890
<VirtualHost *:890>
ServerName chat.domain.tld
ServerSignature off
ProxyRequests off
RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://mappedsubdomain.somedyndns.tld:890/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://mappedsubdomain.somedyndns.tld:890/$1 [P,L]
<Location />
Order deny,allow
Allow from all
ProxyPassReverse http://mappedsubdomain.somedyndns.tld:890/
ProxyPassReverse ws://mappedsubdomain.somedyndns.tld:890/
</Location>
DocumentRoot /somewhere/on/my/disk
</VirtualHost>
But nothing. Websockets not working.
Then i tried it from a on the WAN vHost running NodeJS Websocket Tunnel:
https://www.npmjs.com/package/wstunnel
With this call:
wstunnel -t 8091 ws://mappedsubdomain.somedyndns.tld:890/
and with changed Virtual Host Config:
RewriteRule /(.*) ws://localhost:8091/$1
RewriteRule /(.*) http://localhost:8091/$1 [P,L]
ProxyPassReverse ws://localhost:8091/
ProxyPassReverse http://localhost:8091/
When wstunnel is running, a http Request on chat.domain.tld:890 ends with a timeout. Without wstunnel, i've got a 503.
Have anyone a helpful hint for me?
#seekwhencer Would this guide help? https://docs.mattermost.com/install/config-proxy-apache2.html
For troubleshooting WebSocket connections, this page might help: https://docs.mattermost.com/install/troubleshooting.html#please-check-connection-mattermost-unreachable-if-issue-persists-ask-administrator-to-check-websocket-port

WebSockets and Apache proxy: how to configure mod_proxy_wstunnel?

I have :
Apache 2.4 on port 80 of my server, with mod_proxy and mod_proxy_wstunnel enabled
Node.js + socket.io on port 3001 of the same server
Accessing example.com (with port 80) redirects to 2. thanks to this method with the following Apache configuration:
<VirtualHost *:80>
ServerName example.com
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
ProxyPass / ws://localhost:3001/
ProxyPassReverse / ws://localhost:3001/
</VirtualHost>
It works for everything, except the websocket part : ws://... are not transmitted like it should by the proxy.
When I access the page on example.com, I have:
Impossible to connect ws://example.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.
Question: How to make Apache proxy the WebSockets as well?
I finally managed to do it, thanks to this topic. TODO:
1) Have Apache 2.4 installed (doesn't work with 2.2), and do:
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel
2) Have nodejs running on port 3001
3) Do this in the Apache config
<VirtualHost *:80>
ServerName example.com
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/socket.io [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P,L]
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
</VirtualHost>
Note: if you have more than one service on the same server that uses websockets, you might want to do this to separate them.
Instead of filtering by URL, you can also filter by HTTP header. This configuration will work for any web applications that use websockets, also if they are not using socket.io:
<VirtualHost *:80>
ServerName www.domain2.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:3001/$1 [P,L]
ProxyPassReverse / http://localhost:3001/
</VirtualHost>
May be will be useful.
Just all queries send via ws to node
<VirtualHost *:80>
ServerName www.domain2.com
<Location "/">
ProxyPass "ws://localhost:3001/"
</Location>
</VirtualHost>
As of Socket.IO 1.0 (May 2014), all connections begin with an HTTP polling request (more info here). That means that in addition to forwarding WebSocket traffic, you need to forward any transport=polling HTTP requests.
The solution below should redirect all socket traffic correctly, without redirecting any other traffic.
Enable the following Apache2 mods:
sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
Use these settings in your *.conf file (e.g. /etc/apache2/sites-available/mysite.com.conf). I've included comments to explain each piece:
<VirtualHost *:80>
ServerName www.mydomain.com
# Enable the rewrite engine
# Requires: sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
# In the rules/conds, [NC] means case-insensitve, [P] means proxy
RewriteEngine On
# socket.io 1.0+ starts all connections with an HTTP polling request
RewriteCond %{QUERY_STRING} transport=polling [NC]
RewriteRule /(.*) http://localhost:3001/$1 [P]
# When socket.io wants to initiate a WebSocket connection, it sends an
# "upgrade: websocket" request that should be transferred to ws://
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P]
# OPTIONAL: Route all HTTP traffic at /node to port 3001
ProxyRequests Off
ProxyPass /node http://localhost:3001
ProxyPassReverse /node http://localhost:3001
</VirtualHost>
I've included an extra section for routing /node traffic that I find handy, see here for more info.
With help from these answers, I finally got reverse proxy for Node-RED running on a Raspberry Pi with Ubuntu Mate and Apache2 working, using this Apache2 site config:
<VirtualHost *:80>
ServerName nodered.domain.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:1880/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:1880/$1 [P,L]
</VirtualHost>
I also had to enable modules like this:
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
For me it works after adding only one line in httpd.conf as below (bold line).
<VirtualHost *:80>
ServerName: xxxxx
#ProxyPassReverse is not needed
ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>
Apache version is 2.4.6 on CentOS.
Did the following for a spring application running static, rest and websocket content.
The Apache is used as Proxy and SSL Endpoint for the following URIs:
/app → static content
/api → REST API
/api/ws → websocket
Apache configuration
<VirtualHost *:80>
ServerName xxx.xxx.xxx
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
<Proxy *>
Require all granted
</Proxy>
RewriteEngine On
# websocket
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/api/ws/(.*) ws://localhost:8080/api/ws/$1 [P,L]
# rest
ProxyPass /api http://localhost:8080/api
ProxyPassReverse /api http://localhost:8080/api
# static content
ProxyPass /app http://localhost:8080/app
ProxyPassReverse /app http://localhost:8080/app
</VirtualHost>
I use the same vHost config for the SSL configuration, no need to change anything proxy related.
Spring configuration
server.use-forward-headers: true
My setup:
Apache 2.4.10 (running off Debian)
Node.js (version 4.1.1) App running on port 3000 that accepts WebSockets at path /api/ws
As mentioned above by #Basj, make sure a2enmod proxy and ws_tunnel are enabled.
This is a screenshot of the Apache config file that solved my problem:
The relevant part as text:
<VirtualHost *:80>
ServerName *******
ServerAlias *******
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
<Location "/api/ws">
ProxyPass "ws://localhost:3000/api/ws"
</Location>
</VirtualHost>
Hope that helps.
In addition to the main answer: if you have more than one service on the same server that uses websockets, you might want to do this to separate them, by using a custom path (*):
Node server:
var io = require('socket.io')({ path: '/ws_website1'}).listen(server);
Client HTML:
<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...
Apache config:
RewriteEngine On
RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]
RewriteCond %{REQUEST_URI} ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]
RewriteCond %{REQUEST_URI} ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]
(*) Note: using the default RewriteCond %{REQUEST_URI} ^/socket.io would not be specific to a website, and websockets requests would be mixed up between different websites!
User this link for perfact solution for ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
You have to just do below step..
Go to /etc/apache2/mods-available
Step...1
Enable mode proxy_wstunnel.load by using below command
$a2enmod proxy_wstunnel.load
Step...2
Go to /etc/apache2/sites-available
and add below line in your .conf file inside virtual host
ProxyPass "/ws2/" "ws://localhost:8080/"
ProxyPass "/wss2/" "wss://localhost:8080/"
Note : 8080 mean your that your tomcat running port because we want to connect ws where our War file putted in tomcat and tomcat serve apache for ws.
thank you
My Configuration
ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected
For "polling" transport.
Apache side:
<VirtualHost *:80>
ServerName mysite.com
DocumentRoot /my/path
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io
</VirtualHost>
Client side:
var my_socket = new io.Manager(null, {
host: 'mysite.com',
path: '/my-connect-3001'
transports: ['polling'],
}).socket('/');
TODO:
Have Apache 2.4 installed (doesn't work with 2.2), a2enmod proxy and a2enmod proxy_wstunnel.load
Do this in the Apache config
just add two line in your file where 8080 is your tomcat running port
<VirtualHost *:80>
ProxyPass "/ws2/" "ws://localhost:8080/"
ProxyPass "/wss2/" "wss://localhost:8080/"
</VirtualHost *:80>
For the same issue on Windows, just uncomment the below line from http.conf:
Then add the below line to your apache config:
LoadModule proxy_module modules/mod_proxy_wstunnel.so

Resources