---
okf: "0.1"
type: decision
visibility: private
status: active
updated: 2026-07-09
links:
  - ../services/gokapi.md
  - ../runbooks/gokapi-cutover.md
---

# Gokapi — decyzje: storage, szyfrowanie E2E, siec

## Storage — lokalny dysk VPS (nie S3)

Decyzja Oskara: bez S3, dysk lokalny VPS. VPS ma tylko 80 GB SSD dzielone z
npm/outline/joplin/ai-cluster/fleet-prometheus — więc **ograniczenia
rozmiaru + brak globalnego domyślnego expiry to jedyna ochrona dysku**:

- `GOKAPI_MAX_FILESIZE=5120` (5 GB/plik; upstream default to 100 GB — za
  dużo na ten dysk).
- `GOKAPI_MIN_FREE_SPACE=2048` (2 GB headroom zanim Gokapi odmówi uploadu;
  upstream default 400 MB, za mało przy dzielonym dysku).
- **Gokapi NIE MA globalnego domyślnego expiry/limitu pobrań** — to wybór
  per-upload w formularzu web. Nie da się tego wymusić przez env var ani
  config. Praktyka: przy każdym uploadzie ustawiać rozsądne wartości (np.
  **7 dni / 10 pobrań**), żeby wygasające linki faktycznie czyściły dysk.

## Szyfrowanie E2E — WŁĄCZONE (decyzja Oskara)

Gokapi ma 3 poziomy szyfrowania (żaden / lokalny / **end-to-end**). Wybór
robi się w kroku "Encryption" wizardu `/setup` przy pierwszym starcie — nie
ma env vara. Level 3 (E2E) = plik szyfrowany w przeglądarce przed uploadem,
serwer nigdy nie widzi treści w plaintext. Uwaga upstream: implementacja
szyfrowania nie była niezależnie audytowana; Firefox ma problemy z
pobieraniem zaszyfrowanych plików (znane ograniczenie, nie nasz bug).

Klucz szyfrowania trafia do `config.json` w `/app/config` — **to jest część,
którą trzeba backupować**, inaczej utrata configu = utrata dostępu do już
zaszyfrowanych plików.

## Sieć — bind tylko na Tailscale, nigdy 0.0.0.0

Port 53842 binduje się **wyłącznie** na Tailscale IP VPS-a
(`TAILSCALE_BIND_IP=100.95.58.48`), nigdy na `0.0.0.0`. Publiczny adres
Hetznera (`135.181.153.108`) w ogóle nie widzi tego portu — jedyna droga na
zewnątrz to `npm@VPS` (TLS na 443) → `share.okit.pl`. npm i gokapi żyją na
tym samym hoście jako osobne stacki compose; npm dociera do gokapi przez
Docker hairpin NAT po tym samym realnym interfejsie (ten sam trik co
`fleet-prometheus`/`nextcloud` — `127.0.0.1` by tu NIE zadziałało).
`GOKAPI_TRUSTED_PROXIES=172.16.0.0/12` mówi Gokapi, żeby ufał
`X-Forwarded-For` z tego zakresu (podsieć mostka Docker), bo źródłowy IP po
hairpinie to brama bridge'a, nie prawdziwy klient.

