Host Multiple Ghost Instances with Docker
I use Ghost in my day job to host our corporate blog & internal knowledge base, I also use it for my personal website and a few publication projects.
Ghost is very powerful and versatile, it can be especially useful for writers, podcasters and video creators as a second source of income with built in Paid Membership and Newsletter features.
Ghost is Open Source and promotes independent publishing.
Unfortunately self hosting Ghost can be a pain & managed plans are expensive, especially when hosting multiple sites, using Docker & Compose can streamline and automate this process for seamless and maintenance-free updates. Hopefully, this detailed guide should help you get started!
Before you Begin
You will need a Server or VPS running Ubuntu or other Debian based distribution with the following installed:
- nginx
- docker
- docker-compose
I use Digital Ocean for my VPS, they have plans starting at $5 a month which would be more than capable for even a couple of Ghost instaces.
Create Docker Compose file
Create and Change Directory to the new folder that will contain your Docker image data.
mkdir ghostSite && cd ghostSite
Create a file named docker-compose.yml and open it in your text editor. Paste in the contents from the following snippet. Replace example.com with your domain, and use your folder name and location in place of /root/ghostSite.
Setup NGINX
I use the following NGINX configuration for my Ghost instances, remember to replace example.com with your domain, including in SSL and log section. If you're not using SSL while testing comment out that section or remove it.
# example.com redirect block
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# example.com
server {
listen 443;
server_name example.com www.example.com;
root /opt/ghost/system/nginx-root;
access_log /var/log/nginx/example-com-access.log;
error_log /var/log/nginx/example-com-error.log;
ssl on;
ssl_certificate /etc/nginx/ssl/example-com.pem;
ssl_certificate_key /etc/nginx/ssl/example-com.key;
ssl_session_timeout 5m;
ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3001;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
Test Your Site
From your ghost directory in this example ghostSite run the following command, this will download the latest ghost image and run with your settings defined in docker-compose.yml.
docker-compose up
Access it from the domain you've configured, running docker-compose without the -d option will slow debug information when creating and running your new container.
If your ghost intance is created succesfully and loads in the browser you can start it with the -d option which will run Ghost in the background.
docker-compose up -d
Complete Ghost Setup
To complete the setup process, navigate to the Ghost configuration page by appending /ghost
to the end of your blog’s URL or IP. This example uses https://example.com/ghost
.
On the welcome screen, click Create your account:
Enter your email, create a user and password, and enter a blog title:
Invite additional members to your team. If you’d prefer to skip this step, click I’ll do this later, take me to my blog! at the bottom of the page:
Navigate to the Ghost admin area to create your first post, change your site’s theme, or configure additional settings:
Automation and Updates
Automation
The bellow script is what I use to start, stop, restart & update my ghost instances. It's quick and dirty but can be used with Cron to auto-update your sites as well as quick access to manual operations.
- Create script touch /root/ghost-manage.sh You're free to place this script where you like.
- To configure the script change location to where your ghost instances are stored from /, in the example they are in /root/joelduncan-io & /root/renegademedia-uk.
- Change sites to reflect the name of your ghost instance folders.
- If not using a Debian & systemd based system comment or remove lines 43 & 44.
- Set script permissions
Manual Functions
Below is a list of manual functions provided by ghost-manage.sh:
# Start All Containers
./ghost-manage.sh start
# Stop All Containers
./ghost-manage.sh stop
# Restart All Containers
./ghost-manage.sh restart
# Upgrade Ghost Image
./ghost-manage.sh update
# Clean-up Old Docker Images, APT Cache & systemd
./ghost-manage.sh cleanup
Automatic Updates
Run crontab -e and enter the following to update your Ghost version daily.
45 4 * * * /root/ghost-sites.sh update
Maintenance
Regular Docker image updates will build up old versions, to stop these from consuming space on your server also add the following by running crontab -e.
0 0 * * 0 /root/ghost-manage.sh cleanup
Multiple Sites
Docker Compose
Adding a second site is as simple as creating a new folder in the same location as your previous Ghost instance, you will need another docker-compose file modified to match the new location e.g.
/root/ghostSite2/data:/var/lib/ghost/content
You'll also need to change the local port from 3001 to 3002 as shown below.
NGINX
This is much the same story, use the same configuration but update the URL & proxy_pass port to match your new site e.g.
# example.com redirect block
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# example.com
server {
listen 443;
server_name example.com www.example.com;
root /opt/ghost/system/nginx-root;
access_log /var/log/nginx/example-com-access.log;
error_log /var/log/nginx/example-com-error.log;
ssl on;
ssl_certificate /etc/nginx/ssl/example-com.pem;
ssl_certificate_key /etc/nginx/ssl/example-com.key;
ssl_session_timeout 5m;
ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3002;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
Modify ghost-manage.sh
Remember to refer to Automation and Updates when adding other sites as they will need to be added to ghost-manager.sh.
Configuring Email
In your docker-compose file paste the following below url in the environment section, then simply adjust the details to suit.
mail__transport: SMTP
mail__options__service: Gmail
mail__options__host: smtp.gmail.com
mail__options__port: 465
mail__options__secureConnection: 'true'
mail__options__auth__user: youremail@gmail.com
mail__options__auth__pass: yourpassword