zz.Pages

zz.Pages is the static website hosting service provided by zz.nic. Repositories and Forgejo Actions are hosted on zz.Git, while the public service documentation is available at pages.zz.ac.

Push a website repository to Forgejo and zz.Pages will run its build command and publish the result on your domain. Later pushes replace the live release automatically. Visitors never see a partially updated site.

zz.Pages is suitable for blogs, project documentation and frontend-only websites. It does not run PHP, Python or Node.js services, databases, or other server-side applications.

Before you begin

You need:

You do not need to request a Runner or create a personal access token. Forgejo automatically provides each workflow with a short-lived token that is valid for the current repository.

The service provides one Runner environment through the zz-pages label. It contains the runtime required by the deployment Action, but it does not provide or select a static site generator for the repository. Each repository is responsible for installing its own build tools in the workflow.

1. Configure the domain

Suppose the repository is alice/website and the site domain is example.zz.ac. Add these DNS records:

example.zz.ac. CNAME pages.zz.ac.
_zz-pages.example.zz.ac. TXT "repo=alice/website"

The CNAME sends website traffic to the current zz.Pages ingress host. The TXT record authorizes the alice/website repository to publish that domain.

The authorization record must meet all of these requirements:

An apex domain usually cannot use an ordinary CNAME. Use an ALIAS or ANAME record if the DNS provider supports one. Otherwise, configure A and AAAA records using the current addresses of pages.zz.ac.

Wait for DNS changes to propagate before deploying. Changing the repository in the TXT record transfers publishing authority to the new repository.

2. Add the deployment workflow

Create .forgejo/workflows/pages.yml in the repository:

name: Deploy with zz.Pages

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: zz-pages
    steps:
      - uses: https://data.forgejo.org/actions/checkout@v6
      - uses: https://git.zz.ac/zz/pages@v0.1.0
        with:
          domain: example.zz.ac
          build-command: |
            npm ci
            npm run build -- --outDir "$ZZ_PAGES_OUTPUT"

This example deploys every push to main. Forgejo cancels an older run of the same workflow and branch when a newer push starts.

Replace example.zz.ac with the fully qualified site domain. Do not include https://, a port, a path, or a trailing dot.

zz.Pages creates an empty ZZ_PAGES_OUTPUT directory before it runs build-command. The command must write the final site into that directory and must leave the directory itself in place.

Common build commands

The build command runs inside the job container. The required generator must already be available there. Install it in an earlier workflow step. Tools installed by earlier steps in the same job remain available to the zz.Pages Action. The Action does not install Hugo, MkDocs, or other site generators.

For example, install Hugo before invoking the Action:

- name: Install Hugo
  run: |
    apt-get update
    apt-get install --yes hugo

Then use this build command in the zz.Pages Action:

build-command: hugo --destination "$ZZ_PAGES_OUTPUT"

MkDocs:

build-command: mkdocs build --site-dir "$ZZ_PAGES_OUTPUT"

Astro, Vite, or another npm project:

build-command: |
  npm ci
  npm run build -- --outDir "$ZZ_PAGES_OUTPUT"

If the repository already contains generated files, copy a dedicated public directory:

build-command: cp -a public/. "$ZZ_PAGES_OUTPUT/"

You may also build into a normal repository directory in an earlier step. Then use build-command to copy the result into ZZ_PAGES_OUTPUT. A step placed after the zz.Pages Action runs after publication and cannot change that release.

Published sites

The first successful deployment initializes the Nginx site configuration and HTTPS certificate. Later deployments switch atomically to the new release and do not require an Nginx reload.

A release may contain regular files, directories and symbolic links. The full target chain of every symbolic link must stay within the same release. zz.Pages rejects absolute, dangling, cyclic or escaping links, hard links and special files.

The workflow above maps one repository to one domain. zz.Pages does not map different branches in one repository to different sites.

Troubleshooting

Start with the build log on the repository's Actions page. Common failures include:

Contact the zz.Pages administrator if the build succeeds but server-side publication, site configuration, or HTTPS certificate issuance fails.

Administrator documentation

Server installation, Runner configuration, systemd, Nginx, logging, upgrades and removal are documented in DEPLOYMENT.md. Site publishers do not need to run the system commands in that guide.