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:

zz.Pages accepts zz.ac subdomains, including deeper names such as docs.project.zz.ac. It does not accept the zz.ac apex or domains under any other suffix.

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@main
        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.

Limit builds to relevant changes

Use a paths filter when only some repository files affect the website. This avoids starting the shared Runner for unrelated changes. For a site generated from Markdown, the trigger can be restricted as follows:

on:
  push:
    branches:
      - main
    paths:
      - '**/*.md'
      - '.forgejo/workflows/pages.yml'

Adjust the patterns for the site's build system. Include every content, template, configuration and dependency file that can change the generated site. A matching workflow file ensures that changes to the deployment process can publish a new release. Quote patterns that begin with * so YAML does not interpret them as aliases.

Replace example.zz.ac with the fully qualified zz.ac subdomain. 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.