Forgejo Pages
Forgejo Pages — Complete Setup Guide
**Wiki:** wiki.gi7b.org | **Last updated:** 2026-04-28
**Status:** Production — `pages.gi7b.org` live on PC03
Overview
Forgejo does not have a built-in static site server. To serve Pages, you run a
separate ronmi/forgejo-pages container alongside Forgejo. It reads files from a
special branch in each repo via the Forgejo API and serves them over HTTP.
Browser → Cloudflare DNS → NPM (SSL) → forgejo-pages:8080 → Forgejo API → repo branch- **Forgejo:** `https://git.gi7b.org` (container: `forgejo`, internal port 3000)
- **Pages server:** `https://pages.gi7b.org` (container: `forgejo-pages`, internal port 8080)
- **Routing:** path-based — `https://pages.gi7b.org/{owner}/{repo}/`
- **Branch name:** `static-pages` (exact, hardcoded default in this image)
Gotchas — Read This First
1. There is no built-in Pages in Forgejo
ENABLE_FORGEJO_PAGES = true in app.ini does nothing. It is not a real setting.
You need the external ronmi/forgejo-pages container.
2. Branch must be named exactly `static-pages`
Not gh-pages, not pages, not static_pages. The image default is static-pages.
If the branch doesn't exist in the repo, the server returns 404.
3. Use two separate tokens
| Token | Scope | Used by |
|---|---|---|
| `repository: read` | Docker container reads repo files via API | ||
| `repository: read+write` + `user: read` | You/AI push code via git CLI |
Never use your account password for git CLI over HTTPS — it will be rejected.
4. NPM forward port is the internal container port
When NPM uses the container DNS name (forgejo-pages), forward to port 8080 (internal).
If using the host IP (192.168.196.76), forward to port 8585 (exposed host port).
Mixing these up causes 502 Bad Gateway.
5. Remove NPM Access List from git.gi7b.org
HTTP Basic Auth at the NPM layer blocks git CLI, API calls, and webhooks. Forgejo's own auth (tokens, SSH keys, 2FA) is the correct security layer for a git host.
6. SSH is more reliable than HTTPS for git push
HTTPS git auth has multiple failure modes (token scopes, credential helpers, NPM layers). SSH just works. Set it up once per machine and never deal with tokens for pushing again.
Docker Compose Setup
File: /home/user/forgejo/compose.yml
services:
server:
image: codeberg.org/forgejo/forgejo:13
container_name: forgejo
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- ./data:/data
- /etc/localtime:/etc/localtime:ro
ports:
- "3001:3000"
- "223:22"
networks:
- internal
- proxy
pages:
image: ronmi/forgejo-pages
container_name: forgejo-pages
restart: unless-stopped
command: serve --server http://forgejo:3000 --token ${FORGEJO_PAGES_TOKEN} --bind :8080
ports:
- "8585:8080"
networks:
- internal
- proxy
depends_on:
- server
networks:
internal:
driver: bridge
proxy:
external: true
name: npm_proxy
File: /home/user/forgejo/.env
FORGEJO_PAGES_TOKEN=your_read_only_repository_token_hereTokens
Service Token (for forgejo-pages container)
Generated in Forgejo → Settings → Applications:
- **Name:** `forgejo-pages-service`
- **Repository and Organization Access:** All
- **Permissions:** `repository: Read` only, everything else No access
- Goes in `/home/user/forgejo/.env` as `FORGEJO_PAGES_TOKEN`
Personal Push Token (for git CLI / AI agents)
Generated in Forgejo → Settings → Applications:
- **Name:** `git-push-{machinename}`
- **Repository and Organization Access:** All
- **Permissions:** `repository: Read and Write`, `user: Read`, everything else No access
- Used as the **password** when git prompts, or embedded in SSH-less workflows
NPM Proxy Host — pages.gi7b.org
Details tab:
| Field | Value |
|---|---|
| `pages.gi7b.org` | |
| `http` | |
| `forgejo-pages` (container name) OR `192.168.196.76` (host IP) | |
| `8080` if using container name / `8585` if using host IP | |
| ✅ On | |
| ✅ On | |
| Off | |
| **Publicly Accessible** (no HTTP Basic Auth) |
SSL tab:
| Field | Value |
|---|---|
| `pages.gi7b.org` (Let's Encrypt) | |
| ✅ On | |
| ✅ On |
SSH Setup for Git Push (per machine)
Run once on each machine that needs to push to Forgejo:
# Generate key
ssh-keygen -t ed25519 -C "{machinename}-git" -f ~/.ssh/id_ed25519 -N ""
# Show public key to add to Forgejo
cat ~/.ssh/id_ed25519.pub
Add the public key in Forgejo → Settings → SSH / GPG Keys → Add Key.
Set remote URL to SSH (note custom port 223):
git remote set-url origin ssh://git@192.168.196.76:223/{owner}/{repo}.git
Use the ZeroTier IP `192.168.196.76` directly — port 223 is not forwarded through
the public relay (PC06). SSH over ZeroTier is reliable for internal machines.
For external machines, either forward port 223 through PC06 or use HTTPS with a token.
Publishing a Page (Repeatable Workflow)
New repo — first time
git clone ssh://git@192.168.196.76:223/{owner}/{repo}.git
cd {repo}
# Create orphan branch (no shared history with main)
git checkout --orphan static-pages
git rm -rf . 2>/dev/null || true
# Create your site
mkdir -p .
cat > index.html <<'EOF'
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>My Page</title></head>
<body>
<h1>Hello from Forgejo Pages</h1>
</body>
</html>
EOF
git add .
git commit -m "Initial pages content"
git push -u origin static-pages
Live immediately at: https://pages.gi7b.org/{owner}/{repo}/
Update existing pages
git checkout static-pages
# edit files
git add .
git commit -m "Update pages"
git push
Via Forgejo Web UI (no git needed)
1. Open repo → click New File
2. Filename: index.html, add content
3. In commit section: select "Create a new branch"
4. Branch name: static-pages
5. Commit
Verification
# Local test (on PC03)
curl -i http://localhost:8585/{owner}/{repo}/
# Expected: HTTP/1.1 200 OK + your HTML
# Check pages server logs
docker logs forgejo-pages --tail 20
Browser: https://pages.gi7b.org/{owner}/{repo}/ (trailing slash matters)
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| No valid owner/repo path in URL | URL must be `/{owner}/{repo}/` | ||
| `static-pages` branch missing or no `index.html` at root | Create branch, push `index.html` to root | ||
| NPM port mismatch or container not on `npm_proxy` network | Check forward port (8080 internal / 8585 host). Verify: `docker network inspect npm_proxy \ | grep forgejo` | ||
| Wrong token scope or using account password | Use personal push token with `repository: write`. Use SSH instead. | ||
| Port 223 not reachable from external machine | Use ZeroTier IP for internal machines. Forward port via PC06 for external. | ||
| Missing `serve` command or bad token | Check `docker logs forgejo-pages`. Verify `.env` token is correct. | ||
| Browser cache | Hard refresh (Ctrl+Shift+R) or test with `curl` |