- Create SSH keys (without passphrase):
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "[email protected]"
- Add authorized keys:
cd ~/.ssh
cat id_rsa.pub >> authorized_keys
-
Ensure public key authentication is enabled (use your editor of choice, example with
vim):sudo vim /etc/ssh/sshd_config- using
/, search for:RSAAuthenticationand make sure it is set toyesPubkeyAuthenticationand make sure it is set toyesUsePAMand make sure it is set toyesPreferredAuthenticationsand make surepublickeyis the first in the list
- if the file is changed, restart the
sshdservice (service sshd restart)
-
Ensure permissions are correctly set:
chmod 750 ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
| Secret variable name | Description | Example |
|---|---|---|
DEPLOY_SSH_PRIVATE_KEY |
The private key generated on the server. Typically, the content of the id_rsa file. |
-----BEGIN RSA PRIVATE KEY----- |
DEPLOY_SSH_HOST |
The host name of the destination server. | sub.domain.tld, 888.888.888.888 |
DEPLOY_SSH_USER |
The user with which to identify when using rsync ; has the public key content in its ~/.ssh/authorized_keys file. |
www-data |
DEPLOY_PATH_FILTERS |
The filters given to rsync to determine what to deploy. |
+ included.html |
DEPLOY_PATH |
The destination folder on the destination server. | /var/www/public_html |
name: rsync-deploy
on:
push:
branches: master
jobs:
build:
runs-on: ubuntu-latest
env:
REMOTE_PATH: ${{ secrets.DEPLOY_PATH }}
SSH_KEY: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}
SSH_FILE: id_rsa
SSH_USER: ${{ secrets.DEPLOY_SSH_USER }}
SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}
SSH_FILE: id_rsa
# Sample directory tree:
# .
# ├── included
# │ ├── excluded
# │ │ └── excluded.html
# │ └── included.html
# ├── included_all
# │ ├── included
# │ │ └── included.html
# │ └── included.html
# ├── excluded.html
# └── included.html
#
# Sample RSYNC_FILTERS_CONTENT whitelist content:
# + included.html
# + /included/
# + /included/*
# + /included_all/***
# - /**
#
# Above filters combined with "--prune-empty-dirs" results in the following being transferred:
# included.html
# included/
# included/included.html
# included_all/
# included_all/included.html
# included_all/included/
# included_all/included/included.html
RSYNC_FILTERS_CONTENT: ${{ secrets.DEPLOY_PATH_FILTERS }}
RSYNC_FILTERS_FILE: rsync_filters.txt
steps:
# checkout the repo
- uses: actions/checkout@v3
- name: Configure SSH
# create ~/.ssh/ directory if not exists
# adjust permissions of ~/.ssh/ directory
# create the specified private key file from secrets
# adjust permissions of private key file
# get the remote host in a variable
# get the content to add to ~/.ssh/known_hosts
# setup ~/.ssh/known_hosts
run: |
mkdir -p ~/.ssh/
chmod 700 ~/.ssh
echo "$SSH_KEY" > ~/.ssh/$SSH_FILE
chmod 600 ~/.ssh/$SSH_FILE
host=SSH_HOST
hosts="$(dig +short "$host" | grep -v '\.$' | sed -z 's|\n|,|g')$host"
ssh-keyscan -H "$SSH_HOST" > ~/.ssh/known_hosts
- name: Setup rsync filters
run: |
touch $RSYNC_FILTERS_FILE
echo "$RSYNC_FILTERS_CONTENT" > $RSYNC_FILTERS_FILE
- name: Deploy with rsync
# Details:
# - checksum-based comparison, archive mode, compressed, quiet
# - connect with ssh using specified identification key file, suppressing logs that are not errors
# - specify that files not included in filtered source will be deleted at destination (other files are preserved)
# - apply filters as defined in rsync_filters.txt
# - specify empty directories will be removed from filtered source (other empty directories are preserved)
# - transfer the specified source path
# - transfer to specified remote destination path
# Remarks:
# - remove `q` and/or add `v` or `vv` in `-cazq` to show more info about file transfers
# - it is highly recommended to add a `--dry-run \` line before the specified source path `./ \` to test the filters ; remove afterwards
run: |
rsync -cazq \
-e "ssh -i ~/.ssh/$SSH_FILE -o LogLevel=ERROR" \
--delete \
--filter="merge $RSYNC_FILTERS_FILE" \
--prune-empty-dirs \
./ \
$SSH_USER@$SSH_HOST:$REMOTE_PATH