Introduction

ℹ️
I am not affiliated with any of the services mentioned in this post.

With more people questioning big tech's role and impact on their lives, now is as good a time as any to reduce our reliance on traditional, force-for-evil social media and carve out our own little corners of the web.

If you want to own your data and build up an audience, Ghost is a solid option, combining blogging and newsletter delivery into one free, open source package.

Following is a comprehensive guide on getting set up with Ghost using the cheap and simple PikaPods service, written for the layperson in hopes to promote the indie web.

As for how I came about writing such a guide: I wanted to follow my own advice to reduce complexity, and in doing so, decided to moved this site over from Eleventy to Ghost.

This may seem like a step backwards — Eleventy is a very simple static site generator, whereas Ghost runs on a node server and requires a database — but the complexity that bothered me was not in how the site runs, but in how much I need to maintain myself. Now, with the new setup, there's virtually no maintenance.

What Is Ghost?

Ghost is a modern, open source writing platform for anyone who has an interest in writing — including those sending newsletters. Along with individual open source contributors, it's built by the Ghost NPO, meaning it's about as free from corporate-sponsored drama as can be (looking at you, WordPress).

But I'm not here to sell you on Ghost — just to help you set it up.

Most Don't Host Ghost

Having decided to use Ghost, you've got two major ways to go: either sign up for an account at ghost.org or host it yourself.

Using ghost.org is, without a doubt, the easiest way to run a Ghost site. You'll get a bulletproof platform that you don't have to think about: just pay your fees and the team will take care of everything for you. And you'll be supporting Ghost directly, which is a big plus. I'd thoroughly recommend going this way for most users.

If you host it yourself, you might get away with paying less, but you'll have to maintain the installation with updates, ensure your backups are solid, manage your SSL certificate, and the list goes on. Even if you're comfortable with all of this, are you comfortable with the extra time you'll spend on it?

A typical SaaS vs DIY conundrum, then. You need to weigh the pros and cons yourself, which will very likely depend on the size of your audience and the feature set you need.

But there are middle-ground options, as well: Ghost is open source, so you can just as well use an alternative host that handles the mundane parts.

Enter: PikaPods.

PikaPods is a service by Peakford, of BorgBase fame. They make it cheap and easy to run your own, managed instance of various different open source applications — including Ghost. They take care of all the infra, including updates, backups, and SSL.

⚠️
This approach may not scale. If you expect heavy traffic, look at ghost.org or consider hosting everything yourself, depending on what fits your needs and budget. If that's a "later" problem, don't worry: you can take all your data with you as you migrate away from PikaPods.

Spinning up a new instance of Ghost on PikaPods is just a matter of selecting some basic instance parameters (CPU cores, memory, storage) and giving it a name. You'll then see a projected monthly cost of a couple of bucks.

But for a batteries-included, production-ready install, there are additional steps that aren't necessarily trivial. That's why I've written this guide. Don't worry, though: there's nothing to maintain; this is a one-time setup.

So roll up your sleeves, we're about to get our hands dirty!

The Guide

This guide is designed to be easy enough for anyone comfortable with the idea of publishing their writing on the web to follow. That is, no prior experience is necessary. Some parts may push you out of your comfort zone, and it may take some time to get through, so take a deep breath, set aside a few of hours, and assure yourself that you can do this.

We'll need to sign up for a few accounts for this process, which I recommend doing right at the start:

  • A PikaPods account — the host/platform we'll be using.
  • An AWS account — for transactional email and backups.
  • A Mailgun account — only if you want to send newsletters.

Notes on AWS

AWS is notoriously complex, and if you're not used to working with it, deserves a couple of notes before you begin.

Sign In as Root User

For reasons I won't detail here, you'll need to sign in with an AWS root user account unless you've explicitly made changes to users. Look for the Sign in as root user button on the sign in page.

First Sign In

After signing in for the first time, you may be prompted with additional one-time steps, like attaching a security token. If you want to skip that and are given the option, feel free to do so.

Choosing a Region

AWS operates in many different regions. Some services are considered "global" and others get deployed to specific regions. Deploying to regions that are closer to your readers typically means a faster experience for them, so keep this in mind when choosing a region. At the time of writing, you can find a full list of available regions at awsregion.info.

After signing in, can select a preferred region at the top-right of the page.

Get You a Domain Name

If you already have a domain name, great! Skip this step.

If you don't have a domain name, you need to register one at a domain registrar — a place you can buy domains. There are plenty registrars to choose from, and most people have their preferences (I tend to prefer Porkbun).

It's usually a straightforward process: enter the domain name you want, and if it's available, proceed to buy.

AWS SES

Let's get the worst out of the way first.

We are going to set up AWS SES, or "Amazon Simple Email Service," which is what Ghost will use to send its primary e-mails. These emails can be anything from sign-up confirmations to password reset requests, so they're important to the functioning of your site.

Head over to AWS and sign in.

ℹ️
Be sure to choose "Sign in using root user email" and select "Root user" on the following page.

At first sign in, you might be prompted for additional details. Either follow the instructions or skip for now.

