Ingen beskrivning
  • Jinja 34.2%
  • Python 21.4%
  • HCL 20.9%
  • Shell 11.8%
  • Makefile 11%
  • Övrigt 0.7%
Hitta en fil
2026-06-15 14:30:30 +02:00
.vscode fix: restart web app after deploy 2026-06-15 09:22:59 +02:00
ansible refactor: allow login with gitborg auth 2026-06-15 14:19:13 +02:00
cost feat: add cost control measurements 2026-06-10 22:40:17 +02:00
docs docs: update architecture diagram 2026-06-15 14:30:30 +02:00
local fix: adjustments for first deploy 2026-06-15 08:42:36 +02:00
opentofu fix: adjustments for first deploy 2026-06-15 08:42:36 +02:00
scripts fix: restart web app after deploy 2026-06-15 09:22:59 +02:00
.editorconfig chore: initial commit 2026-06-10 21:00:18 +02:00
.gitignore fix: restart web app after deploy 2026-06-15 09:22:59 +02:00
README.md docs: update architecture diagram 2026-06-15 14:30:30 +02:00

gitborg-infra

Infrastructure-as-code and decision record for gitborg, a self-hosted git hosting service built on Forgejo and running on Bahnhof Cloud (Swedish, GDPR-focused).

This repository is intended to eventually be hosted on gitborg itself — the service hosts its own infrastructure code.

Guiding principles

gitborg is built, in priority order, to be:

  1. Owned, operated and hosted in Sweden — Swedish-owned, Swedish-operated, on Swedish soil. Users' code never passes through US-owned or US-operated infrastructure (beyond reach of the US CLOUD Act).
  2. Respectful of user integrity — GDPR and other EU/EEA data-protection law today, and built to adapt to future regulation.
  3. Free and open source — a fully FOSS stack, preferring the freer alternative (copyleft, community/non-profit governance) when options are comparable.
  4. Secure with users' data — minimal attack surface, least privilege, secrets never in plaintext, encrypted backups and tested restores.

These take precedence over convenience and govern every decision in this repo. See docs/principles.md for what each means concretely and how the stack embodies them.

What this is

A single instance on Bahnhof's OpenStack VPC runs Forgejo + PostgreSQL + Kanidm (identity provider) + the public portal (gitborg-web) as rootless Podman containers managed by Quadlet (systemd), fronted by Caddy for automatic TLS across four hosts. The instance is provisioned with OpenTofu and configured with Ansible. Backups run on systemd timers as encrypted archives kept on the host, with optional off-site upload to Bahnhof S3 (off by default — S3 isn't available at first deploy).

flowchart LR
    Internet([Internet])
    Admin([Admin])

    Internet -->|"gitborg.se :443"| Caddy
    Internet -->|"www :443"| Caddy
    Internet -->|"git :443"| Caddy
    Internet -->|"auth :443"| Caddy
    Internet -->|":22 git SSH"| Forgejo["Forgejo<br/>:3000 + SSH"]
    Admin -->|":2222"| SSHD["admin sshd"]
    Caddy -->|"apex → 308 www"| Caddy
    Caddy -->|www| Web["gitborg-web<br/>Astro"]
    Caddy -->|git| Forgejo
    Caddy -->|"auth (re-encrypt)"| Kanidm["Kanidm<br/>OIDC IdP :8443"]
    Web --> Forgejo
    Forgejo -.->|"OIDC login"| Kanidm
    Web --> Postgres[("PostgreSQL")]
    Forgejo --> Postgres
    Forgejo -.-> Timers["systemd timers"]
    Timers --> Local["Encrypted backups<br/>(local)"]
    Local -. optional .-> S3[("Bahnhof S3")]

Layout

Path Purpose
docs/principles.md Guiding principles that govern every decision
docs/architecture.md Component overview and how they fit together
docs/runbook.md Operations: deploy, upgrade, restore, rotate secrets
docs/roadmap.md Planned growth: HA, Forgejo Actions, off-site backups
docs/decisions/ Architecture Decision Records (ADRs)
ansible/ All host provisioning and service configuration
opentofu/ OpenTofu config to provision the host on OpenStack
cost/ Bahnhof unit prices + gathered usage samples
scripts/ Cost audit/30-day projection and complete teardown
local/ Podman preview of Forgejo config/branding (no cloud)

Quickstart

Prerequisites: a Bahnhof OpenStack project with clouds.yaml configured, OpenTofu and Ansible installed locally, and the ansible-vault password for the encrypted secrets. The image is Debian 13 (trixie)+ (needs Podman ≥ 4.4 for Quadlet) — already the default in the OpenTofu config.

# 1. Provision the instance on Bahnhof OpenStack
cd opentofu
cp terraform.tfvars.example terraform.tfvars        # set ssh_public_key
tofu init && tofu apply                             # outputs the floating IP

# 2. Configure it (copy the floating IP into the inventory first)
cd ../ansible
ansible-galaxy install -r requirements.yml          # install collections
# set the floating IP in inventory/hosts.yml and your domain in group_vars/all/vars.yml
ansible-playbook site.yml -e ansible_port=22        # first run: sshd still on 22 (ADR 0006)
ansible-playbook site.yml                           # subsequent runs use 2222

Then complete Forgejo first-run (create admin, lock down registration) per docs/runbook.md.

To preview configuration and branding changes locally — no cloud resources or vault needed: cd local && make up (see local/README.md).

Decisions at a glance

Area Choice
Hosting Bahnhof OpenStack VPC (OpenTofu)
Container runtime Podman + Quadlet (systemd)
Config management Ansible
Database PostgreSQL (container)
Reverse proxy / TLS Caddy (automatic HTTPS, Let's Encrypt)
Identity / SSO Kanidm (OIDC) on auth; group→role mapping (ADR 0014)
Public portal gitborg-web (Astro) on www; invite sign-up
Email (deferred) Sweego (EU); newsletter + verification

See docs/decisions/ for the full reasoning behind each.