if-then-else condition in apache virtual host - apache

I have an Apache virtual host defined for https ://sb.domain1.com and I need to do a different action depending on the IP address which calls the virtual host. If the call comes from 172.16.xxx.yyy then i need to redirect to http ://sb.domain2.com else i need to redirect to http ://sb.domain1.com.
That is I don't know how to translate the following lines (which come from /etc/http/conf.d/ssl.conf file):
<VirtualHost 192.168.254.68:443>
ServerName sb.domain1.com
SSLProxyEngine on
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
SSLCertificateChainFile /etc/httpd/conf/ssl.crt/STAR.ca-bundle
SSLEngine on
SSLSessionCacheTimeout 600
if IP = 172.16.xxx.yyy
then
Redirect to http ://sb.domain2.com
else
ProxyPass / http ://sb.domain1.com/
ProxyPassReverse / http ://sb.domain1.com/
else
ErrorLog "|/usr/sbin/rotatelogs /var/log/httpd/sb/ssl_error_log 86400"
CustomLog "|/usr/sbin/rotatelogs /var/log/httpd/sb/ssl_access_log 86400" combined
</VirtualHost>
can you suggest me translating the above directives?

Something along the lines of this should work:
RewriteEngine On
RewriteCond %{REMOTE_ADDR} ^172\.16\.
RewriteRule ^/(.*) http://sb.domain2.com/$1 [L,QSA]
and then just
ProxyPass / http://sb.domain1.com/
ProxyPassReverse / http://sb.domain1.com/
After all, if you match the IP, you will be redirected, so no other requests will be made here. Everyone else will then be proxied.

Related

Redirect specifc HTTPS request to a specific port with apache

