How to Host Multiple Ghost Sites with One DigitalOcean Droplet

Photo by chuttersnap on Unsplash


You can absolutely do this tutorial still but you might want to choose a bigger Droplet than the $5 one listed below. I ran into the issue when attempting to upgrade Ghost. I just thought you should know before you get too deep into this tutorial.

Don’t Run Multiple Ghost Instances on a Small Virtual Machine
I found out the β€œhard way” why most people only host one Ghost instance on a DigitalOcean droplet. This is why they are called experiments.

So the first time I set up darrenbeattie.com on DigitalOcean I made some mistakes. It worked but using the DigitalOcean one-click set up for the initial blog made it difficult to add additional domains.

I spent several days trying to make it work and I finally found an article that sort of detailed what I wanted to do. Sadly, the easiest solution was to blow up an existing droplet and create a new one.

The nice thing about $5 droplets is that they give you an inexpensive way to play. Sadly during my web development bootcamp I did not learn a ton about servers and deployment. I can code, but getting it up on a Ubuntu/Nginx server all by myself?

That's new...

I'm going to condense and update that article for you in my own words to give you a little more detail/specifics.

What To Do

I'm going to assume you have purchased your domain(s).

The majority of registrars only have good rates for a year, then the fees climb a ton. I had one domain climb to $50+ a year to keep. Others nickel and dime you until you end up paying triple or quadruple their initial offer.

I recently moved all of my domain names over to Google Domains (GD) for this reason.

As a Canadian it's a $17 CAD flat rate with private registration and it's very easy to use without all the annoying upsells of nearly every other provider (GoDaddy, HostGator, BlueHost, etc...) I've used in the past.

It's a good sign if I'm telling you that and I don't get any referral $$ for sharing that info with you. That's how annoying I've found nearly every other registrar prior to GD.

Step #1 - Sign Up For DigitalOcean

You should have some basic understanding as to how the terminal works on either a mac, linux or a windows machine.

You can sign up here. And if you do, this time I will get a referral bonus of $25 but you'll also get $100 worth of credit for 60 days or two free months if you choose the $5 droplet and I don't see why you wouldn't.

Unless you already have a gigantic audience the $5 droplet will easily handle most of the traffic of a small blog. I spent the extra $1 a month for weekly backups but you don't have to if you don't want to.

