AWS Application Load Balancer - https not working properly - amazon-web-services

I have a web application developed with React JS, for server side rendering, I am using NodeJS. Following is the overall architecture -
Deployed React JS app on EC2 - Ubuntu 18.04 with Nginx
Obtained SSL from AWS ACM
Attached ALB to EC2 instance, added 2 listeners - PORT 80, PORT 443 (Forwarding request to target group on PORT 80)
Added A record on Godaddy with EC2 elastic IP, added CNAME record www pointing to ALB
Following is my nginx config file -
server {
server_name mydomain.ai;
return 301 https://www.mydomain.ai$request_uri;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
#server_name www.mydomain.ai;
if ($host !~ ^www\.) {
rewrite ^ https://$host$request_uri permanent;
}
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location /error {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8000;
}
location /aws/ {
try_files $uri $uri/ /aws/aws.html;
}
}
server {
listen *:443 default_server;
server_name mydomain.ai www.mydomain.ai;
if ($host !~ ^www\.) {
rewrite ^ https://$host$request_uri permanent;
}
location / {
proxy_hide_header 'Access-Control-Allow-Origin';
add_header 'Access-Control-Allow-Origin' "*" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
proxy_pass https://localhost:8000;
proxy_http_version 1.1;
}
}
When I type https://mydomain.ai it throws "ERR_SSL_PROTOCOL_ERROR", however following cases are working fine -
mydomain.ai //redirected to https://www.mydomain.ai
http://mydomain.ai //redirected to https://www.mydomain.ai
http://www.mydomain.ai //redirected to https://www.mydomain.ai
Can anyone please help me?

I think you forgot to attach the procured certificate to ALB.
It can be done from AWS console by following the steps mentioned:
https://aws.amazon.com/premiumsupport/knowledge-center/associate-acm-certificate-alb-nlb/

Related

Nginx append a trailing slash to the url

I am having an issue in Safari and IE where a django redirect does not include the authorization headers. This leads to the requests being rejected.
These redirects happen with the URL does not end with a /.
So I am trying to handle adding the / in the nginx config before it is passed to the app.
Here is my nginx config:
server {
server_name ~^((stage|prod)-)?chalktalk-react-40.*;
listen 28000 default_server;
location ~ ^/static/(?P<file>.*) {
root /chalktalk/var/chalktalk-react-40;
add_header 'Access-Control-Allow-Origin' $cors_origin;
# Inform downstream caches to take certain headers into account when reading/writing to cache.
add_header 'Vary' 'Accept-Encoding,Origin';
try_files /staticfiles/$file =404;
}
location ~ ^/media/(?P<file>.*) {
root /chalktalk/var/chalktalk-react-40;
try_files /media/$file =404;
}
location / {
if ($request_uri ~ ^([^.\?]*[^/])$) {
return 301 $1/;
}
}
# API endpoints have their own authentication and authorization
# schemes, so we bypass basic auth.
location ~ ^/(api|admin|ws)/ {
try_files $uri #proxy_to_app;
}
rewrite ^(.*)/favicon.ico$ /static/pages/homepage/logo-nonname.png last;
location #proxy_to_app {
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_read_timeout 1200;
proxy_redirect off;
proxy_pass http://chalktalk-react-40_app_server;
}
# Forward to HTTPS if we're an HTTP request...
if ($http_x_forwarded_proto = "http") {
set $do_redirect "true";
}
# Run our actual redirect...
if ($do_redirect = "true") {
rewrite ^ https://$host$request_uri? permanent;
}
}
I know I have to add a rewrite and this is the rewrite I am trying to add:
server {
...
listen 28000 default_server;
rewrite ^([^.]*[^/])$ $1/ permanent;
...
}
The issue that I have with that is when I try to visit: example.com/admin, I get example.com:28000/admin/.
How do i make sure it leads to this example.com/admin/ without the port # inserted there?
UPDATE:
I updated the config to have the following:
server {
server_name ~^((stage|prod)-)?chalktalk-react-40.*;
listen 28000 default_server;
port_in_redirect off;
rewrite ^([^.]*[^/])$ $1/ permanent;
...
}
But I get this error in Safari:
Use either the port_in_redirect directive, for example:
port_in_redirect off;
Or tell Nginx exactly what you want in the rewrite directive, for example:
rewrite ^([^.]*[^/])$ $scheme://$host$1/ permanent;

Adding SSL to the Django app, Ubuntu 16+, DigitalOcean

