« Go Back

How I set up LetsEncrypt on a single instance AWS Elastic Beanstalk docker app.

June 9th, 2019 · Written by Nick Vernij

Elastic Beanstalk is an easy way to get an application up and running. However having a load-balancer is quite expensive for your average side-project, so you want a single instance app. This little config file sets up `https` for you, without needing a load-balancer.

Let's encrypt is a free service that provides ssl certificates. While amazon's AWS Certificate Manager is also free, a load balancer is required. Running an elastic load-balancer costs ~20 dollars a month. Let's not.

There is already a gist that does this. However it's a bit outdated, so I updated it. Full credits to the original author though.

Drop the config file below in your `.ebextensions` folder. Give it a nice name (but make sure its extension is `.config`). And replace the placeholder `%DOMAIN%` and `%EMAIL%` with your domain and email.

      
Resources:
  sslSecurityGroupIngress: 
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
      IpProtocol: tcp
      ToPort: 443
      FromPort: 443
      CidrIp: 0.0.0.0/0

files:

  # The Nginx config forces https, and is meant as an example only. 
  /etc/nginx/conf.d/000_http_redirect_custom.conf:
    mode: "000644"
    owner: root
    group: root
    content: |
      server {
        listen 8080;
        return 301 https://$host$request_uri;
      }

  # The Nginx config forces https, and is meant as an example only. 
  /etc/nginx/conf.d/https_custom.pre:
    mode: "000644"
    owner: root
    group: root
    content: |
      # HTTPS server
      server {
        listen       443 default ssl;
        server_name  localhost;
        error_page  497 https://$host$request_uri;
        
        ssl_certificate      /etc/letsencrypt/live/ebcert/%DOMAIN%/fullchain.pem;
        ssl_certificate_key  /etc/letsencrypt/live/ebcert/%DOMAIN%/privkey.pem;

        ssl_session_timeout  5m;
        ssl_protocols  TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_prefer_server_ciphers   on;

        if ($ssl_protocol = "") {
          rewrite ^ https://$host$request_uri? permanent;
        }

        location / {
            proxy_pass  http://docker;
            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;
            proxy_set_header        Upgrade         $http_upgrade;
            proxy_set_header        Connection      "upgrade";
        }
      }

packages: 
  yum:
    epel-release: [] 

container_commands:
  10_installcertbot:
    command: "wget https://dl.eff.org/certbot-auto;chmod a+x certbot-auto"
  20_getcert:
    command: "sudo ./certbot-auto certonly --debug --non-interactive --email %EMAIL% --agree-tos --standalone --domains %DOMAIN% --keep-until-expiring --pre-hook \"sudo service nginx stop\" --post-hook \"sudo service nginx start\""
  30_link:
    command: "ln -sf /etc/letsencrypt/live/${certdomain} /etc/letsencrypt/live/ebcert"
  40_config:
    command: "mv /etc/nginx/conf.d/https_custom.pre /etc/nginx/conf.d/https_custom.conf"
  50_restartnginx:
    command: "sudo service nginx restart"
      
      

Now, run `eb` deploy. On launch your app will run `certbot`, move some files around, and accept https connections. 🎉

« Go Back