Repository navigation
Installation
How to get AstroBaaS running: on your own machine for development, and as a production build you start yourself. It is for anyone installing the CMS for the first time; for putting it on a server behind a reverse proxy, continue with Deployment.
AstroBaaS is pre-alpha (version 0.1.3). Read Security before exposing an install to the internet.
| Requirement | Notes |
|---|---|
| Node.js 22.12 or newer | Enforced by engines in package.json; .nvmrc pins 22.12. |
| npm | Ships with Node. The repository has a package-lock.json. |
| git | To clone the repository. |
| Disk for data | The default database is a JSON file plus an uploads directory. Both must be on persistent, writable storage in production. |
sharp (optional dependency) |
Installed automatically by npm install where a prebuilt binary exists. Without it, uploads get no dimensions and no WebP derivatives; the deep health check reports this as image_pipeline. |
No separate database server is needed for the default setup. SQLite and remote libSQL (Turso) are optional; see Choosing a database driver.
These are two different things, and it matters which one you want.
| You want to... | Use |
|---|---|
| Run the CMS: admin, public site, REST API | Clone the repository. This is the supported install. |
Call a running AstroBaaS from your own project (astrobaas/client), write a plugin or theme against astrobaas/core, or use the CLI |
npm install astrobaas@alpha |
| Let an AI agent drive a running install |
npx -y astrobaas-mcp (a separate, zero-dependency package) |
The astrobaas npm package contains the libraries (astrobaas/core, astrobaas/client, astrobaas/plugins), the astrobaas CLI and a few helper scripts. It does not contain the application source, so installing it does not give you a running site. Pre-1.0 releases are published under the alpha dist-tag; see Upgrading.
npx astrobaas init is not a project scaffolder either: it writes a .env file with a freshly generated AUTH_SECRET in the current directory (and refuses to overwrite an existing one without --force). npx astrobaas secret prints a new secret without touching any file.
See SDK, CLI and MCP for the package in detail.
git clone https://github.com/operator888/astrobaas.git
cd astrobaas
cp .env.example .env # optional in development
npm install
npm run dev # http://localhost:4321npm run dev runs astro dev. With no configuration at all it:
- uses the JSON-file database (
db.jsonin the project root, created on first boot); - stores uploads under
public/uploads/; - seeds a bootstrap admin account and two demo blog posts;
- logs outgoing email to the console instead of sending it.
Open http://localhost:4321/login to sign in and http://localhost:4321/admin for the admin.
Copying .env.example is optional in development. The file is almost entirely commented out; the only active lines are the AUTH_SECRET placeholder and SEED_DEMO_CONTENT=1.
AstroBaaS reads its configuration from process.env. npm run dev runs scripts/dev.mjs, which loads .env.local and then .env into it before starting astro dev:
npm run dev # loads .env.local, then .env
npm run dev -- --port 5000 # arguments pass through to astro devVariables already set in your shell win over the files.
On 0.1.3 and earlier,
npm run devran plainastro dev, which leavesprocess.envempty, so values in.env(for exampleSITE_LOCALES) silently did nothing. Runnode scripts/dev.mjsinstead on those versions. The same rule applies tonpm startand the offline scripts: none of them read.envon their own (see below).
On the first boot of an empty database, AstroBaaS creates one admin account. What it looks like depends on the environment:
| Variable | Effect | Default |
|---|---|---|
ADMIN_EMAIL |
Address of the bootstrap admin. An invalid value falls back to the default with a warning. | admin@local |
ADMIN_NAME |
Display name, so demo posts carry your byline. | Admin |
ADMIN_PASSWORD |
Password of the bootstrap admin. | Development: admin. Production: randomly generated (see below). |
These are read once, when an empty database is first opened. Changing them later does nothing; edit the account under Admin → Users instead.
admin@local cannot receive mail, so a password reset has nowhere to go. Set ADMIN_EMAIL to a real address before the first start of anything you intend to keep.
Sign in with admin@local / admin (unless you set ADMIN_EMAIL or ADMIN_PASSWORD). Change the password straight away.
"Production" here means a built server: npm run build output started with npm start or node ./dist/server/entry.mjs. AstroBaaS decides this from the build itself, not only from NODE_ENV, so the bare node ./dist/server/entry.mjs path is treated as production even when NODE_ENV is unset (isProductionRuntime() in src/lib/auth.ts).
In production:
-
No well-known default password is seeded. If
ADMIN_PASSWORDis not set, a random password is generated and printed once to stdout, in a box headed "generated an admin password for this install". Under systemd that means the journal; under Docker, the container log. It is not stored anywhere in plain text and is never shown again. -
The login refuses the seeded
adminpassword, even for an older install that still has it. The response is HTTP 403 with the codeSEED_PASSWORD_REFUSEDand a message telling you to runnpm run reset-password.ALLOW_SEED_PASSWORD=1overrides this for a trusted private deployment; do not use it on anything reachable from the internet. -
AUTH_SECRETmust be real. A missing secret, one shorter than 16 characters, or the.env.exampleplaceholder is refused; nobody can sign in until you replace it, and the reason is logged. Generate one withopenssl rand -hex 32(ornpx astrobaas secret). -
Session and CSRF cookies get the
Secureflag, so the site must be served over HTTPS. To test a production build over plainhttp://localhost, setCOOKIE_SECURE=0.
The simplest route is to set ADMIN_EMAIL and ADMIN_PASSWORD in the environment before the first start.
Two offline scripts manage admin accounts without the web UI:
npm run setup # create or replace an admin account (prompts)
npm run reset-password -- you@example.com # set a new password for an existing user-
setupprompts for email, password (at least 8 characters, entered twice) and display name, then writes anadminaccount. If you create an account with a different address, the seededadmin@localaccount is removed. It is safe to re-run. -
reset-passwordprompts for a new password for an existing user and errors out if the email does not exist. -
Password input is not masked. For unattended use, pipe the answers in, for example:
printf 'you@example.com\nyour-strong-password\nyour-strong-password\nYour Name\n' | npm run setup
Both work only with the JSON-file database. They honour DB_PATH, and on an install configured with DATABASE_URL (SQLite, libSQL or relational) they refuse to run and tell you so, because there is no db.json to write to. On those installs, manage users through the admin screens or the REST API, set ADMIN_EMAIL/ADMIN_PASSWORD before the first boot, or use the forgot-password flow once email is configured (see Email).
Because npm scripts do not read .env, export DB_PATH in your shell first if your install uses a non-default path.
npm run build
node --env-file=.env ./dist/server/entry.mjsnpm run build runs astro check, astro build, and builds dist/mail-test.mjs (the email self-test used after deploys).
npm start does not read .env. It runs NODE_ENV=production node ./dist/server/entry.mjs and nothing more. Either export the variables yourself, or start Node with --env-file as above. In the reference systemd unit the variables come from EnvironmentFile=.
To try a production build on your own machine over plain HTTP, put these in .env:
AUTH_SECRET=<output of: openssl rand -hex 32>
COOKIE_SECURE=0The built server is the @astrojs/node standalone server. It listens on the address and port given by the HOST and PORT environment variables (the Docker image sets HOST=0.0.0.0, PORT=4321; the reference systemd unit uses HOST=127.0.0.1, PORT=3002).
Some variables are read by astro.config.ts while the bundle is built, so they must be set before npm run build, not only at runtime:
-
SITE_URL(Astro'ssite, used for absolute URLs) - every
CSP_*variable andANALYTICS_PROVIDERS(the Content-Security-Policy is assembled at build time)
See Configuration.
The repository includes a Dockerfile and a docker-compose.yml:
echo "AUTH_SECRET=$(openssl rand -hex 32)" > .env
docker compose up -d --buildThe image runs node ./dist/server/entry.mjs as a non-root user, sets NODE_ENV=production, and stores the database, uploads and private uploads under the /app/data volume. The compose file publishes the port on 127.0.0.1:4321 only; put a reverse proxy in front for public traffic. More in Deployment.
The storage engine is selected by environment variables at boot. All application code goes through one Storage interface, and the full HTTP smoke suite runs against all three drivers in CI.
DATABASE_URL |
DATABASE_DRIVER |
Driver | Use for |
|---|---|---|---|
| unset | — |
lowdb: one JSON file at DB_PATH (default ./db.json) |
Local development; a small single-process site. |
file:./data/astrobaas.db |
unset | libSQL doc-blob, local SQLite file | Durable single host. |
libsql://<db>.turso.io plus DATABASE_AUTH_TOKEN
|
unset | libSQL doc-blob, remote (Turso) | Durable, not tied to one machine's disk. |
file: or libsql://
|
relational |
Relational libSQL: one row per entity | Production, especially more than one writer or host. |
How to choose:
- lowdb is zero-configuration and the default. It is a single-process file: it cannot be shared between replicas and is lost on ephemeral filesystems.
- Doc-blob keeps the whole dataset in one row, so writes are last-write-wins. That is fine for one long-lived process, and risky if two processes write (a second instance, or a CLI writing while the site runs).
- Relational gives row-level writes and is what the project recommends for production multi-writer or multi-host use.
Examples:
# Local SQLite, relational
DATABASE_URL=file:./data/astrobaas.db
DATABASE_DRIVER=relational
# Turso, relational
DATABASE_URL=libsql://my-app.turso.io
DATABASE_AUTH_TOKEN=...
DATABASE_DRIVER=relationalOn first boot against an empty database, AstroBaaS creates its schema defaults and the bootstrap admin automatically, on every driver. There is no separate migration command: pending schema migrations run at startup.
Switching drivers later is not automatic. Backup export and restore are same-driver only, and doc-blob and relational are different schemas. Choose before you have content you care about. STORAGE.md explains how to move content between drivers (through the API or by re-running an importer) and how to back up SQLite files safely under WAL.
| What | Default location | Override |
|---|---|---|
| JSON database | ./db.json |
DB_PATH |
| SQLite database | the path in the file: URL |
DATABASE_URL |
| Public uploads | public/uploads/<yyyy>/<mm>/... |
UPLOADS_DIR |
| Private uploads (files attached to public forms) |
private-uploads/ beside the database |
PRIVATE_UPLOADS_DIR |
db.json and uploads are gitignored. In development, deleting db.json resets the install to a fresh seed.
curl -s http://localhost:4321/healthz # liveness
curl -s http://localhost:4321/readyz # readiness: 200 once storage is reachable and the schema is currentSigned in as an admin, GET /api/health/deep runs the fuller checks (image pipeline, uploads writable, database write, email channel and more). See Deployment.
To check email before you depend on it:
npm run mail:test -- you@example.com- Set the site's addresses under Admin → Settings (
Site URLandAddress of this CMS); see Configuration. - Configure outgoing mail: Email.
- Look around the admin: Admin tour.
- Going live: Deployment and Security.
- Configuration: every environment variable
- Deployment: server layout, reverse proxy, TLS
- Backups and storage
- FAQ and troubleshooting
- README.md
- STORAGE.md
- .env.example
AstroBaaS is free software under GPL-3.0-or-later. This wiki describes the latest release; the repository and its CHANGELOG are the final word. Found a mistake here? Open an issue.
Getting started
Using the CMS
Building with it
Extending
Commerce and email
Operating
Project