A site you built yourself
Move a site made with PHP templates, a static generator or by hand onto HotDog, keep how it looks and every address, and see what you get for it.
On this page
The importers cover WordPress, Ghost, Hugo, Jekyll and MkDocs. Plenty of good sites are none of those: a few PHP templates, an old generator, pages written by hand. This page is the way through for those, step by step. It's how we moved our own sites, and the end of the page says what that bought.
Before you start: measure
You'll want to know what changed, so write down where you are first:
- The page sizes: open your browser's developer tools, Network tab, reload the front page and a long page, and note the total and the number of requests.
- What the server runs: how much memory, how many processes, and the size of its container image, if it's in one.
- Known problems: if you run containers, a scanner such as Grype lists known vulnerabilities in an image (
grype your-image:tag).
Do the same at the end.
1. Start a site beside the old one
hotdog-cms new newsite
cd newsite
Keep the old site running until the new one is checked and live.
2. Bring the look across
HotDog's templates are plain HTML with a few placeholders, so the quickest way to keep a look is to start from what your site actually sends to browsers:
- Save a rendered page from your live site (View source) and split it into the parts every page shares:
partials/head.html(everything in<head>), the header and navigation, the footer. A page's own part goes in a layout. - Point every file at
{{ asset }}:<link href="{{ asset "styles.css" }}">instead ofhref="/css/styles.css?v=3". HotDog puts a fingerprint in each file's name, so you never bump a version number again and browsers can keep files for a year. - Move inline scripts into files in
assets/. They then work under a strict security policy, whichhotdog-cms check -cspprints for you. - Copy pictures and fonts into
static/at the same addresses.
Compare the two sites side by side as you go: same width, same page, light and dark if your site has both.
3. Bring the words across
- Pages that are mostly words become Markdown files in
content/. - A front page made of sections (a hero, feature cards, a closing band) becomes sections: each one a small template, its words in the page's front matter.
- Anything with real HTML in it can stay HTML: put
format: htmlin its front matter.
4. Keep every address working
Old addresses live in bookmarks, search engines and other people's pages. List them (your old sitemap is a good start) and give each one a home:
- A page at the same address needs nothing.
- A page that moved gets a redirect in
site.yaml:
redirects:
- { from: /privacy.php, to: /privacy/ }
5. Check, then compare
hotdog-cms check
It finds broken links, missing alt text, a page without a title, a tracker that loads before visitors agree, and more (see what the checks mean). Fix what it finds.
Then compare page by page with the old site. A script helps for a big site: fetch each address from both, and compare the titles, the links and the text.
6. Publish it locked down
A HotDog site is files, so the thing that serves it can be as small and as closed as a web server gets. Publish it as a container and run it locked down: read-only, not root, no capabilities, with limits. Then measure again.
What you get
We moved a company site, five product sites, a blog and two documentation sites (one of 19 pages, one of 430) this way in October 2026. Each kept its content, so the differences are what the move itself made.
Security
- Nothing runs when someone visits. The PHP sites ran an interpreter for every page (17 files, about 1,200 lines on the smallest), reachable from the web; the HotDog sites run none.
- Known vulnerabilities, counted by Grype in each container image: from 48 (13 of them high) on every PHP site, and 37 (12 high) on each documentation site, to 4 (2 high) on every one. What's left is in the C library and zlib under the web server, with no fix released yet.
- Not root, no capabilities. The old containers ran their main process as root; the new ones run as an ordinary user with every Linux capability dropped and no way to gain one, on a read-only filesystem.
- A strict security policy. Each site now tells browsers that nothing but its own files may run or load. None of them had a policy before.
Speed
- Smaller pages to fetch. The documentation sites lost a theme's JavaScript bundle and web fonts: one front page went from 495 KB and 18 requests to 88 KB and 11, the other from 309 KB to 231 KB.
- Faster answers where the server did work. The blog's PHP did real work on each visit: 8.6 ms of server time per page, now 0.7 ms. The template-only sites were already under a millisecond, and still are.
- Files cached for good. Fingerprinted names mean a browser keeps a stylesheet or a picture for a year and never fetches a stale one.
Stability
- Images about a fifth of the size: 134 to 149 MB down to 22 to 29 MB for the five sites without much media of their own, 101 and 134 MB down to 26 and 58 MB for the documentation (most of what's left there is screenshots). The two that carry a lot of media themselves (videos, a large archive) shrank less: their files are most of their size.
- Less to go wrong. Memory per site went from about 20 MB to 8 MB, and processes from 12 to 9. There's no interpreter to crash, leak or need patching.
- Every deploy checked. The built site is what gets served, so it can be checked before it goes out: our deploy rebuilds it from the commit and stops if anything differs, then runs a check against every server.
- Nothing lost. On the documentation sites, all 449 pages kept their addresses, titles, section anchors and links, checked page by page against the old builds.
Your numbers will differ with what your site is. The direction won't.

