Web application behind reverse proxy - how do I handle SSL? - apache

I have a public Apache server which needs to proxy to an internal Apache server (for SVN access). What I'd like to have is:
User ---[HTTPS]---> Web Server ---[HTTP]---> SVN Server
I'm not too familiar with SSL handling, so I'd like some opinions on this approach. Is this an ok model; should I be using SSL everywhere, etc.
My approach works for the most part, but fails when rewriting redirects back to HTTPS. If a user goes to
https://acme.web.mcx/svn (no trailing '/')
they are redirected by the SVN server to
http://acme.web.mcx/svn/ (almost there!)
Here's my config for the Web Server (Proxying server):
<VirtualHost *:443>
ServerAdmin me#admin.com
ServerAlias *.web.mcx www.web.mcx web.mcx
DocumentRoot /server/web/app/webroot
ErrorLog logs/web-error_log
CustomLog logs/web-access_log common
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.web\.mcx$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^.]+)\.web\.mcx$ [NC]
RewriteRule ^/svn(.*) http://db.mcx/svn$1 [P]
ProxyPassReverse /svn http://db.mcx/svn
ProxyPreserveHost on
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/server.crt
SSLCertificateKeyFile /etc/httpd/ssl/server.key
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyVia On
<Location /svn/>
<Limit OPTIONS PROPFIND GET REPORT MKACTIVITY PROPPATCH PUT CHECKOUT MKCOL MOVE COPY DELETE LOCK UNLOCK MERGE>
Order Deny,Allow
Allow from all
Satisfy Any
</Limit>
</Location>

I keep answering my own questions :)
Here's my 'works until it breaks' solution: I changed my VirtualHost setting to always redirect http:// requests for /svn* to https. The client will be redirected twice sometimes (if they don't use the trailing slash), but that's ok with me. Redirect one: SVN server redirects client to the proper path with a slash (although forgets about https), redirect two: Web server redirects client back to https.
<VirtualHost *:80>
ServerAdmin me#admin.com
ServerAlias *.web.mcx www.web.mcx web.mcx
DocumentRoot /server/web/app/webroot
ErrorLog logs/web-error_log
CustomLog logs/web-access_log common
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.web\.mcx$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^.]+)\.web\.mcx$ [NC]
RewriteCond %{REQUEST_URI} svn.*
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R,L]
ProxyRequests Off
</VirtualHost>

Related

Websockets not working while running Portainer with Httpd proxying

