Skip to content

Instantly share code, notes, and snippets.

@8trackbattlecat
Last active June 16, 2021 03:37
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save 8trackbattlecat/b5fb2361bc9b7a938532e0e783b2ed12 to your computer and use it in GitHub Desktop.
Save 8trackbattlecat/b5fb2361bc9b7a938532e0e783b2ed12 to your computer and use it in GitHub Desktop.
Let's Encrypt SSL Single Instance PHP Elastic Beanstalk .ebextensions
#Do not include this file until your production certificate is working
#This config Forcing ssl will prevent lets encrypt from verifying your domain
#https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-singleinstance.html
Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
CidrIp: 0.0.0.0/0
#For this to work you need to update environment variables via EB console for LETSENCRYPT_DOMAIN and LETSENCRYPT_EMAIL.
#see 20_install_certificate for the workflow of getting a staging certificate, then a production certificate.
#based on https://blog.lucasferreira.org/howto/2017/07/21/set-up-let-s-encrypt-ssl-certificate-with-aws-elastic-beanstalk-single-instance.html
#update on 20191012 --need to set ServerName and ServerAlias to fix error "server certificate does NOT include an ID which matches the server name"
# be careful about where the www prefix appears, for servername you need to have it WITHOUT www. i had it in my EB console variable
# so i had to just manually put it in as the ServerName on line 33 and then with www on line 34, it might be easier to not use the console variables
packages:
yum:
mod24_ssl : []
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>
/tmp/ssl.conf:
mode: "000644"
owner: root
group: root
content: |
LoadModule ssl_module modules/mod_ssl.so
Listen 443
<VirtualHost *:443>
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ServerName ${LETSENCRYPT_DOMAIN}
ServerAlias www.${LETSENCRYPT_DOMAIN}
SSLEngine on
SSLCertificateFile "/etc/letsencrypt/live/ebcert/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/ebcert/privkey.pem"
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLSessionTickets Off
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
ProxyPass / http://localhost:80/ retry=0
ProxyPassReverse / http://localhost:80/
ProxyPreserveHost on
RequestHeader set X-Forwarded-Proto "https" early
</VirtualHost>
/tmp/certificate_renew:
mode: "000644"
owner: root
group: root
content: |
0 0 * * 0 root /opt/certbot/certbot-auto renew --webroot --webroot-path /var/www/html/ --pre-hook "killall httpd" --post-hook "sudo restart supervisord || sudo start supervisord" --force-renew --preferred-challenges http-01 >> /var/log/certificate_renew.log 2>&1
container_commands:
# creates a swapfile to avoid memory errors in small instances
00_enable_swap:
command: "sudo swapoff /tmp/swapfile_certbot ; sudo rm /tmp/swapfile_certbot ; sudo fallocate -l 1G /tmp/swapfile_certbot && sudo chmod 600 /tmp/swapfile_certbot && sudo mkswap /tmp/swapfile_certbot && sudo swapon /tmp/swapfile_certbot"
# installs certbot
10_install_certbot:
command: "mkdir -p /opt/certbot && wget https://dl.eff.org/certbot-auto -O /opt/certbot/certbot-auto && chmod a+x /opt/certbot/certbot-auto"
# issue the certificate if it does not exist
# after you have verified that the staging certificate is working, switch to the second version that is not staging with the --force-renewal so it doesnt keep your staging cert
# after the production cert is working you can switch to the third version that does not force the renewal.
20_install_certificate:
command: "sudo /opt/certbot/certbot-auto certonly --debug --non-interactive --email ${LETSENCRYPT_EMAIL} --agree-tos --webroot --webroot-path /var/www/html/ --domains ${LETSENCRYPT_DOMAIN} --keep-until-expiring --preferred-challenges http-01 --staging"
#command: "sudo /opt/certbot/certbot-auto certonly --debug --non-interactive --email ${LETSENCRYPT_EMAIL} --agree-tos --webroot --webroot-path /var/www/html/ --domains ${LETSENCRYPT_DOMAIN} --keep-until-expiring --preferred-challenges http-01" --force-renewal
#command: "sudo /opt/certbot/certbot-auto certonly --debug --non-interactive --email ${LETSENCRYPT_EMAIL} --agree-tos --webroot --webroot-path /var/www/html/ --domains ${LETSENCRYPT_DOMAIN} --keep-until-expiring --preferred-challenges http-01"
# create a link so we can use '/etc/letsencrypt/live/ebcert/fullchain.pem'
# in the apache config file
30_link:
command: "ln -sf /etc/letsencrypt/live/${LETSENCRYPT_DOMAIN} /etc/letsencrypt/live/ebcert"
# move the apache .conf file to the conf.d directory.
# Rename the default .conf file so it won't be used by Apache.
40_config:
command: "mv /tmp/ssl.conf /etc/httpd/conf.d/ssl.conf && mv /etc/httpd/conf.d/wsgi.conf /etc/httpd/conf.d/wsgi.conf.bkp || true"
# clear the swap files created in 00_enable_swap
50_cleanup_swap:
command: "sudo swapoff /tmp/swapfile_certbot && sudo rm /tmp/swapfile_certbot"
# kill all httpd processes so Apache will use the new configuration
60_killhttpd:
command: "killall httpd ; sleep 3"
# Add renew cron job to renew the certificate
70_cronjob_certificate_renew:
command: "mv /tmp/certificate_renew /etc/cron.d/certificate_renew"
`
@8trackbattlecat
Copy link
Author

8trackbattlecat commented Feb 27, 2018

Getting SSL from Let's Encrypt on an Elastic Beanstalk PHP Single Instance. Config files go in .ebextensions directory.
Based on this python version

Once it is working remove the --staging flag in 20_install_certificate section, you will probably need to replace with --force-renewal so it updates to a real certificate

@r4f43ls1gu3s
Copy link

r4f43ls1gu3s commented Jun 5, 2018

@8trackbattlecat I have not been successful. My Elastic Beanstalk is giving error loading the App: "During an aborted deployment, some instances may have deployed the new application version. To ensure all instances are running the same version, re-deploy the appropriate application version." Do you have any suggestions for help? I really need to run HTTPS on a simple instance of EB and I see little content on this since AWS recommends use with Balancer.

@CodeZeno
Copy link

This worked for me but I excluded the last line (78).
For those having issues it's probably best to deploy your app without this script and ensure it is accessible via http first as this is needed to confirm the certificate. If your app is not accessible try the "Rebuild Environment" option in Beanstalk. In my case the proxy stopped working and a redeploy did not fix it.

I also setup another script to run before this with the following:

option_settings:

  • option_name: LETSENCRYPT_DOMAIN
    value: mysub.domain.com
  • option_name: LETSENCRYPT_EMAIL
    value: myemail@address.com

@tuanalumi
Copy link

tuanalumi commented Aug 1, 2018

For anyone having troubles:

  1. Update environment variable via EB console for LETSENCRYPT_DOMAIN and LETSENCRYPT_EMAIL. From original python version:

Note that the file is using these two environment variables. You must set them inside the Elastic Beanstalk console or through other means

  1. If you are using symfony or other framework that you have to change your webroot: update your webroot path to correct one. For symfony 3+: --webroot-path /var/www/html/public/

@douwevdijk
Copy link

Hi all, I am getting two errors:

  1. Sorry, you must have a tty to run sudo
  2. If I remove 'sudo' I get: /bin/sh: swapoff: command not found

Can someone help me? Thanks!

@Chris1234567899
Copy link

In case someone runs into the same issue of getting back an unauthorized error:
make sure you can access the folder where the http-01-challenge file is stored by the browser. I had a laravel application running and hat to modify the --webroot-path (under 20_install_certificate) to /var/www/html/public so it could be accessed.

@ederbaum
Copy link

My browser gives the error "SEC_ERROR_UNKNOWN_ISSUER" when accessing the site.
I followed exactly the instructions of 8trackbattlecat and CodeZeno.

ssl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment