I am currently deploying a Django + uWSGI app using a single container docker environment in AWS ElasticBeanstalk. This environment already ships with nginx, which I am currently trying to configure.
I am trying to achieve the following:
Environment information:
This is my current configuration:
.ebxtensions/00-loadbalancer-terminatehttps.config
option_settings:
aws:elb:listener:443:
ListenerEnabled: true
ListenerProtocol: HTTPS
SSLCertificateId: <resource-id-here>
InstancePort: 443
InstanceProtocol: HTTP
aws:elb:listener:80:
ListenerEnabled: true
ListenerProtocol: HTTP
InstancePort: 80
InstanceProtocol: HTTP
.ebextensions/01-nginx-proxy.config
files:
"/etc/nginx/sites-available/test.domain.com.conf":
mode: "000644"
owner: root
group: root
content: |
server {
listen 80;
server_name test.domain.com;
access_log /var/log/nginx/$server_name.access.log;
location / {
return 301 https://$server_name$request_uri;
}
location = /status/ {
access_log /var/log/nginx/$server_name.healthd.log healthd;
include uwsgi_params;
uwsgi_pass docker;
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 $host;
proxy_set_header X-Forwarded-Server $host;
}
}
server {
listen 443;
server_name test.domain.com;
access_log /var/log/nginx/$server_name.access.log;
location / {
include uwsgi_params;
uwsgi_pass docker;
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 $host;
proxy_set_header X-Forwarded-Server $host;
client_max_body_size 100m;
}
location /static {
alias /var/www/static;
}
}
commands:
00_enable_site:
command: 'rm -f /etc/nginx/sites-enabled/* && ln -s /etc/nginx/sites-available/test.domain.com.conf /etc/nginx/sites-enabled/test.domain.com.conf'
.ebextensions/02-healthcheckurl.config
option_settings:
- namespace: aws:elasticbeanstalk:application
option_name: Application Healthcheck URL
value: /status/
application.ini (uwsgi config)
[uwsgi]
master = true
socket = :3031
processes = 4
enable-threads = true
threads = 2
chdir = /opt/app/
wsgi-file = test/wsgi.py
logto2 = /var/log/uwsgi.log
callable = application
py-autoreload = 3
Now, when testing the configuration:
Checking http://test.domain.com/status/ works fine
$ wget http://test.domain.com/status/
--2017-01-14 23:00:18-- http://test.domain.com/status/
Resolving test.domain.com... 52.xx.xx.xx, 52.xx.xx.xy
Connecting to test.domain.com|52.xx.xx.xx|:80... connected.
HTTP request sent, awaiting response... 200 OK
Checking http://test.domain.com/hello/ doesn't work as expected. It redirects fine, but it then hangs until the request times out.
$ wget http://test.domain.com/hello/
--2017-01-14 22:59:13-- http://test.domain.com/hello/
Resolving test.domain.com... 52.xx.xx.xx, 52.xx.xx.xy
Connecting to test.domain.com|52.xx.xx.xx|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://test.domain.com/hello/ [following]
--2017-01-14 22:59:15-- https://test.domain.com/hello/
Connecting to test.domain.com|52.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 408 REQUEST_TIMEOUT
2017-01-14 23:00:17 ERROR 408: REQUEST_TIMEOUT.
Running NGINX Plus in a Docker ContainerDocker can also be used with NGINX Plus. The difference between using Docker with NGINX Open Source is that you first need to create an NGINX Plus image, because as a commercial offering NGINX Plus is not available at Docker Hub.
Each of the instances in the environment run the same set of containers, which are defined in a Dockerrun. aws. json v2 file. In order to get the most out of Docker, Elastic Beanstalk lets you create an environment where your Amazon EC2 instances run multiple Docker containers side by side.
If nginx is running in a container then your site is going to be 100% dead to the world while Docker isn't running. Users will get a connection error. When nginx is installed directly on your host you can serve a 503 maintenance page that doesn't depend on Docker or any containers running.
Following @deviavir's suggestion, I needed to allow traffic from the load balancer into the EC2 instance.
This is my final configuration:
.ebextensions
|-- 00-resources.config
|-- 01-nginx-proxy.config
.ebextensions/00-resources.config:
Resources:
AWSEBSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "Allow traffic to ports 80 and 443 from the load balancer. Restrict SSH access."
AWSEBLoadBalancer:
Type: "AWS::ElasticLoadBalancing::LoadBalancer"
Properties:
Listeners:
- {LoadBalancerPort: 80,
Protocol: 'HTTP',
InstancePort: 80,
InstanceProtocol: 'HTTP'}
- {LoadBalancerPort: 443,
Protocol: 'HTTPS',
InstancePort: 443,
InstanceProtocol: 'HTTP',
SSLCertificateId: 'arn:aws:acm:us-east-1:xxxx:certificate/yyyy'}
HealthCheck:
Target: HTTP:80/status/
HealthyThreshold: '3'
UnhealthyThreshold: '5'
Interval: '30'
Timeout: '5'
Port80SecurityGroupIngress:
Type: "AWS::EC2::SecurityGroupIngress"
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 80
FromPort: 80
SourceSecurityGroupName: {"Fn::GetAtt" : ["AWSEBLoadBalancer" , "SourceSecurityGroup.GroupName"]}
Port443SecurityGroupIngress:
Type: "AWS::EC2::SecurityGroupIngress"
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
SourceSecurityGroupName: {"Fn::GetAtt" : ["AWSEBLoadBalancer" , "SourceSecurityGroup.GroupName"]}
SSHSecurityGroupIngress:
Type: "AWS::EC2::SecurityGroupIngress"
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 22
FromPort: 22
CidrIp: xx.xx.xx.xx/yy
.ebextensions/01-nginx-proxy.config:
files:
"/etc/nginx/sites-available/test.domain.com.conf":
mode: "000644"
owner: root
group: root
content: |
server {
listen 80;
server_name test.domain.com;
access_log /var/log/nginx/$server_name.access.log;
location / {
return 301 https://$server_name$request_uri;
}
location = /status/ {
access_log /var/log/nginx/$server_name.status.log;
uwsgi_pass docker;
include uwsgi_params;
}
}
server {
listen 443;
server_name test.domain.com;
access_log /var/log/nginx/$server_name.access.log;
location / {
uwsgi_pass docker;
include uwsgi_params;
client_max_body_size 100m;
}
location /static/ {
root /var/www;
}
}
commands:
00_enable_site:
command: 'rm -f /etc/nginx/sites-enabled/* && ln -s /etc/nginx/sites-available/test.domain.com.conf /etc/nginx/sites-enabled/test.domain.com.conf'
edit:
OP's problem was resolved here Configuring nginx in a single docker container environment (AWS ElasticBeanstalk), I'm leaving the below info for completeness.
Remove the "server" block for port 443 from your nginx config, and in .ebxtensions/00-loadbalancer-terminatehttps.config
, set aws:elb:listener:443:
's InstancePort
to 80, and check for HTTPS using nginx '$http_x_forwarded_proto'.
if ($http_x_forwarded_proto != "https") {
rewrite ^(.*)$ https://$server_name$1 permanent;
}
Why? Currently it seems your nginx+elb are trying to terminate HTTPS together, but your nginx does not reply with any. If you're not planning on having internal HTTPS, it makes more sense to just stick to one nginx server block and do all of your logic there.
I'd propose the following config files:
.ebxtensions/00-loadbalancer-terminatehttps.config
option_settings:
aws:elb:listener:443:
ListenerEnabled: true
ListenerProtocol: HTTPS
SSLCertificateId: <resource-id-here>
InstancePort: 80
InstanceProtocol: HTTP
aws:elb:listener:80:
ListenerEnabled: true
ListenerProtocol: HTTP
InstancePort: 80
InstanceProtocol: HTTP
.ebextensions/01-nginx-proxy.config
files:
"/etc/nginx/sites-available/test.domain.com.conf":
mode: "000644"
owner: root
group: root
content: |
server {
listen 80;
server_name test.domain.com;
access_log /var/log/nginx/$server_name.access.log;
if ($http_x_forwarded_proto != "https") {
set $test http;
}
if ($request_uri = /status/) {
set $test "${test}+status";
}
if ($test = "http") {
return 301 https://$server_name$request_uri;
}
location = /status/ {
access_log /var/log/nginx/$server_name.healthd.log healthd;
include uwsgi_params;
uwsgi_pass docker;
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 $host;
proxy_set_header X-Forwarded-Server $host;
client_max_body_size 100m;
}
location /static {
alias /var/www/static;
}
location / {
include uwsgi_params;
uwsgi_pass docker;
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 $host;
proxy_set_header X-Forwarded-Server $host;
client_max_body_size 100m;
}
}
commands:
00_enable_site:
command: 'rm -f /etc/nginx/sites-enabled/* && ln -s /etc/nginx/sites-available/test.domain.com.conf /etc/nginx/sites-enabled/test.domain.com.conf'
Note that I am by no means claiming this is the best solution to your problem (or even a solution at all), the 408 seems to indicate a somewhat strange problem- however, this should get you to a somewhat simpler config to debug and hopefully get you going immediately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With