- Shell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| infra | ||
| .env.example | ||
| .gitignore | ||
| install.sh | ||
| README.md | ||
| TODO.md | ||
Infrastruktur DevOps — bitbox.id
Ringkasan (rangkuman) infrastruktur DevOps yang menjalankan layanan Bitbox: reverse proxy, identitas (IAM), Git hosting, dan mail server. Semua layanan berjalan sebagai container Podman di dalam satu VM Proxmox.
⚠️ Catatan: seluruh kredensial (password, master key, secret, token, OAuth client secret) disunting/redacted dalam dokumen ini. Dokumen ini untuk dokumentasi arsitektur, bukan untuk menyimpan rahasia.
1. Ringkasan
| Aspek | Nilai |
|---|---|
| Host fisik | Proxmox VE (cluster Prox-P1337-A/B/D) |
| Node | Prox-P1337-B |
| VM | 1030 — nama dev.bitbox.id |
| OS VM | Debian GNU/Linux 13 (trixie), kernel 6.12 |
| Spesifikasi VM | 4 vCPU · 8 GB RAM · 60 GB disk |
| IP publik | 103.176.77.13/29 (gw 103.176.77.9) |
| Container runtime | Podman 5.4.2 (rootful) |
| Orkestrasi | systemd Quadlet (/etc/containers/systemd/*.container) |
| Jaringan container | Podman network bitbox — 10.89.0.0/24 |
| Reverse proxy / TLS | Caddy 2.11.7 + auto-HTTPS Let's Encrypt |
| IAM / SSO | Zitadel v4.19.4 |
| Git hosting | Forgejo 16.0.5 |
| Mail server | Stalwart v0.16.25 + Bulwark Webmail 1.13.0 |
| Database | PostgreSQL 17.11 (khusus Zitadel) |
2. Arsitektur Keseluruhan
graph TB
Internet([Internet])
subgraph PVE["Proxmox VE — node Prox-P1337-B"]
subgraph VM["VM 1030 · dev.bitbox.id · Debian 13"]
subgraph Net["podman network: bitbox (10.89.0.0/24)"]
Caddy["caddy<br/>:80 :443"]
Forgejo["forgejo<br/>:2222 :3000"]
ZitadelAPI["zitadel-api<br/>:8080"]
ZitadelLogin["zitadel-login<br/>:3000"]
Stalwart["stalwart<br/>:25 :465 :587 :993 :995 :4190 :8080"]
Bulwark["bulwark<br/>:3000"]
Postgres[("postgres<br/>:5432")]
end
end
end
Internet -->|80/443| Caddy
Internet -->|25/465/587/993/995/4190| Stalwart
Internet -->|2222| Forgejo
Caddy --> Forgejo
Caddy --> ZitadelLogin
Caddy --> ZitadelAPI
Caddy --> Stalwart
Caddy --> Bulwark
ZitadelAPI --> Postgres
ZitadelLogin --> ZitadelAPI
Bulwark -->|OIDC| ZitadelAPI
Forgejo -->|OIDC SSO| ZitadelAPI
Poin penting:
- Hanya Caddy (80/443), Stalwart (port mail), dan Forgejo (SSH 2222) yang mengekspos port ke host/publik.
- Container lain (
zitadel-api,zitadel-login,bulwark,postgres) hanya bisa diakses internal lewat networkbitbox. - Semua service dijalankan otomatis oleh systemd melalui Quadlet (
.container→ unit systemd saat boot).
3. Alur Request (Routing Caddy)
flowchart LR
U([Pengguna / Browser]) -->|HTTPS :443| C{{Caddy}}
U -->|SMTP/IMAP :25/465/587/993| S[stalwart]
C -->|auth.bitbox.id<br/>/ & /ui/v2/login| ZL[zitadel-login :3000]
C -->|auth.bitbox.id<br/>/api, /oidc, /oauth| ZA[zitadel-api :8080]
C -->|dev.bitbox.id| F[forgejo :3000]
C -->|mail/imap/smtp/autodiscover<br/>/jmap, /.well-known/jmap| S[stalwart :8080]
C -->|mail.bitbox.id webmail| B[bulwark :3000]
C -->|mailops.bitbox.id admin| S
ZA <-->|SQL| PG[(postgres :5432)]
B -->|Login SSO OIDC| ZA
F -->|Login SSO OIDC| ZA
Domain & virtual host
| Domain | Diarahkan ke | Fungsi |
|---|---|---|
auth.bitbox.id |
zitadel-login + zitadel-api |
Login SSO / IAM (UI v2) |
dev.bitbox.id |
forgejo |
Git hosting (web + API) |
mail.bitbox.id, imap.bitbox.id, smtp.bitbox.id, autodiscover.bitbox.id |
bulwark (webmail) & stalwart (JMAP/autoconfig) |
Webmail + protokol mail |
mailops.bitbox.id |
stalwart |
Panel admin Stalwart |
3.1 Alur Login SSO (OIDC)
Forgejo dan Bulwark tidak punya login lokal — keduanya memakai Zitadel sebagai Identity Provider (Authorization Code Flow).
sequenceDiagram
autonumber
actor U as Pengguna
participant B as Browser
participant A as App (Forgejo / Bulwark)
participant ZL as Zitadel Login (UI v2)
participant ZA as Zitadel API
U->>B: Buka https://dev.bitbox.id
B->>A: GET /
A-->>B: 302 redirect ke auth.bitbox.id (OIDC authorize)
B->>ZA: GET /oauth/v2/authorize
ZA-->>B: redirect ke /ui/v2/login
B->>ZL: Halaman login Zitadel
U->>ZL: Kredensial (+ MFA bila aktif)
ZL->>ZA: Verifikasi & buat authRequest
ZA-->>B: redirect balik ke App dengan ?code=...
B->>A: GET /user/oauth2/zitadel/callback?code=...
A->>ZA: POST /oauth/v2/token (tukar code)
ZA-->>A: access_token + userinfo
A-->>B: Buat sesi login, tampilkan dashboard
4. Podman & Quadlet
Runtime memakai Podman dengan pendekatan Quadlet: file unit di /etc/containers/systemd/ dikonversi menjadi service systemd secara otomatis.
/etc/containers/systemd/
├── bitbox.network # network bridge "bitbox" (10.89.0.0/24)
├── bitbox-caddy.container
├── bitbox-forgejo.container
├── bitbox-postgres.container
├── bitbox-zitadel-api.container
├── bitbox-zitadel-login.container
├── bitbox-stalwart.container
└── bitbox-bulwark.container
Systemd unit yang aktif:
bitbox-network.service (exited) network dibuat
bitbox-postgres.service running PostgreSQL (DB Zitadel)
bitbox-caddy.service running Reverse proxy + TLS
bitbox-zitadel-api.service running Zitadel API
bitbox-zitadel-login.service running Zitadel Login UI v2
bitbox-forgejo.service running Forgejo
bitbox-stalwart.service running Mail server
bitbox-bulwark.service running Webmail
Mengelola service:
systemctl status|restart bitbox-<nama>(bukanpodman runmanual).
📁 Salinan file konfigurasi asli (unit systemd/Quadlet,
Caddyfile, config Stalwart) tersedia di folderinfra/— rahasia sudah disensor menjadi placeholder. Deploy otomatis denganinstall.sh.
5. Daftar Container
| Container | Image | Port host | Volume | Peran |
|---|---|---|---|---|
caddy |
docker.io/library/caddy:2 |
80, 443/tcp, 443/udp |
bitbox_caddy-data, bitbox_caddy-config (+ /srv/bitbox/Caddyfile) |
Reverse proxy & TLS otomatis |
postgres |
docker.io/library/postgres:17-alpine |
internal 5432 |
bitbox_pgdata |
Database Zitadel |
zitadel-api |
ghcr.io/zitadel/zitadel:v4.19.4 |
internal 8080 |
bitbox_zitadel-bootstrap |
IAM / OIDC / OAuth2 API |
zitadel-login |
ghcr.io/zitadel/zitadel-login:v4.19.4 |
internal 3000 |
bitbox_zitadel-bootstrap (ro) |
UI login Zitadel v2 |
forgejo |
code.forgejo.org/forgejo/forgejo:16 |
2222 (SSH), internal 3000 |
bitbox_forgejo-data |
Git hosting (web/API/SSH) |
stalwart |
docker.io/stalwartlabs/stalwart:v0.16.25 |
25, 465, 587, 993, 995, 4190, internal 8080 |
bitbox_stalwart-data (+ /srv/bitbox/stalwart/etc) |
Mail server (SMTP/IMAP/POP3/JMAP/managesieve) |
bulwark |
ghcr.io/bulwarkmail/webmail:1.13.0 |
internal 3000 |
bitbox_bulwark-{settings,config,state,telemetry} |
Webmail (login via Zitadel OIDC) |
Volume Podman (data persisten):
bitbox_caddy-data bitbox_zitadel-bootstrap
bitbox_caddy-config bitbox_stalwart-data
bitbox_forgejo-data bitbox_bulwark-settings
bitbox_pgdata bitbox_bulwark-config
bitbox_bulwark-state
bitbox_bulwark-telemetry
6. Detail Layanan
6.1 Caddy — Reverse Proxy & TLS
- Image
caddy:2(v2.11.7), config:/srv/bitbox/Caddyfile(mount read-only). - Sertifikat Let's Encrypt di-issue & diperbarui otomatis untuk semua vhost.
- Menangani
encode zstd gzip, HSTS/redirect HTTPS, dan routing per-domain (lihat §3). - Zitadel API diproksikan via h2c (HTTP/2 cleartext) ke
zitadel-api:8080.
6.2 Zitadel — IAM / SSO
- Dua container:
zitadel-api(backend) danzitadel-login(UI v2). Database: PostgreSQL. - Mode
start-from-init(first-instance di-bootstrap otomatis: org, admin, service account, login client). - Login UI v2 aktif (
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED=true, base URIhttps://auth.bitbox.id/ui/v2/login/). - OIDC discovery:
https://auth.bitbox.id/.well-known/openid-configuration. - Dipakai sebagai Identity Provider untuk Forgejo dan Bulwark (auto-registrasi user).
6.3 Forgejo — Git Hosting
- Image
forgejo:16(v16.0.5+gitea-1.22.0), URLhttps://dev.bitbox.id/. - Git SSH di port 2222, dengan SSH server bawaan (
START_SSH_SERVER=true). - Database internal SQLite (
/data/gitea/gitea.db) — terpisah dari PostgreSQL Zitadel. INSTALL_LOCK=true, registrasi mandiri dimatikan (DISABLE_REGISTRATION=true); user dibuat via SSO OAuth2 Zitadel.- Mendukung LFS (
LFS_START_SERVER=true).
6.4 Mail Server — Stalwart + Bulwark
graph LR
subgraph Mail["Layanan Mail bitbox.id"]
MX["MX 10 mail.bitbox.id"] --> S["stalwart"]
S -->|SMTP 25/587/465| Ext[(Internet)]
S -->|IMAP 993 / POP3 995| Clients([Mail client])
S -->|JMAP + Webmail| B["bulwark :3000"]
Admin([Admin]) -->|mailops.bitbox.id| S
end
B -->|SSO OIDC| Z["zitadel (auth.bitbox.id)"]
- Stalwart
v0.16.25: server mail all-in-one (SMTP25/465/587, IMAPS993, POP3S995, ManageSieve4190, JMAP/admin8080). Config & sertifikat di/srv/bitbox/stalwart/{etc,cert}. - Bulwark Webmail
1.13.0: webmail modern, login hanya via OIDC (OAUTH_ONLY=truekehttps://auth.bitbox.id), berbicara ke Stalwart lewat JMAP. - DNS mail: MX
10 mail.bitbox.id; DMARCp=quarantine(adkim=s; aspf=s), laporan kedmarc@bitbox.id.
6.5 PostgreSQL
postgres:17-alpine(PostgreSQL 17.11), databasezitadel, healthcheckpg_isready.- Hanya melayani Zitadel; Forgejo memakai SQLite.
7. Port & Jaringan
Port terbuka di host (VM):
| Port | Protokol | Dibelakang layar |
|---|---|---|
| 22 | TCP | sshd (admin, key-only) |
| 80, 443 | TCP/UDP | Caddy |
| 25, 465, 587 | TCP | Stalwart (SMTP submission/relay) |
| 993 | TCP | Stalwart (IMAPS) |
| 995 | TCP | Stalwart (POP3S) |
| 4190 | TCP | Stalwart (ManageSieve) |
| 2222 | TCP | Forgejo (Git over SSH) |
Port internal saja (tidak dipublikasikan): 5432 (postgres), 8080 (zitadel-api & stalwart admin), 3000 (forgejo, zitadel-login, bulwark).
Zona jaringan: VM di
vmbr1700Proxmox dengan IP publik103.176.77.13/29; container saling terhubung di bridge Podmanbitbox(10.89.0.0/24).
8. DNS & TLS
| Nama | Tipe | Target |
|---|---|---|
dev.bitbox.id |
A | 103.176.77.13 |
auth.bitbox.id |
A | 103.176.77.13 |
mail.bitbox.id |
A / MX | 103.176.77.13 / prio 10 |
smtp.bitbox.id, imap.bitbox.id |
A | 103.176.77.13 |
bitbox.id |
A | 103.55.39.179 |
- TLS: Let's Encrypt (Caddy), berlaku ±3 bulan, auto-renew.
- DMARC:
v=DMARC1; p=quarantine; adkim=s; aspf=s; rua=mailto:dmarc@bitbox.id; ruf=mailto:dmarc-fail@bitbox.id.
9. Data Persisten & Backup
- Seluruh state disimpan di Podman volume (
bitbox_*) dan dua bind-mount:/srv/bitbox/Caddyfile(konfigurasi Caddy)/srv/bitbox/stalwart/{etc,cert}(konfigurasi & sertifikat mail)
- Backup penting:
bitbox_pgdata(Zitadel),bitbox_forgejo-data(repo Git),bitbox_stalwart-data+stalwart/etc(mail),bitbox_caddy-data(sertifikat).
9.0 Topologi Volume
graph LR
subgraph VOL["Podman Volume — data persisten"]
V1[("bitbox_pgdata<br/>DB Zitadel")]
V2[("bitbox_zitadel-bootstrap<br/>PAT & admin seed")]
V3[("bitbox_forgejo-data<br/>repo Git + SQLite")]
V4[("bitbox_stalwart-data<br/>mail + kredensial")]
V5[("bitbox_caddy-data<br/>sertifikat TLS")]
V6[("bitbox_caddy-config<br/>config runtime")]
V7[("bitbox_bulwark-settings")]
V8[("bitbox_bulwark-config")]
V9[("bitbox_bulwark-state")]
V10[("bitbox_bulwark-telemetry")]
end
subgraph BIND["Bind mount — file di host"]
B1["/srv/bitbox/Caddyfile"]
B2["/srv/bitbox/stalwart/etc"]
B3["/srv/bitbox/stalwart/cert"]
end
PG["postgres"] --> V1
ZA["zitadel-api"] --> V2
ZL["zitadel-login"] -.ro.-> V2
FJ["forgejo"] --> V3
ST["stalwart"] --> V4
ST --> B2
ST -.ro.-> B3
CA["caddy"] --> V5
CA --> V6
CA -.ro.-> B1
BU["bulwark"] --> V7
BU --> V8
BU --> V9
BU --> V10
| Volume | Dipakai oleh | Isi | Prioritas backup |
|---|---|---|---|
bitbox_pgdata |
postgres | Database Zitadel | 🔴 Tinggi |
bitbox_forgejo-data |
forgejo | Repo Git, gitea.db, LFS |
🔴 Tinggi |
bitbox_stalwart-data |
stalwart | Mail, akun, DKIM | 🔴 Tinggi |
bitbox_caddy-data |
caddy | Sertifikat & akun ACME | 🟡 Sedang |
bitbox_caddy-config |
caddy | Config runtime Caddy | 🟡 Sedang |
bitbox_zitadel-bootstrap |
zitadel-api/-login | PAT & seed admin | 🟡 Sedang |
bitbox_bulwark-* (4) |
bulwark | Settings, config, state, telemetry | 🟢 Rendah |
9.1 Backup
# 1) Dump database Zitadel (konsisten, tanpa mematikan service)
podman exec postgres pg_dump -U postgres zitadel | gzip > zitadel-$(date +%F).sql.gz
# 2) Backup Forgejo (database + repo + konfigurasi)
podman exec -u git forgejo forgejo dump -c /data/gitea/conf/app.ini -f /data/dump.zip
# 3) Arsipkan volume Podman (tar) + bind-mount
podman volume export bitbox_forgejo-data > forgejo-data.tar
podman volume export bitbox_stalwart-data > stalwart-data.tar
tar czf bitbox-config.tar.gz -C /srv bitbox/Caddyfile bitbox/stalwart/etc bitbox/.env
9.2 Restore
# 1) Pulihkan volume dari tar
podman volume create bitbox_forgejo-data
podman volume import bitbox_forgejo-data forgejo-data.tar
# 2) Pulihkan database
gunzip -c zitadel-2026-01-01.sql.gz | podman exec -i postgres psql -U postgres -d zitadel
# 3) Pulihkan konfigurasi & secret
tar xzf bitbox-config.tar.gz -C /srv
# 4) Mulai ulang seluruh stack
systemctl restart bitbox-postgres bitbox-zitadel-api bitbox-zitadel-login \
bitbox-forgejo bitbox-stalwart bitbox-bulwark bitbox-caddy
Untuk lingkungan baru, salin
.env.example→/srv/bitbox/.envlalu isi nilai asli sebelum menjalankan stack (lihat §10).
10. Catatan Keamanan
- Registrasi publik dimatikan di Forgejo dan Zitadel; akun via SSO/invite.
- SSH host:
PasswordAuthentication no(hanya public key). - Secret disimpan di:
/srv/bitbox/.env(master key Zitadel, password Postgres, ACME email, admin Zitadel) — template tersedia di.env.example,- environment Quadlet tiap container,
- dan di-redact pada dokumen ini.
- Jangan commit
.envasli..env.examplehanya berisi placeholder non-produksi. - Rekomendasi: rotasi kredensial yang pernah terekspos, dan simpan secret di manajer rahasia (mis. Podman secrets / SOPS / Vault), bukan langsung di file
.container.
11. Roadmap & TODO
Analisis celah terhadap praktik DevOps profesional (HA, backup teruji, secret manager, observability, IaC/CI-CD, hardening) ada di:
- 📋
TODO.md— daftar per prioritas (P0/P1/P2) - 🐞 Issues Forgejo — tiap item dengan label
area/*&priority/*
Ringkasan gap utama:
| Aspek | Kondisi sekarang | Target profesional |
|---|---|---|
| Availability | 1 VM, semua layanan (SPOF) | HA / pemisahan peran + failover |
| Backup | belum otomatis/teruji | 3-2-1 + uji restore + PITR |
| Secret | inline & plaintext | secret manager + rotasi |
| Observability | tidak ada | metrik + log + alert |
| Keamanan | firewall/fail2ban belum | default-deny + fail2ban/WAF |
| Rilis | manual | IaC + CI/CD + staging |
| Docs/Proses | README saja | runbook + RPO/RTO + review |
Dokumen ini dihasilkan dari inspeksi langsung VM dev.bitbox.id (Proxmox VM 1030) melalui QEMU guest agent. Jangan mempublikasikan berkas ini bersama kredensial asli.