Set Up Multilingual Ghost.org Blog

In this post I’ll try to explain my method for setup multilingual Ghost.org blog.

Motivation

I was looking for a blogging framework for long time to start my own blog. (Yes, this is it.) Beside Ghost.org I consider Wordpress, blogger, medium or jekyll. But I have some base rules to choose. Easy to set up, minimal and clean design, fast responding structure, self-hosting option and support for multi language. After giving some thought about this, I was nearly deciding for ghost.org but there was a minor problem. Ghost doesn’t support multilingual structure in single domain.

After some research I thought a way to make it can be doable. And here is how.

What Did I Use

As a server I use Digital Ocean standard droplet. (5$/mo, the cheapest one). And here is $10 gift from me. That may cover you for two whole month. Click here to get $10.

I use PuTTY for SSH client.

FileZilla for FTP Client if I need it. (I did need it)

That’s all.

Ghost Set Up Guide

You can use for Ghost.org install guide for this. It is more than enough.

But first read this post to see which parts of this guide you need change for multi language structure.

Let’s Begin

I set up Ubuntu 16.04 version on my droplet. I use PuTTYGen to generate SSH key. It comes with PuTTY installation. You can and need to use this key to connect SSH and/or FTP (SFTP).

Then you can connect to server with SSH and follow Ghost.org install guide until you see “Install Ghost via the CLI” heading.

After that heading you should follow this post: (Please check Ghost.org guide on the side)

Create new folders for all languages

sudo mkdir -p /var/www/html/en sudo mkdir -p /var/www/html/tr

Your user must own these directories

sudo chown [user]:[user] /var/www/html/en sudo chown [user]:[user] /var/www/html/tr

Your installation folders must have the correct permissions

sudo chmod 775 /var/www/html/en sudo chmod 775 /var/www/html/tr

Navigate to the new folders and install ghost

cd /var/www/html/en ghost installcd /var/www/html/tr ghost install
  • This will install and start your blog in production mode using MySQL as the default database
  • For MySQL use root user and it’s password with all installations.
  • If you want to install Ghost with Sqlite3, please read how here
  • Checkout Prompts heading, which explains all the questions you’ll be asked during install.
  • Use different database names with root user. Example: en_prod, tr_prod.

Prompts

Here I give example answers for prompts that you will see in installation process. You can also checkout Ghost.org’s detailed prompts guide for some detailed explanation.

Enter your blog URL: https://irensaltali.com/en 
Enter your MySQL hostname: (localhost) localhost
Enter your MySQL username: root
Enter your MySQL password: [input is hidden] **********
Enter your Ghost database name: (en_prod) ghost_en_prod
Do you wish to set up "ghost" mysql user? (Y/n) Y
Do you wish to set up Nginx? (Y/n) Y
Do you wish to set up SSL? (Y/n) Y
Do you wish to set up Systemd? (Y/n) Y
Do you want to start Ghost? (Y/n) n

On second language setup, it may show an error about nginx configuration or SSL. Don’t worry about it we’ll set it manually anyway.

As a second language I use my native language Turkish of course.

Enter your blog URL: https://irensaltali.com/tr 
Enter your MySQL hostname: (localhost) localhost
Enter your MySQL username: root
Enter your MySQL password: [input is hidden] **********
Enter your Ghost database name: (tr_prod) ghost_tr_prod
Do you wish to set up "ghost" mysql user? (Y/n) n
Do you wish to set up Nginx? (Y/n) n
Do you wish to set up SSL? (Y/n) Y
Do you wish to set up Systemd? (Y/n) Y
Do you want to start Ghost? (Y/n) n

Nginx Configuration

With these settings both ghost blogs should be successfully set up. Now we need to configure nginx to reach both blog via https.

cd /etc/ngnix/site-available 
rm -rf *
cd /etc/ngnix/site-enabled
rm -rf *

After all files are deleted in these two directories we need set new configuration. As configuration file I used first blog’s files and modified them to be compatible with both blogs and root directory.

cd /var/www/html/en/system/files vi irensaltali.com.conf

irensaltali.com.conf:

server {
listen 80;
listen [::]:80;
server_name irensaltali.com;
root /var/www/html;
location ^~ /en {
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:2368;
alias /var/www/html/en/system/nginx-root;
proxy_redirect off;
}
location ^~ /tr {
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:2369;
alias /var/www/html/tr/system/nginx-root;
proxy_redirect off;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}

irensaltali.com-ssl.conf:

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name irensaltali.com;
root /var/www/html;
ssl_certificate /etc/letsencrypt/irensaltali.com/fullchain.cer;
ssl_certificate_key /etc/letsencrypt/irensaltali.com/irensaltali.com.key;
include /etc/nginx/snippets/ssl-params.conf;
location ^~ /en {
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:2368;
alias /var/www/html/en/system/nginx-root;
proxy_redirect off;
}
location ^~ /tr {
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:2369;
alias /var/www/html/tr/system/nginx-root;
proxy_redirect off;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}

Explanation of configuration

Actually there only three lines of change from original configuration that ghost script would do.

First:

alias /var/www/html/en/system/nginx-root;

Second:

alias /var/www/html/en/system/nginx-root;

Third:

root /var/www/html;

First two is for showing nginx-root’s of blogs to nginx. Third one is to define how meet domain root address access. As you noticed we set our blogs to ‘irensaltali.com/en’ and ‘irensaltali.com/tr’. But what about only ‘irensaltali.com’?

As we set above Nginx will redirect root domain calls to ‘/var/www/html’. For me I didn’t want to set up another website or anything. I needed to redirect visitors to either ‘irensaltali.com/en’ or ‘irensaltali.com/tr’. So decided to redirect visitors according to their geolocation. So I wrote another post to describe how to redirect visitors. Here it is Visitor (User) Routing by Geolocation. Even without redirecting your users both blogs are accessible by typing direct addresses.

Note: These two blogs are not synced or connected. These are completely different websites in single server.

After set up two blogs you also need to configure translation for standard texts in theme of ghost for non-English blog. There is coming another post and repository to help you with this. Keep in touch.

I hope this post has helped you.

Originally published at irensaltali.com on February 9, 2018.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store