Update: Google has introduced managed SSL for Google App Engine.
The main purpose of using Let's Encrypt SSL is to ensure SSL setup and renewal could be executed automatically, usually using shell scripts and cronjob.
Install Certbot
Install Certbot on Ubuntu
sudo add-apt-repository ppa:certbot/certbotsudo apt-get updatesudo apt-get install certbot
Create SSL cert
We will create the SSL cert using manual way, which is without using any plugins. We shall be using HTTP domain verification because it's easier to write script to deploy file up App Engine server. If we use DNS domain verification, we would need to write a script to make DNS TXT update.
Create script to HTTP verification file to App Engine
In order to support cert renewal, we must include --manual-auth-hook. We shall write a script which upload a certain file up App Engine server for the domain verification to take place. Create authenticator.sh bash script with the following code.
Note: chmod +x authenticator.sh
to make the script executable.
#!/bin/bash# for debugging purpose onlyset -x# won't work# sudo su username# create the HTTP domain validation filecd /projects/hello-appmkdir -p "acme-challenge"echo $CERTBOT_VALIDATION > ./acme-challenge/$CERTBOT_TOKEN# using non-root user# cmd1="source /projects/google-cloud-sdk/path.bash.inc"# cmd2="gcloud app deploy --version 1 --project hello-app --quiet"# sudo -u myusername -H bash -c "$cmd1; $cmd2;"# using root: make sure gloud is installed and conigure for rootgcloud app deploy --version 1 --project hello-app --quiet# exitset +x
Edit app.yaml
Edit app.yaml to make sure the acme-challenge created by authenticator.sh are served.
handlers:- url: /.well-known/acme-challenge static_dir: acme-challenge
Install gcloud for root
Certbot shall be run as root using sudo, thus authenticator.sh also shall be run as root. We need to install gcloud tools for root.
Download the latest Google Cloud SDK.
Extract the package (e.g. tar -zxf google-cloud-sdk*.tar.gz)
sudo su# install gcloud for root./google-cloud-sdk/install.sh# reload shellsource ~/.bashrc# problem launching chrome as root, use following methodgcloud auth login --no-launch-browser# Output: Go to the following link in your browser:# Output: Enter verification code:
Run script to obtain SSL certs
Provide full path to the /fullpath/authenticator.sh
script and make sure the location is permanent (the same script shall be used for SSL renewal every 90 days). Run the following command to create SSL cert.
sudo sucertbot certonly --manual --preferred-challenges http --manual-auth-hook /fullpath/authenticator.sh -d www.mydomain.com
Take note of the location of the SSL directory (/etc/letsencrypt/live/www.mydomain.com/) and the expiry date (90 days)
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.mydomain.com/fullchain.pem. Your cert
will expire on 2017-10-31. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run "certbot
renew"
Renew SSL cert
Renewal Configuration
A renewal configuration file is created (after executing certbot certonly) at /etc/letsencrypt/renewal/www.mydomain.com.conf
with the following content. If you forgotten to include --manual-auth-hook when executing certbot certonly, you can edit the .conf
to include manual_auth_hook.
# renew_before_expiry = 30 days
version = 0.14.2
archive_dir = /etc/letsencrypt/archive/www.mydomain.com
cert = /etc/letsencrypt/live/www.mydomain.com/cert.pem
privkey = /etc/letsencrypt/live/www.mydomain.com/privkey.pem
chain = /etc/letsencrypt/live/www.mydomain.com/chain.pem
fullchain = /etc/letsencrypt/live/www.mydomain.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
authenticator = manual
installer = None
account = d25e296e5ef6dc39627bb0a6c64dxxxx
pref_challs = http-01,
manual_public_ip_logging_ok = True
manual_auth_hook = /fullpath/authenticator.sh
SSL renewal test run
You can test if the renewal will run properly.
# remove sudo certbot renew --dry-run
List Certificates
You can list all certificates available.
certbot certificates# Output# Found the following certs:# Certificate Name: www.mydomain.com# Domains: www.mydomain.com# Expiry Date: 2017-10-31 04:35:00+00:00 (VALID: 89 days)# Certificate Path: /etc/letsencrypt/live/www.mydomain.com/fullchain.pem# Private Key Path: /etc/letsencrypt/live/www.mydomain.com/privkey.pem
You can also delete them if you no longer want to renew them.
certbot delete --cert-name www.mydomain.com
Cronjob
A renew will only happen if you run certbot renew
where the cert is less than 30 days from expiry. You can run it daily or run it weekly. It should be run as root's cronjob.
You need to be careful when running this as a cronjob as authenticator.sh is executed where it will upload the entire project up to the server (make sure you are not in development mode and uploaded unwanted/untested changes to the server).
sudo crontab -e # m h dom mon dow command# 8AM every monday0 8 * * 1 certbot renew --quiet
Configure SSL on App Engine
Create deploy_ssl.sh script to deploy the SSL to App Engine Server and chmod +x deploy_ssl.sh
to make the script executable. You probably want to test run gcloud beta
to trigger installation of beta component.
gcloud beta app# OutputYou do not currently have this command group installed. Using itrequires the installation of components: [beta]
You can run it with certbot renew --post-hook "/fullpath/deploy_ssl.sh"
.
Note: If you bump into error of Caller is not authorized to administer this certificate. You must be a verified owner of the certificate's domain(s) [www.mydomain.com] to create, modify, or delete this resource.
, run gcloud beta domains verify www.mydomain.com
to verify domain ownership.
#!/bin/bash# for debugging purpose onlyset -x# /etc/letsencrypt/live/www.mydomain.com# `privkey.pem` : the private key for your certificate.# `fullchain.pem`: the certificate file used in most server software.# `chain.pem` : used for OCSP stapling in Nginx >=1.3.7.# `cert.pem` : will break many server configurations, and should not be used without reading further documentation (see link below).# gcloud beta need user intervention when running 1st time to install [beta] component.# capture stderr output: Created [560873].certId=$({ gcloud beta app ssl-certificates create --display-name mydomain-letsencrypt-aug2017 \ --certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem \ --private-key /etc/letsencrypt/live/www.mydomain.com/privkey.pem \ --project hello-app; } 2>&1)# extract number from "Created [560873]."certId=$(echo $certId | cut -d "[" -f2 | cut -d "]" -f1)# Output: Created [560873].# certId=$(echo "Created [560873]." | cut -d "[" -f2 | cut -d "]" -f1)gcloud beta app domain-mappings update www.mydomain.com \ --certificate-id $certId \ --project hello-appset +x
Open Google Cloud Console: Goto App Engine > Settings > SSL Certificates (or search SSL Certificates at the top search bar) to verify that SSL certs are setup properly.
After deploying the SSL, your website should be SSL enabled (https://www.mydomain.com
).
app.yaml secure always
If you want your website to always serve using HTTPS, enable secure: always
in app.yaml
handlers:- url: .* script: main.app secure: always