I am trying to add my SSL certificate to my django application according to this tutorial. I can turn on my website using 'https://ebluedesign.online'. But web browsers return something in style 'The certificate can not be verified due to a trusted certificate authority.' After accepting the messages, my page is displayed correctly.
My nginx file looks like this:
upstream app_server {
server unix:/home/app/run/gunicorn.sock fail_timeout=0;
}
server {
#listen 80;
# add here the ip address of your server
# or a domain pointing to that ip (like example.com or www.example.com)
server_name ebluedesign.online;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/ebluedesign.online/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/ebluedesign.online/privkey.pem;
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/app/logs/nginx-access.log;
error_log /home/app/logs/nginx-error.log;
location /static/ {
alias /home/app/static/;
}
# checks for static file, if not found proxy to app
location / {
try_files $uri #proxy_to_app;
}
location #proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
server {
listen 80;
listen [::]:80;
server_name ebluedesign.online;
return 301 https://$host$request_uri;
}
My certificates are also visible here:
/etc/letsencrypt/live/ebluedesign.online/...
How can I solve this problem with SSL certificate. I use free SSL by https://letsencrypt.org/.
EDIT:
What is odd is if you go to http://bluedesign.online/ it works fine even though your file makes it seem as if port 80 isn’t listened too at all. Do you happen to have two setup files in nginx? It is possible that the one you posted is not being used.
I’ve followed this tutorial many times with success. You could try using it from scratch if you have the opportunity: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04

How to set nginx to use static and dynamic page on the same domain?

I have a Ruby on Rails application, using Nginx webserver with HTTPS running with success in a specific domain (e.g. https://testing.com).
Now, I purchased a landing page template (HTML and JS only) and I need to set it up in the same domain.
Being more specific, what I need is:
https://testing.com/ -> renders landing page template
https://testing.com/* -> renders RoR application
As far as I do not have much knowledge on Nginx configuration, here it's my nginx current configuration:
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/var/www/poseidon/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name testing.com www.testing.com;
return 301 https://$server_name$request_uri;
}
server {
# SSL configuration
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
include snippets/ssl-testing.com.conf;
include snippets/ssl-params.conf;
server_name testing.com;
root /var/www/poseidon/public;
try_files $uri/index.html $uri #app;
location #app {
proxy_pass http://app;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on; # Optional
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
location ~ /.well-known {
allow all;
}
}
I uploaded the landing page nginx configuration and I tried something like, but I had no success:
location /* {
root /var/www/landingtesting.com;
}
Any help will be really appreciated!

Elasticbeanstalk - Force HTTPs on Docker container with Nginx

I have a single-container Docker running a React environment on Elasticbeanstalk with Nginx. I pointed a subdomain to the ELB URL, and want to force a HTTPS redirection if you visit the subdomain (i.e. you type subdomain.domain.com and it should redirect you to HTTPS).
Now, if I visit the default ELB URL (something.eu-central-1.elasticbeanstalk.com), it will be redirected to HTTPS. But I want my custom domain (which is parked somewhere else but points to something.eu-centralblabla with a CNAME) to be forced to use HTTPS as well, but it doesn't happen. It allows regular HTTP requests.
I've tried several guides and followed AWS documentation, but I cannot seem to force it to redirect to HTTPS on my custom subdomain.
These are my files:
/.ebextensions folder
http-instance.config
files:
/etc/nginx/conf.d/https.conf:
mode: "000644"
owner: root
group: root
content: |
# HTTPS Server
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate /etc/pki/tls/certs/server.crt;
ssl_certificate_key /etc/pki/tls/certs/server.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://docker;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
#SSL CRT and KEY below
https-instance-single.config
Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
CidrIp: 0.0.0.0/0
/nginx folder
default.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html?/$request_uri;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
error_page 500 504 /500.html;
error_page 502 /502.html;
error_page 503 /503.html;
client_max_body_size 4G;
keepalive_timeout 10;
location ~ ^/(favicon|static)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
# add_header Last-Modified "";
# add_header ETag "";
open_file_cache max=1000 inactive=500s;
open_file_cache_valid 600s;
open_file_cache_errors on;
break;
}
}
What am I doing wrong? Thanks for your help!
You should be able to manage this in your nginx config by adding this within the server context:
set $redirect_to_https 0;
if ($http_x_forwarded_proto != 'https') {
set $redirect_to_https 1;
}
if ($redirect_to_https = 1) {
rewrite ^ https://$host$request_uri? permanent;
}
Or something to that effect.
Route all http traffic to https:
server {
listen 80;
return 301 https://$host$request_uri;
}
Then hangle the proxy stuff in the 443 block

How to set up HTTPS on Amazon EC2 with Elastic Load Balancer

I have requested a certificate in Amazon Certificate Manager. Now it has status 'issued'.
In EC2 console I have created Load Balancer. There are 2 listeners: HTTP and HTTPS. I tried Application Load Balancer and Classic Load Balancer, but I can't connect to my site via HTTPS.
My nginx config:
server {
listen 80;
#listen 443 ssl;
rewrite ^(.*) https://$host$1 permanent;
server_name site.com www.site.com;
root /home/ubuntu/www/site.com/wordpress;
index index.php;
client_max_body_size 20m;
gzip on;
gzip_disable "msie6";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
location ~* ^/(\.htaccess|xmlrpc\.php)$ {
return 404;
}
location ~ /\. {
deny all;
}
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
set $is_https 'off';
if ($http_x_forwarded_proto ~ 'https') {
set $is_https 'on';
}
proxy_set_header HTTPS $is_https;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
#try_files $uri $uri/ /index.php?$args; # permalinks
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
How can I import the certificate manually? Or there is a way to set up HTTPS connection with the Amazon certificate?
If you have an ACM cert, you can just select that certificate from the ELB Listener for HTTPS/443 and you don't need to bother setting up the SSL config in your nginx instance. Just have it respond on port 80.
You just need both HTTP/80 and HTTPS/443 in the ELB to HTTP port 80 on the instance (This sample is using the Classic ELB)
If the Cert is in ACM you should see it in the dropdown once when you select "Change" under SSL Certificate.
Now you just need to make sure your ELB security group is set up to allow Ingress from 80/443 and Egress from 80. And you need to make sure your instance allows Ingress from the ELB Security Group.
Depending on your ELB setup and port mapping, the $https variable won't always work when your instance is behind an AWS ELB (h/t #Michael - sqlbot). You should use HTTP_X_FORWARDED_PROTO header instead and move your rewrite rule inside the IF statement that checks for the HTTP_X_FORWARDED_PROTO header:
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if ($http_x_forwarded_proto != "https") {
rewrite ^(.*)$ https://$server_name$1 permanent;
}
.
.
.
}
Note on Security Groups
Also, you need to ensure that your load balancer can communicate with registered targets on both the listener port and the health check port. For more info:
Security Groups for Your Application Load Balancer
Security Groups for Your Classic Load Balancer