The source code for wilburx9.com, which is built on Ghost. The code lives in two directories frontend and backend; the former is a Ghost theme, and the latter contains Go services that manage newsletters.
The custom template which was originally cloned from the Ghost Starter theme . It's written in handlebars, css and a mixture of JQuery and vanilla JS.
Deviating from the usual Ghost themes, I repurposed "/" into a self-aggrandizing landing page. So the blog lives on "/blog" and the listing pages of individual tags are on "/blog/tag_slug". This was implemented using a custom route. Consequently, an empty page was created on Ghost dashboard with the slug "blog" and a custom title and description. See the Ghost doc on this.
Some of my articles live on Kodeco and Medium, and can't be imported to Ghost. However, I added "external articles" that contain nothing but bookmark cards pointing to the original article. These articles have the "#external" private tag. Special provision has been made such so that such articles are not indexed, and clicking the post-cards from any such article on any article listing section opens the original article.
- Clone this repo
- Install Ghost.
- Create a symlink in Ghost's installations theme directory that points to this repo's frontend directory by running
ln -s PROJECT_DIR/frontend GHOST_DIR/content/themes/wilburx9
. cd PROJECT_DIR/frontend
and runyarn dev
to build and watch for new changes.cd GHOST_DIR
and runghost restart
.- Go to installed themes in the design settings of Ghost dashboard and select "wilburx9".
Deployment can be done manually or using the CD workflow.
- Manually
- Clone the repo
cd PROJECT_DIR/frontend
.yarn pretest
to build.yarn zip
to package the theme into a zip file.- Go to Theme settings and upload the generated zip file.
- CD Workflow: The steps for building, deploying and applying the theme are packaged into a CD workflow which runs when there's a push event on the live branch that changed the frontend directory. To take advantage of this:
- Fork the repo
- Create a Ghost custom integration, add Admin API Key and Url to your projects secrets and add these as
GHOST_ADMIN_API_KEY
andGHOST_ADMIN_API_URL
respectively. - Add
GEN_SOURCEMAPS
to GitHub variables withtrue
orfalse
depending on if you want to deploy the theme along with the source maps. - After deployment, the workflow clears the cdn cache to ensure the new theme reflects immediately. And this works on the assumption that your website is deployed on a Lightsail instance behind a Lightsail Distribution. So create a GitHub OIDC provider AWS on aws IAM and ensure the policy has a Resource that points to the ARN of the Lightsail instance's Distribution and has a
lightsail:ResetDistributionCache
in theActions
array. Then, add the ARN of the role and AWS region to GitHub secrets asAWS_ROLE
andAWS_REGION
.
Ghost's newsletter implementation is not very customizable as I wanted readers to choose the kind of newsletter to want to receive. Hence, the backend directory contains two Go Services deployed to AWS Lambda:
- subscribe service receives the email and newsletter preferences from the frontend, validates the captcha and forwards it to MailerLite.
- broadcast when a new article is published, Ghost hits this webhook to broadcast to appropriate subscribers.
Deployment is done by a CD workflow which is triggered when there's a new push event on the live branch that changed the backend directory.
- Secrets: AWS Systems Manager Parameter Store is used to store the secrets used by both services. These secrets are:
WILBURX9_ALLOWED_ORIGINS
: The origins allowed by the Lambdas; should be the site's homepage. Without this, the subscription form will fail because of good old CORS error.WILBURX9_EMAIL_SENDER
: The email for the sender of the newsletter.WILBURX9_MAILER_LITE_TOKEN
: API token for MailerLite.WILBURX9_TURNSTILE_HOSTNAME
: Your website domain configured on Cloudflare Tunrnstile dashboard.WILBURX9_TURNSTILE_SECRET
: Turnstile site's Secret key.
- Create Lambdas
- Create two Lambda Functions on AWS using the Go 1.x runtime and x86_64 architecture. Ensure their roles has a statement that allows reading from
ssm:GetParameter
; this is to ensure the services can read the secrets created above. - Add the function names to GitHub variables using
LAMBDA_FUNCTION_SUBSCRIBE
andLAMBDA_FUNCTION_BROADCAST
.
- Create two Lambda Functions on AWS using the Go 1.x runtime and x86_64 architecture. Ensure their roles has a statement that allows reading from
- IAM Role
- Add
lambda:UpdateFunctionCode
to theActions
array of the IAM role created when deploying the frontend. This is so the CLI pipeline can update Lambda function. - Add the ARNs of the Lambda functions to the
Resource
array of same IAM role.
- Add