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/frontendand runyarn devto build and watch for new changes.cd GHOST_DIRand 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 pretestto build.yarn zipto 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_KEYandGHOST_ADMIN_API_URLrespectively.
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_SUBSCRIBEandLAMBDA_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:UpdateFunctionCodeto theActionsarray 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
Resourcearray of same IAM role.
- Add