I have a problem to redirect some request to an other port. Here's my configuration:
I have a public domain like XXXX.ddns.net
I have a Rapsbian server with apache and files in my /var/www folders are correctly served (angular website)
On the same Raspbian server there is a REST server running on the 3000 port
This is running on HTTPS with SSL(letsencrypt)
I would like that all requests to XXXX.ddns.net/api/* to be redirected to the 3000 port.
I change the .htaccess file and the rewrite rule seems to works on local but I can't make it working from my internet site. API requests achieve with a error 500.
Here is my current .htaccess file:
RewriteEngine On
RewriteRule ^api/(.*) https://localhost:3000/api/$1 [QSA]
# not sure if it should be http or https in the rule but nothing works
#RewriteRule ^api/(.*) http://localhost:3000/api/$1 [QSA]
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested pattern is file and file doesn't exist, send 404
RewriteCond %{REQUEST_URI} ^(\/[a-z_\-\s0-9\.]+)+\.[a-zA-Z]{2,4}$
RewriteRule ^ - [L,R=404]
Here is my current 000-default-le-ssl.conf file (in /etc/apache2/sites-available):
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ServerName XXXX.ddns.net
SSLCertificateFile /etc/letsencrypt/live/XXXX.ddns.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/XXXX.ddns.net/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
<Location /api>
ProxyPass http://127.0.0.1:3000/api
ProxyPassReverse http://127.0.0.1:3000/api
</Location>
</VirtualHost>
</IfModule>
If someone could help me to achieve it...
Thanks!
Your self-found solution looks strange to me. You switch on the SSLProxyEngine and than disable all security measures. Is the backend API running under HTTPS and HTTP at port 3000 at the same time? This is not possible.
I use this setup (apache as proxy to backend application) pretty often and would suggest the following configuration:
As I did not understand the purpose of the rewrite directives I left them out. The VirtualHost at port 80 always redirects HTTP requests to HTTPS. If this works add permanent to the directive (permanent is cached by some browsers, see comment in VirtualHost *:80).
The VirtualHost for HTTPS serves content from your DocumentRoot at /var/www/html. The Directory directive takes care that only correctly addressed files are served (no lookups possible). The VirtualHost also provides the proxy for the /api on the same server on port 3000.
It should work for apache 2.4 if your letsencrypt configuration is correct (fill-in the XXXX). Both VirtualHost configurations can be written into a single file, usually located in /etc/apache2/sites-available with a symlink to /etc/apache2/sites-enabled. Please remove/rename your .htaccess file and other configurations before testing this configuration. If you need access control through apache this could also be configured directly in the VirtualHost configuration.
<VirtualHost *:80>
ServerName XXXX.ddns.net
# Always https
Redirect / https://XXXX.ddns.net/
# Redirect permanent / https://XXXX.ddns.net/
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster#localhost
ServerName XXXX.ddns.net
# These are your SSL settings; your responsibility
SSLCertificateFile /etc/letsencrypt/live/XXXX.ddns.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/XXXX.ddns.net/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
# Your document root; where the JavaScript application lives
DocumentRoot /var/www/html
<Directory /var/www/html/ >
Options -Indexes +FollowSymLinks -MultiViews
AllowOverride None
Order Allow,Deny
Allow From All
</Directory>
# Reverse proxy settings for api
ProxyRequests Off
ProxyPreserveHost On
<Location /api >
ProxyPass http://127.0.0.1:3000/api
ProxyPassReverse http://127.0.0.1:3000/api
</Location>
</VirtualHost>
Thanks for your help. I don't really know how but it works now!
I dont rember exactly what i did, but the last one was to modify my 000-default-le-ssl.conf file like this:
SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
<Location /api>
ProxyPass http://127.0.0.1:3000/api/
ProxyPassReverse http://127.0.0.1:3000/api/
ProxyPass https://127.0.0.1:3000/api/
ProxyPassReverse https://127.0.0.1:3000/api/
</Location>

apache RewriteRule and proxypass

I am in the process of setting up a jira server and will use apache to be a proxy to the tomcat service. I have my apache setup 90% completed but can't workout the final configuration. The goal is to have users be able to access the FQDN, the alias or the fully qualified alias but the URL is always rewritten to the DNS alias. e.g user browses to:
http://jira.domian.com rewrite to https://jira
http://nbsrvjira-07v rewrite to https://jira
http://nbsrvjira-07v.diasemi.com rewrite to https://jira
All the above work however the below fail:
https://jira.domian.com rewrite to https://jira
https://nbsrvjira-07v rewrite to https://jira
https://nbsrvjira-07v.diasemi.com rewrite to https://jira
Unless a specific URL is used it will cause issue within the application, the apache configuration is below:
The http to https redirect:
<VirtualHost *:80>
ServerName nbsrvjira-07v.domain.com
ServerAlias jira-test jira-test.domain.com
ErrorLog "/var/log/httpd/nbsrvjira-07v.domain.com_error.log"
ServerSignature Off
CustomLog "/var/log/httpd/nbsrvjira-07v.domain.com_access.log" combined
RewriteEngine On
RewriteRule ^/(.*) https://jira-test/ [noescape,last,redirect=302]
</VirtualHost>
The https to proxy pass:
VirtualHost *:443>
ServerName nbsrvjira-07v.domain.com
ServerAlias jira jira.domain.com
ErrorLog "/var/log/httpd/nbsrvjira-07v.domain.com_error.log"
ServerSignature Off
CustomLog "/var/log/httpd/nbsrvjira-07v.domain.com_access.log" combined
SSLEngine On
SSLCertificateFile "/etc/pki/tls/certs/nbsrvjira-07v.domain.com.cert"
SSLCertificateKeyFile "/etc/pki/tls/private/nbsrvjira-07v.domain.com.key"
RewriteEngine On
ProxyPass / http://localhost:8080/ connectiontimeout=5 timeout=300
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
I have tried various rewrite rules within the https configuration but none seem to work. Can someone help?
Chris
Maybe set up more than one VirtualHost for *:443 where one or more will just redirect to https://jira and only one will act as https://jira and contain the proxying? Just a guess.

ProxyPassReverse dropping HTTPS

On my home network, I have a web server and a DNS server. I have various other application servers that I have added redirects for so I can simply visit sites like myapplication.domain.com or www.domain.com/application to get to my various services. I have a Subsonic server running on another server, and my goal is to be able to visit https://subsonic.domain.com and get my Subsonic traffic served over SSL on my web server. Eventually I hope to access this from outside the home, which is why it's important to proxy the non-secured HTTP traffic over HTTPS, but for right now, I'm just trying to get it working at home.
When I visit https://subsonic.domain.com, I end up getting an "unable to connect" error. The address I appear to be redirected to is subsonic.domain.com/login.view. If I tack HTTPS onto the front of that URL, I get the login page I'm looking for. Once I log in again, however, the URL changes, I'm redirected, and I end up losing the HTTPS again an have to keep re-adding it. Obviously I am doing something wrong.
I have set up a VirtualHost for subsonic.domain.com and am trying to use ProxyPass and ProxyPassReverse to get the traffic redirected in the way I want. Here is my VirtualHost for this site:
<VirtualHost subsonic.domain.com:443>
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
ProxyRequests Off
ProxyErrorOverride Off
ProxyPreserveHost On
ServerAdmin webmaster#localhost
ProxyPass / http://192.168.1.5:4040/
ProxyPassReverse / http://192.168.1.5:4040/
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
</VirtualHost>
SSL is definitely up and running with no problem. I have another identical virtualhost for another directory that works fine (redirects on https://www.domain.com/directory), so I'm not sure what the problem is here. After the ProxyPassReverse, the URL just seems to be losing the https:// part. If I add it in, the site works fine until I visit another page and https:// is lost again. If I visit the application server directly at http://192.168.1.5:4040, I have no issues whatsoever.
Any advice would be most welcome.
EDIT
A little clarification on what I'm trying to do. I want to have my Apache server doing all of my redirecting and handling all of my SSL requests. Basically, from the browser to the Apache server is HTTPS, the ProxyPass from the Apache server to the application server us unencrypted HTTP (which is fine, this is my internal network), the ProxyPassReverse from the application server to the Apache server is plain HTTP, then the Apache server sends out the traffic as HTTPS.
Here's another VirtualHost that does what I want for a different subdomain. This is tested and works 100%. I connect to my Apache server via HTTPS, the Apache server contacts my ownCloud server in plain old HTTP, the response to my Apache server is plain HTTP, then the Apache server returns the request in HTTPS to the browser:
<VirtualHost www.domain.com:443>
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
ProxyRequests Off
ProxyErrorOverride Off
ProxyPreserveHost On
ServerAdmin webmaster#localhost
ProxyPass /owncloud/ http://192.168.1.251/owncloud/
ProxyPassReverse /owncloud/ http://192.168.1.251/owncloud/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
</VirtualHost>
So I ran into this problem as well and while commenting out ProxyPreserveHost fixes the problem with the configuration above, there is a better way.
The ProxyPass1 statement tells Apache to take an incoming request on the URI and pass it through to the specified host. With ProxyPreserveHost On, Apache does not change the Host: HTTP header and passes the request unmodified. (By default it changes it to match the backend host specified in the ProxyPass statement).
The ProxyPassReverse2 statement tells Apache to match the host specified with the Host: header on the outgoing response and if it matches to adjust the Location:, Content-Location:, and URI: headers to match the VirtualHost or more specifically what Apache thinks is the canonical name.
So with the following configuration:
<VirtualHost subsonic.domain.com:443>
ProxyPreserveHost On
ProxyPass / http://192.168.1.5:4040/
ProxyPassReverse / http://192.168.1.5:4040/
</VirtualHost>
This is taking a request:
https://subsonic.domain.com/ -> http://192.168.1.5:4040/
but since ProxyPreserveHost is on, it is leaving the Host: header in the request intact as subsonic.domain.com
Your web application is most likely sending a response from subsonic.domain.com but that does not match the ProxyPassReverse rule you have specified:
http://subsonic.domain.com/ <- http://subsonic.domain.com/
So the configuration:
<VirtualHost subsonic.domain.com:443>
ProxyPreserveHost On
ProxyPass / http://192.168.1.5:4040/
ProxyPassReverse / http://subsonic.domain.com/ # Changed to match canonical host
</VirtualHost>
This rule should match the replies coming from the proxy host.
In my VirtualHost for Subsonic, I had to disable the ProxyPreserveHost On directive. I can now access the site externally and internally.
For some reason, this worked fine for my other VirtualHost, but for this one it did not. I'm assuming it's because in my one VirtualHost, the ProxyPass is working on a directory and not a hostname. In my VirtualHost for Subsonic, I don't specify a directory.
To anyone that actually knows what they're talking about in regards to Apache, VirtualHosts, redirects, etc, please feel free to clarify if I'm not describing accurately what's going on.
Here is my VirtualHost for anyone else that is experiencing this same issue.
<VirtualHost subsonic.domain.com:443>
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
ProxyRequests Off
ProxyErrorOverride Off
#ProxyPreserveHost On - This line now commented out
ServerAdmin webmaster#localhost
ProxyPass / http://192.168.1.5:4040/
ProxyPassReverse / http://192.168.1.5:4040/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
</VirtualHost>

Apache proxying subdomain root requests

Description
Internal Tomcat server that has webapps listening on 8080:
"http://internal:8080/foo-webservice/"
"http://internal:8080/foo-website/"
External facing Apache server is proxying requests for a subdomain:
"http://foo.domain.com/"
Any requests of the root of the subdomain would be proxied to the foo-website webapp on Tomcat.
Any other requests would be proxied to the appropriate path / webapp
Use Case A
Request:
"http://foo.domain.com/index.html"
Proxied to:
"http://internal:8080/foo-website/index.html"
Use Case B
Request:
"http://foo.domain.com/webservice/listener.html?param1=foo&param2=bar"
Proxied to:
"http://internal:8080/foo-webservice/listener.html?param1=foo&param2=bar"
VirtualHost definition
Current virtual host definition which satisfies Use Case B:
<VirtualHost *:80>
ServerName foo.domain.com
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ErrorLog /var/log/apache2/foo_error.log
LogLevel warn
CustomLog /var/log/apache2/foo_access.log combined
# RewriteRules
# ?
# ProxyPass
ProxyPreserveHost On
ProxyPass / http://internal:8080/
ProxyPassReverse / http://internal:8080/
</VirtualHost>
Attempt 1
# RewriteRules
RewriteEngine On
RewriteRule ^/(.*) http://internal:8080/foo-website/$1 [P]
Use Case A is satisfied
Use Case B fails
Attempt 2
# RewriteRules
RewriteEngine On
RewriteRule ^/$ http://internal:8080/foo-website/$1 [P]
Use Case B is satisfied
Use Case A is not completely satisfied
The index.html in foo-website is loaded, but none of the files in the js, img or css folders.
ProxyPass rules match in order
ProxyPass /webservice/ http://internal:8080/foo-webservice/
ProxyPassReverse /webservice/ http://internal:8080/foo-webservice/
ProxyPass /website/ http://internal:8080/foo-website/
ProxyPassReverse /website/ http://internal:8080/foo-website/
ProxyPass / http://internal:8080/foo-website/
ProxyPassReverse / http://internal:8080/foo-website/
No rewrite rule. Isn't that good enough ?
I think that you need to use the first attempt but include the QSA (query string append) flag in the square brackets at the end of each RewriteRule directive.
I think the issue with Attempt 2 (none of the files in the js, img or css folders being mapped) was a sign that my approach was wrong.
My solution now is to redirect any requests to the root, to the foo-website webapp.
<VirtualHost *:80>
ServerName foo.domain.com
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ErrorLog /var/log/apache2/foo_error.log
LogLevel warn
CustomLog /var/log/apache2/foo_access.log combined
# RewriteRules
RewriteEngine On
RewriteRule ^/$ /foo-website/ [R]
# ProxyPass
ProxyPreserveHost On
ProxyPass / http://internal:8080/
ProxyPassReverse / http://internal:8080/
</VirtualHost>
This was not what I originally wanted, but I think this is the resolution.

Apache mod-proxy ProxyErrorOverride for specific URL patterns

I am using Apache 2.2 with mod-proxy and I have configured it with several ProxyPass statements to proxy from remote URL to local URL. I need to have custom error documents returned from Apache for these proxied URLs so I set "ProxyErrorOverride On" in my mod-proxy configuration along with some ErrorDocument directives (with local URL path) to return custom error pages for a few HTTP status codes of interest. However, when a status code is returned for which I have NOT created an ErrorDocument directive for, Apache replaces the response body with a default error page instead of leaving the original response body intact. This won't work with the application. So I really have 2 questions:
1) Is it possible to configure Apache to leave the original response body intact for a particular status code if I don't have an ErrorDocument override defined for it?
2) Is it possible to have the ProxyErrorOverride directive only apply to some of the URLs in my ProxyPass statements?
As arober11 pointed out in the comment above:
Afraid the answer is: No and No. If the directive could be limited to
a location, directory, or set of URL's, then there would be something
in the "Context" section, of the man page:
httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxyerroroverride
on the other hand: you can always add it to mod_proxy.c yourself.
For question 2:
Definitely doable. Using internal redirects to either new host or port this is possible. Brief outline using hosts (add noErrorOverrideUrl,doErrorOverrideUrl in DNS or /etc/hosts of apache-machine):
NameVirtualHost *:80
<VirtualHost *:80>
RewriteEngine On
RewriteRule ^(/noErrorOverrideUrl/.*) http://noErrorOverrideUrl$1 [L,P]
RewriteRule ^(/doErrorOverrideUrl/.*) http://doErrorOverrideUrl$1 [L,P]
</VirtualHost>
<VirtualHost *:80>
ServerName noErrorOverrideUrl
ProxyErrorOverride Off
ProxyPass ...
...
</VirtualHost>
<VirtualHost *:80>
ServerName doErrorOverrideUrl
ProxyErrorOverride On
ProxyPass ...
...
</VirtualHost>
Brief outline using ports:
Listen 80
Listen 81
Listen 82
<VirtualHost *:80>
RewriteEngine On
RewriteRule ^(/noErrorOverrideUrl/.*) http://server:81$1 [L,P]
RewriteRule ^(/doErrorOverrideUrl/.*) http://server:82$1 [L,P]
</VirtualHost>
<VirtualHost *:81>
ProxyErrorOverride Off
ProxyPass ...
...
</VirtualHost>
<VirtualHost *:82>
ProxyErrorOverride On
ProxyPass ...
...
</VirtualHost>
You can upgrade apache and use the If sentence avaible on 2.4+
<VirtualHost *:80>
...
<If "%{REQUEST_URI} =~ m#^\/QA(.*)$#">
ProxyErrorOverride Off
</If>
..
</VirtualHost>
Documentation