**Tags:** "Hello World" Examples · Astro

# Astro SSR Hello World

A minimal Astro SSR application with a server-rendered health check page that
connects to a PostgreSQL database, runs idempotent migrations, and queries live
data — demonstrating the full Zerops SSR integration pattern.

### Available Environments

- [AI Agent](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=ai-agent)
- [Remote (CDE)](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=remote-cde)
- [Local](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=local)
- [Stage](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=stage)
- **Small Production** ← current
- [Highly-available Production](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=highly-available-production)

### Services in this Environment

**Services:**

- **core** (core@1)
  - Containers: 1 × Shared Core, 0.00 GB RAM, 0 GB Disk
- **app** (nodejs@22) :4321
  - Containers: 2 × Shared Core, 0.38 GB RAM, 1 GB Disk
  - Repository: [zerops-recipe-apps/astro-ssr-hello-world-app](https://github.com/zerops-recipe-apps/astro-ssr-hello-world-app)
- **db** (postgresql@16) :5432, :6432
  - Containers: 1 × Shared Core, 0.75 GB RAM, 1 GB Disk

**Total Resources:** 4 containers, 1.50 GB RAM, 3 GB Disk

### One-Click Deploy (Import YAML)

Use this YAML with `zcli project import` to deploy this environment:

```yaml
# Astro SSR Hello World - Small Production Environment
#
# A minimal Astro SSR application with a server-rendered health check
# page that connects to a PostgreSQL database, runs idempotent
# migrations, and queries live data - demonstrating the full Zerops
# SSR integration pattern.
#
# Production-ready setup with horizontal redundancy and auto-scaling.

project:
  name: astro-ssr-hello-world-small-prod

services:
  - hostname: app
    type: nodejs@22
    zeropsSetup: prod
    # buildFromGit pulls source code and zerops.yaml from this public
    # repo and triggers the first build automatically on import.
    buildFromGit: https://github.com/zerops-recipe-apps/astro-ssr-hello-world-app
    enableSubdomainAccess: true
    # minContainers: 2 ensures at least two containers are always
    # running - eliminates single points of failure and enables
    # zero-downtime deploys (new containers start before old ones
    # are removed from the project balancer).
    minContainers: 2
    verticalAutoscaling:
      minRam: 0.25
      # Reserve free RAM for V8 GC cycles and SSR rendering spikes.
      # Without headroom, memory pressure triggers OOM restarts.
      minFreeRamGB: 0.125

  # PostgreSQL for app data. Priority 10 starts the database before
  # app containers, preventing connection errors on cold start.
  - hostname: db
    type: postgresql@16
    # NON_HA = single-node. Suitable for moderate traffic where a
    # brief DB restart is acceptable. Use HA for zero-downtime needs.
    mode: NON_HA
    priority: 10
    verticalAutoscaling:
      minRam: 0.5
      minFreeRamGB: 0.25

```

---

## Next Steps

After deploying one of the environments and getting to know Zerops, you have two paths to choose from:

1. **Template Flow** — Clone our GitHub repositories and use the whole recipe as a template
2. **Integrate Flow** — If you already have an existing application on a similar stack, integrate the recipe setup with your application

Select a flow: [Template Flow](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=small-production&guideFlow=template) or [Integrate Flow](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=small-production&guideFlow=integrate)

Both flows are shown below:

## How to take over the Small Production environment

### 📦 Clone the template repositories

Fork or clone the following repositories to your local machine or GitHub account:

- [zerops-recipe-apps/astro-ssr-hello-world-app](https://github.com/zerops-recipe-apps/astro-ssr-hello-world-app)

### 1. Find your service name

Many commands and configurations need the exact name of your service. You can find it in the Zerops Dashboard.

- Open your project in the Zerops Dashboard.
- In the project overview, find the service you want to manage.
- Use this exact name whenever a command or pipeline configuration asks for `<service-name>`.

<img src="https://storage-prg1.zerops.io/4gfos-storage/copy1_cd2a6044c8.jpg" style="display: block; margin: 0 auto;" alt="Zerops GUI: Locating the Service Name" width="500" />

### 2. Configure deployment pipeline

Go to Service Settings > Pipelines & CI/CD Settings in the Zerops Dashboard and connect your repository.

For production, use a trigger on new tags. This keeps deployments intentional and tied to a specific version. You can also add a regex filter, such as `^v[0-9]+\.[0-9]+\.[0-9]+$`, if you want to allow only semantic version tags.

<img src="https://storage-prg1.zerops.io/4gfos-storage/triggerborder_b865860a89.jpg" style="display: block; margin: 0 auto;" alt="Zerops GUI: Triggers" width="500" />

Alternatively, add `zcli push` to your existing CI/CD pipeline if you want full control over when deployments happen.

Learn more about pipeline triggers: https://docs.zerops.io/features/pipeline

### 3. Deploy to production

Create and push a new Git tag to deploy a specific version of your app:

```bash
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
```

> [!TIP]
> Open the pipeline detail in the Zerops Dashboard to check the build progress and verify that all steps finish successfully.

### 4. Configure autoscaling

Review the autoscaling settings for your runtime services and databases in Service Settings > Automatic Scaling Configuration in the Zerops Dashboard.

<img src="https://storage-prg1.zerops.io/4gfos-storage/scaling_ac0880aef5.png" style="display: block; margin: 0 auto;" alt="Zerops GUI: Autoscaling configuration" width="500" />

The most important settings are:

```yaml
verticalAutoscaling:
  minRam: 1
  minFreeRamGB: 0.5
  minFreeRamPercent: 20
```

> [!CAUTION]
> Pay attention to `minFreeRamGB`. This value tells Zerops when to scale RAM vertically. Adjust it based on your app’s real memory needs. RAM scales up immediately, while CPU scales after two consecutive measurements below the threshold.

> [!TIP]
> Run a quick stress test with a tool like hey before real users arrive. This helps you see how your app behaves under load and tune the autoscaling settings.

### 5. Set up your domain

To send real traffic to your app, configure public HTTP access in Service Settings > Public Access & Internal Ports in the Zerops Dashboard.

Add your custom domain and point your DNS records to the Zerops IPs shown in the dashboard:

<img src="https://storage-prg1.zerops.io/4gfos-storage/subdomain_8cafd801e8.jpg" style="display: block; margin: 0 auto;" alt="Zerops GUI: Public access and custom domain" width="500" />

```text
Type   Name          Content          TTL
A      example.com   <zerops-ipv4>    Auto
AAAA   example.com   <project-ipv6>   Auto
```

For wildcard domains, add a CNAME record for SSL validation.

Check the public access documentation: https://docs.zerops.io/features/access

> [!TIP]
> When changing DNS records for production, start with a low TTL value. Make sure SSL certificates are active before you disable the fallback Zerops subdomain.

Once everything works, you can disable the Zerops subdomain so all traffic goes through your custom domain.

---

### 🎉 You are good to go!

Your application is live in production and the core setup is complete.

The following sections are optional. They cover extra production features such as log forwarding, backups, and diagnostic access. You can stop here and come back later when you need them.

---

### 6. Set up log forwarding (Optional)

To send logs to an external service, go to Project Settings > Log Forwarding & Logs Overview in the Zerops Dashboard.

You can forward logs to services like Better Stack, Papertrail, or your own self-hosted solution.

Learn more about log forwarding: https://docs.zerops.io/references/logging

### 7. Configure database backups (Optional)

Manage automated encrypted backups in Service Settings > Backups in the Zerops Dashboard.

By default, backups run daily between 00:00 and 01:00 UTC.

Before a major deployment, create a manual protected backup:

```bash
zcli backup create <db-service> --tags pre-deploy,protected
```

Read the backup documentation for more options: https://docs.zerops.io/features/backup

### 8. Set up diagnostic access (Optional)

Use zCLI and VPN access when you need to inspect or maintain services directly.

For runtime services:

```bash
zcli vpn up
ssh <service-name>.zerops
```

For databases, connect through the VPN to reach the project’s private network, or set up secure direct IP access for your database admin tools.

Check the VPN documentation: https://docs.zerops.io/references/cli/commands#vpn-up

## How to integrate app with Zerops

### 1. Adding `zerops.yaml`

The main application configuration file you place at the root of your
repository. It tells Zerops how to build, deploy, and run your application.

```yaml
# The 'prod' setup builds optimized SSR artifacts for deployment.
# The 'dev' setup deploys full source code for live development.
zerops:
  - setup: prod
    build:
      base: nodejs@22
      # Astro uses Vite + Rollup for bundling. Rollup ships a native
      # binary for glibc (Ubuntu/Debian) and musl (Alpine) separately.
      # The npm optional dep resolution sometimes misses the musl binary
      # on Alpine build containers, causing build failures. Ubuntu
      # avoids this - the runtime (Alpine) doesn't need Rollup at all
      # since node_modules contains only runtime deps after deploy.
      os: ubuntu

      buildCommands:
        # npm ci installs exact versions from package-lock.json -
        # reproducible builds, faster than npm install.
        - npm ci
        - npm run build

      deployFiles:
        # Astro uses @astrojs/node adapter (not self-contained) -
        # node_modules must be deployed alongside the build output
        # so pg and other runtime deps resolve at startup.
        - dist
        - node_modules
        - package.json
        # Migration script runs in initCommands via zsc execOnce.
        - migrate.js

      cache:
        # node_modules cached between builds - skips npm ci on
        # unchanged dependencies (major speed win on cold builds).
        - node_modules

    # Readiness check: Zerops waits for a 200 from the app before
    # routing traffic from the project balancer to new containers.
    deploy:
      readinessCheck:
        httpGet:
          port: 4321
          path: /

    run:
      base: nodejs@22

      # Run migration once per deploy using zsc execOnce. Placed in
      # initCommands (not buildCommands) so migration and code are
      # deployed atomically - a failed deploy leaves the schema unchanged.
      # zsc execOnce ${appVersionId} ensures exactly one container runs
      # the migration even when minContainers > 1; others wait for success.
      initCommands:
        - zsc execOnce ${appVersionId} -- node migrate.js

      ports:
        - port: 4321
          httpSupport: true

      envVariables:
        NODE_ENV: production
        # HOST: 0.0.0.0 tells the Astro Node.js adapter to bind to all
        # interfaces. Without it the server listens on localhost only,
        # making it unreachable from the project balancer.
        HOST: "0.0.0.0"
        PORT: "4321"
        DB_NAME: db
        # Referencing variables: ${hostname_key} resolves to the value
        # generated by the named service at runtime. hostname=db means
        # the db_hostname, db_port, etc. vars are auto-populated by Zerops.
        DB_HOST: ${db_hostname}
        DB_PORT: ${db_port}
        DB_USER: ${db_user}
        DB_PASS: ${db_password}

      # @astrojs/node standalone adapter starts a Node.js HTTP server
      # from the compiled entry point. HOST and PORT are read from env.
      start: node ./dist/server/entry.mjs

  - setup: dev
    build:
      base: nodejs@22
      # Ubuntu provides a richer toolset for interactive SSH development
      # (git, curl, editors) vs Alpine's minimal environment.
      os: ubuntu

      buildCommands:
        # npm install (not npm ci) - tolerates a missing or
        # out-of-date lock file in active development.
        - npm install

      # Deploy the full working directory so the developer has the
      # complete source tree available after SSH-ing in.
      deployFiles: ./

      cache:
        - node_modules

    run:
      base: nodejs@22
      os: ubuntu

      initCommands:
        # Migration runs on every deploy/restart - zsc execOnce ensures
        # it executes only once per version even across container restarts.
        - zsc execOnce ${appVersionId} -- node migrate.js

      ports:
        - port: 4321
          httpSupport: true

      envVariables:
        NODE_ENV: development
        HOST: "0.0.0.0"
        PORT: "4321"
        DB_NAME: db
        DB_HOST: ${db_hostname}
        DB_PORT: ${db_port}
        DB_USER: ${db_user}
        DB_PASS: ${db_password}

      # zsc noop keeps the container alive without starting the app.
      # The developer SSHs in and runs `npm run dev` manually,
      # enabling hot-reload and interactive debugging.
      start: zsc noop --silent
```

### 🎯 What's next?

**Deploy other environments** — Ready to scale? Deploy additional environments for different stages of your workflow:

- [AI Agent](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=ai-agent)
- [Remote (CDE)](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=remote-cde)
- [Local](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=local)
- [Stage](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=stage)
- [Highly-available Production](https://app.zerops.io/recipes/astro-ssr-hello-world.md?environment=highly-available-production)

## Knowledge Base

### Platform Reference

- [Routing & Domains](https://docs.zerops.io/features/access)
- [Scaling](https://docs.zerops.io/features/scaling)
- [Environment Variables](https://docs.zerops.io/features/env-variables)
- [CLI (zcli)](https://docs.zerops.io/references/cli)

### Service Type Reference

**Node.js**

- [Build & Deploy](https://docs.zerops.io/nodejs/how-to/build-pipeline)
- [Customize Runtime](https://docs.zerops.io/nodejs/how-to/customize-runtime)

**PostgreSQL**

- [Connect](https://docs.zerops.io/postgresql/how-to/connect)
- [Backup & Restore](https://docs.zerops.io/postgresql/how-to/backup)
- [Manage](https://docs.zerops.io/postgresql/how-to/manage)
- [Scale](https://docs.zerops.io/postgresql/how-to/scale)

---

## Related Recipes

- [Astro Static Hello World](https://app.zerops.io/recipes/astro-static-hello-world.md)
- [Bun Hello World](https://app.zerops.io/recipes/bun-hello-world.md)
- [Go Hello World](https://app.zerops.io/recipes/go-hello-world.md)
- [Zerops showcase](https://app.zerops.io/recipes/zerops-showcase.md)

