Setting up Continuous Deployment for a vue app on a VPS using Github Actions
Tags: vue, devops, linux, githubactions
Published: 2022-07-31 23:01:00

**Continuous Deployment** is a part of the **Continuous Delivery** process in **CI/CD**. This process covers the part of deploying the builds to production (or other environments), although to get to this part we must have touched some processes in **Continuous Integration**. However, this article will majorly be focusing on automatic deployment. It's important to note that there are other configurations and setup that should be done to have a decent CI/CD process. For example, one might setup ways to manage and keep each release on the server.

##What you need to get started

The assumption here is you have a github account and you have setup your github repository. It's also assumed that you have a Virtual Private Server that has been provisioned, if you do not have this, you can get it from any of the hosting platform (e.g. DigitalOcean, Linode) that offers this.

## Setting Up

- We need to set up the server

I'm currently using Ubuntu 20.04.2 LTS for this. It doesn't really matter what OS you use but if your setup has its peculiarities, just try to factor that in your modifications. If you don't already have ssh key pairs generated, do that by running the command below in your terminal.

You can generate the keys on your local machine or on the remote server. If you'll be generating on the remote server run the next line (1.1) of code. If not skip and move to line 1.2.

 1.1. `ssh username@host` where username is your username and host is probably the ip to your host.

Then run;

 1.2. `ssh-keygen -t rsa -b 4096 -C "email@example.com"`

You do not need to specify the flags, by default the best options available will be picked. `-t` flag represents the algorithm type to use , `-b` flag represents the size. You could also add an `-f` flag which takes the *filename* you want to store the key in. The `-C` flag is for commenting the keyfile, you can put anything in the comment but it's common to put one's email in.

After running the last command you'll be prompted to enter the file you want to store the keys in, just press enter. You'll be asked to specify a passphrase afterwards, press enter two times to set it up with no passphrase. However, if you specify a passphrase, you'll have to include it in your deploy script.

- Add the public key to your authorized keys

Run the command below to append the previously created public key to your authorized_keys. Although you can as well do that manually by copying the public key and opening your authorized_keys file to paste it at the end.

 2.1. `cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys`

If you created the keys on your local machine, run the following to copy the key to your remote server or you can as well just do it manually;

 2.2. `ssh-copy-id -i ~/.ssh/id_rsa.pub username@host`

- Copy the private key from your server or local machine

Run the following command to do that

 3.1. `cat ~/.ssh/id_rsa`

The command will print out the content of the `id_rsa` file to the terminal. Copy this to somewhere else you can easily access (like your clipboard) later. It should be noted that the name doesn't have to be `id_rsa`, this depends on what you saved your keys as in the previous step or the kind of algorithm you're making use of. The private key should start with something like `-----BEGIN OPENSSH PRIVATE KEY-----` and end with `-----END OPENSSH PRIVATE KEY-----`.

- Setup Github Actions Secrets

Go to the the app's github repository, then from there navigate to settings. Then use **"New Repository Secret"** button repeatedly adding the following parameters.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62c22uzhh06g3yqke004.png)

1. SSHKEY - Input the key you copied in the previous step.

2. HOST - Input your server's hostname (i.e ip address).

3. USERNAME - Input the username you use to ssh into your sserver.

4. PORT - Input the ssh port no, default is 22.

5. TARGET - Input your vue app's root path .i.e `/var/www/staging`

6. STAGING_ENV - This is optional, and you can name it whatever you want. I use the format ENVIRONMENT_ENV to specify the environment I'm deploying to. If you don't make use of the env file to store environment variables, this should be ignored.

7. PASSPHRASE - This is optional, if you left the passphrase empty in step 1 above, ignore this.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jx7beldad0ouwp03fv40.png)

- Add YAML file to configure your repository for automatic deployment

There are couple of ways to go about this. You can do this by going to **"actions"** tab in your repository and then clicking on the link that says **"set up a workflow yourself"**. Then copy the content of the YAML file that is below into the provided text box. You may change the name of the file to *whatevername.yml* (in my case, I named it deploy-staging.yml because it's for the staging environment) and then commit it.

However, for easy control, in your local repository, in the root folder create the following `.github/workflows/deploy-staging.yml `where **.github** and **workflows** are directories. After doing this, you can then commit and push the changes to your remote repository.

```
name: Deploy to Staging

on: 
  push:
    branches:
      - development
jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Copy repository contents to remote server via scp
      uses: appleboy/scp-action@master
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        port: ${{ secrets.PORT }}
        key: ${{ secrets.SSHKEY }}
        passphrase: ${{ secrets.PASSPHRASE }}
        source: "."
        target: ${{ secrets.TARGET }}

    - name: Executing remote command via ssh
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        port: ${{ secrets.PORT }}
        passphrase: ${{ secrets.PASSPHRASE }}
        key: ${{ secrets.SSHKEY }}
        script: |
              cd ${{secrets.TARGET}} && npm install
              printf "%s" "${{secrets.STAGING_ENV}}" > "${{secrets.TARGET}}/.env.staging"
              npm run build:staging
```


A run through of what the script is doing;

1. In order not to deploy on every push, we have specified the branch(es) that pushing to must trigger the deploy process. Here, we specified the development branch, however we can specify multiple branches.

2. The **checkout** action checks out the repository so our workflow can access it.

3. **scp-action** handles the copying of the files from the repository to the remote server using the credentials we have provided via actions secrets. If you left the passphrase empty in step 1 above, remove the passphrase line.

5. **ssh-action** handles running the remote command to facilitate the deployment, also using the credentials we provided via actions secret to access the remote server. If you left the passphrase empty in step 1 above, remove the passphrase line.

6. The commands are quite straightforward
  - navigate to the root directory then run `npm install` to install the dependencies.
  - write the environment variables stored in the STAGING_ENV secret into `.env.staging` file on the remote server [This is an optional line, if it's not applicable to you, remove it].
  - build the app using a custom script. I added a custom script, `"build:staging": "vue-cli-service build --mode staging"`, in my package.json to build for the staging environment. If you do not have a special need like me, you might as well change that to `npm run build`.

After pushing the changes to the specified branch(es). switch to the **Actions** tab on your repository and you should get something like the below image if all went well. Now, you have successfully deployed your app to your environment of choice.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6twzia420f3mt9oq7bdj.png)

In the above, we have used the set of actions listed below. You may check them out to learn one or more things you can equally do with them;

1. [Checkout](https://github.com/marketplace/actions/checkout)

2. [SCP Files](https://github.com/marketplace/actions/scp-files)

3. [SSH Remote Commands](https://github.com/marketplace/actions/ssh-remote-commands)

**NB:** 
1. There is a lot you can do with github actions and I would advise we explore this more. Visit the github actions [page](https://docs.github.com/en/actions) to learn what we can do and how you can better equip yourself.
2. This process will also work for other related codebases, albeit with one or more modifications.
3. I assumed you must have point your server block to the **dist** directory, this directory is where vue builds the app by default.
4. Github Actions has limited free minutes and storage for private repositories. You might want to check [here](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions) to see what is applicable to you.

I hope you find this useful. If you have questions or comments, please drop them below and let's learn together.