Exercise: Deploy Over SSH

Give the book club's server a short name in an SSH config file, then write deploy.sh, one command that checks the site, copies it to the server with rsync over SSH, lists what's live with ssh and can rehearse first, and let a check script that needs no server tell you what's done.

Freelancer · Unix · Linux · Updated

The Maple Street Book Club's website is a folder of four files, and it lives on a server called bookclub. Every time someone changes a page, somebody has to put it live: copy the right files to the right folder, remove the page the club took down, and check what's there now. Done by hand, one of those steps gets forgotten. You'll make it one command: give the server its short name in ssh-config, then write deploy.sh, which checks the site, copies it with rsync over SSH, lists what's live with ssh, and can rehearse first. A check script tells you what's done, and it needs no server at all.

Before you start

You need a terminal: the Terminal app on a Mac, or Ubuntu on Linux or in WSL on Windows. ssh and rsync are already there, and the check runs with bats, a small program that runs checks written for bash. If bats --version or rsync --version doesn't print a version number yet, install them:

sudo apt install bats rsync      # Ubuntu, and Ubuntu in WSL
brew install bats-core           # a Mac, with Homebrew

sudo asks for your password, the one you use to sign in; nothing shows on the screen while you type it.

Get the exercise code

Open this lesson's GitHub repository, github.com/ask-codey/exercise-bash-deploy-over-ssh, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your terminal-practice folder. Or clone it with Git. On Windows, put it inside Ubuntu, in your Linux home folder, not in a Windows folder under /mnt/c, so chmod works on the scripts.

The folder holds:

  • site/: the book club's website, the pages you deploy.
  • ssh-config and deploy.sh: the two files you write. Each starts with a comment that says exactly what it must do.
  • stand-in/ssh: a pretend ssh, for trying your script on a computer with no SSH server.
  • check.bats: the check. You don't need to change it.

What to do

Open a terminal in the exercise folder, make the scripts runnable (Your First Script), and open the first file in nano:

chmod +x deploy.sh stand-in/ssh
nano ssh-config
  1. ssh-config: a Host block that gives the name bookclub the HostName localhost, your own user name as User (whoami prints it), and the IdentityFile ~/.ssh/id_ed25519. These are the lines for your ~/.ssh/config.
  2. deploy.sh copies what's inside site/ into the folder bookclub-site on the server bookclub, with rsync over SSH, so the server's copy matches site/ exactly: a page deleted from site/ is deleted from the server too. Then it prints Live on bookclub: and the files in bookclub-site on the server, by running ls there with ssh.
  3. deploy.sh -n rehearses: rsync lists what it would copy and changes nothing, then the script prints Rehearsal: nothing was copied. and stops with exit code 0.
  4. No site/index.html, no deploy. If it's missing, deploy.sh says so, copies nothing and stops with exit code 1, so an empty or wrong site/ can never replace the live site.

Try it as you go. With no SSH server, the stand-in runs every ssh command on your own computer, in the folder stand-in/server-home/; it's first on the PATH for this one command only (PATH: How a Command Is Found):

PATH="$PWD/stand-in:$PATH" ./deploy.sh -n

When every check passes, you can also deploy for real: see Optional: deploy to a real server below.

Check your work

From the exercise folder:

bats check.bats

At first almost every check fails. That's expected: each job you finish turns its checks into a ✓. The check reads ssh-config with your own ssh -G, which connects to nothing, and runs a copy of deploy.sh on a made-up garden club site of its own, in a throwaway folder, with its own stand-in ssh. A failing check says what to look at, for example about.html was deleted from site/, but it's still live on the server after the next deploy.

Hints

  • Check the config before you trust it. ssh -F ssh-config -G bookclub shows the settings ssh would use, as in SSH Keys and ~/.ssh/config. If it says hostname bookclub, ssh didn't find your Host block.
  • Mind the slash and the colon. Copying Between Computers: scp and rsync shows what site/ and site each copy, and what the colon in bookclub:bookclub-site/ does.
  • Rehearse. The option that makes rsync only list what it would copy is the one you rehearsed with in Backups That Work: rsync. ${1:-} is the first argument, or nothing when there isn't one.
  • Which computer fills it in? Running Commands on Another Computer shows which quotes let your script's $folder reach the server already filled in.
  • Check first, copy second. Checking Before You Act: File Tests shows how to test that a file is there before anything else runs.

