Automating Deployments with GitHub Actions

This guide will walk you through how to automate your deployments with GitHub Actions. This is useful for deploying your application to your servers when you push to your repository.

Default Behavior

By default, Spin Pro comes with a GitHub Actions workflow that will deploy your application to your server when you push to your main branch in your repository. This workflow is located in the .github/workflows directory of your repository. You can customize this workflow to fit your needs.

Creating a dedicated "deploy user"

To deploy your application with GitHub Actions, you'll need to create a dedicated "deploy user" on your server.

Create a dedicated public-private key pair

To create a dedicated public-private key pair, you can use the following command:

Create a dedicated public-private key pair

ssh-keygen -o -a 100 -t ed25519 -f ~/Desktop/id_ed25519_deploy -C deploy

This command will create a new key pair in the ~/Desktop directory with the name id_ed25519_deploy. You can replace deploy with your username.

It will create two files:

Files created

~/Desktop/id_ed25519_deploy # PRIVATE key
~/Desktop/id_ed25519_deploy.pub # PUBLIC key

We will need to reference the content of both files in the next steps.

Add the PUBLIC key to .spin.yml

You can uncomment the docker_user.authorized_keys section in your .spin.yml file and add the value of your .pub file to the authorized_keys section.

Add the public key to .spin.yml

docker_user:
  username: deploy
  uid: 9999
  group: deploy
  secondary_groups: "docker"
  gid: 9999
  authorized_ssh_keys:
    # 👇 Change this value to your public key value
    - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKNJGtd7a4DBHsQi7HGrC5xz0eAEFHZ3Ogh3FEFI2345 fake@key"

Notice how we're creating a dedicated user named deploy with a uid and gid of 9999. We will use this user to run deployments instead of using a general user like alice or bob to deploy. This user is strictly for deployments.

Run spin provision to update your server

After this is complete, you can run spin provision to update your server with the new public key.

Configure GitHub Actions Secrets/Environment Variables

The following environment variables can be set as secrets in GitHub Actions.

VariableDescriptionExample ValueRequired
ENV_FILE_BASE64The base64 encoded .env file.ABCDEFG1234...⚠️ Yes
SSH_DEPLOY_PRIVATE_KEYThe private SSH key dedicated for the deploy user.-----BEGIN OPENSSH PRIVATE KEY-----abc123...⚠️ Yes
SSH_REMOTE_HOSTNAMEThe hostname/IP of your server.server01.example.com⚠️ Yes
SSH_REMOTE_KNOWN_HOSTSIf provided, the SSH connection will validate the connection against your known_hosts file and remove the "SSH_KNOWN_HOST" warning. (Learn more)github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC...no

To add these environment variables to your GitHub repository, you can follow these steps:

  1. Go to your GitHub repository.
  2. Click on Settings.
  3. Click on Secrets and variables → Actions.
  4. Click on New repository secret

Set the Name to the environment variable name and Value to your value.

Adding a new secret to GitHub Actions

How your ".env" file is used

Your .env file is very important in the deployment process. Not only does it configure your application, but we'll also use the variables during the Docker Swarm deployment to configure your services.

Since Spin uses Docker images as a single source of truth, the only dynamic part of the application between the environments is the .env file. This means that 99% of the time when it's working on one machine and not the other is because the .env file is not set correctly between machines. It's very important to take your time and get this part right.

Variables used in docker-compose.prod.yml

VariableDescriptionSourceExample Value
SPIN_APP_DOMAINThe domain of your application.SPIN_APP_DOMAIN will be used if it's defined in the .env file, otherwise we'll attempt to automatically detect the domain from your APP_URL in .envmyapp.example.com
DB_DATABASEThe database name.Loaded from .envmyapp
DB_USERNAMEThe database username.Loaded from .envmyuser
DB_PASSWORDThe database password.Loaded from .envmypassword
REDIS_PASSWORDThe Redis password.Loaded from .envmyredispassword
REVERB_HOSTThe DNS hostname to use for Reverb. (⚠️ must be different than your SPIN_APP_DOMAIN)Loaded from .envsocket.example.com

ENV_FILE_BASE64

GitHub Actions requires the .env file to be base64 encoded to prevent interpolation of the values in the file. This adds a few steps, but Spin has a command called spin base64 to help you with this.

Create a text file (it can be called anything). For our example, we will call ours env.txt. Save this securely on your computer or with your password manager.

Paste the contents of what the environment file would look like into this file. For example:

env.txt

APP_NAME=Laravel
APP_ENV=production
APP_KEY=base64:abcdefghijklmnopqrstuvwxyz1234567890=
APP_DEBUG=false
APP_TIMEZONE=UTC
APP_URL=https://laravel.example.com
# Rest of your .env file

Next, you can run the following command to base64 encode the file:

Base64 encode the file

spin base64 -e env.txt # Linux/Windows
spin base64 -e env.txt | pbcopy # Mac

Make sure you're not copying any extra whitespace. With Mac, the pbcopy command will copy the value to your clipboard automatically.

DEPLOYMENT_SSH_PRIVATE_KEY

To get the value of the SSH_DEPLOY_PRIVATE_KEY environment variable, you can get the value of the private key file you created earlier.

Get the value for the SSH_DEPLOY_PRIVATE_KEY

cat ~/Desktop/id_ed25519_deploy #Linux/Windows
cat ~/Desktop/id_ed25519_deploy | pbcopy #Mac

Further customization

If you'd like advanced customization, refer to the following GitHub Actions that we've created. You can customize the workflows in .github/workflows to customize even more options (like SSH ports, different registries, etc.):

You can also refer to the Workflow syntax for GitHub Actions document if you'd like even more customization options.

Running a deployment

By default, a production deployment will run when you push to your main branch. You can customize this behavior by modifying the .github/workflows/deploy.yml file in your repository.

Changing the deployment trigger

You'll see in the default triggers by looking at the on section of the workflow file. Refer to the GitHub Actions documentation for more information if you'd like to change the trigger.

Where to watch the status of your deployment

You can watch the status of your deployment by going to the Actions tab in your repository. You can see the status of the deployment and any logs that are generated.

Watching the status of your deployment in GitHub Actions

Using self-hosted runners to improve security

If you'd like to improve the security of your deployments, you can use self-hosted runners. This will allow you to run your deployments on your own infrastructure instead of GitHub's infrastructure. You can learn more about self-hosted runners in the GitHub Actions documentation.

Once you have a self-hosted runner set up, you can use a firewall to limit SSH access to your server only from IP addresses that are associated with your self-hosted runner and a dedicated VPN for your team.