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…