How to force https on amazon elastic beanstalk without failing the health check [duplicate] - apache

This question already has answers here:
How to force https on elastic beanstalk?
(23 answers)
Closed 5 years ago.
I have configured my Elastic Beanstalk environment to redirect all pages to https, redirection works, however, the instance fails the health check and gets terminated, any ideas how to configure the rewrite rules?
My configuration:
NameVirtualHost *:80
<VirtualHost *:80>
.
.
.
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule !/_hostmanager/healthcheck https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
</VirtualHost>

There's multiple hostmananger URLs that Elastic Beanstalk needs to access besides the health check. Grepping /var/log/httpd/elasticbeanstalk-access_log, I see requests to /_hostmanager/tasks and /_hostmanager/healthcheck.
Here are the rules that I added to /etc/httpd/sites/elasticbeanstalk on my EC2 instances:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/status$
RewriteCond %{REQUEST_URI} !^/version$
RewriteCond %{REQUEST_URI} !^/_hostmanager/
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
Note that I'm also allowing non-https traffic to my /status and /version pages. I'm actually using /status as the actual healthcheck lookup URL, so having that traffic skip the rewrite will avoid the redirect and make the status lookup faster (I'm assuming).

I think that some of the other answers on here may not be based on whatever the arbitrary User-Agent AWS is currently setting. When I watch the Apache logs, I see this User-Agent:
ELB-HealthChecker/1.0
As of writing this, the following mod_rewrite rule is working for me:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker.*
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

As of 2016, none of these answers works for me, but this worked:
1 Retrieve /etc/httpd/conf.d/wsgi.conf
2 Add the following to the virtual host: (Note that the third line prevents an issue where the setup script /opt/elasticbeanstalk/hooks/config.py waits 5 minutes failing to load the path /.)
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} !localhost
RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker.*
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
3 Put the file in your repository, and add the following container command:
06_https:
command: "cp wsgi.conf /opt/python/ondeck/wsgi.conf"
This file is then copied automatically by the setup script into /etc/httpd/conf.d.

It looks like the AWS Health Checker uses the user agent 'AWSHealthCheck'.
I got round this by avoiding the redirect if the request came from the Health Checker User Agent.
SOmething like:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{USER_AGENT} !^AWSHealthCheck$
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

You can configure ELB to use a specific path for health checks, such as /ping. You can then explicitly tell apache not to redirect that URL, rather than relying on the UserAgent string.
You can also tell ELB to use HTTPS for the health check and then redirect all HTTP URLs to HTTPS, including the health check.
Both these settings can be changed in the EC2 Console in the Load Balancer section.

If you are trying to do this in Wordpress or PHP, you can setup your .htaccess as follows without having to modify anything through .ebextensions:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/status\.html$
RewriteCond %{REQUEST_URI} !^/_hostmanager/
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
</IfModule>
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Remember to change status.html to whatever path you are using to do your Elastic Beanstalk health check
For more info see my response here.

