how to configure nginx to use SSL Certificate in ubuntu 16.04 - django

https://www.petercuret.com/how-ssl-encrypt-your-django-heroku-projects-free-lets-encrypt/
This article about encrypt django app is a great tutorial. I did most of the process, except the last one. "Adding the security certificate to Heroku", mine is cloud server with Ubuntu 16.04. So it's not adapted to my server.
Googled around about "Nginx ssl encrypt", and found this tutorial(https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04)
I configured nginx server as this tutorial. When all finished, I tested it with "curl https://example.com(my domain)", it returns "Failed to connect to example.com port 443: Connection refused"
PS: nginx runs in host, and Django app runs in a docker container
Some results of my server:
root#i-atbxncfv:~# sudo ufw status
Status: active
To Action From
-- ------ ----
Nginx Full ALLOW Anywhere
443/tcp ALLOW Anywhere
443 ALLOW Anywhere
22/tcp ALLOW Anywhere
Nginx Full (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
22/tcp (v6) ALLOW Anywhere (v6)
root#i-atbxncfv:~# sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
root#i-atbxncfv:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b082bf17c218 e5b11bf09f49 "/usr/sbin/sshd -D" 2 days ago Up 2 days 0.0.0.0:21->22/tcp, 0.0.0.0:32789->80/tcp, 0.0.0.0:32788->5000/tcp django_app_1
root#i-atbxncfv:/etc/nginx/sites-enabled# cat example-com.conf
server {
listen 80;
server_name example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://0.0.0.0:32788;
}
}
root#i-atbxncfv:/etc/nginx/sites-available# cat default
server {
listen 80;
listen [::]:80;
server_name test.doask.net;
return 301 https://$server_name$request_uri;
# SSL configuration
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# include snippets/snakeoil.conf;
}
server {
# SSL configuration
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-test.doask.net.conf;
include snippets/ssl-params.conf;

Related

NGINX on AWS EC2 to forward HTTPS to HTTP://localhost

I have some dockers containers deployed on AWS EC2, that listens on http.
My idea is using nginx as reverse proxy, to pass traffic from https, to http://localhost.
Each container listens on a specific http port. The EC2 instance will accept traffic just on http:80 and http:443 and I will use subdomain to chose the right port.
So I should have:
https://backend.my_ec2instance.com --> http://localhost:4000
https://frontend.my_ec2instance.com --> http://localhost:5000
I'v got my free TSL certificate from Let's Encrypt (it's just on file containing public and private keys), and put it in
/etc/nginx/ssl/letsencrypt.pem
Then I have configured nginx in this way
sudo nano /etc/nginx/sites-enabled/custom.conf
and wrote
server {
listen 443 ssl;
server_name backend.my_ec2instance;
# Certificate
ssl_certificate letsencrypt.pem;
# Private Key
ssl_certificate_key letsencrypt.pem;
# Forward
location / {
proxy_pass http://localhost:4000;
}
}
server {
listen 443 ssl;
server_name frontend.my_ec2instance;
# Certificate
ssl_certificate letsencrypt.pem;
# Private Key
ssl_certificate_key letsencrypt.pem;
# Forward
location / {
proxy_pass http://localhost:5000;
}
}
then
sudo ln -s /etc/nginx/sites-available/custom.conf /etc/nginx/sites-enbled/
Anyway, if I open my browser on https://backend.my_ec2instance it's not reachable.
http://localhost:80 instead correctly shows the nginx page.
HTTPS default port is port 443. HTTP default port is port 80. So this: https://localhost:80 makes no sense. You are trying to use the HTTPS protocol on an HTTP port.
In either case, I don't understand why you are entering localhost in your web browser at all. You should be trying to open https://frontend.my_ec2instance.com in your web browser. The locahost address in your web browser would refer to your local laptop, not an EC2 server.
Per the discussion in the comments you also need to include your custom Nginx config in the base configuration file.

LoadBalancer in EC2 Instance showing status OutOfService

Here is My Scenario.
I'm using ACM to generate 2 SSL certificates. example.com and *.example.com
I have 2 load balancers linked to the same EC2 instance.
1) Linked to my wordpress website - example.com
2) Linked to my app - *.example.com
Checklist I followed to troubleshoot outofservice error:
1) Instance State - Running
2) Status Checks - 2/2
3) Security Group Setting - Port 80/443/22 are open
4) Below are my Health Check settings
Ping Target - HTTP:80/
Timeout - 5 seconds
Interval - 30 seconds
Unhealthy threshold - 2
Healthy threshold - 10
I'm using NGINX webserver. I have checked the status, it shows its active.
Here is my config file example.com:
server
{
server_name www. example.com;
return 301 $scheme://example.com$request_uri;
}
server {
listen 80;
listen 443;
server_name example.com;
root /opt/bitnami/apps/wordpress/htdocs;
}
server {
listen 80;
listen 443;
server_name ~^(.*)\. example\.com$ ;
root /opt/bitnami/apps/example_app;
}
What could be the problem here? Is the problem related to NGINX config settings or is it related to Load Balancer settings?
Your nginx settings are definitely not correct. There is no SSL at the instance level. Instead, the elb would terminate the SSL connection to the client. The only connection the ec2 instance should accept is on Port 80 and only from the elb. I suggest you remove the SSL report for for three references in nginx and make sure it's configured as above.
You'll definitely need to configure nginx to run php scripts. Since php is a pre processing engine, your nginx configuration needs to know how to handle php files.
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name server_domain_or_IP;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
reference: https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-in-ubuntu-16-04
Since you mentioned this was a wordpress website, you'll need to setup a LEMP stack.

