DEV Community

Michael Staszel
Michael Staszel

Posted on • Originally published at mikestaszel.com on

Ghost + Docker + Nginx + SSL

Setting up a blog with Ghost is extremely easy. You don't need to worry about NodeJS, SQL databases, or whether your machine will be able to run it. Last time I used Ghost, I remember messing around with NodeJS and NPM. Nowadays, it's much easier. You can run this on a machine with 1 CPU core and 512MB of RAM (you can get one of these on the GCP free tier).

At the end of this guide you'll have a Ghost blog with a free, auto-renewing SSL certificate.

Installing Ghost and Nginx

First, install Docker. Your Linux distribution's version of Docker is just fine.

sudo apt install -y docker.io
sudo systemctl enable docker
sudo gpasswd -a YOURUSERNAME docker
# now, log out of the terminal and log back in
Enter fullscreen mode Exit fullscreen mode

Next, run:

mkdir -p $HOME/content
docker run \
    --name ghost \
    -p 2368:2368 \
    -e url=https://example.com \
    -v $HOME/content:/var/lib/ghost/content \
    --restart=always \
    -d \
    ghost:alpine
Enter fullscreen mode Exit fullscreen mode

You should save this in a script called create.sh if you ever need to recreate the container.

Next, install nginx (sudo apt install -y nginx) and modify the configuration:

# /etc/nginx/nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

# /etc/nginx/sites-enabled/default:

server {
    server_name example.com;
    listen [::]:80;
    listen 80;

    location / {
        proxy_pass http://127.0.0.1:2368;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, start Nginx: sudo systemctl restart nginx

Now we'll set up an SSL certificate using Let's Encrypt and CertBot. You'll need to get your Linux distribution's exact instructions from this page: https://certbot.eff.org/lets-encrypt/debianbuster-nginx

Select "Nginx" and your distribution. On Debian, it was as simple as:

sudo apt-get install certbot python-certbot-nginx
sudo certbot --nginx
sudo reboot
Enter fullscreen mode Exit fullscreen mode

When the system starts back up, your Ghost blog should be up and running with SSL!

Updating Ghost

When it's time to update, all I have to do is:

docker stop 123
docker rm 123
docker pull ghost:alpine
./create.sh
Enter fullscreen mode Exit fullscreen mode

Since my content is mounted to the container, I can delete and recreate the container without worrying.

Backups

Backing up the content is straightforward too. Since I'm using Ghost with SQLite, all I need to do is back up my content directory. I use rclone to back this up to Backblaze B2 (10GB free!) on a daily basis.

FILENAME=backup_`date '+%Y%m%d'`.tar.gz
tar -zcf backups/$FILENAME content
rclone copy backups/$FILENAME b2:/my-bucket/blogbackup/
Enter fullscreen mode Exit fullscreen mode

That's all there is to it. I'm very happy with my lightweight Ghost blog set up!

Top comments (0)