Skip to main content

Self-hosted Live Updates with Github Actions and S3

Overview

Self-hosted Live Updates allows customers to build and host their web artifacts then deploy them as Live Updates to app users. To help ensure secure end-to-end delivery, code signing and signature verification steps are included as well.

This example walks through setting up Self-hosted live updates in a Capacitor app using Github Actions and Amazon S3.

Requirements

For this example, we've already followed the Self-hosted live update App Setup instructions. This includes creating an Appflow app, a personal access token (PAT), a public/private key, and configuring the Capacitor app.

Github Actions Setup

With your Capacitor app configured to use self-hosted live updates, we can configure Github Actions next.

Store the Private Key Securely

To store the private key securely in Github, you can upload it as a repository secret, found under your repository settings -> Security -> Secrets and variables -> Actions -> Repository secrets. You can save this secret as PRIVATE_KEY (or something similar). Doing so will make it available to the pipeline we'll write shortly.

Store a Personal Access Token Securely

The personal access token is used to authenticate access to your Appflow account via the Appflow CLI, so it also needs to be made available to the pipeline. Under "Repository secrets", create a new secret named IONIC_TOKEN (or something similar) and paste your Personal Access Token.

Store your AWS Credentials Securely

The last two secrets we need to store are your AWS credentials. Login to AWS and navigate to IAM (Identity and Access Management). On the right sidebar, under "Quick Links", select "My security credentials". Create a new access key and store your access key and secret access key individually as repository secrets. They can be named AWS_ACCESS_KEY and AWS_SECRET_ACCESS_KEY or something similar.

Create an S3 Bucket

The final step before writing our pipeline involves creating an S3 bucket to host the live updates. From your AWS account, navigate to S3 and click "Create bucket", naming it anything you like.

Under "Object Ownership", you can select "ACLs enabled" for the purposes of this demo. You may wish to implement a bucket policy at a later date to simplify permissions.

Under "Public Access settings for this bucket", make sure to uncheck "Block all public access". Public access is required for the Capacitor Live Updates plugin to download live updates onto your app user's devices.

Next, click "Create bucket". Once our bucket is created, we can begin writing our pipeline.

Write a Pipeline

Now, we're ready to write a Github Actions pipeline that creates and registers a live update. Here's the complete YAML script:

Complete YAML Script

name: Deploy Self-Hosted Live Update

on:
push:
branches:
- 'main'

jobs:
LiveUpdate-Deploy:
runs-on: ubuntu-latest

env:
IONIC_TOKEN: ${{ secrets.IONIC_TOKEN }}
APP_ID: 'YOUR_APP_ID_GOES_HERE'

steps:
- name: Install Appflow CLI
run: curl -sL https://ionic.io/get-appflow-cli | bash

- name: Checkout repository
uses: actions/checkout@v2

- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 18

- name: Install project dependencies
run: npm install

- name: Build project
run: npm run build

- name: Generate manifest file
run: |
appflow live-update generate-manifest \
--build-dir=dist \
--signing-key="${{ secrets.IONIC_PRIVATE_KEY }}"

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2

- name: Copy bundle to AWS
run: |
aws s3 sync dist s3://shlu-github-actions-s3-demo/$GITHUB_SHA --acl public-read

- name: Register artifact with Appflow
run: |
appflow live-update register-artifact \
--app-id=$APP_ID \
--commit-sha=$GITHUB_SHA \
--commit-ref=main \
--commit-message="${{ github.event.head_commit.message }}" \
--artifact-url="https://shlu-github-actions-s3-demo.s3.us-east-2.amazonaws.com/$GITHUB_SHA/live-update-manifest.json" \
--artifact-type=manifest

Let's walk through this pipeline step by step.

Pipeline Trigger and Job

This pipeline will run a job called "LiveUpdate-Deploy" every time there is a commit to the "main" branch. We recommend running on a Linux VM, so ubuntu-latest is used.

name: Deploy live update

on:
push:
branches:
- 'main'

jobs:
LiveUpdate-Deploy:
runs-on: ubuntu-latest

Create Variables

Next, we'll prepare some environment variables. We're receiving our Ionic PAT from our repository secrets for ease of reference and setting it as an environment variable called IONIC_TOKEN. This will allow us to utilize the Appflow CLI without having to pass the token as an argument.