I've set up the Portainer UI as a docker container, and it's working great if I connect my browser to port 9000 (as in http://foo.bar.com:9000). I can navigate around the UI and open up container consoles (which use websockets) without a problem.
But, what I need to do i connect with SSL (as in https://foo.bar.com).
I set up an httpd container on the same machine, and gave it the following configuration file:
<VirtualHost *:443>
ServerName foo.bar.com
ProxyPass / http://foo.bar.com:9000/
ProxyPassReverse / http://foo.bar.com:9000/
RequestHeader set X-Forwarded-Proto "https"
<Location /api/websocket/>
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule /api/websocket/(.*) ws://foo.bar.com:9000/api/websocket/$1 [P]
</Location>
## SSL directives
SSLEngine on
SSLCertificateFile "/usr/local/apache2/conf/server.crt"
SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"
## Logging
ServerSignature Off
ErrorLog "logs/error_ssl.log"
CustomLog "logs/access_ssl.log" common
</VirtualHost>
Both httpd and portainer are being brought up by separate docker-compose.yml files.
Now, the Portainer web pages still come up just fine, but the consoles for the containers won't work. Somehow, my websocket configuration above is broken. Any ideas on what I might be doing wrong?
After hours of playing with it, I finally got this to work and wanted to share. First, at least in httpd 2.4, you need to explicitly load mod_proxy_wstunnel.so so make sure and put a LoadModule in. Until you do that, nothing will work.
Here is the httpd configuration that was successful:
<VirtualHost *:443>
ServerName foo.bar.com
ProxyPreserveHost on
ProxyPreserveHost On
ProxyRequests Off
# allow for upgrading to websockets
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/?(.*) ws://foo.bar.com:9000/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule ^/(.*) http://foo.bar.com:9000/$1 [P,L]
ProxyPass "/" "http://foo.bar.com:9000/"
ProxyPassReverse "/" "http://foo.bar.com:9000/"
## SSL directives
SSLEngine on
SSLCertificateFile "/usr/local/apache2/conf/server.crt"
SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"
## Logging
ServerSignature Off
ErrorLog "logs/error_ssl.log"
CustomLog "logs/access_ssl.log" common
</VirtualHost>
Thanks a lot - saved me lot of trouble setting this up in Apache. I'm using it in local network only so I don't care much about https and certs so I've modified it bit to go through http
<VirtualHost *:80>
ServerName foo.bar.com
ServerAlias foo.bar.alias.com
ProxyPreserveHost On
ProxyRequests Off
# allow for upgrading to websockets
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/?(.*) ws://localhost:9000/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule ^/(.*) http://localhost:9000/$1 [P,L]
ProxyPass "/" "http://localhost:9000/"
ProxyPassReverse "/" "http://localhost:9000/"
# Logging
ErrorLog ${APACHE_LOG_DIR}/portainer_error.log
CustomLog ${APACHE_LOG_DIR}/portainer_access.log combined
</VirtualHost>

Redirect http to https only works after page refresh Apache2

I have installed SSL Certificates on my website and on the example.com everything works fine, meaning that typing example.com redirects correctly to https://example.com. However, I have installed a certificate for a subdomain as well such that the link becomes: subdomain.example.com.
My goal is to have subdomain.example.com redirect to https://subdomain.example.com . This might sound weird but this semi-works meaning that when I first surf to subdomain.example.com it uses the http protocol but when I refresh that same page it switches to https protocol.
This is my VirtualHost conf file (port 80):
<VirtualHost *:80>
ServerName subdomain.example.com
ServerSignature Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
<Location />
Require all granted
ProxyPassReverse http://127.0.0.1:8181
ProxyPassReverse http://example.com/
</Location>
RewriteEngine on
#Forward all requests to gitlab-workhorse except existing files like error documents
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_URI} ^/uploads/.*
RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [P,QSA,NE]
# needed for downloading attachments
DocumentRoot /opt/gitlab/embedded/service/gitlab-rails/public
RewriteCond %{SERVER_NAME} =subdomain.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
#RewriteCond %{SERVER_PORT} !443
#RewriteRule ^(/(.*))?$ https://%{HTTP_HOST}/ [R=301,L]
</VirtualHost>
I have removed to non related lines from this sample above. Here is the 443 conf file:
< IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName subdomain.example.com
ServerSignature Off
< IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName subdomain.example.com
ServerSignature Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
<Location />
Require all granted
#Allow forwarding to gitlab-workhorse
ProxyPassReverse http://127.0.0.1:8181
ProxyPassReverse http://domain/
</Location>
RewriteEngine on
#Forward all requests to gitlab-workhorse except existing files like error documents
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_URI} ^/uploads/.*
RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [P,QSA,NE]
# needed for downloading attachments
DocumentRoot /opt/gitlab/embedded/service/gitlab-rails/public
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/subexample.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
Header always set Strict-Transport-Security "max-age=31536000"
SSLUseStapling on
Header always set Content-Security-Policy upgrade-insecure-requests
</VirtualHost>
</IfModule>
Worth noting is that I am using certbot.
Hopefully someone can help me.
You say "My goal is to have subdomain.example.com redirect to https://subdomain.example.com".
Then why have all that proxy configuration in your :80 VirtualHost? Simply force the redirection to :443, and let :443 handle the proxy (and other).
So your VirtualHost would become:
<VirtualHost *:80>
ServerName subdomain.example.com
CustomLog logs/subdomain_80_access.log combined
ErrorLog logs/subdomain_80_error.log
RewriteEngine On
RedirectMatch ^/(.*)$ https://subdomain.example.com/$1
</VirtualHost>

Why doesn't the URL rewrite doesn't handle the non-WWW to www?

