Create a blog using Ghost
This guide covers setting up a Ghost blog using Docker on Debian. You'll learn how to configure Docker, set up Ghost with MariaDB, and route it to your domain using Nginx. I also cover SSL setup with Certbot and options for hosting via Cloudflare Tunnels or a VPS.
(How I created this blog, A step by step guide)
About this guide
- This is focused on setting up a Blog using Ghost via Docker on Debian (or its derivatives). While you can use this on a VPS, I used my own server that I made out of a mini-PC. More on that in a future post.
- Every underlined word/set of words is a relevant link.
- I created this guide because I couldn't find simple & concise instructions to set up Ghost fast on a Linux system using docker.
Initial Setup
- Open a terminal window (or a shell).
- Install docker if not already installed.
- Make sure you have the appropriate permissions to use Docker in your system. (you may need to add your user to the Docker group).
The main course
Follow these steps to set up Ghost in the fastest and cleanest way possible.
I prefer installing new software using Docker because if I mess up, or simply don't like the software, I can remove all traces of it using standard docker container, image and volume commands.
Whereas, installing something on your PC directly makes changes/adds more dependent software that you either have to manually keep track of, or forget to remove. This with time, clutters up your PC and strongly affects performance.
Steps:
- At your desired place, create a new directory, let's call it
Ghost.mkdir Ghost
- Navigate to this directory, and create a new file
docker-compose.yml. This is the YAML file that we will use to tell docker what to do. Open this file and paste the code below.cd Ghosttouch docker-compose.yml- Open using any editor, I'm using nano because of simplicity. Type
nano docker-compose.yml. - Copy this configuration and paste it into the file:
services:
ghost:
image: ghost:latest
restart: always
ports:
- "2368:2368"
depends_on:
- db
environment:
url: <YOUR_BLOG_URL>
database__client: mysql
database__connection__host: db
database__connection__user: ghost
database__connection__password: ghostdbpass
database__connection__database: ghostdb
volumes:
- /home/ghost/content:/var/lib/ghost/content
- type: bind
source: /location/of/config.production.json
target: /var/lib/ghost/config.production.json
db:
image: mariadb:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: <YOUR_ROOT_PASSWORD>
MYSQL_USER: ghost
MYSQL_PASSWORD: ghostdbpass
MYSQL_DATABASE: ghostdb
volumes:
- /home/ghost/mysql:/var/lib/mysqldocker-compose.yml
- Edit the docker-compose.yml file to fit your blog. Going from the top-down, following changes need to be made:
- (Under environment)
url: Instead of<YOUR_BLOG_URL>enter the URL of the website where the blog will be accessible. Even if you're using a reverse proxy, the URL must be the public facing one, instead of the local URL. For example, for this blog it washttps://blog.samirkabra.com. - (Under volumes)
source: Replace/location/of/config.production.jsonwith thecurrent dir/config.production.json.- Get current directory using
pwd. Example:/home/user/Ghost/, so then we would replace it with/home/user/Ghost/config.production.json. - This file doesn't exist yet, do not worry, we will create it.
- Get current directory using
- (In db > environment)
MYSQL_ROOT_PASSWORD: Replace<YOUR_ROOT_PASSWORD>with a strong password consisting of letters and numbers (You can use symbols, but some symbols like$can result in erroneous behavior, so I prefer to avoid them entirely).
- (Under environment)
- Save the
docker-compose.ymlfile and exit nano.ctrl + sctrl + x
- Now create the configuration file for Ghost. We created a bind mount so that the config we create here is mirrored to the Ghost Docker container.
touch config.production.jsonnano config.production.jsonPaste the following into the file:
{
"url": "http://localhost:2368",
"server": {
"port": 2368,
"host": "::"
},
"mail": {
"from": "<FROM_EMAIL>",
"transport": "SMTP",
"options": {
"host": "smtp.mailgun.org",
"port": 587,
"service": "Mailgun",
"secure": false,
"requireTLS": true,
"auth": {
"user": "<YOUR_USER>",
"pass": "<YOUR_PASS>"
}
}
},
"logging": {
"transports": [
"file",
"stdout"
]
},
"process": "systemd",
"paths": {
"contentPath": "/var/lib/ghost/content"
}
}- Configure Mailgun using this Official Tutorial by Ghost. Fill out the credentials within the config file after setting up SMTP credentials on Mailgun.
- Save this and exit nano.
- Use the following command to start the docker container.
docker compose up -d- Check out your local instance of Ghost at
localhost:2368orVPS_IP_ADDRESS:2368. To access the admin panel, visitlocalhost:2368/ghostorVPS_IP_ADDRESS:2368/ghost.
Routing Ghost to Your Domain
Depending on where you've hosted Ghost, there are a few ways:
If you're self hosting
- Look into Cloudflare Tunnels. Without exposing a port, you can host the Ghost instance on your domain. However, this requires Cloudflare to be your DNS provider. If you do not want to do that, we have a few alternatives.
- Expose a port on your router, request your ISP to provision you a static IP address, and then follow the steps for VPS. (I don't recommend this, and I have never done this because of security concerns.)
- Use a VPN like Tailscale or WireGuard that you can either:
- Give access to your users to (Tailscale has a limited amount of users you can share it with on their free plan.)
- Get a lightweight VPS that acts as a public facing intermediary that is connected to your VPN.
If you're using a VPS
- Pointing a Domain to a VPS:
- Using a Reverse Proxy:
- Install Nginx or Traefik on the VPS and configure it to route requests for your domain to the Ghost container:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:2368;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}- SSL Configuration
- Use Certbot to generate SSL certificates for your domain. Certbot can automatically configure Nginx for SSL:
sudo certbot --nginx -d yourdomain.com
Final Thoughts
By following this guide, you should now have a fully functioning Ghost blog up and running using Docker on your Debian-based system. Docker makes it easy to manage, maintain, and scale your application while keeping your system clean and clutter-free. Additionally, I’ve provided options for routing Ghost to your domain, whether you’re self-hosting or using a VPS.
If you run into any issues, feel free to revisit the official documentation or explore alternative configurations that best suit your setup.
What's Next?
In future posts, I plan to cover:
- How I built my own mini-server out of a mini-PC.
- Other OSS that I host on my mini-PC.
If you're interested in these topics, or would like the ability to comment make sure to subscribe. It's free and always will be!
Get in Touch
If you have questions or suggestions, feel free to reach out via Twitter or drop me an email at [email protected]. I’d love to hear your thoughts or help troubleshoot any issues you encounter!
Samir | www.samirkabra.com