CI/CD-driven static page server for Forgejo and Gitea. Uses OAuth2 to enforce repository permissions on pages.
  • Go 97%
  • Shell 1.7%
  • Dockerfile 1.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-03 21:48:29 +00:00
.devcontainer chore(devcontainers): added todo-highlight extension 2025-12-27 18:45:37 +00:00
.forgejo/workflows fix(ci): pipeline used obsolote variables 2026-11-03 21:48:29 +00:00
.gitignore feat: add custom routes config for clean subdomain URLs 2026-05-29 15:03:54 +02:00
compose.yml chore: Added README and example compose.yml, closes #5 2025-11-29 16:25:14 +01:00
config.example.yml chore: removed slop comments 2026-11-02 18:33:31 +00:00
config.go feat: add custom routes config for clean subdomain URLs 2026-05-29 15:03:54 +02:00
config_test.go feat: add unit tests for config, url_path_helper and utils 2026-03-29 13:23:35 +00:00
CONTRIBUTORS chore: removed excess files from PR 2026-06-09 22:20:10 +02:00
deploy_api.go fix(deploy): accept access token via Authorization header\n\nThe deploy/delete endpoints used to read the Forgejo token only from the\naccess_token query parameter. Query parameters are often logged by proxies,\nso prefer reading the token from an Authorization: Bearer <token> header.\n\nThe access_token query parameter is still accepted as a fallback for\nbackwards compatibility.\n\nCloses #22 2026-11-03 22:11:39 +01:00
deploy_api_test.go fix(deploy): accept access token via Authorization header\n\nThe deploy/delete endpoints used to read the Forgejo token only from the\naccess_token query parameter. Query parameters are often logged by proxies,\nso prefer reading the token from an Authorization: Bearer <token> header.\n\nThe access_token query parameter is still accepted as a fallback for\nbackwards compatibility.\n\nCloses #22 2026-11-03 22:11:39 +01:00
deploy_ops.go feat(deploy): stage deployments and roll back on failure 2026-11-03 21:26:54 +01:00
deploy_ops_test.go feat(deploy): stage deployments and roll back on failure 2026-11-03 21:26:54 +01:00
Dockerfile chore(ci): added workflows 2025-11-29 16:25:33 +01:00
etc-hosts_TESTING chore: removed slop comments 2026-11-02 18:33:31 +00:00
forgejo.go fix: wrong url for checking repo permissions 2025-11-29 20:44:13 +01:00
go.mod chore: go mod tidy 2025-11-28 18:46:51 +01:00
go.sum chore: go mod tidy 2025-11-28 18:46:51 +01:00
LICENSE chore: add LICENSE 2026-06-09 22:53:16 +02:00
main.go chore: change bind address to all interfaces 2025-11-29 18:02:57 +01:00
oauth2.go fix(oauth): build redirect URLs from configuration instead of request 2026-11-03 22:22:16 +01:00
page_handler.go fix(oauth): build redirect URLs from configuration instead of request 2026-11-03 22:22:16 +01:00
page_handler_test.go fix(oauth): build redirect URLs from configuration instead of request 2026-11-03 22:22:16 +01:00
README.md chore: added docs for additional base path feature 2025-12-27 17:27:47 +00:00
renovate.json Add renovate.json 2026-11-03 17:30:40 +00:00
test-delete.sh chore: updated test scripts 2025-12-27 17:18:13 +00:00
test-deploy.sh chore: updated test scripts 2025-12-27 17:18:13 +00:00
url_path_helper.go fix: missing seperator for path remainder 2025-12-27 18:45:08 +00:00
url_path_helper_test.go fix: tests 2026-03-29 19:45:19 +00:00
utils.go feat: full clickable URL is now visible in response and logs 2025-11-29 23:50:03 +01:00
utils_test.go fix: tests 2026-03-29 19:45:19 +00:00

Forge Pages

Forge Pages is a GitHub/GitLab Pages pendant for Forge Servers (Forgejo/Gitea) to deploy static webpages.

Unlike other pages services such as the Codeberg Page Server, static assets do not have to be committed into a separate branch or registry, but can be built and deployed directly from within a workflow. There is also a suitable action that simplifies the deployment.

Deployed pages can be secured by enforcing the user permissions configured in the repository, the page was deployed from. This makes this tool a great fit for deploying private pages as well!

Features

  • Deploy static pages using the Forge Pages Action or manually using tar and curl
  • Uses the worflow token (e.g. ${{ forgejo.token }}) to ensure write permissions to the repository before deployment
  • Can protect pages with the Forgejo/Gitea OAuth2 provider
  • Same URL-layout as with GitHub/GitLab Pages: https://<owner>.<base-url>/<repo>/*
    • Can optionally add an additional base path after the <repo> part that can be seperatly protected (useful when deploying multiple versions in one repo or for previewing contents of a pull request)

How does it work?

The Forge Pages Server is a Go application that provides a POST /deploy endpoint. Pages must be TAR'ed and GZIP'ed and posted to this endpoint, together with the following query parameters:

  • repo: Repository slug. Used to construct the URL where the page will be deployed to. To prevent confusion, the repo name is always lowercased!
  • access_token: The workflow token (e.g. ${{ forgejo.token }}) to verify permissions to deploy a page to the target specified by repo.
    • This can also be a PAT, as long as it has the appropriate permissions
  • protect: If existent, the page will be protected using the Forgejo/Gitea OAuth2 provider. Only users with at least read/pull permissions can view this page.
    • Alternativly, you can add an empty file called .protect to the root of the page to enable protection
  • additional_base_path: Can be used to set an additional base path suffix to allow for multiple deployments per repo

When visiting a protected page, you will get redirected to the configured OAuth2 provider, where you must log in. If you have the correct permission, you will get redirected to the page.

Deployments can be deleted using the DELETE /deploy endpoint or by uploading an empty page to the same location. The delete endpoint also requires the repo and access_token parameters (and additional_base_path if set during deployment).

Installation

You can use the provided compose.yml. Copy the config.example.yml to config.yml and adjust it for your needs:

  • forge_url: URL to your Forgejo/Gitea instance. Used to make API calls to verify permissions.
  • pages_url: Public URL where you intend to deploy the Forge Pages server. Keey in mind that you need to have a wildcard DNS entry for subdomains on this URL as well!
  • serve_path: Base path where pages will be stored and served from. To persist deployments across container restarts, create a bind/volume mount for this path (already contained in the compose.yml)
  • oauth.*: OAuth2 settings as returned by the OAuth2 provider (see here for how to set up a new OAuth2 application with Forgejo)

This application does not support serving HTTPS directly so you will need to configure a reverse proxy as well.

After setting everything up, you can start Forge Pages with docker compose up -d.

Deploy using the Forge Pages Action

See here for documentation and an example.

Local development

You can use the CLI flag -skip_deploy_checks to skip checking the access_token when deploying new pages. This way, you don't need a valid access token.

It is recommended to add the Pages URL and some subdomains you intend to deploy to as static local hosts. See etc-hosts_TESTING to see some examples.

Create a basic config.yml and start the application with go run . -skip_deploy_checks.