We are also setting our Appflow App ID to be used later when registering our artifact.

env:
IONIC_TOKEN: ${{ secrets.IONIC_TOKEN }}
APP_ID: 'YOUR_APP_ID_GOES_HERE'

Install Appflow CLI

The first step in the build process involves installing the Appflow CLI so we can use Self-hosted live update features:

steps:
- name: install a cli
run: curl -sL https://ionic.io/get-appflow-cli | bash

Checkout our Repository

Next, we need to checkout the code from our repository using the actions/checkout@v2 action.

- name: checkout repository
uses: actions/checkout@v2

Build the Web App

Next, we build the web app. Make any changes needed to build your app.

- name: setup node
uses: actions/setup-node@v2
with:
node-version: 18

- name: install dependencies
run: npm install

- name: build project
run: npm run build

Create a Signed Live Update

Now that the web app has been built, we can use the Appflow CLI generate-manifest command to create a live update manifest file. The resulting live-update-manifest.json file includes a hash for every file in the compiled web app directory. If a native app has a live update manifest file, local files on disk are compared with the manifest and only changed files are downloaded. This makes the update much smaller and faster, resulting in improved performance over slower connections.

  • build-dir: The top-level build directory containing the compiled web app, such as dist for a React app.
  • signing-key: The private key we stored as a repository secret, used to sign the live update.
- name: Generate manifest file
run: |
appflow live-update generate-manifest \
--build-dir=dist \
--signing-key="${{ secrets.IONIC_PRIVATE_KEY }}"

Upload Live Update to Amazon S3

With the new live update created, we can upload it to S3. There are several ways to do so; in this case, we can use the configure-aws-credentials@v2 Action and the AWS CLI.

The configure-aws-credentials@v2 Action will prepare the AWS CLI for us to use. We need to provide our aws-access-key-id and aws-secret-access-key, both of which we have stored as repository secrets. We also need to provide an aws-region for the purposes of configuring the CLI, though IAM and S3 are both global services, so we can just use us-east-2.

Next, we need to sync our build directory with S3. We are uploading the full contents of our build directory (along with the live-update-manifest.json) to a directory in our S3 bucket named after the commit SHA. You may choose to take a different approach, if you'd prefer. Finally, we are also ensuring that the uploaded contents are publicly accessible using the --acl parameter.

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2

- name: Copy bundle to AWS
run: |
aws s3 sync dist s3://shlu-github-actions-s3-demo/$GITHUB_SHA --acl public-read

Register Signed Live Update with Appflow

In this last step, we will inform Appflow that a new live update is available with the Appflow CLI register-artifact command.

  • app-id: The Appflow app id, like 042a1261. Find this value under the app's name in Appflow or the URL (https://dashboard.ionicframework.com/app/042a1261/getting-started).
  • artifact-type: The type of artifact being registered, either zip or manifest for differential live updates (recommended).
  • artifact-url: The URL where the new live update artifact is stored. The Capacitor live update plugin will download the live update from your storage provider. When using manifest artifact-type (recommended), URL should end with live-update-manifest.json. When using zip artifact-type, URL should end with .zip.
  • commit-ref: The branch name of the commit, such as "main" or "production". In this case, we have hardcoded "main", as this workflow is only triggered on pushes to the main branch.
  • commit-sha: The Git commit SHA, such as "adf9137y45".
  • commit-message: The Git commit message, such as "Fix login bug."
# Register the signed live update with Appflow
- name: Register artifact with Appflow
run: |
appflow live-update register-artifact \
--app-id=$APP_ID \
--commit-sha=$GITHUB_SHA \
--commit-ref=main \
--commit-message="${{ github.event.head_commit.message }}" \
--artifact-url="https://shlu-github-actions-s3-demo.s3.us-east-2.amazonaws.com/$GITHUB_SHA/live-update-manifest.json" \
--artifact-type=manifest

Save and run the pipeline. A self-hosted live update hosted in Github Actions is now available!

Deploy a Live Update

Once the pipeline has finished running, you'll find the new Self-hosted live update in your App's Builds list in Appflow. From there, you can follow the standard Live Update flow of assigning the build to a Live Update Channel.