Hosting Ghost on PikaPods + Cloudflare
When I rebuilt my website, I wanted to use something simple that allowed me to easily publish my thoughts without a lot of technical work. Sure, I could have built it myself, but that's time I didn't want to spend.
Fortunately, I found Ghost. To get started quickly, I used Ghost's own paid hosting service. Honestly, it's great, but at $31 a month it always felt a bit pricey. Since Ghost is open source, I looked for ways to host it myself that didn't add a bunch of overhead I was trying to avoid.
Turns out there are some great alternatives, such as Magic Pages, that are dedicated for Ghost. However, to save cost, I wound up going with PikaPods. They have a bunch of open source apps that you can spin up with a click, including Ghost. All of this for around $2 a month? Perfect.
Here's how I set everything up, using Cloudflare for my DNS provider.
Setting up PikaPods
Add a new pod, selecting Ghost as your app. Name the pod whatever you'd like.
Ghost requires some minimum resources in terms of CPU and memory, so make sure you set those appropriately. My site is basic, so I'm using half of a CPU core, 1 GB of RAM, and 10 GB of storage.
Once everything is set up, you will be assigned a random pod domain name, such as example.pikapod.net
. You can rename that if you'd like, but make sure to jot it down as you'll need it in the next step.
Setting up Cloudflare DNS
I've heard over the years that hosting your website at the www
subdomain is useful for search engines, so that's what I usually do. I also wanted anyone who visited timcheadle.com
to be redirected to www.timcheadle.com
In order to make this work, I had to set Cloudflare DNS up in a very specific way.
In the DNS interface for your domain in Cloudflare, we need to add a CNAME
record for our root domain. Note that it's important that proxy is enabled for this domain, as we need Cloudflare to be able to redirect it (in a later step).
Type: CNAME
Name: @
Target: www.timcheadle.com
Proxy status: Proxied
TTL: Auto
We also need to add a CNAME
record for the www
subdomain. It's important that proxying is disabled for the subdomain, as it will break SSL certificates with PikaPods.
Type: CNAME
Name: www
Target: example.pikapod.net
Proxy status: DNS Only
TTL: Auto
When you're all done, it should look something like this:
Add custom domain to PikaPods
Once those records are in place, you need to set up a custom domain with your pod. Fortunately it's dead simple. Click the gear icon in your pod admin, go to Domain, and add your full domain name, such as www.timcheadle.com
Redirecting the root domain to www
The last step is making sure any traffic that goes to your your root domain is redirected to the www
subdomain. Cloudflare has a super extensive rules engine that can be intimidating, but fortunately our example is pretty simple.
In Cloudflare's navigation, go to Rules, then Redirect Rules. Create a new rule, give it a description such as "Redirect to www". You want a "Custom filter expression" that matches the hostname and redirects, like this:
If:
Hostname equals timcheadle.com
Then:
URL redirect
Type: Dynamic
Expression: concat("https://www.timcheadle.com", http.request.uri.path)
Status code: 301
Preserve query string: true
The "dynamic" redirect will make sure any path names stay in tact, so someone that visits timcheadle.com/about/
will be redirected to www.timcheadle.com/about/
It should look like this when you're done:
Click save, wait a few minutes, then everything should be working!
Testing with curl
Just to ensure things are sorted, I like to use curl
to make sure the URLs are responding with what we expect. Open a terminal window and check the headers.
For the root domain, we should get an HTTP 301
code with the redirect:
➜ curl -I https://timcheadle.com/
HTTP/2 301
date: Wed, 07 Aug 2024 16:02:14 GMT
content-type: text/html
content-length: 167
location: https://www.timcheadle.com/
cache-control: max-age=3600
expires: Wed, 07 Aug 2024 17:02:14 GMT
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=z0oRn4Utoqih5VMsbTf0iYLnbuDXNnxtvihruTNDXT7Si0GFtgCqRfiI182U5S5mbCbpteScguzKiTGtLZjpw9zjM4%2FR8VJUOG9gEmjJKsMJ6BPpsuhoPMtN0jR7%2Bi%2BOIQ%3D%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 8af87d68e8b2bd3a-ATL
For the www
subdomain, we should get an HTTP 200
with the page itself:
➜ curl -I https://www.timcheadle.com/
HTTP/2 200
alt-svc: h3=":443"; ma=2592000
cache-control: public, max-age=0
content-type: text/html; charset=utf-8
date: Wed, 07 Aug 2024 16:14:42 GMT
etag: W/"17873-Mt340fW+6Mk06cdXFfZcmdIEj44"
server: Caddy
strict-transport-security: max-age=31536000;
vary: Accept-Encoding
x-powered-by: Express
content-length: 96371
Hope this helps! Please contact me if you have any questions.