At the time of writing the process looked like this:

  1. Pick the Ubuntu 18.04 option for your distribution
  2. Pick 'standard'
  3. Scroll left for the $5 droplet.
  4. Choose your location (I chose Toronto because as I said, I'm Canadian)
  5. I didn't choose any additional options but that's up to you
  6. I set up SSH authentication (mentioned below, DO will walk you through it)
  7. You probably only need the 1 droplet
  8. Choose a hostname
  9. Add any tags you think are relevant
  10. Select the project (you'll need to create one if you haven't already)
  11. I added backups, you don't have to, but it's $1 a month on a $5 droplet
  12. Double check your selections and click create droplet

Yes, I get a kick-back this time, but similar to GD, DigitalOcean (DO) has an upfront no-BS approach to business. It's a simple service without the incessant upsells. We used them when we were running Koachable years ago and they helped us easily scale when we needed to.

You can use AWS or Google Cloud or Azure if you want, they are often free for the first year but then they can get expensive quickly past that. Those services tend to serve medium to larger sized businesses well but not tiny startups. We actually switched from AWS in 2014 to DO for this reason. I'm sure DO is more expensive when your traffic is huge but for now mine isn't.

I think it's wise to set up SSH for your droplet, but that's just me. It's more secure and it's annoying to type in your password every time you want to access your droplet (AKA virtual private server). For more on that...

How to Set Up SSH Keys on Ubuntu 18.04 | DigitalOcean
SSH-key-based authentication provides a more secure alternative to password-based authentication. In this tutorial we’ll learn how to set up SSH key-based authentication on an Ubuntu 18.04 installation.

Although you may still want to use a passphrase from your favourite password manager, so you'll still be entering a password when you first login to your server each time.

Step #2 - Point Your DigitalOcean Nameservers To your Registrar

You'll have to point your DigitalOcean Nameservers to whatever provider you choose and you can read the following for more on that:

How To Point to DigitalOcean Nameservers From Common Domain Registrars | DigitalOcean
DNS is the naming system that is used to bind a domain name to a web server. In this guide, we will change the nameservers for a domain that we have registered and point it to a DigitalOcean Droplet.

Basically you need to add these custom NS's under the DNS settings of the domain you want to use on your registrar's site:

ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com

Once you've done that, from within your project/droplet on DO you'll need to add the domain to DO and set up at least two A records within DO.

How to Add Domains | DigitalOcean Product Documentation
Add a domain to your DigitalOcean account to manage its DNS records from the control panel and API.
  1. thenameofyourwebsite.com
  2. www.thenameofyourwebsite.com

This ensures you'll be redirected appropriately no matter what people put into their web browser.

Step #3 - Initialize Your Server

Here is where I went wrong in my first attempt, at least for creating multiple blogs/sites on a single droplet. DigitalOcean has a 1-Click Ghost App Deploy set up in the marketplace and I just used that.

It works if you only want to create one site on your droplet. I wanted at least two, possibly more as I move some old wordpress sites over to ghost.

My mistake was not doing this myself and setting up users for each site. I used the root user instead, don't do that if you want multiple sites.

In fact, you shouldn't really do that even if you don't want multiple sites on one droplet. You should still set up a user with superuser permissions and use that instead.

The following is only partially correct in what we want but you should still read it. I didn't on my first attempt and regretted it.

Initial Server Setup with Ubuntu 18.04 | DigitalOcean
When you first create a new Ubuntu 18.04 server, there are a few configuration steps that you should take early on as part of the basic setup. This will increase the security and usability of your server and will give you a solid foundation for subsequent...

Don't code along with that guide, I recommend coding along with me below. There are some differences.

Step A: Login to Your Droplet/Server

The '$' in these can be omitted it's just a common way to write out the input of the terminal. Experienced developers will know this, beginners might be confused.

$ ssh root@your_server_ip

Then you're going to get a couple of questions:

Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '<ip_address>' (ECDSA) to the list of known hosts.

You can just type 'y' rather than 'yes' if you want. If you are using SSH with a passphrase you'll be asked for it so make sure you have it handy.

Enter passphrase for key 'C:\Users\<you>/.ssh/id_rsa': <passphrase>

It's probably a best practice for security but it's up to you to implement it or not.

Once complete you'll be logged in to your droplet as what's called 'the root' and ready to get it set up. A mildly entertaining explanation:

Step B: Update The Server

$ apt-get update && apt-get upgrade

This may take a while and you'll get a ton of lines printing off.

Step C: Add a User

This example creates a new user called sammy, but you should replace it with a username that you want to use:

$ adduser sammy

I like to use acronyms for the domains I'm installing and I write the details down in my password manager.

You will be asked a few questions.

Enter a strong password and, optionally, fill in any of the additional information if you would like. This is not required and you can just hit ENTER in any field you wish to skip.

Step D: Make that User a Superuser

To unlock admin privileges for your new user we'll you'll need to do the following:

$ usermod -aG sudo sammy

Now, when logged in as your regular user, you can type sudo before commands to perform actions with superuser privileges. We'll need this, and we'll need to set up new users for additional sites per droplet in the same fashion.

Step E: Login as that User

$ su - sammy

Step F: Install Nginx

Nginx ('engine-X') is a reverse proxy. It's like the middleman between your Ubuntu (Linux) server and the rest of the internet. What makes the server do it's thing based on the requests really. A better back end engineer can probably correct me on that.

$ sudo apt-get install nginx 
[sudo] password for sammy: 

Enter your password and let it run. Then:

$ sudo ufw allow 'Nginx Full'

The second command allows HTTP and HTTPS connections. You should see a much faster confirmation on this command than the previous one. I don't know if that has relevance to any firewall but I've seen it mentioned a few times. In any case, this is what I did and it appears to have worked correctly.

Step G: Install MySQL

Ghost databases use MySQL so this is what we'll need. I'm far more used to postgreSQL and SQLite but they are all more similar than dissimilar so no big deal.

$ sudo apt-get install mysql-server

Once installed if you want to set a password you'll need to log into the MySQL shell which will look a little different in the terminal and we're switching to a structured query language (SQL) now:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

Replace 'password' with your stronger (stored-in-a-password-manager) password, but keep the quotations around your password or it won't work.

You should see the following after you change your password successfully:

Query OK, 0 rows affected (0.00 sec)

Then exit MySQL:

mysql> quit

Step F: Install Node.js

And npm...

Node.js is the server side JavaScript engine that will run your ghost site. As I said in my last post I really like node.

Anyhoo, we're installing the latest stable 10.x version using a curl command.

$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -

Once that's done it will tell you something along the lines of:

## Run `sudo apt-get install -y nodejs` to install Node.js 10.x and npm
## You may also need development tools to build native addons:
     sudo apt-get install gcc g++ make
## To install the Yarn package manager, run:
     curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
     echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
     sudo apt-get update && sudo apt-get install yarn

You'll want to run the first command at a bare minimum:

$ sudo apt-get install -y nodejs

If you want to use the increasingly popular yarn package manager you'll also need to run the yarn related code too. But I'm happy with npm in this context and the rest of my instructions will use npm too.

Anecdotally yarn feels a bit faster, but I don't know how much npm or yarn I'll ever be using on this server so flip a coin Β―\_(ツ)_/Β―

Step #4 - Set Up Ghost

The server is good to go, but you're not done yet if you want a ghost blog for your site.

We're going to use the Ghost-CLI command line tool to get Ghost installed and configured with the following npm package:

$ sudo npm install ghost-cli@latest -g

It's pretty quick. Next you'll want to make a directory (mkdir) for your site:

$ sudo mkdir -p /var/www/<yourblognamehere>

Replace <yourblognamehere> with whatever you want to call this file to keep track of your new ghost blog or website.

Then you want change the owner of this new directory to the user you created earlier:

$ sudo chown sammy:sammy /var/www/<yourblognamehere>

Again, replace sammy with whatever your username is and <yourblognamehere> with the name of your actual directory.

Set the correct permissions:

$ sudo chmod 775 /var/www/<yourblognamehere>

Then you need to navigate into that directory:

$ cd /var/www/<yourblognamehere>

This will change your prompt in the terminal to something like:

sammy@ubuntu-nameofserver:/var/www/<yourblognamehere>

That last bit helps you know that you're in the right directory and it's important that you're in the right directory. I always double check where I am before I run commands. It will save you time later.

From the directory (triple check it even):

$ ghost install

Now you'll get a bunch of command line prompts:

βœ” Checking system Node.js version
βœ” Checking logged in user
βœ” Checking current folder permissions
βœ” Checking operating system compatibility
βœ” Checking for a MySQL installation
βœ” Checking memory availability
βœ” Checking for latest Ghost version
βœ” Setting up install directory
βœ” Downloading and installing Ghost v3.11.0
βœ” Finishing install process

Followed by a bunch of questions:

  • Blog URL β†’ http://<your_domain_address>.com
  • MySQL hostname β†’ <default> hit enter
  • MySQL username β†’ root
  • MySQL password β†’ <your MySQL password>
  • Ghost database name β†’ <default> hit enter
  • Do you wish to set up β€œghost” mysql user? β†’ yes
  • Do you wish to set up Nginx? β†’ yes
  • Do you wish to set up SSL? β†’ yes
  • Enter your email (For SSL Certificate) β†’ <email_address_you_want_to_use>
  • Do you wish to set up Systemd? β†’ yes
  • Do you want to start Ghost? β†’ yes

You'll get some check marks, with some other stuff along the way and hopefully everything goes smoothly for you.

I forgot to change my A server name stuff because I was moving an existing domain from one droplet to a new one. This led to an error on the SSL certificate portion, and it took me too long to figure out where I screwed up. Basically Lets Encrypt timed me out for too many requests and I had to wait an hour to fix that part before my site was live.

Lets Encrypt is a free SSL service that lets you run secure https:// connections. You'll need it if you want to use Stripe via Ghost memberships or any payment processor for that matter. But it's also just a generally good practice these days.

The Ghost-CLI documentation is your friend if you get stuck or have to troubleshoot any errors.

Now apparently if it goes smoothly it will prompt you to visit yourblognamehere.com/ghost but mine didn't. I previously knew I had to do this, so you simply navigate there in your web browser to get the ghost admin set up so you can start writing and playing with your site live.

Choose your theme make your changes and Bob's your uncle. If you only wanted one blog, adios amigo!

If not, keep reading...

Step #5 - Adding Additional Ghost Websites

Here is where things get a little trickier...

You'll need to logout from your current user situation (sammy in the example above) which is ctrl-d or you can simple type:

$ logout

Make sure you're using root so you should see something like:

root@ubuntu-nameofserver:~#

As your command line prompt. Or if you created a site and are just logging back into your server it should also take your right to root.

Step A - Create Another New User

To quickly reiterate:

$ adduser janey

Make that user a super user so that they have admin privileges:

$ usermod -aG sudo janey

Login as that new user:

$ su - janey

Step B - Set Up MySQL for New User

Open mysql this time with a slightly different command:

$ mysql -u root -p

When prompted submit your MySQL password from before (this is why you put these things in a safe place). We're going to use the same MySQL database here essentially but you need a separate user to keep your ghost websites separated.

Now that you're in the MySQL shell we need to create a new user. Again, replace janey with whatever you want to use* as your username and the password with whatever you want to use to secure it:

mysql> CREATE USER 'janey'@'localhost' IDENTIFIED BY 'password';

Remember don't remove the quotes, they are needed in SQL queries and you should get a 'Query OK' response.

*I simply used the same username for MySQL that I did for for my server user to keep things organized but I have a feeling this is not a best practice.

Next make sure you grant this new user the appropriate privileges and assuming you get a good response, you can exit MySQL with ctrl-d or type 'exit':

mysql> GRANT ALL PRIVILEGES ON *.* TO 'user2'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> exit

Step C - Set Up Another New Directory

Similar to before you'll need a new folder for your new ghost install.

$ sudo mkdir -p /var/www/<yoursecondwebsitenamehere>

Make sure change the owner of this new folder to your current user (second one):

$ sudo chown janey:janey /var/www/<yoursecondwebsitenamehere>

And grant yourself the right permissions:

$ sudo chmod 775 /var/www/<yoursecondwebsitenamehere>

Then navigate into that directory:

$ cd /var/www/<yoursecondwebsitenamehere>

Make sure you use your usernames and your site names rather than the ones supplied here.

Step D - Install a New Instance of Ghost

Once here you'll run the same command as before to install ghost but there will be several changes from the first time you did it because you're putting it on the same droplet as the previous one:

janey@ubuntu-nameofserver:/var/www/<secondblogname>$ ghost install

I'm just showing you how the command line should look in that example. The command is simply ghost install because we already npm installed it on the root.

This time after you get all your prompts answer the following questions like so:

  • Blog URL β†’ http://<your_second_domain_address>.com
  • MySQL hostname β†’ <default> hit enter
  • MySQL username β†’ <janey> (*or whatever your second username was)
  • MySQL password β†’ <janey's MySQL password>
  • Ghost database name β†’ <default> hit enter (*it creates a new db name for you)
  • Do you wish to set up β€œghost” mysql user? β†’ No (*It should skip this...)
  • Do you wish to set up Nginx? β†’ yes
  • Do you wish to set up SSL? β†’ No
  • Enter your email (For SSL Certificate) β†’ <email_address_you_want_to_use>
  • Do you wish to set up Systemd? β†’ yes
  • Do you want to start Ghost? β†’ No

Notice the three No's this time? That's really important and you'll see why in a minute. We need to make some changes to this Nginx configuration file before we set up the ssl certificate and start ghost on this site.

Step E - Change Second Site's Nginx Configuration

Navigate into your Nginx configuration (config or conf) directory:

$ cd /etc/nginx/sites-enabled/

Then make sure you stop your Nginx server:

$ sudo service nginx stop

*Note: This command will make the server of your first site unavailable until your restart it again.

Open the Ubuntu nano terminal editor and modify your secondblog file:

$ nano <secondblogname>.com.conf

You can use the 'ls' command to list the conf files in this folder if you forget what you named the file exactly.

Change the <port> number (probably a 4 digit number currently) of the proxy_pass to an unoccupied but valid port number. Β 

You may have to troubleshoot this if you guess wrong, certain ports will be occupied but pretty much any 4 digit combo should in theory work as long as it wasn't the existing one.

...
location / {
        ...
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:<port>;
}
...

*Remember the port number you choose you'll need it again in a minute.

You don't want two sites going to the same place if they are different sites, so you can't skip this step. If you configure this wrong, you'll likely be directed to site number one. Keep that in mind if you have to troubleshoot it after the fact. I'd start here with the port number.

When you hit ctrl-x to exit it will ask if you want to save. Make sure you say 'yes' and then hit enter to confirm the save before you exit.

Step E - Restart your Nginx Server and Set Up the SSL

Start your server again:

$ sudo service nginx start

Then navigate back to the second site directory:

$ cd /var/www/<secondblogname>

From here you'll have to open nano again on the config.production.json:

$ nano config.production.json

And make sure you change your config on the port to match whatever port you created on the second sites port:

...
{
  "url": "http://<secondblogname>.com",
  "server": {
    "port": <newportnumber>,
    "host": "127.0.0.1"
  },
...

Obviously put the port number you chose from before for this new set-up.

Now you can set the ssl with a special command from ghost-cli:

$ ghost setup ssl

Assuming everything goes smoothly you can now start ghost for your second site:

$ ghost start

Now everything should be good to go on yoursecondsitenamehere.com/ghost for you to walk through your admin set up and get that site up and running in a similar manner to the first. It's pretty self-explanatory.

If for some reason you run into a roadblock I encourage you to checkout the incredible ghost documentation.

Finishing Up

Phew...long article...

Alright that's it, I now have two ghost sites (working towards at least one more) up and running on one DigitalOcean droplet. Google analytics confirms that people can google them and other visitors have been this week.

Now I have to figure out how to force https:// without any errors...

Any suggestions?

Darren Beattie

Read more posts by this author.