The easiest way to get around in AWS is to use the Search bar at the top. Simply enter SES, and you will see an option for Amazon Simple Email Service. Go there.

Screenshot of the AWS search interace, in which "SES" is typed", revealing the "Amazon Simple Email Service".
Finding SES.

Get Started Wizard

Click Get Started and you'll start the SES setup process. This may look a little different for you as things change over time, but the instructions below should be adaptable.

Prompted to verify your email address, enter your regular e-mail address — not one that that is especially tied to my new Ghost setup. This is for verification purposes.

Next, enter a sending domain. Enter your full domain — if it's domain.com then enter domain.com.

For a Mail From domain, enter m, which expands to m.domain.com.

Leave everything else at the defaults and continue through the wizard. Once that's done, you should be booted to a dashboard with a bunch of open tasks.

DNS Records

One of the open tasks is Verify sending domain. Under this, you'll see Get DNS records. This provides a list of DNS records that you need to add via your domain registrar — the place you registered your domain.

Head over to your domain registrar in a new tab. Most registrars will provide some control panel in which DNS records can be modified. Then, referring to the AWS tab with the DNS record information, add each record, taking care to enter the type, name, and value correctly.

Skip the MX record for now.

With that done, head back to AWS and you should see that Verify sending domain is now under Completed tasks. If not, give it some time and refresh; it can theoretically take hours but generally completes in a couple of minutes.

At this point, it would also be a good idea to follow the instructions to send a test mail. I leave that to you.

Production access

To prevent abuse, AWS requires that you request production access to use SES outside of a sandbox environment. You should see a button on the dashboard named Request production access. Click that and you will see a form.

Be sure to select Transactional under mail type, and fill in the rest of the details as requested.

Amazon claims that this process can take up to 24 hours, but you can continue with the other steps in the meantime. In my case, Amazon responded requesting more details, to which I said I'd just be using transactional emails with Ghost, and approval came pretty quickly after that.

Credentials

Finally, we need to get SES credentials for use later on.

Head over to the SES dashboard and click SMTP settings. While you're here, make a note of the SMTP endpoint for later.

Now press Create SMTP credentials. This opens a form, and the defaults are perfectly fine so go ahead and click Create user.

Now you are presented with credentials. We will need the SMTP user name and SMTP password later, so either make a temporary note or store them in a password manager.

Backups with S3

PikaPods provides database backups and a full snapshot of your Ghost data on a daily basis, but we need to tell it where to store these backups. That's what we're going to use S3 for.

Back on AWS, search for and select S3. Click Create bucket and give your "bucket" a name. Since this is just a place for storing your backups, you could call it something like yourdomain-backups. Leave everything else at the default values and continue.

⚠️
Do not include a dot (.) in your bucket name. At the time of writing, PikaPods has a bug in which it fails to accept bucket names containing dots.

Now that you've made the bucket, click on it for more details, followed by Properties. Copy down the bucket's name, ARN (it will look something like arn:aws:s3:::yourdomain-backups), and region (e.g. eu-central-1) for later. Now leave everything else at the default values and continue.

Newsletters via Mailgun

Mailgun is only required if you intend to send newsletters; if not, skip this step.

Wondering why you need both Mailgun and SES? Postmark has a good (albeit biased) write-up. Technically, you could use Mailgun exclusively and forego SES, but it's not as price-efficient.

Anyway, let's get into it.

💡
If you decide on an EU server when setting up Mailgun, you might find that the site is a little janky. If something goes wrong, make sure you haven't been kicked to the US version like I was.

Sign into Mailgun and you should land on the Get started guide. From here, select Set up a custom domain. Enter m.domain.com, replacing domain.com with your domain name. This will provide you with another list of DNS records that you need to add to your registrar, just the same as you did before with SES.

Hit enable DMARC to reveal an additional record, too.

Now head over to your DNS registrar and get those records added!

⚠️
MX records start with a numeric priority, like 10. If your registrar provides a field for priority, enter the number there and don't include it in the value.

Once you're done, hit Verify in Mailgun. If verification fails, double-check your DNS records or try again later; it can take some time.

Conjure Up a Ghost

Time for the more interesting stuff: setting up Ghost!

Head over to PikaPods and click Add Pod. Choose Ghost, give the pod a name — this is for your own records, so enter what you like — and select a region.

