With this rebuild, I moved away from serving the site directly through Drupal, and shifted to a Jamstack-style approach: building the site in Drupal, generating static HTML files, and serving those publicly.
Jamstack is an architectural approach to building websites that combines three technologies: JavaScript, APIs, and Markup. Unlike traditional systems such as WordPress, it delivers pre-generated static pages via CDN, resulting in high security and extremely fast load times. --- Quoted from Gemini
Strictly speaking, this doesn't match the formal definition of Jamstack, but the approach — using a CMS or other program to generate pages, then serving those as static files via CDN without any database or runtime — is widely recognized as one form of Jamstack, which is why I'm calling it that.
Outside Japan, this is also referred to as "Static Drupal."
" Table of Contents "
- Top --- An Overview of Jamstack.
- #01 Structure --- Summary of the process we followed in migrating to Jamstack.
- #02 Conclude --- Thoughts on Adopting Jamstack.
Clicking the numbers in the simple navigation bar at the bottom of the page will jump to that part of the article. Feel free to use it when re-reading.
Introduction.
The reason I moved toward Jamstack was the end of the Lightsail–Bitnami partnership in May 2026. The blueprint-based service — which offered CMS-packaged Lightsail instances — was to be discontinued, and security updates became my own responsibility.
The existing Lightsail + Bitnami + Drupal package ran PHP 8.2.x and supported only up to Drupal 10.x, with LTS running through December 2026. An upgrade to Drupal 11.x was inevitable at some point, and since Bitnami doesn't support user-managed PHP upgrades, I had been planning to migrate to an EC2 + RDS setup before the end of the year.
Up to this point, the site ran on Drupal hosted on a web server — building and serving everything from that same server.
- Drupal was hosted on web infrastructure — Lightsail + Bitnami + Drupal.
- Both site building and publishing were handled by Drupal running on that same web server.
- This setup requires PHP and a database to serve the site.
Since a migration was unavoidable, I decided not to simply move the existing Drupal setup, but to take the opportunity to pursue the Jamstack approach I'd had in mind from the beginning. The process I followed for this migration is outlined below.
Structure
Here I've put together a brief overview of how the Jamstack setup is structured. The actual configuration steps and how-to details would make this article too long, so I plan to cover those in separate posts.
Mac Book Pro
The site-building work that previously ran on the web now happens entirely on my local Mac Book Pro.
1. Set up an environment using OrbStack + DDEV + Drupal + Tome that lets me handle the entire site build on my MacBook.
2. Using Tome — a Drupal module — to convert the site's page structure into static HTML.
3. The advantage of serving HTML-converted pages is that neither PHP nor a database is needed to publish the site.
4. This makes it possible to serve the site from storage-only solutions like AWS S3, with no server runtime required.
Running Drupal locally also reduces the overhead of managing security patches and dependency conflicts that come with updates.
AWS
The actual site is served through AWS Lightsail and CloudFront.
1. The website files are hosted on Lightsail. The difference from before is that Lightsail now runs only Apache and SSH (including sFTP) — no programs of any kind are involved in serving the site. Lightsail is being used essentially as storage with Apache.
2. In the previous Lightsail + Bitnami + Drupal setup, DNS was handled within Lightsail. This time I moved DNS to Route 53. The reason: Lightsail's default configuration only gives access to its simplified CDN — a limited version of CloudFront.
Using the full feature set of CloudFront requires some non-standard configuration. I chose Route 53 to make that configuration possible. This also improves future scalability and simplifies ongoing work.
3. SSL for CloudFront is handled through AWS Certificate Manager (ACM), and the certificate must be issued in the us-east-1 region.
4. I'm now using CloudFront as a CDN, which wasn't part of the previous Drupal-based setup. AWS WAF, which comes packaged with CloudFront, is also enabled. Together, these have improved both page load speed and security.
5. Assigning CloudFront to Lightsail isn't possible with the default setup, so some additional configuration was needed.
6. Lightsail is configured to accept traffic only from CloudFront. This is enforced at the Lightsail firewall level. Since the number of IP ranges involved is large, I handled the configuration with a script.
7. This access restriction achieves security similar to S3's internal routing advantage — direct external access to the origin is blocked.
Static files built locally are placed on Lightsail — used as storage — and served through CloudFront, which packages CDN and WAF together. This approach achieves a setup that closely follows the Jamstack model.
Cloudflare — which bundles CDN and WAF — would be a simpler setup and is the more common approach, but keeping everything within AWS has clear advantages, which is why I chose CloudFront over Cloudflare.
This kind of Jamstack approach is also called serverless, and the standard choice is S3 + CloudFront — which AWS itself recommends. My reason for choosing Lightsail + CloudFront instead comes down to simplifying the deployment process.
With S3 + CloudFront, uploading files requires either the AWS CLI or Git. (Automation is possible, but the workflow is fundamentally command-line.) S3 doesn't support GUI-based methods like sFTP by default. (Some sFTP apps with S3 bucket support do make this possible.)
Lightsail + CloudFront is different — Lightsail has server capabilities, used here in a limited way. Opening SSH also enables sFTP. The advantage of sFTP is that file uploads are GUI-based.
Taking what would otherwise be a command-line deployment task and reducing it to a GUI copy-paste operation is a significant simplification, and that's exactly what this setup achieves.
S3 doesn't have Apache's routing capabilities by default, which means a path like learn/ would be exposed as learn/index.html. Having a Drupal-generated URL display that way felt off, which is another reason I went with Apache on Lightsail. (Routing can be configured in S3 as well.)
By choosing Lightsail and running only Apache and SSH, I arrived at what I think of as "S3 with Apache and SSH." Restricting access to CloudFront IPs only — similar to S3's internal routing advantage — combined with key-based authentication and IP-restricted SSH, and serving only static files through CloudFront with AWS WAF, the overall security is meaningfully higher than what I had before.
Security
All external access goes through CloudFront. The origin — Lightsail — is IP-restricted to CloudFront addresses only. This achieves security comparable to S3's internal routing, where the origin isn't directly reachable from outside.
SSH and sFTP use private key authentication only. Combined with IP restrictions, this means connections from anything other than my MacBook Pro are blocked. If port scanning becomes a concern, adding sshd to fail2ban can tighten security further.
Usability
The setup avoids the typical Jamstack workflow of using the AWS CLI or Git for publishing (cache clearing included), and instead enables publishing through sFTP's GUI.
Removing Git simplifies the process from MacBook → GitHub → AWS down to MacBook → AWS — one fewer platform to manage.
A setup where updating the site means copying Tome's HTML output into a GUI client is simple and reliable. This is a personal blog — small in scale, infrequent in updates — so a minimal-tooling configuration like this is exactly right.
Back to Basics
This is the same approach as 1990s homepages — build a site on a personal computer, then upload the pages to your ISP's web space via something like FFFTP.
'1999: Homepage Builder' --- '2026: OrbStack - DDEV - Drupal - Tome'
'1999: FFFTP' --- '2026: Transmit'
'1999: ISP web space (iij4u, so-net, etc.)' --- '2026: AWS - Lightsail - CloudFront'
After a long and winding road, the approach from thirty years ago turns out to be the right one.
Conclude
This article covers the move from Drupal-based publishing to a Jamstack setup — including the migration — at a fairly high level. Since the build and publishing system has changed significantly, I'm treating this as an introductory post, which is why it moves quickly. I hope to write more detailed, configuration-focused articles going forward.
Alongside the Jamstack migration, I also revised the page design and reworked the English translations. Doing all of that by hand was the bulk of the work — the actual AWS configuration and cutover, including verification and the switch, was done in a few hours.
This Jamstack project was done with the help of Claude. It's an agentic AI well-suited to automation, but I used it differently here — working through the entire process with Claude from the planning stage: migration plan, translation and proofreading, and the actual cutover. That ongoing collaboration is what allowed us to land on a plan suited to this site's scale and character, and why the migration itself went smoothly.
The way I worked with Claude on this project goes beyond what's usually described as an AI assistant — it was closer to AI consulting.
I'd like to write about how I used Claude in this project when the opportunity comes.
What made Jamstack possible was Tome — a Drupal module that handles static HTML generation. I'd like to cover Tome in detail in the next article.