Install via Docker / Podman
The official image is codeberg.org/forgejo/forgejo (Codeberg hosts the project). A minimal compose file:
# docker-compose.yml
services:
forgejo:
image: codeberg.org/forgejo/forgejo:10
container_name: forgejo
restart: unless-stopped
environment:
USER_UID: 1000
USER_GID: 1000
FORGEJO__database__DB_TYPE: postgres
FORGEJO__database__HOST: db:5432
FORGEJO__database__NAME: forgejo
FORGEJO__database__USER: forgejo
FORGEJO__database__PASSWD: ${DB_PASSWORD}
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:3000:3000" # HTTP, behind reverse proxy
- "2222:22" # SSH for git over ssh
depends_on: [ db ]
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: forgejo
POSTGRES_USER: forgejo
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- ./db:/var/lib/postgresql/data
For a single-user / homelab install, swap Postgres for SQLite by dropping the db service and setting FORGEJO__database__DB_TYPE: sqlite3. SQLite handles low-dozens-of-users projects without issue.
Binary install on Debian
For a non-container deploy:
FJV=10.0.0 # check codeberg.org/forgejo/forgejo/releases for current
sudo useradd -r -m -d /var/lib/forgejo -s /bin/bash forgejo
curl -L -o /usr/local/bin/forgejo \
"https://codeberg.org/forgejo/forgejo/releases/download/v${FJV}/forgejo-${FJV}-linux-amd64"
sudo chmod +x /usr/local/bin/forgejo
sudo mkdir -p /etc/forgejo
sudo chown root:forgejo /etc/forgejo
sudo chmod 770 /etc/forgejo
# Sample systemd unit at /etc/systemd/system/forgejo.service
sudo tee /etc/systemd/system/forgejo.service <<'EOF'
[Unit]
Description=Forgejo
After=network.target postgresql.service
[Service]
RestartSec=2s
Type=simple
User=forgejo
Group=forgejo
WorkingDirectory=/var/lib/forgejo
ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini
Restart=always
Environment=USER=forgejo HOME=/var/lib/forgejo GITEA_WORK_DIR=/var/lib/forgejo
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
First-run setup wizard at http://<host>:3000/ writes app.ini. After it, sudo systemctl enable --now forgejo.
Reverse proxy
# Caddy
git.example.com {
reverse_proxy 127.0.0.1:3000
}
# nginx
server {
listen 443 ssl http2;
server_name git.example.com;
# ssl_certificate / ssl_certificate_key ...
client_max_body_size 1024M;
proxy_request_buffering off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Then in app.ini → [server]: ROOT_URL = https://git.example.com/ and DOMAIN = git.example.com. Restart.
SSH access for git push/clone
Two options:
- Built-in SSH server — the Forgejo binary listens on its own SSH port (
[server] START_SSH_SERVER = true). Simplest: container exposes 2222, users dossh -p 2222 git@git.example.com, or DNS+SRV trick to make port-22 connections find it. - System sshd integration — Forgejo writes user keys into
/var/lib/forgejo/.ssh/authorized_keyswithcommand=wrappers; system sshd on port 22 routes git users through. Set[server] START_SSH_SERVER = false.
The system-sshd path is the standard for production; built-in SSH is faster for a homelab.
Forgejo Actions (GitHub-Actions-compatible CI)
Forgejo Actions reuses the GitHub Actions YAML syntax and most existing action marketplace items. The runner is a separate process (similar to GitHub's actions-runner):
# On a runner host
RV=6.0.0
curl -L -o /usr/local/bin/forgejo-runner \
"https://code.forgejo.org/forgejo/runner/releases/download/v${RV}/forgejo-runner-${RV}-linux-amd64"
sudo chmod +x /usr/local/bin/forgejo-runner
# Register with the Forgejo instance
# 1. On the Forgejo web UI: Site Admin → Runners → Create new runner → copy token
sudo forgejo-runner register \
--instance https://git.example.com \
--token <runner-token> \
--name builder-01 \
--labels docker:docker://node:20,ubuntu-22.04:docker://gitea/runner-images:ubuntu-22.04
# Run as a systemd service
sudo forgejo-runner daemon
Each repository can enable Actions in Settings → Actions, then drop a workflow file at .forgejo/workflows/ci.yaml:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm test
Most actions/* from the GitHub Actions marketplace work out of the box because Forgejo Actions reads the same workflow format and provides compatible system env vars. For actions that hit GitHub's REST API expecting github.com, there's a Forgejo-specific replacement or a tweak.
Container and package registries
Forgejo includes registries for:
- OCI / Docker images (under
git.example.com/<user>/-/packages/container/...) - npm, Maven, PyPI, RubyGems, Cargo, Composer, NuGet, Helm, Go modules
Authenticate by creating a personal access token (User Settings → Applications → Access Tokens) and use it as the password:
docker login git.example.com -u amir -p <pat>
docker tag my-app:latest git.example.com/amir/my-app:latest
docker push git.example.com/amir/my-app:latest
# npm
npm config set @amir:registry https://git.example.com/api/packages/amir/npm/
npm config set //git.example.com/api/packages/amir/npm/:_authToken <pat>
npm publish
Backups
Three sources:
- The data directory (
/datain containers,/var/lib/forgejoin binary installs) — repositories, attachments, LFS, avatars. - The database —
pg_dumpfor Postgres, file-copy for SQLite. - app.ini — configuration, JWT secrets, SECRET_KEY.
Or use the built-in dumper, which produces a single tarball with all three:
sudo -u forgejo /usr/local/bin/forgejo dump \
--config /etc/forgejo/app.ini \
--file /var/backups/forgejo-$(date +%F).zip
The output is restorable on a different Forgejo instance via forgejo restore.
Migrating from GitHub / GitLab
For each repo to import: New Repository → Migration tab → paste the source URL and credentials. Forgejo mirrors the full Git history, issues, pull requests (with comments), labels, milestones, releases, and wiki. For bulk migration, the Forgejo CLI has forgejo migrate.