How to solve 502 Bad Gateway errors with Elastic Load Balancer and EC2/Nginx for HTTPS requests?

I'm running into '502 Bad Gateway' issues for HTTPS requests when using AWS Elastic Load Balancer (Application type) in front of EC2 instances running Nginx. Nginx is acting as a reverse proxy on each instance for a waitress server serving up a python app (Pyramid framework). I'm trying to use TLS termination at the ELB so that the EC2 instances are only dealing with HTTP. Here's the rough setup:
Client HTTPS request > ELB (listening on 443, forwarding to 80 on backend) > Nginx listening on port 80 (on Ec2 instance) > forwarded to waitress/Pyramid (on same ec2 instance)
When I make requests on HTTPS I get the 502 error. However, when I make regular HTTP requests I get a response as expected (same setup as above except ELB is listening on port 80).
Some additional info:
ELB health checks are working.
All VPC/Security groups are configured correctly (I believe).
I'm using an AWS certificate on the ELB using the standard setup/walkthrough on AWS.
I SSH'd into the Ec2 instance and in the Nginx access log it looks like the HTTPS request are still encrypted? Or some encoding issue?
And here's nginx.conf on the EC2 instance:
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /etc/nginx/access.log;
sendfile on;
# Configuration containing list of application servers
upstream app_servers {
server 127.0.0.1:6543;
}
server {
listen 80;
server_name [MY-EC2-SERVER-NAME];
# Proxy connections to the application servers
# app_servers
location / {
proxy_pass http://app_servers;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
Ok I figured it out (I'm a dummy). I had two listeners set up on the ELB, one for 80 and one for 443, which was correct. The listener for 80 was set up correctly to forward to backend (Nginx) port 80 over HTTP as expected. The 443 listener was INCORRECTLY configured to send to port 80 on the backend over HTTPS. I updated the 443 listener to use the same rule as the 80 listener (i.e. listen on 443 but send to backend 80 over HTTP) and it worked. Disregard y'all.

CNAME to a secure url

I have an AWS Elastic Load Balancer with the following secure url:
https://example.us-west-2.elasticbeanstalk.com/
I also have the following 1&1 registered domain name:
example.com
I then in 1&1 config add a subdomain of www resulting in www.example.com.
I would like to add a CNAME alias to route traffic from the domain name to the ELB.
www.example.com -> https://example.us-west-2.elasticbeanstalk.com/
So I try add the CNAME:
As you can see, it is not accepting the url, as it is an Invalid host name.
I need the alias to pint to the secure (https) url. However, I think this may be the reason for the error.
Question
How do I set up a CNAME to point to a secure url?
Thanks
UPDATE
My Elastic Load Balanacer does have a secure listener.
You have to specify HTTPS in your NGINX using a redirect or Apache using mod_rewrite. If you want a little higher level HTTP to HTTPS roll over, you can do this (most of the time) in your application by specifying where your certs are located and doing a listen on Port 80 with a redirect/relocate to Port 443
On the DNS level you only specify the location. In your application, or on your server somewhere, you specify the HTTP/HTTPS protocol. DNS, being a protocol itself, cannot specify other protocols in its response. HTTPS is a processor intensive encryption operation done on your server.
I would highly recommend using AWS Certificate Manager to assign a certificate to your domain. If you'd rather have it in your beanstalk application, check out letsencrypt. It's a wonderful CLI tool for this stuff.
Here is a helpful resource
Ubuntu + NGINX + letsencrypt
Configuring HTTP to HTTPS on Ubuntu. Yes, only one operating system specific example, but letsencrypt should work anywhere with anything, anytime.
sudo apt-get update
sudo apt-get install letsencrypt
sudo apt-get install nginx
sudo systemctl stop nginx #if it starts by default...
sudo letsencrypt certonly --standalone -n -m richard#thewhozoo.com.com -d thewhozoo.com -d cname.thewhozoo.com --agree-tos
sudo ls -l /etc/letsencrypt/live/thewhozoo.com/ #you should see your stuff in this folder
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 #make yo'self a diffie
sudo vim /etc/nginx/sites-available/default
In your default file:
(Snippets from: HERE and HERE and HERE and HERE)
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name thewhozoo.com www.thewhozoo.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name thewhozoo.com www.thewhozoo.com;
ssl_certificate /etc/letsencrypt/live/thewhozoo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/thewhozoo.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
}
Now that your NGINX file has your certs/keys/pems/whatever listed, you have to double check your firewall.
For Ubuntu and ufw, you can allow access via:
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
sudo ufw allow 'OpenSSH'
sudo ufw enable
sudo ufw status
And you should see Nginx HTTPS enabled.
No matter what your flavor of HTTPS is (SSL, TLSvXX, etc.) you'll need Port 22 open on the firewall level cause they all use it, hense the 'OpenSSH'.
BE SURE TO RUN allow 'OpenSSH' BEFORE ufw enable. If you do not... your SSH session will be terminated and...good luck.
Now your firewall is good to go, restart nginx and you should be set:
sudo systemctl start nginx
Helpful tips for the future:
NGINX by default set the renewal policy to 3 months. I'm not certain if this is a "standard" of internet law or not, but the add-on for renewing your certs is:
Add this to your crontab:
sudo systemctl stop nginx
sudo letsencrypt renew
sudo systemctl start nginx
HELPFUL NOTES:
You must have the domain name linked to the server of choice BEFORE running letsencrypt. It does a reverse IP Lookup to make sure you are the owner/admin of the domain.
You do not need the giant list of encryption types but I would highly recommend keeping most of them. Elliptical Curve Diffie Hellman is a must for the type of key used above, but you can probably cut it down to ECDH?E, AES, GCM, and RSA or SHA depending on how many cipher suites you want to support. IF you aren't going to support SSLvX and only do TLSvX you only need to support (and restrict) the following: ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DHE+AES128:!ADH:!AECDH:!MD5;
AWS Certificate Manager (ACM) + Elastic Load Balancer
Go to your Load Balancer in the EC2 Resource Console
Select your listener
Should probably say: HTTPS: 443 in bold letters
Check it and click Actions => Edit
Double check that your Protocol is HTTPS on Port 443 and your target group is good
At the bottom of the pop-up, select "Choose an existing certificate from AWS Certificate Manager (ACM)
Then select your ACM Certificate
Save it
SSH into your instance/application on EBS/whatever
Write an NGINX policy for redirecting HTTP traffic to HTTPS:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name thewhozoo.com www.thewhozoo.com;
return 301 https://$host$request_uri;
}
Restart NGINX
For Elastic Beanstalk environment check THIS INFO.
Wait about 5 minutes for everything to sink in and you should be good to go!
Check this for help if needed
Drop the 'http://' from the CNAME and just use:
example.us-west-2.elasticbeanstalk.com

elastic beanstalk weird nginx configuration

I am trying to follow the configuration of nginx on elastic beanstalk and some things do not add up.
The instance is opening port 80 in the security groups, so I assume all incoming traffic is coming through that port
The nginx configuration in cat /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf states:
server {
listen 8080;
location / {
proxy_pass http://nodejs;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
gzip on;
}
Port 8080? Where did that come from? I've tried to mess with it, this is the actual directive that is working.
server_name is missing, yet tt doesn't matter what you put in it. If I put any value in server_name myself, this server rule will still match all requests, even the ones that are not remotely reseble the server_name value.
While connected to the instance itself it seems both ports are being served:
[ec2-user#ip-172-31-45-222 ~]$ sudo netstat -lnptu
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 22506/nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 22506/nginx
Yet again, 8080 is never opened in the security group, so elastic load balanced is getting inside through port 80. Does traffic magically goes from 80 to 8080? Any ideas what is going on here?
You are forgetting to look at one part of that nginx config:
upstream nodejs {
server 127.0.0.1:8081;
keepalive 256;
}
That part is telling nginx to make a group of servers called nodejs as you can read about here.
8081 is the port that NodeJS is running on (if you use the sample application for instance).
You can verify this by looking at the Elastic Beanstalk logs:
-------------------------------------
/var/log/nodejs/nodejs.log
-------------------------------------
Server running at http://127.0.0.1:8081/
Then if we continue in the nginx.conf file we can see what you already posted:
server {
listen 8080;
location / {
proxy_pass http://nodejs;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
This tells nginx to use the proxy pass module to pass all from port 8080 to our upstream group nodejs which is running on port 8081. This means that port 8081 is just for accessing it locally but port 8080 is what let's outside entities talk to the nginx which then passes stuff onto nodejs.
Some of the reasoning for not exposing NodeJS directly can be found in this StackOverflow answer.
Port 8080 is used because it is the HTTP alternate port that is "commonly used for Web proxy and caching server, or for running a Web server as a non-root user."
That explains the ports. Now the issue of ELB and how things are talking to each other.
Since the security group is only allowing access on port 80, there is an iptables rule that is setup to forward port 80 to port 8080. This allows non-root to bind to port 8080 because lower port numbers require root privileges.
You can verify this by running the following:
[ec2-user#ip-xxx-xx-xx-x ~]$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- anywhere anywhere tcp dpt:http redir ports 8080
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- anywhere anywhere tcp dpt:http redir ports 8080
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
So in summary, when you load your CNAME, the load balancer is rerouting the traffic to a given instance on port 80, which is allowed through the security group, then iptables is forwarding that to port 8080, which is the port that nginx is using a proxy to pass the traffic to port 8081 which is the local port of NodeJS.
Here's a diagram:
incoming connections
-> :80 - Load Balancer
-> :80 - Security group
-> :80 -> :8080 - EC2 instance, iptables forward
-> :8080 -> :8081 - nginx, proxy pass
-> :8081 - nodejs, your app
Hopefully that helps.