Setup and serve Quasar SSR in a Droplet in 30 minutes and in 3 Quick and Easy Steps.
Tags: fullstack, vue, ssr, quasarframework
Published: 2019-10-23 16:46:52

I struggled for a few hours the other day trying to convince `now.sh` to let me run a `Vue SSR` site using the Quasar Framework as my engine. Contrary to what is claimed at the [quasar.dev docs](https://quasar.dev/quasar-cli/developing-ssr/deploying#Deploying-with-Now.sh), Quasar SSR and now.sh is an absolute NON-STARTER. NOT V1. NOT V2. [That recommendation to use V1](https://github.com/quasarframework/quasar/commit/9addc85088cc0326773fe15ac8395c3a46997db9) of the `now.sh` API actually breaks some functionality of the now.sh user interface, especially when you are on the free tier. :(

Running out of time in the deploy window, I thought, well - how hard is it to setup a proper server with Digital Ocean? (And yes, I hate docker and k8's.) It took me about 30 minutes. Here's how it went down:

Some notes on nomenclature:
- `xxx.xxx.xxx.xxx` is the public IP of the droplet
- `%project` is the name of your website, ie: `myproject.com`
- `home: $` is your local dev workstation bash console
- `root: $` is remote root user bash console
- `web: $` is the remote sudo user bash console 

Tech Used:
- DigitalOcean
- Ubuntu 18
- Curl
- NVM, Node, Yarn, NPM, PM2
- Quasar SSR (VueJS)
- Nginx
- Let’s Encrypt Certbot
- SSH
- Bash

### Step -1. Create a Quasar SSR app
```
home: $ quasar create %project
home: $ cd %project
home: $ git init #link with github however you prefer
home: $ quasar build -m ssr
home: $ git add -a
home: $ git commit -m 'feat(init): quasar ssr'
home: $ git push origin master
home: $ cat .ssh/id_rsa.pub # -> copy to your clipboard
```

### Step 0. Make a new droplet
- Choose Ubuntu 18
- Choose SSH key and paste your dev machine's key that you just copied
- Note the IP Address
- Submit and wait 30 seconds to a minute for the provisioning to finish

### Step 1. Setup a new user.

```
home: $ ssh root@xxx.xxx.xxx.xxx
-----
root: $ useradd web -m
root: $ passwd web # Write this password down, or manage it.
root: $ visudo
```
> # User privilege specification
> root    ALL=(ALL:ALL) ALL
> web     ALL=(ALL) ALL

```
root: $ usermod --shell /bin/bash web
root: $ su web
-----
web: $ mkdir .ssh
web: $ nano .ssh/authorized_keys
   # paste the key, make ONE new line, save and exit
web: $ exit
-----
root: $ exit
```

### Step 2. Make the Github deploy key
```
home: $ ssh web@xxx.xxx.xxx.xxx
-----
web: $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.0/install.sh | bash
web: $ nvm install 10
web: $ sudo apt-get update
web: $ sudo apt-get install git
web: $ ssh-keygen # DO NOT ENTER A PASSWORD!
web: $ cat .ssh/id_rsa.pub
   # copy the lines to your clipboard
```
Visit: https://github.com/%org/%project/settings/keys
- create a new deploy key
- paste the public ssh key
- give it permissions to change the repo (if you wish)
- give a good name like `web@xxx.xxx.xxx.xxx` (the IP address of your server)
- use an ORG, not a personal account (because permissions works differently and better)

### Step 3. Setup your deploy instance and dependencies
```
web: $ npm install -g yarn pm2 @quasar/cli
web: $ git clone git@github.com:%org/%project.git
web: $ cd %project
web: $ git config user.email "web@%project" # in case you want to push back to github
web: $ git config user.name "deploy" # in case you want to push back to github
web: $ yarn
web: $ quasar build -m ssr
web: $ yarn deploy:ssr-pm2
web: $ yarn deploy:ssr-pm2_kill
web: $ yarn deploy:ssr-pm2_watch
```
#### VERIFY
- Visit `http://xxx.xxx.xxx.xxx:3000` to confirm that pm2 is working.

#### NOTES
> Quasar SSR defaults to serving at 3000. This is fine. Make sure that you are happy with its very conservative CSP settings. Consider using Helmet.
> Scroll to the end to see the helpful deploy commands (and a few more) that make managing this much easier.

### Step 4. Get nginx to proxy-pass 3000 to :80 and :443
```
web: $ sudo apt install nginx
web: $ sudo ufw app list
web: $ sudo ufw allow 'Nginx Full'
web: $ sudo ufw allow 'OpenSSH'
web: $ sudo ufw enable
web: $ sudo ufw status
web: $ sudo ufw disable
web: $ sudo ufw status
web: $ sudo ufw enable
web: $ sudo nano /etc/nginx/sites-available/%project
```

`/etc/nginx/sites-available/mywebsite.com`
```
# in this file we are using a fake website url (mywebsite.com) 
# just because NGINX can be a pain to debug. Use your own,
# and be sure that the file name is also `%project`.

server {
    listen 80;
    listen 443 ssl;

    server_name mywebsite.com www.mywebsite.com;

    location / {
        proxy_pass http://127.0.0.1:3000/;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```


```
web: $ sudo ln -s /etc/nginx/sites-available/%project /etc/nginx/sites-enabled/
web: $ sudo rm /etc/nginx/sites-enabled/default
web: $ sudo systemctl restart nginx
web: $ systemctl status nginx
```
#### VERIFY
- Visit `http://xxx.xxx.xxx.xxx` to make sure the proxy is working

#### NOTES
In the next step, Certbot will slightly rewrite your nginx conf. We are doing it this way because certbot NEEDS port 80 to help itself make the certs.


### Step 5. Set up Let’s Encrypt with Certbot
#### SETUP
- set the `@-record` in your DNS management interface to `xxx.xxx.xxx.xxx`
- set the www record in your DNS management to %project

```
web: $ sudo apt install software-properties-common
web: $ sudo add-apt-repository universe
web: $ sudo add-apt-repository ppa:certbot/certbot
web: $ sudo apt-get update
web: $ sudo apt install  certbot python-certbot-nginx
web: $ sudo certbot --nginx -d %project,www.%project
web: $ sudo systemctl restart nginx
web: $ sudo ufw status
web: $ sudo certbot renew --dry-run
```

#### VERIFY
- Visit `http://%project` to make sure it redirects to `https://%project` 


## That's it!
Ok, it was click-baity of me to say 3 steps, but starting a list at -1 and also using 0 let me subtract 2 from 5 - so sue me. ;) And maybe there's better ways to do this, important security features I missed or something else. If so, please leave a comment and I'll consider revising.


### Deploy Scripts
Here are some useful scripts for managing `pm2` (that you should place in the root package.json of your Quasar project):
```
package.json
“scripts” :{
  "build": "quasar build -m ssr",
  "start": "node dist/ssr/index.js",
  "deploy:fresh": "git pull && quasar build -m ssr && yarn deploy:ssr-pm2_restart",
  "deploy:ssr-pm2": "pm2 start ./dist/ssr/index.js --name quasar-ssr",
  "deploy:ssr-pm2_clusterize": "pm2 start ./dist/ssr/index.js --name quasar-ssr -i max",
  "deploy:ssr-pm2_watch": "pm2 start ./dist/ssr/index.js --name quasar-ssr --watch ./dist/ssr",
  "deploy:ssr-pm2_deep-monitoring": "pm2 start ./dist/ssr/index.js --name quasar-ssr --deep-monitoring",
  "deploy:ssr-pm2_restart": "pm2 restart quasar-ssr",
  "deploy:ssr-pm2_stop": "pm2 stop quasar-ssr",
  "deploy:ssr-pm2_monitor": "pm2 monitor quasar-ssr",
  "deploy:ssr-pm2_unmonitor": "pm2 unmonitor quasar-ssr",
  "deploy:ssr-pm2_kill": "pm2 kill"
}
```

----
Image from [jeahnlaffitte](https://unsplash.com/@jeahnlaffitte?utm_medium=referral&amp;utm_campaign=photographer-credit) at unsplash.