Deploy an Astro Site
Push your Astro project to GitHub and Faable builds and serves it β no Dockerfile, no YAML. The builder detects Astro from your package.json, installs your dependencies, runs npm run build, and serves the contents of dist/ from Faableβs shared static runtime behind automatic SSL at https://<app>.faable.link, hosted 100% in Europe.
Astro has two output modes, and they deploy differently. Which one you are on decides everything below, so check astro.config.mjs first.
Static Astro β the default
If your config has no output (or output: 'static'), astro build writes real HTML files per page into dist/. That is the zero-config path:
- The builder detects
astroin yourdependenciesordevDependencies. - It installs, runs your
buildscript, and ships onlydist/to the static runtime β no Node.js process boots. - SPA fallback stays off. Astro builds a real file per route, so an unknown path 404s instead of rewriting to
index.html. That is the correct behaviour for a multi-page site; it is not a bug.
Nothing else to do. Push and it is live.
Server-rendered Astro β add a start script
If your config sets output: 'server' or output: 'hybrid' with an adapter such as @astrojs/node, astro build writes something else entirely:
dist/
βββ client/ β assets
βββ server/
βββ entry.mjs β your serverThere is no index.html at the root of dist/. If you deploy this with no start script, the build goes green, Faable serves dist/ as a static directory, and every route β the homepage included β 404s. It looks like a successful deploy that serves nothing.
Add a start script so the builder runs your server instead of serving files:
{
"scripts": {
"build": "astro build",
"start": "node ./dist/server/entry.mjs"
}
}A start script switches the app to a Node.js container and disables static serving β which is exactly what you want here.
Bind to 0.0.0.0
The @astrojs/node standalone server reads HOST and PORT from the environment. Faable injects PORT; it does not set HOST, and the adapterβs default is localhost, which nothing outside the container can reach. Set it once:
faable deploy secrets set HOST=0.0.0.0Or configure it in the adapter and skip the variable. Either way, the rule is the $PORT contract: listen on 0.0.0.0 at process.env.PORT.
Deploy
From the dashboard β the normal path:
- Create a Project and an App in the Faable DashboardΒ .
- Click Link repository and pick your Astro repo.
- Push to your release branch. Faable builds and takes it live.
Or from your laptop, for an ad-hoc deploy:
npm i -g @faable/faable
faable login
faable deployYour site is ready at https://<app>.faable.link, with automatic SSL and the WAF already inspecting traffic.
Environment variables
Astro exposes variables prefixed PUBLIC_ to client-side code, compiled into the bundle at build time. So:
- Set them before the build, with the CLI or the dashboard, then redeploy.
- A
PUBLIC_variable is public β it ships inside the JavaScript your visitors download. Never put a secret there.
faable deploy secrets set PUBLIC_SITE_URL=https://example.comOn a static site there is no server, so non-PUBLIC_ variables only exist during the build. On a server-rendered site they are also readable at runtime through import.meta.env / process.env.
A different output directory
Faable expects the Astro default, dist/. If astro.config.mjs sets outDir elsewhere, the build fails the post-build check with Static build output 'dist' not found after the build. Drop the override, or force the static buildpack in faable.json:
{ "buildpack": "static" }Monorepos
If the Astro site lives in a subdirectory, point rootDir at it in faable.json at the repository root:
{ "rootDir": "apps/site" }See Monorepos.
Troubleshooting
- The build is green but every route 404s β you are on
output: 'server'with nostartscript, so a server build is being served as static files. See above. - A sub-page 404s on a static site β that page was not built. Check your routes and any
getStaticPaths. Astro deliberately does not rewrite unknown paths toindex.html. - Requests time out on a server-rendered site β the adapter is bound to localhost. Set
HOST=0.0.0.0. Static build output 'dist' not foundβoutDiris notdist/, or the build wrote nothing.- A
PUBLIC_variable is empty β it was set after the build. Redeploy.
Related
- What the Builder Expects β detection rules, static frontends, the
$PORTcontract - Deploy Vite β the SPA sibling, with rewrite-to-index on
- Deploy Next.js Β· Deploy Node.js Express
- Migrate from Vercel Β· Migrate from Netlify
- Custom domains Β· WAF
- Add authentication to your app β Faable Auth is included in the same subscription
Last updated on