Required Environment

  • CentOS 7.x
  • Docker
  • Ghost
  • MySQL 5.7

Installing Docker

sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce -y
sudo systemctl start docker
docker network create ghost --subnet 10.0.0.0/24

You can replace ‘ghost’ with your own custom network name.

Creating Directories for Blog Data

mkdir -p \
/var/local/blog \
/var/local/nginx \
/var/local/mysql \
/var/local/web/sites \
/var/local/web/logs
  • /var/local/blog for storing blog images and other media data;
  • /var/local/nginx for saving nginx configuration files;
  • /var/local/mysql for storing database files;
  • /var/local/web/sites for deploying other websites in nginx if needed in the future;
  • /var/local/web/logs for storing logs.

Database

docker run --name mysql \
-h mysql \
-v /var/local/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=Ghost@2019 \
--net ghost \
--ip 10.0.0.2 \
--network-alias mysql \
-d mysql:5.7

Running a Ghost Service Container

docker run --name george \
-h george \
--net ghost \
--ip 10.0.0.3 \
--network-alias george \
-e database__client=mysql \
-e database__connection__host=mysql \
-e database__connection__user=root \
-e database__connection__password=George@1994 \
-e database__connection__database=george \
-e url=https://george.betterde.com \
-v /var/local/blog/george:/var/lib/ghost/content \
-d ghost:latest

Fill in the url with your own website domain name.

Running an Nginx Container

Nginx is used to proxy client requests to the specified port of Ghost. Before starting, first generate default configuration files using the Nginx image.

docker run --name nginx \
-v /var/local/nginx:/var/nginx \
--rm nginx sh -c 'cp -Rf /etc/nginx/* /var/nginx' \
nginx:latest

After completion, the container will be automatically deleted. If all goes well, the /var/local/nginx directory should now have nginx’s default configuration files. Next, run the nginx container.

docker run \
-p 80:80 \
-p 443:443 \
--name nginx \
-h nginx \
--net betterde \
--ip 10.0.0.4 \
--network-alias nginx \
-v /var/local/web/sites:/web/sites \
-v /var/local/nginx:/etc/nginx \
-v /var/local/web/logs:/web/logs \
-d nginx:latest

At this point, accessing your domain or host IP should show the nginx welcome page.

mv /var/local/nginx/conf.d/default.conf yourdomain.conf
vim yourdomain.conf
server {
    listen 80;
    server_name yourdomain;
    location / {
        proxy_pass http://george:2368/; #Fill in the hostname you specified when running the Ghost image, the default port is 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;

        # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
        proxy_set_header X-Forwarded-Proto $scheme;
        
        proxy_buffering off;
        proxy_request_buffering off;
    }
}
server {
    listen 80;
    server_name yourdomain.com;
    return 308 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_tokens off;
    server_name yourdomain.com;
    ssl_certificate /etc/nginx/cert/fullchain.cer;
    ssl_certificate_key /etc/nginx/cert/betterde.com.key;

    # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # disable any limits to avoid HTTP 413 for large image uploads
    client_max_body_size 0;

    # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
    chunked_transfer_encoding on;

    location / {
        proxy_pass http://george:2368/; #Fill in the hostname you specified when running the Ghost image, the default port is 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;

        # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
        proxy_set_header X-Forwarded-Proto $scheme;
        
        proxy_buffering off;
        proxy_request_buffering off;
    }
}

For how to obtain an HTTPS certificate, please see my other article: “Apply for a Wildcard Certificate for Your Domain”

Copy the obtained certificate to the /var/local/nginx/cert directory, and change the corresponding file name to your own certificate name!

docker restart nginx

After restarting the Nginx container, try accessing your domain such as https://yourdomain.com/ghost or http://yourdomain.com/ghost. If all goes well, you should see Ghost’s initialization admin panel.

I hope this is helpful, Happy hacking…