Now select the Resources tab and change as needed. If you're not sure what sort of power you need, I recommend starting with 0.5 CPU cores, 1GB Memory, and 5GB Storage — that's what I'm running this site on right now, and I'll report back if I ever become famous and it causes problems (don't expect an update).

☺️
Don't worry, you can always scale the server later, as needed! It'll just go down for a few seconds.

Finally, the ENV Vars section is how we hook Ghost up to SES. Enter these, following the patterns below:

  • mail__transport: SMTP
  • mail__from: Your Name <you@yourdomain.com>
  • mail__options__service: SES
  • mail__options__host: The SMTP endpoint you wrote down earlier
  • mail__options__port: 465
  • mail__options__secureConnection: true
  • mail__options__auth__user: The SMTP user name you wrote down earlier
  • mail__options__auth__pass: The SMTP password you wrote down earlier

That's it. You're ready to run Ghost!

Click Add Pod and, following a quick startup process, you'll see a warning with a link to your new Ghost instance's admin panel!

A screenshot of the described warning, providing a link to <the-subdomain>.pikapod.net/ghost.

Visit that link and you'll be able to set up your new account.

Ghost is now ready!

Point Your Domain At It

You likely don't want to access your new Ghost site via the .pikapod.net domain.

Head back to your domain registrar and add a new DNS record. This will be a CNAME pointing to your-full-pikapods-domain.pikapod.net. If creating a CNAME fails, try to create an ALIAS instead — just go with it, the reasons are beyond the scope of this guide.

Back to the Pikapods dashboard. Find your pod, then click the settings cog and Domain on the left. Check Enable Custom Domain and enter your domain name. Click Save and you should be good to go. It might require you wait a few minutes between setting your DNS record and clicking Save, though.

Go ahead and try to access your domain — hopefully, you'll be looking at the front page of the Ghost instance, and if not, give it some time.

About Those Backups...

Right, yes, by default you're not going to get any backups. Bad idea. Let's sort that out right away!

We're going back to AWS for this, where we need to create a user in order to generate the credentials we need.

Setup

Go to AWS and jump to IAM using the search. Select Users and click Create user. Pick a reasonable name — since this "user" is there for backing up our Ghost instance, I named it "Pikapods-Ghost-Backup". Hit Next.

Now select Attach policies directly and click Create policy. A policy is a list of permissions that can be attached to a user, which will allow that user to do things. In our case, we want to lock the user down so that all it can do is interact with the single S3 bucket you made earlier.

You could create a policy by using the interface, or you could just click on JSON and replace the code with that below, swapping YOUR-ARN-HERE for your S3 bucket's ARN from earlier.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::YOUR-ARN-HERE",
        "arn:aws:s3:::YOUR-ARN-HERE/*"
      ]
    }
  ]
}

Click Next, name the policy PikapodsGhostBackupBucketAccess, and click Create policy.

Back to the browser tab you were creating a user in: hit the refresh button (it's a circular arrow at the time of writing) and search for Pika. You should see your policy there. Check the box next to it and click Next, followed by Create user.

Finally, we can get at the access keys we need.

Click on the user you just created, and Create access key. Select Other and click Next. For a description, write something like Pikapods Ghost Backups and click Create access key. Copy down the key and secret.

Back to PikaPods!

Find your pod in the PikaPods interface click the settings cog, and Backups on the left. You should have all the values you need to fill in the fields. Most are straightforward, except the endpoint; this follows this pattern: s3.YOUR-REGION.amazonaws.com. Finish filling in the form and click Apply. You're done!

Testing

Under your Ghost pod, click More and Backup to trigger a manual backup. This should complete in a few seconds. Refresh the page and you should see, under Backups, that the date was set to today. Congratulations, backups are working!

A screenshot of PikaPods, showing Backups: Manual (2025-04-04).

If you really want to make sure all is well, you can go back to AWS and look at the bucket in S3: you should see a bunch of files in there. I recommend having a read of the PikaPods documentation on how to use these files with restic to make sure that you're prepared should something bad happen.

Automated Backups

You can use the method above to make a manual backup, but really you want backups to be fired off automatically so you don't have to think about them. Fortunately, PikaPods makes that easy too.

Head back to your pod's settings and go to Backups. Simply enable the Enable daily automated backups switch. Hit apply and you're done.

You may also want to enable pruning, especially if your site grows large or you embed a lot of images. This could drive up S3 costs, though for most sites it'll remain a few pennies.

💸
If your S3 costs are high enough to warrant attention, consider using another S3-compatible service like Backblaze B2.

And The Newsletters?

This step is optional — skip it if you don't intend to send newsletters. But if you do, you'll already have sorted yourself out a Mailgun account earlier in the guide. Now you just need to plug it into Ghost.

Head to the Ghost admin page — this is at <your-domain>/ghost and sign in if needed. Click on the little cog icon at the bottom-left, which will take you to Settings. Now scroll down until you find Mailgun settings.

A screenshot of the Mailgun settings as they appear in Ghost, with fields for region, domain, and API key.

Select the region you signed up to, along with the domain you selected earlier — m.domain.com, where domain.com is your custom domain, if you're following along. Then follow the link to get a new API key. Hit Create API Key inside Mailgun, give it a descriptive name for your own records, like "Ghost", and copy the generated key.

Back over to Ghost, pop that API key into the settings, click Save and you're done!

Conclusion

Whew, that was quite a bit of work, but nothing you can't handle with a couple of hot drinks and some spare time. The beauty of this approach is that it's set and forget — no regular updates to manage yourself, thanks to PikaPods handling them for you. So, in theory, it's smooth sailing now!

Let me know if you found this helpful, ran into issues, or already use PikaPods!

Further Reading