In order to update a production website hosted with Docker, I’ve come up with a system where I leverage GitHub Action secrets and a consistent block of commands.
GitHub Action Secrets config
Here are the 4 variables I set:
- SSH_HOST: ip address of your server
- SSH_PRIVATE_KEY: the private key you need to access that server over SSH
- SSH_USER: the SSH user
- WORK_DIR: the working directory where you have your docker-compose.yml
To access the settings, once you’re inside your repo, click on the Settings menu across top of the repo, then the Secrets & variables drop down in the left nav, and finally on the Actions menu.
You obviously have to have your server already setup for ssh access. I always forgot which ssh identity so this is more of a note to self but you can run this on macOS:
cat .ssh/id_ed25519 | pbcopy
and then paste the clipboard into your SSH_PRIVATE_KEY variable.
GitHub Action deploy step
Then I include this step after I’ve built and pushed the updated Docker image:
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: install ssh keys
run: |
install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
- name: connect and pull
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd ${{ secrets.WORK_DIR }} && docker compose pull && docker compose down && docker compose up -d && exit"
- name: cleanup
run: rm -rf ~/.ssh
Enhancements
Enhancements I have planned for the future or recommend folks reading this consider.
Security
These are additional security enhancements for consideration:
- Since I’m moving to Tailscale we’re accessing all my services securely, I need to update my GitHub runners accordingly. If you’re not running Tailscale or it is too difficult to add Tailscale to ephemeral runners, another alternative would be to better limit SSH access to particular IPs and ranges. I believe
- Move to Docker credential-store to avoid storing unencrypted credentials in GitHub runner (‘/home/runner/.docker/config.json’)