This answer assumes you have already enabled https in the load balancer security group, added the SSL certificate to the load balancer, added 443 to the ports forwarded by the load balancer, and pointed your domain name at the Elastic Beanstalk environment with Route 53 (or equivalent DNS service).
Amazon Linux 2
Most AWS Linux version 2 based platforms have the option to pick Apache as your proxy host. This can be done by going to "Configuration" > "Software" >
"Container Options" and setting "Proxy Server" to "Apache", or adding the following to one of your .config files in .ebextensions:
option_settings:
aws:elasticbeanstalk:environment:proxy:
ProxyServer: apache
Having done that, add a configuration file named .platform/httpd/conf.d/ssl_rewrite.conf to your codebase (relevant AWS docs) with the following contents:
RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</If>
Amazon Linux 1
All you need to do is add the following to one of your [.config files in the .ebextensions directory of your project][2]:
files:
"/etc/httpd/conf.d/ssl_rewrite.conf":
mode: "000644"
owner: root
group: root
content: |
RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</If>
Explanation
This is moderately straight forward outside of Elastic Beanstalk. One usually adds an Apache rewrite rule like the following:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
Or, if behind a load balancer, like we are in this case:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
However, these configurations only work within a <VirtualHost> block. Changing the RewriteCond to an <If> block allows it to work properly outside of a <VirtualHost> block, allowing us to put in in a standalone Apache config file. Note that standard Apache setup on CentOS (including the setup on ElasticBeanstalk) inculdes all files matching /etc/httpd/conf.d/*.conf, which matches the file path where we are storing this file.
The -n '%{HTTP:X-Forwarded-Proto}' part of the condition prevents it from redirecting if you are not behind a load balancer, allowing you to have shared configuration between a production evironment with a load balancer and https, and a staging environment that is single instance and does not have https. This is not necessary if you are using load balancers and https on all of your environments, but it doesn't hurt to have it.
Bad solutions I have seen
I have seen a lot of bad solutions to this problem, and it is worth going through them to understand why this solution is necessary.
Use Cloudfront: Some people suggest using non-cached Cloudfront setup in front of Elastic Beanstalk to do the HTTP to HTTPS redirect. This adds a whole new service (thus adding complexity) that isn't exactly appropriate (Cloudfront is a CDN; it's not the right tool for forcing HTTPS on inherantly dynamic content). Apache config is the normal solution to this problem and Elastic Beanstalk uses Apache, so that's the way we should go.
SSH into the server and...: This is completely antithetical to the point of Elastic Beanstalk and has so many problems. Any new instances created by autoscaling won't have the modified configuration. Any cloned environments won't have the configuration. Any number of a reasonable set of environment changes will wipe out the configuration. This is just such a bad idea.
Overwrite the Apache config with a new file: This is getting into the right realm of solution but leaves you with a maintenance nightmare if Elastic Beanstalk changes aspects of the server setup (which they very well may do). Also see the problems in the next item.
Dynamically edit the Apache config file to add a few lines: This is a decent idea. The problems with this is that it won't work if Elastic Beanstalk ever changes the name of their default Apache config file, and that this file can get overwritten when you least expect: https://forums.aws.amazon.com/thread.jspa?threadID=163369

Create a static health.html. If possible, as a configuration Template.

this is an easy solution
ssh into your EC2 instance
copy the contents of /etc/httpd/conf.d/wsgi.conf into a local file called wsgi.conf which will be placed in the base folder of your application
Edit the local version of wsgi.conf and add the following redirect rules within the < VirtualHost> < /VirtualHost> tags
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule !/status https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
Change the “/status” to whatever page you are using as a health check page.
Save the file
Edit your < app>.conf file inside your .ebextensions directory to add a container command to copy this version of wsgi.conf over Amazon’s version
container_commands:
01_syncdb:
command: "django-admin.py syncdb --noinput" leader_only: true
02_collectstatic:
command: "django-admin.py collectstatic --noinput"
03_wsgireplace:
command: 'cp wsgi.conf ../wsgi.conf'
...
Deploy the code.
The deployed version of wsg.conf at /etc/httd/conf.d/wsgi.conf will now include the necessary redirect rules.
It should work and the file will be properly updated for each deployment. The only thing to watch for is if Amazon changes their base wsgi.conf file contents in the future, then your copy may no longer work.
Autor rickchristianson

For me, copying the wsgi.conf into place never worked. Either EB would fail to deploy, or the file would be overwritten.
The only answer I found that worked was here. Essentially, he used sed to insert the necessary rewrite rules into the wsgi.conf. He says the container command to add is
container_commands:
01_http_to_https_redirect:
command:
sed -i '/\<VirtualHost \*:80\>/a RewriteEngine On\nRewriteCond %{HTTP:X-Forwarded-Proto} !https\nRewriteRule \!/robots.txt https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]' /opt/python/ondeck/wsgi.conf
Don't forget to change your health check endpoint from robots.txt.

As a general strategy what has worked for us, with both Apache and Nginx EC2 instances behind an AWS secured Load Balancer, is:
At the load balancer, forward port 80 to port 80 on the instances
forward port 443 to port 8080 (for example) on the instances
In the web server, listen on both ports (80 and 8080)
redirect port 80 to port 443
Add environment variable "HTTPS", with value "on" to the EC2's, e.g. using the Elastic Beanstalk Software Configuration
Step 1 ensures that AWS internal traffic is treated "naturally".
Step 2 allows only secure external traffic to reach our code
Step 5 tells the web server and what's behind it (Laravel, in our case) that generated URL's should be given the https: scheme. Other frameworks may need some other environment variables set in order to trigger that behavior.

Related

apache rewrite rule for http_host containing port

In the local network, I have synology server with a number of services running in docker on different ports and accessible in-browser like that
192.168.1.2:8989 or server.spb.lan:8989
How to make a rewrite rule to convert them like that 192.168.1.2/servicename or server.spb.lan/servicename?
Like that
192.168.1.2:8989 -> 192.168.1.2/servicename
server.spb.lan:8989 -> server.spb.lan/servicename
Based on your shown samples, could you please try following. Please make sure you clear your browser cache after placing these rules in your htaccess file.
RewriteEngine ON
RewriteCond %{HTTP_HOST} 192\.168\.1\.2
RewriteCond %{REQUEST_URI} ^/servicename [NC]
RewriteRule ^ http://%{HTTP_HOST}:8989%{REQUEST_URI} [NE,L]
RewriteCond %{HTTP_HOST} server\.spb\.lan
RewriteCond %{REQUEST_URI} ^/servicename [NC]
RewriteRule ^ http://%{HTTP_HOST}:8989%{REQUEST_URI} [NE,L]
I assume, that those backend services operate based on the http protocol, since you did not specify anything else...
Easiest probably is to use the apache proxy module to expose those backend services. You can use it within the rewriting module which makes the approach pretty convenient:
RewriteEngine on
RewriteRule ^/?servicename(/.*)$ https://server.spb.lan:8989$1 [P]
An alternative to the rewriting module would be to implement a reverse proxy:
ProxyRequests off
ProxyPass /servicename https://server.spb.lan:8989
ProxyPassReverse /servicename https://server.spb.lan:8989
I suggest you read about the details in the apache documentation. As typical for OpenSource it is of excellent quality and comes with great examples.
I couldn't solve the issue with apache installed directly on Synology. So I deleted it, deleted web station. Then I install nginx in docker. Synology has integrated nginx running on port 80, which cannot be deleted and there is no access to its settings.
So I just mapped internal port 80 of nginx container to port 82 on Synology, make forward port 80 from router to port 82 on Synology.
And then in config of nginx container I did simply that for each of my app running in docker
server {
server_name sonarr.lan;
location / {
proxy_pass http://192.168.1.2:8989;
}
}

.htaccess two domains redirects to one ssl domain

I've been struggling to get this code to work. I have two domains in my site, and I need to redirects all traffic to the secure url.
This is my code:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?old-domain\.cl$ [OR]
RewriteCond %{HTTPS} ^(www\.)?old-domain\.cl$ [OR]
RewriteCond %{HTTP_HOST} ^www\.new-domain\.cl$ [NC]
RewriteRule ^(.*)$ https:\/\/new-domain\.cl/$1 [L,R=301]
RewriteCond %{HTTPS} !=on
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
Works with the root url: http://new-domain.cl --> https://new-domain.cl and http://old-domain.cl --> https://new-domain.cl, but not in others locations within the site (ex: http://old-domain.cl/foo not changing at all).
I understand from your question that "new-domain.cl" is the host name you want to redirect to? So that %{SERVER_NAME} points to that host name? If so this probably is what you are looking for:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?old-domain\.cl$ [OR]
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,END]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,END]
It is a good idea to start out with a 302 temporary redirection and only change that to a 301 permanent redirection later, once you are certain everything is correctly set up. That prevents caching issues while trying things out...
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
This implementation will work likewise in the http servers host configuration or inside a distributed configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a distributed configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using distributed configuration files (".htaccess"). Those distributed configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).

Google load balancer with apache rewrite engine (mod_rewrite) won't work?

I recently set up a load balancer with Google Compute Engine to manage SSL certificates for me for my apache instance. (simple website)
But I am very confused. I am using a rewrite engine to change the clients URL to the proper one.
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=302]
RewriteCond %{HTTP_HOST} ^([^.]+\.)?example?\. [NC]
RewriteRule ^ https://%examples.co%{REQUEST_URI} [L,NE,R=302]
Rewrites: http to https, www to non-www, non-plural to plural, and all to TDL .co.
This code works without a load balancer. But with a load balancer, it's completely useless.
I've put this code in my /etc/apache2/sites-enabled/default-ssl.conf and also tried in my 000-default.conf file as well. Yes I did an apache reset after each edit. Other configurations such as Document Root all work fine in these conf files.
I also did sudo a2enmod rewrite in case you're wondering. Also, I get no errors! Other mods such as VirtualDocumentRoot which I am also using in the same conf files work perfectly.
Both http and https websites work, but their urls are just not changing according to rewrite engine.
I've also tried to use the solution here from Google forms, but with no success.
I am completely stumped on what to do at this point. Any ideas or suggestions. Am I missing headers or something? Why won't any of the RewriteEngine work?!

.htaccess redirect from foo.com/sub to bar.com/sub

I would like to htaccess-redirect all visitors from a subfolder of a domain to the same subfolder in another domain. That should apply to all subfolders and files - but only for the folder "folder"
For example:
foo.com/folder -> bar.com/folder
and with sub-structure
foo.com/folder/subfolder/file.php -> bar.com/folder/subfolder/file.php
All the posts I found were only concerning (sub)folders and not the domains.
Thanks!
Update: Thanks to the contributers - of course I tried to search, but Drupal blocked the redirects, so I didn't think the answers I found worked. Thanks anyways for the correct answer!
This should roughly be what you are looking for:
RewriteEngine on
RewriteRule ^/?(.*)$ https://example.com/$1 [END,QSA]
That rule will work likewise in the http servers host configuration and in dynamic configuration files (".htaccess").
In case you receive an "internal server error (http status 500)" with this chances are that you operate a very old version of the apache http server. In that case will find a hint on this in the http servers error log files. You need to replace the [END] flag with the [L] flag in that case.
In case you operate both domains as virtual hosts on a single http server you need to take care not to create an endless rewriting loop. In that case add a condition to prevent such loop:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^example\.com$
RewriteRule ^/?(.*)$ https://example.com/$1 [END,QSA]
A general hint: you should always prefer to place such rules inside the http servers (virtual) host configuration instead of using dynamic configuration files (.htaccess style files). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).
UPDATE:
In a comment below you mention that you want to apply such redirection only to a specific subfolder in the request path. To do that you just have to modify the matching pattern:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^example\.com$
RewriteRule ^/?folder/(.*)$ https://example.com/folder/$1 [END,QSA]
An alternative would be that:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^example\.com$
RewriteRule ^/?(folder/.*)$ https://example.com/$1 [END,QSA]

Apache mod rewrite to direct from one server to another

I've got to apache web servers running. One on port 80 and another on port 8077.
I'm wanting to try and redirect all the traffic through the port 80 version if possible.
What I'm ideally wanting is to be able to go to http://translate.example.com
and the traffic get directed to http://www.example.com:8077
I've already got a lot of mod_rewrite going on at the main port 80 server, but I'm not sure which of the servers needs configuration or whether both do.
I'm wanting to make sure that translate.example.com/img (or any other subdirectory) actually points to the 8087/images directory.
update
I've now got the following:
RewriteCond %{HTTP_HOST} example[NC]
RewriteCond %{REQUEST_URI} ^/glot$ [NC]
RewriteRule ^(.*)$ http://www.example.com:8077/$1 [P]
ProxyPassReverse / http://www.example.com/
I'm getting to see the other servers new pages, but I'm finding all the resources aren't found like images, css etc
Doing a view source all the resources in the installed product are set with leading slash
For example
/img/glotpress-logo.png
So I'm not sure how to get the resources loaded up.
Note I'm happy enough if the original starting point is www.example.com/glot instead of glot.example.com as in the original question
You can remap your resources to another server but having the other server on non-default port might prevent some of your visitors from viewing them as they might be block (firewalled) from accessing the port. If you're not worry about the port being block you can use mod_rewrite Remapping Resources. method.
RewriteEngine On
RewriteRule ^/images/(.+) http://www.example.com:8077/images/$1 [R,L]
If you want to make sure that everyone is able to view the external resources, you need to use proxy where apache will tunnel the visitor connection to example.com:8077 transparently. You can read more about mod_rewrite for Proxying at apache website.
RewriteEngine on
RewriteBase /images/
RewriteRule ^images/(.*)$ http://example.com:8077/images/$1 [P]
ProxyPassReverse /images/ http://example.com/images/
UPDATE
Have you tried to remove
RewriteCond %{HTTP_HOST} example[NC]
This line basically tells that it will only process if the HTTP_POST is example.com if its coming from www.example.com this rule is not applicable. I'm hoping that "example[NC]" is a typo.
In the end it probably looks like
RewriteRule ^/glot/(.*)$ http://www.example.com:8077/glot/$1 [P]
ProxyPassReverse /glot/ http://www.example.com:8077/glot/
You need to do the configuration at the port 80 server to make it act as a proxy for the 8077 server.
The Apache document is here: http://httpd.apache.org/docs/trunk/rewrite/proxy.html