Setting Up a Ghost Blog with Vagrant, Docker, and Apache on Debian

In this post, we'll walk you through setting up a Ghost blog using Vagrant, Docker, and Apache on a Debian-based virtual machine. This setup allows for an easily reproducible development environment.

Directory Structure

First, let's set up the directory structure for our project:

.
├── data
│   ├── docker-compose.yml
│   └── example.site.conf
├── scripts
│   └── provision.sh
└── Vagrantfile

Vagrantfile

The Vagrantfile sets up the virtual machine. Here's the content:

Vagrant.configure("2") do |config|
  config.vm.box = "debian/bullseye64"
  config.vm.network "private_network", type: "dhcp"
  config.vm.network "public_network", bridge: "wlp0s20f3"

  config.vm.provider "virtualbox" do |vb|
    vb.name = "debian"
    vb.memory = "2048"
    vb.cpus = 4
  end

  config.vm.hostname = "debian"
  config.vm.synced_folder "./data", "/data"

  config.vm.provision "shell", inline: <<-SHELL
    echo "[TASK $((++count))] Initial configuration"
    apt update >/dev/null 2>&1
    apt upgrade -y >/dev/null 2>&1
    apt install -y git htop tmux vim >/dev/null 2>&1 
    ln -sf /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime
  SHELL

  config.vm.provision "shell", path: "./scripts/provision.sh"
end

Provisioning Script

Create a provisioning script at scripts/provision.sh to automate the installation of Docker and Apache:

#!/bin/bash

# Add Docker's official GPG key:
echo "[TASK $((++count))] Add Docker's official GPG key"
sudo apt install -y ca-certificates curl >/dev/null 2>&1
sudo install -m 0755 -d /etc/apt/keyrings >/dev/null 2>&1
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc >/dev/null 2>&1
sudo chmod a+r /etc/apt/keyrings/docker.asc >/dev/null 2>&1

# Add the repository to Apt sources:
echo "[TASK $((++count))] Add the repository to Apt source"
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null >/dev/null 2>&1
sudo apt update >/dev/null 2>&1

# Install Docker:
echo "[TASK $((++count))] Install Docker"
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null 2>&1

# Install Apache:
echo "[TASK $((++count))] Install Apache"
sudo apt install -y apache2 >/dev/null 2>&1
sudo systemctl enable apache2 >/dev/null 2>&1
sudo systemctl start apache2 >/dev/null 2>&1

# Configure files:
echo "[TASK $((++count))] Configure data"
mkdir /opt/ghost
cp /data/docker-compose.yml /opt/ghost/ 
cp /data/example.site.conf /etc/apache2/sites-available/

# Activate Apache modules:
echo "[TASK $((++count))] Activate Apache modules"
sudo a2enmod proxy >/dev/null 2>&1
sudo a2enmod proxy_http >/dev/null 2>&1
sudo a2enmod ssl >/dev/null 2>&1
sudo a2enmod rewrite >/dev/null 2>&1

# Restart Apache:
echo "[TASK $((++count))] Restart Apache"
sudo a2ensite example.site.conf >/dev/null 2>&1
sudo systemctl restart apache2 >/dev/null 2>&1

# Run Docker Compose for Ghost:
echo "[TASK $((++count))] Run Ghost Docker Compose"
cd /opt/ghost/
docker compose up -d >/dev/null 2>&1

Docker Compose Configuration

Create a Docker Compose file at data/docker-compose.yml to define the Ghost and MySQL services:

services:
  ghost:
    image: ghost:latest
    container_name: ghost
    restart: always
    ports:
      - 8080:2368
    environment:
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      url: http://example.site
    volumes:
      - ./data/ghost:/var/lib/ghost/content
    depends_on:
      - db

  db:
    image: mysql:latest
    container_name: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - ./data/db:/var/lib/mysql

volumes:
  ghost:
  db:

Apache Virtual Host Configuration

Create an Apache virtual host configuration file at data/example.site.conf:

<VirtualHost *:80>
    ServerName example.site

    ProxyPreserveHost On
    ProxyRequests Off

    <Location />
        ProxyPass http://localhost:8080/
        ProxyPassReverse http://localhost:8080/
        Order allow,deny
        Allow from all
    </Location>    

    ErrorLog ${APACHE_LOG_DIR}/example.site.error.log
    CustomLog ${APACHE_LOG_DIR}/example.site.access.log combined
</VirtualHost>

Updating the Hosts File

To access the Ghost blog using http://example.site, you'll need to update your host machine's hosts file. Add the following line, replacing 192.168.0.X with the actual IP address of your Vagrant machine:

192.168.0.X example.site

On Unix-based systems, this file is located at /etc/hosts, and on Windows, it's located at C:\Windows\System32\drivers\etc\hosts.

Bringing Up the Environment

With all the configurations in place, you can now bring up the Vagrant environment:

vagrant up

This command will create and configure the VM, install Docker and Apache, and set up the Ghost blog using Docker Compose.

Accessing Your Ghost Blog

Once the VM is up and running, you can access your Ghost blog at http://example.site. If your network configuration is correct, this should resolve to your Vagrant machine's IP address.

By following these steps, you have set up a fully functional Ghost blog using Vagrant, Docker, and Apache on Debian. This setup is perfect for local development and testing.