When you're done

Every check passes:

check.bats
 ✓ deploy.sh, ssh-config and site/ are here, and so are ssh and rsync
 ✓ 1) ssh-config gives bookclub the HostName localhost
 ✓ 2) ssh-config gives bookclub a User
 ✓ 3) ssh-config gives bookclub the key ~/.ssh/id_ed25519
 ✓ 4) deploy.sh copies what's inside site/ into bookclub-site on the server
 ✓ 5) deploy.sh connects to the short name bookclub
 ✓ 6) deploy.sh lists what's live on the server, with ssh
 ✓ 7) deploy.sh makes the server's copy match site/: a deleted page goes too
 ✓ 8) deploy.sh -n rehearses and changes nothing on the server
 ✓ 9) deploy.sh stops with exit code 1, and copies nothing, when site/index.html is missing
 ✓ 10) deploy.sh copies with rsync -a and --delete, and runs a command with ssh

11 tests, 0 failures

Now look back at deploy.sh. If the club moved its site to a new server tomorrow, which file would you change, and how many lines?

Optional: deploy to a real server

The stand-in pretends. A real SSH server shows you the whole trip, and your own computer can be that server, as in Logging In to Another Computer: ssh. This step is optional: the check and your submission don't need it.

Turning on an SSH server changes your computer: anyone who can reach it over the network can try to log in with your user name and password. Turn it on for this step, and off again when you're done.

  1. Turn the SSH server on. On Ubuntu, and Ubuntu in WSL, install it, which also starts it. On a Mac, open System Settings, then General, then Sharing, and turn on Remote Login.

    sudo apt install openssh-server
    
  2. Put your key on it, as in SSH Keys and ~/.ssh/config. If ls ~/.ssh shows no id_ed25519, make one first with ssh-keygen -t ed25519. Then hand its padlock to your own computer:

    ssh-copy-id "$(whoami)@localhost"
    
  3. Give bookclub its name for real. Open ~/.ssh/config in nano (it's a new, empty file if you don't have one yet), paste the Host bookclub block from your ssh-config at the end, and save. Then try it: ssh bookclub ls should list your home folder without asking for your computer's password. It may ask for your key's passphrase.

  4. Deploy. Rehearse first, then deploy, then look at what's live:

    ./deploy.sh -n
    ./deploy.sh
    ls ~/bookclub-site
    

    The four pages are now in ~/bookclub-site, copied there over SSH, as they would be on a server across the country. Delete a page from site/, deploy again, and watch it go from the live copy too.

  5. Tidy up. Turn the server off, and take the Host bookclub block out of ~/.ssh/config if you won't use it again. On a Mac, turn Remote Login off in the same place.

    sudo apt remove openssh-server
    rm -r ~/bookclub-site
    

On a real server, only the Host block changes: its HostName, its User, and the key you put there. deploy.sh stays the same.

Submit your exercise

The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.

  1. On GitHub, click +, then New repository. Name it (for example exercise-bash-deploy-over-ssh), choose Public, and click Create repository. Leave out the README: your folder already has one.

  2. In a terminal in your exercise folder (Ubuntu in WSL on Windows), send your work to your new repo. If you downloaded the ZIP:

    git init -b main
    git add .
    git commit -m "My solution"
    git remote add origin https://github.com/your-name/exercise-bash-deploy-over-ssh.git
    git push -u origin main
    

    If you cloned the starter instead, point your copy at your own repo, then commit and push:

    git remote set-url origin https://github.com/your-name/exercise-bash-deploy-over-ssh.git
    git add .
    git commit -m "My solution"
    git push -u origin main
    
  3. Paste your repo's address, such as https://github.com/your-name/exercise-bash-deploy-over-ssh, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.

Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.

So what

A deploy script is a checklist that can't skip a step: the same checks, the same copy and the same look at the result, every time, whether you run it or a scheduled job does.

Key terms

Related