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:
- a Forgejo repository on
git.zz.ac; - Forgejo Actions enabled for that repository;
- a domain whose DNS records you can change;
- a build command that writes the final static site to a specified directory.
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:
- its name is
_zz-pages.<site-domain>; - it has exactly one TXT value beginning with
repo=; - the value after
repo=is the complete Forgejo repository path.
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 hugoThen 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:
No matching runner: nozz-pagesRunner is currently available;- DNS authorization failure: the TXT record is missing, has not
propagated, or contains more than one
repo=value; - domain resolution failure: the site domain does not point only to the configured ingress host;
- repository authorization failure: the workflow event does not have write permission to the repository;
- build failure: the command failed or removed
ZZ_PAGES_OUTPUT; - content validation failure: the site contains an escaping symbolic link, hard link, or special file.
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.