Self-hosted, one process
Running in about
ten minutes.
Node 22 or newer and a machine you control. No container required, no managed service, and no account with anybody — including us.
Before you start
The repository is not open yet. The licence is GPL-3.0 and the code is written to be self-hosted by anyone — but the source is still private while the last of the go-public work is finished, so the clone below will not resolve for you today. Everything else on this page is accurate, and every document the project ships is already readable here under Docs.
If you want it before it opens: ask for access.
Get it and install
Node 22.12 or newer. The install pulls the optional image library; let it.
git clone https://github.com/Dimitriou-eCommerceWebServices/AstroCMS_v1.git
cd AstroCMS_v1
npm installSet a secret
AUTH_SECRET signs every session cookie. Under 16 characters, or missing, and a production build refuses to start rather than pretending to be secure.
cp .env.example .env
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# paste it into .env as AUTH_SECRETCreate your account
Interactive. It replaces the seed admin, so there is no default password left behind — a production build refuses to accept one anyway.
npm run setup
npm run dev # http://localhost:4321/adminTell it its own address
Settings → Address of this CMS. Skip this and media URLs are guessed from whatever host each request arrived on — right for the admin, wrong for a storefront on another domain. The health check warns until it is set.
Point your frontend at it
Everything is JSON over HTTP. The response envelope carries media_base, which is what you join relative image paths to.
curl -s localhost:4321/api/products?limit=3 | jq
curl -s localhost:4321/openapi.json | jq '.paths | keys'Deploy, and assert it
A reference nginx vhost and systemd unit are in deploy/, with limits measured against real traffic rather than chosen. The deep health check answers 503 when anything essential is broken, so a deploy script can simply stop.
npm run build
curl -fsS -H "Authorization: Bearer $HEALTH_TOKEN" \
https://cms.example.com/api/health/deepWorth knowing before you deploy
Four things that
fail quietly.
- Body size
- nginx defaults to 1 MB, so every image upload fails with a 413 the app never sees and cannot explain. The reference vhost raises it per location.
- Readiness
- Poll /readyz, not /healthz, before switching traffic over. Migrations run at boot, and only readyz waits for them.
- Uploads path
- Point it outside the release directory. A deploy that swaps the release takes the uploads with it otherwise, and every image added since the last build 404s.
- Build-time variables
- SITE_URL and the CSP allow-lists are read when the bundle is built. Setting them in the service file and restarting does nothing.