EDIT: September 16, 2017:

Google have now got a very convenient managed SSL certificate service in App Engine.

Just use that! It’s free!

Most of the rest of the post is still somewhat valid... but do investigate the Aurelia CLI to make things easier for yourself.

I recently decided to host my Aurelia app on Google App Engine, as static pages are hosted there for free, as long as there are no servers spun up in GAE.

Given that Aurelia apps are essentially static web pages (in terms of the traditional view of ‘server-side work needed to generate’ vs ‘no server-side work needed’), this sounded perfect.

I also wanted to ensure I had SSL, and since Let’s Encrypt provide free SSL certificates, this solution came together nicely, indeed.

Here are the step I took to make it work. This is mostly notes so that I will remember it myself, not a full-blown tutorial, so good luck if you follow in my footsteps. I can’t really offer you any support, but I’m often in the Aurelia Gitter, as @egeland. Come and say hi.

Aurelia App must be bundled

In order to deploy the app anywhere, you really need to bundle it. I followed these steps to get my bundling working. Once you have your app exported into the export/ directory, you are ready to move on to the fun parts.

Letsencrypt must be installed

I’m not including info on how to set up letsencrypt, you can figure that out from their documentation.

Google App Engine setup

There’s quite a bit of documentation about how to get GAE set up, so this is a quick summary of what I needed in terms of config.

Set up your app with the GAE config file

Include the app.yaml file in your export by adding it, and the .well-known directory for letsencrypt, to build/export.json :

{

“list”: [

“index.html”,

“app.yaml”,

“config.js”,

“favicon.ico”,

“robots.txt”,

“.well-known/acme-challenge/**”,

// more files …

app.yaml should look like this:

application: my-application runtime: python27

api_version: 1

threadsafe: true default_expiration: “30d” handlers:

# re-direct to index.html if no path is given

- url: /

static_files: index.html

upload: index.html # get correct mimetype for acme-challenge, needed for letsencrypt

- url: /.well-known/acme-challenge/(.*)

mime_type: text/plain

static_files: .well-known/acme-challenge/\1

upload: .well-known/acme-challenge/(.*) # access the static resources in the root directory

- url: /(.*)

static_files: \1

upload: (.*) # redefine skip_files

skip_files:

- ^(.*/)?#.*#$

- ^(.*/)?.*~$

- ^(.*/)?.*\.py[co]$

- ^(.*/)?.*/RCS/.*$

Upload your app to GAE

I put two lines into the scripts section of my app’s package.json :

“deploy”: “gulp export && appcfg.py -V v1 update export/”,

“postdeploy”: “gulp unbundle”

Note that the ‘v1’ should probably be automatically incremented so you get GAE’s version/rollback functionality. For my simple app, I don’t care about that, so I just keep redeploying ‘v1’.

Run that deploy script with

$ npm run -s deploy

It needs to be run once so you know your app works on HTTP, before we mess with SSL and Letsencrypt.

Set up Letsencrypt

Config file ( cli.ini ):

config-dir = /home/example/ssl/letsencrypt/config

work-dir = /home/example/ssl/letsencrypt/work

logs-dir = /home/example/ssl/letsencrypt/logs

email =

domains = site.example.com # make sure to use valid email and domains!email = myaddress@example.com domains = site.example.com text = True

agree-tos = True

verbose = True authenticator = manual

Request the certificate from Letsencrypt

In a separate shell session, as you’ll need to do some work in your app’s session, run

$ letsencrypt certonly -c ./cli.ini

Follow the prompts and you should see something like:



before continuing: Make sure your web server displays the following content at http://site.example.com/.well-known/acme-challenge/54W5HaD0c5ja5tWqlI09iXpXeY3GxI8Ix4FtRZFZXmY before continuing: 54W5HaD0c5ja5tWqlI09iXpXeY3GxI8Ix4FtRZFZXmY.Z9RAU1fXh5Srfn11JkM8nC-X2LWOP540MoH2JuBNJhg If you don’t have HTTP server configured, you can run the following

command on the target server (as root): mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge

cd /tmp/letsencrypt/public_html

printf “%s” 54W5HaD0c5ja5tWqlI09iXpXeY3GxI8Ix4FtRZFZXmY.Z9RAU1fXh5Srfn11JkM8nC-X2LWOP540MoH2JuBNJhg > .well-known/acme-challenge/54W5HaD0c5ja5tWqlI09iXpXeY3GxI8Ix4FtRZFZXmY

# run only once per server:

$(command -v python2 || command -v python2.7 || command -v python2.6) -c \

“import BaseHTTPServer, SimpleHTTPServer; \

s = BaseHTTPServer.HTTPServer((‘’, 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \

s.serve_forever()”

Press ENTER to continue

Copy the equivalent of the bold line (no linebreaks) into the shell session of your Aurelia app to create the token for Letsencrypt.

Deploy your app again, and then test that the token is available with:

If it is, great, go back to the Letsencrypt shell session and hit Enter.

If all goes well, you should get a happy message that your certificate is ready for you:

Congratulations! Your certificate and chain have been saved at /home/example/ssl/letsencrypt/config/live/site.example.com/fullchain.pem. Your cert will expire on 2016–09–21. To obtain a new version of the certificate in the future, simply run Let’s Encrypt again.

Adding the certificates to GAE

You need to have the certificate and key ready. The key format is different for GAE, so you need to convert it.

Convert private key to a form GAE can read:

$ openssl rsa -inform pem -in ~/ssl/letsencrypt/config/live/site.example.com/privkey.pem -outform pem

The above command will output your key in the format expected by GAE.

Go to your Google App Engine console.

Click Upload a new certificate, fill in the form:

Fill it in and save!

Note that we’re using the fullchain.pem file for the cert and pasting in the private key output from the above openssl step.

Ensure you set the custom domain to actually use the cert, save and then check that you get the lovely green padlock in your app:

Aww… yeah!

That should be all!

Good luck!!

UPDATE

It seems that by installing the gcloud toolkit, some of the GAE steps need to be done slightly differently now.

Remove the application: my-application entry from your app.yaml file

Ensure you log in with gcloud, by running

$ gcloud auth login

Upload your app with

CLOUDSDK_CORE_PROJECT=’my-application’ gcloud app deploy