Ghost in A shell - part IV (and final): Maintenance
Tags: docker, productivity, tutorial, ghost
Published: 2018-06-13 16:04:56

---
title: Ghost in A shell - part IV (and final): Maintenance
published: true
tags: docker,productivity,tutorial,ghost
canonical_url: https://manu.breton.ch/blog/ghost-in-a-shell-part-4-maintenance/
---

 ![Ghost in A shell - part IV (and final): Maintenance](https://manu.breton.ch/blog/content/images/2018/06/GIAS-maintenance.png)

One very good reason to go for [Ghost(Pro)](https://ghost.org/features/) is that you do not have to maintain your blogs. They just run. For ever. Eventhough servers do crash, hard drives do break, electric power do fail, blogs do need to be upgraded... they will continue serving their pages.

Nevertheless, having one's own setup is fun (as long as you are aware of the limits above), and much easier to play with. You could for instance:


- run the Ghost version you want:

```
$ GHOST_VERSION=1.10 PORT=3002 NAME=old make

$ NAME=old make cli-version
  docker exec -it old ghost -v
  Ghost-CLI version: 1.1.1
  Ghost Version (at /var/lib/ghost): 1.10.0
  Latest version on Docker Hub: 1.24.2

```

- maintain many blogs without having to remember the options they were built with:

```
# instead of 
$ PORT=3003 NAME=new URI=my-new-super-blog DOMAIN=me.com make restart

# just use
$ p=instances/new/ make restart

```

- upgrade your blog with no risk and no hassle

```
$ vi instances/old/.env
  GHOST_VERSION=1.24
  
$ make p=instances/old/ upgrade
  docker exec -it old ghost -v
  Ghost-CLI version: 1.8.1
  Ghost Version (at /var/lib/ghost): 1.24.2
  Latest version on Docker Hub: 1.24.2

```

And these three reasons are good enough for me to write this fourth (and last) blog about shells of Ghost . Did I say "fourth" ? yep!. And here are the three first ones:

1. [Part I : localhost](https://dev.to/ebreton/ghost-in-a-shell---part-i--localhost-5he9), that focuses on localhost
2. [Part II : HTTPs is the norm](https://dev.to/ebreton/ghost-in-a-shell---part-ii---https-is-the-norm-1jj4), that shows you how to spawn multiple ghost instances on a given server
3. [Part III: To production, with performance](https://dev.to/ebreton/ghost-in-a-shell---part-iii--to-production-with-performance-10g5), that applies the recommendations from the Ghost team when it comes to DB + emailing, and puts a bit of pressure on the resulting instances

But first of all you need the basic diagnostic tools

# Environment variables

We have seen before the two following commands

- `make ps` to list the running instances
- `make logs` to tail and follow the logs, i.e to see what is happening

Those commands depends on the environment vars, which can be overridden in the command line. E.g.:

1. `make vars` will list for you the currently configured variables

```
$ make vars
# common
 NAME=ghost-local
 GHOST_VERSION=1
# values used for dev
 PORT=3001
# values used by traefik (qa & prod)
 PROTOCOL=http
 DOMAIN=localhost
 URI=ghost-local

```

1. `NAME=my-blog URI=me PROTOCOL=https GHOST_VERSION=1.22 make vars` will show how the variable are overriden

```
$ make vars
# common
 NAME=my-blog
 GHOST_VERSION=1.22
# values used for dev
 PORT=3001
# values used by traefik (qa & prod)
 PROTOCOL=https
 DOMAIN=localhost
 URI=me

```

So far (in the previous blogs) this is the way to go with multiple instances... and it sucks, especially if you want to run different set of values for each of them (which is exactly the reason why we have this series in the first place)

# All-in-one configurations

Therefore, there is a newcomer in the list of available variables: please welcome `p`.

> `p` is the path of the valid instance of the blog you want to act upon. you can use it with most of the `make` commands we have seen so far.

_Valid_ means that the path will contain a _.env_ file with all the overriden variables. For the sake of your sanity, this file is automatically generated when you spawn your instances with `make [dev|qa|prod]`. e.g.:

```
$ NAME=new-blog PORT=3002 make
# Simply start a ghost container making it directly available through $PORT
docker run --rm -d --name new-blog \
		-v /Users/emb/git-repos/ghost-in-a-shell/instances/new-blog:/var/lib/ghost/content \
		-p 3002:2368 \
		-e url=http://localhost:3002 \
		ghost:1-alpine
6330f60a50a834c7acee5916751815e47bba2f68b98f150a6ba2fe59627704ff
make save-vars
creating instances/new-blog/.env

```

The last two lines are the new sweetie... and you can now run the following to make sure your configuration as been saved:

```
$ make p=instances/new-blog/ vars
# common
  p=instances/new-blog/.env
  NAME=new-blog
  GHOST_VERSION=1
# values used for dev
  PORT=3002
# values used by traefik (qa & prod)
  PROTOCOL=http
  DOMAIN=localhost
  URI=new-blog

```

Consequently

- `make p=instances/new-blog/ vars` will list all vars from _./instances/new-blog/.env_
- `make p=instances/new-blog/ logs` will tail and follow the logs of the _./instances/new-blog_ blog instance
- `make p=instances/new-blog/ restart` will restart the blog with the settings defined in _./instances/new-blog/.env_
- `make p=instances/new-blog/ cli-version` show the versions for the new blog
- and so on...

> Note that 1) the path is relative, 2) the trailing `/` is mandatory, but it should come with the bash autocompletion anyway. (that's why it is done like this)

# Upgrade (and Downgrade)

Upgrading may be painful (particularly if you do not do it often enough). It is for sure scary. No ones want to change (break) something that runs smoothly.

You first need a bit of information, e.g with the question 'how far am I behind ?'. `make cli-version` will help you there:

```
$ make cli-version
docker exec -it ghost-local ghost -v
Ghost-CLI version: 1.8.0
Ghost Version (at /var/lib/ghost): 1.23.0
Latest version on Docker Hub: 1.24.2

```

The upgrade mechanism relies on [DockerHub tags](https://hub.docker.com/r/library/ghost/tags/). Which means that the most generic tags point to the latest version, and that the same version may have multiple tags. For instance, if the latest version is 1.24.2, you will get this version with all the following tags: 1.24.2, 1.24, 1, latest.

Hence the following behavior when upgrading:

- `GHOST_VERSION=1` -> will automatically update to all new releases of 1st version
- `GHOST_VERSION=1.x` -> will automatically update for patches only
- `GHOST_VERSION=1.x.x` -> will never automatically update

By default, the GHOST\_VERSION is set to `1`. Therefore, upgrading is as simple as `make upgrade[-qa|-prod]`. This command will pull the lastest (1.x.x) docker image and restart the container for you.

You can force your desired GHOST\_VERSION by overriding the env var:

```
$ GHOST_VERSION=1.24 make upgrade
...
Ghost-CLI version: 1.8.0
Ghost Version (at /var/lib/ghost): 1.24.2
Latest version on Docker Hub: 1.24.2

```

If you have specified a GHOST\_VERSION when you created the blog instance, e.g: `GHOST_VERSION=1.10 PORT=3002 NAME=old make`, the version is stored in the _.env_ file. Therefore the `p` helper variable will not allow you to upgrade automatically. It will stick to the version of the instance specified when it was created, e.g:

```
$ p=instances/old/ make upgrade
...
docker exec -it old ghost -v
Ghost-CLI version: 1.1.1
Ghost Version (at /var/lib/ghost): 1.10.0
Latest version on Docker Hub: 1.24.2

```

You will have to edit manually your _./instance/$NAME/.env_ file and set the new GHOST\_VERSION to upgrade it.

Would you like to rollback to a previous version, e.g. version 1.23.0? Just modify againt the _.env_ file and upgrade again. Or pass the variables through the command line.

```
$ vi instances/old/.env
GHOST_VERSION=1.23.0

$ make p=instances/old/ upgrade
docker exec -it old ghost -v
Ghost-CLI version: 1.8.1
Ghost Version (at /var/lib/ghost): 1.23.0
Latest version on Docker Hub: 1.24.2

```

> the actual docker image downloaded is `ghost:1.x.x-alpine`: the _-alpine_ suffix is added here because I prefer it lighter than heavier.

# Reliability ?

Well, we have seen quite a lot with these series and reliability has more to do with the hosting you are going to choose. And security policies you are going to enforce too. Far too much and too wide for a simple tutorial like this one. Remember also the disclaimer from the begnining: go for Ghost pro if you are looking for reliability :)

Cheers,
Manu