Astro SSR
Copy it into a new project:
pnpm dlx degit antstanley/blogwright/examples/astro-ssr my-siteAstro with @astrojs/node in standalone mode, running on a Lambda Web Function. Fingerprinted /_astro/ assets still serve from S3.
| Framework | Mode | Blogwright config | Source |
|---|---|---|---|
Astro + @astrojs/node |
Server-rendered | ssr |
examples/astro-ssr |
Deploy it
Section titled “Deploy it”-
Copy the example and start a repository:
Terminal window pnpm dlx degit antstanley/blogwright/examples/astro-ssr my-sitecd my-site && git init -
Set
siteNameandregioninconfig/production.jsonc. For SSR,regionmust beus-east-1,us-east-2,us-west-2,ap-northeast-1oreu-west-1. -
Add Blogwright, then commit everything, including
pnpm-lock.yaml- the builder installs with--frozen-lockfile:Terminal window pnpm add -D blogwrightgit add -A && git commit -m "Start from the blogwright example" -
Create the infrastructure:
pnpm exec blogwright bootstrap -
Build and publish:
pnpm exec blogwright deploy
What matters
Section titled “What matters”config/production.jsonc- packages all ofdist/, notdist/server/.@astrojs/nodefinds its files by walking up to a directory namedserver, and fails to start when the entry sits at the package root, soentryPointisserver/lambda.mjs.astro.config.mjs-output: 'server', the Node adapter instandalonemode, andvite.ssr.noExternal: true, which bundles every dependency intodist/serverso the package needs nonode_modules.siteinastro.config.mjsis the public origin. The app receives the endpoint’s domain asHost, so build absolute URLs fromAstro.site.lambda.mjs- the entry shim. It mapsAWS_LAMBDA_HTTP_ENDPOINTontoHOSTandPORT, then importsentry.mjs. The build copies it intodist/server/.
The files
Section titled “The files”// Blogwright config for this example. Paths are relative to the repository// root, so they assume this directory IS the repository - see README.md.{ "region": "us-east-1", "siteName": "astro-ssr", "ssr": { // The whole of dist/: @astrojs/node finds its files by walking up to a // directory named "server", so the package must keep dist/'s layout. "packageDir": "dist", "entryPoint": "server/lambda.mjs", "staticDir": "dist/client", "staticPaths": ["/_astro/*", "/favicon.svg"], },}import node from '@astrojs/node';import { defineConfig } from 'astro/config';
export default defineConfig({ output: 'server', adapter: node({ mode: 'standalone' }), // The app sees the Web Function endpoint's domain as Host, so absolute URLs // are built from `site` (Astro.site), not Astro.url. site: 'https://example.com', vite: { // Bundle every dependency into dist/server, so the package Blogwright // zips is self-contained: Lambda loads nothing outside it. ssr: { noExternal: true }, },});// Entry shim for Lambda Web Functions. Lambda passes the listen address in// AWS_LAMBDA_HTTP_ENDPOINT; Astro's standalone server reads HOST and PORT.const endpoint = process.env.AWS_LAMBDA_HTTP_ENDPOINT;const colon = endpoint.lastIndexOf(':');process.env.HOST = endpoint.slice(0, colon);process.env.PORT = endpoint.slice(colon + 1);await import('./entry.mjs');{ "name": "blogwright-example-astro-ssr", "private": true, "type": "module", "packageManager": "pnpm@11.25.0", "scripts": { "dev": "astro dev", "build": "astro build && cp lambda.mjs dist/server/", "preview": "astro preview" }, "devDependencies": { "@astrojs/node": "^11.1.7", "astro": "^7.3.8" }}Check the package locally
Section titled “Check the package locally”Run it the way Lambda does - from a copy outside the project, so nothing resolves from its own node_modules:
pnpm buildcp -R dist /tmp/pkg && cd /tmp/pkgAWS_LAMBDA_HTTP_ENDPOINT=127.0.0.1:8080 node server/lambda.mjscurl -i http://127.0.0.1:8080/The server must start listening within 10 seconds, and find dist -type l must print nothing: the build agent rejects a package that contains a symbolic link.
Related pages
Section titled “Related pages”- Server-rendered sites: Astro - the full recipe and its options
- Examples overview - every example, and the conventions they share