I am using Apache server for URL redirects.
I'm making url redirects in 00_application.conf of Apache at /etc/httpd/conf.d/elasticbeanstalk in AWS
<VirtualHost *:80>
<Proxy *>
Order Allow,Deny
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/ retry=0
ProxyPassReverse / http://localhost:8080/
ProxyPreserveHost on
RewriteEngine On
RewriteCond %{REQUEST_URI} !^\/qqd [NC,OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.example.com/qqd/ [L,R=301]
ErrorLog /var/log/httpd/elasticbeanstalk-error_log
</VirtualHost>
The second RewriteCond in above code doesn't work.
But first RewriteCond does work.
Following example doesn't work either.
<VirtualHost *:80>
ServerName example.com
Redirect / http://www.example.com
</VirtualHost>
<VirtualHost *:80>
ServerName www.example.com
. . .
. . .
</VirtualHost>
I want non-WWW URLs to be redirected to www.example.com/qqd
Please help.
PS: When I do mywebsite.com without www, this is what I see
https://i.stack.imgur.com/wWIqD.png
I am wondering, when I do mywebsite.com without www, whether that request is hitting my server (or Amazon Route 53 Hosted zone --> web server --> app sever).
I thought this might be an additional info.
Ok, I found the answer.
Yep, My guess was right.
When I do www.example.com it hits my webserver --> URL reroute logic.
But when I do example.com in browser, it doesn't hit my server at all.
I was getting
https://qph.ec.quoracdn.net/main-qimg-99c326b3c6af3d7101645af4a12516b9
We need to have an A record for both
www.example.com as well as
example.com
and make sure both point to web server where you have your URL redirect logic.
Good luck.

Apache - how to make http requests into https only? [duplicate]

This question already has answers here:
http to https through .htaccess
(17 answers)
Closed 6 years ago.
How to tell if http://ttt.com or http://www.ttt.com is used by the user, redirect it to https://www.ttt.com ?
httpd.conf:
<VirtualHost *:80>
ServerName www.ttt.com
ServerAlias ttt.com
DocumentRoot /home/www/html/ttt/public
<Directory /home/www/html/ttt/public>
#Options ExecCGI
#AddDefaultCharset utf-8
DirectoryIndex index.php
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
.htaccess :
RewriteEngine On
############################################
## always send 404 on missing files in these folders
#RewriteCond %{REQUEST_URI} !^/(files)/
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Try the following Code at the main directory .htaccess file :
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R]
You can do it from the httpd.conf with the following:
<VirtualHost *:80>
ServerName www.ttt.com
Redirect "/" "https://www.ttt.com/"
</VirtualHost>
<VirtualHost *:443>
ServerName www.ttt.com
...
...
</VirtualHost>
Or from the .htaccess file:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
Here you go: https://wiki.apache.org/httpd/RedirectSSL
Redirect Request to SSL
Let's say you want http://www.example.com/secure/ to always be sent
over SSL (I presume here that both the normal and the SSL vhost have
the same content). You could do this by linking to the correct page
from within your HTML pages... but there will always be some user who
will sneak by it that way.
Using virtual hosts (using redirect)
When using SSL, you will frequently have at least two virtual hosts:
one on port 80 to serve ordinary requests, and one on port 443 to
serve SSL. If you wish to redirect users from the non-secure site to
the SSL site, you can use an ordinary Redirect directive inside the
non-secure VirtualHost:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName mysite.example.com
DocumentRoot /usr/local/apache2/htdocs
Redirect permanent /secure https://mysite.example.com/secure
</VirtualHost>
<VirtualHost _default_:443>
ServerName mysite.example.com
DocumentRoot /usr/local/apache2/htdocs
SSLEngine On
# etc...
</VirtualHost>
When redirecting everything you don't even need a DocumentRoot:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.example.com
Redirect permanent / https://secure.example.com/
</VirtualHost>
<VirtualHost _default_:443>
ServerName secure.example.com
DocumentRoot /usr/local/apache2/htdocs
SSLEngine On
# etc...
</VirtualHost>
Note: redirect can also be used inside .htaccess files or to address
particular URLs, as in:
Example:
Redirect permanent /login https://mysite.example.com/login
Using mod_rewrite
While the solution is recommended because it is simpler
and safer, you can also use mod_rewrite to get the same effect as
described here: RewriteHTTPToHTTPS
From https://httpd.apache.org/docs/trunk/mod/mod_alias.html#redirect:
# Redirect to a URL on a different host Redirect "/service" "http://foo2.example.com/service"
# Redirect to a URL on the same host Redirect "/one" "/two"
If the client requests http://example.com/service/foo.txt, it will be
told to access http://foo2.example.com/service/foo.txt instead. This
includes requests with GET parameters, such as
http://example.com/service/foo.pl?q=23&a=42, it will be redirected to
http://foo2.example.com/service/foo.pl?q=23&a=42. Note that POSTs will
be discarded. Only complete path segments are matched, so the above
example would not match a request for
http://example.com/servicefoo.txt. For more complex matching using the
expression syntax, omit the URL-path argument as described below.
Alternatively, for matching using regular expressions, see the
RedirectMatch directive.
If you want both the www.example.com/* and the example.com/* to be redirected you could make two VirtualHost with different ServerName or you can use the Rewrite plugin.

Redirect address with folder structure to https?

I want to make sure all my traffic is on ssl even if they type http. But I also want it to pass the folders so mod_rewrite will still work. I tried this poor example but it does not work. Basicly I if they type http://mydomain.com/apage it will redirect to https://mydomain.com/apage
Server: Apache2, LAMP stack.
.htaccess
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule ^(/) https://%{HTTP_HOST}%{REQUEST_URI} [NC,R=301,L]
I am open to tweaking a virtual host files for Apache but I have not seen it done like that before. This is my first adventure into ssl hosting.
Just replacing http with https
RewriteCond %{HTTPS} !on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
I suggest not using mod_rewrite or htaccess if you have access to httpd.conf.
If you want to force all users to use https (a good idea) you can add something like this to httpd.conf:
<VirtualHost 1.2.3.4:80>
ServerName SSL.EXAMPLE.COM
CustomLog /var/log/httpd/EXAMPLE.access_log combined
ErrorLog /var/log/httpd/EXAMPLE.error_log
Redirect / https://ssl.example.com/
</VirtualHost>
<VirtualHost 1.2.3.4:443>
ServerName ssl.example.com
DocumentRoot /var/www/html
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite HIGH:MEDIUM
.
.
.
</VirtualHost>
<Directory /var/www/html>
#If all else fails, this will ensure nothing can get in without being encrypted.
SSLRequireSSL
</Directory>