PicPeak Documentation

Self-hosted webfonts

PicPeak ships with a curated set of webfonts baked into the backend image and serves them from your own origin. No requests go to fonts.googleapis.com or any third-party CDN — guest IPs stay private, which is important for GDPR compliance (LG München 2022).

The font picker in the admin theme customizer is data-driven: whatever the backend finds on disk, the picker offers. This page documents the conventions and the workflow for adding your own families.

What ships out of the box

The Docker image bundles 8 OFL-licensed families at backend/assets/fonts/:

These appear in the admin theme customizer with no configuration.

Adding your own font (drop a folder, restart)

You don't need to fork the repo. Place a font folder in your runtime storage volume — the same volume that holds events, thumbnails, etc. — and it appears in the picker after the next backend restart (or within ~30 seconds of being added, whichever comes first).

1. Choose where on the host

Bind-mount target inside the container is /app/storage/fonts/ (the env var STORAGE_PATH controls the prefix; defaults to /app/storage). On the host, that's wherever your docker-compose.yml mounts ${APP_STORAGE} from — typically ./storage/.

2. Folder layout

storage/fonts/
└── <Family-Name>/
    ├── 400.woff2
    ├── 600.woff2
    ├── 700.woff2
    └── meta.json     (optional)

Rules:

3. Where to download fonts

For Google-Fonts-licensed families, use google-webfonts-helper:

  1. Pick the family.
  2. Charsets section → Latin only (uncheck others unless you actually need them; Cyrillic alone roughly doubles file size).
  3. Styles section → 400, 600, 700 at minimum (these match what the picker uses).
  4. Click "Download files" — you'll get a ZIP containing the .woff2 files plus the family's OFL license.
  5. Rename the files to 400.woff2, 600.woff2, 700.woff2 and drop them in storage/fonts/<Family-Name>/.
  6. Keep the OFL license file alongside (the static handler serves anything in the folder, so /fonts/<Family-Name>/OFL.txt is publicly available — this satisfies OFL §2's "license must be included with all copies").

For non-Google fonts, ensure you have the right to redistribute. SIL Open Font License (OFL), Apache 2.0, and most "free for commercial use" web licenses allow this.

4. Activation

Either:

Refresh the admin customizer; the new family appears in the body and heading dropdowns.

Note: The admin customizer caches the fonts list separately for 5 minutes (React Query staleTime). After the backend picks up a new family, hard-reload the customizer page (⌘+Shift+R / Ctrl+Shift+R) to see it immediately, or wait up to 5 minutes for the frontend cache to expire on its own. The two caches serve different purposes — the backend avoids disk hits per request; the frontend avoids network hits per re-render — so we keep them independent and document the worst case rather than try to synchronise them.

How it works

Caveats and edge cases

Replacing an existing font

Browsers cache font files for up to 7 days. When you overwrite an existing weight file (e.g. swap your Inter/400.woff2 for a different cut), some visitors may keep seeing the old face for up to a week, even after a backend restart.

Two ways to roll out a replacement:

  1. Wait it out. Without immutable on the cache header, browsers send If-Modified-Since once the 7-day window expires; the backend responds based on file mtime, so the new file gets picked up automatically the next time each client revisits the gallery.
  2. Force-bust the cache by renaming the family folder. Move Inter/Inter-v2/ (with the new file inside) and update the affected event themes to use Inter v2. The new folder is served from a new URL, so caches don't apply and every client picks up the new face on next page load. This is the right approach when you need an immediate, gallery-wide rollout.

The first option is fine for cosmetic touch-ups; the second is what to do when a font replacement is genuinely urgent.

License

The bundled fonts are all SIL Open Font License v1.1 (OFL). The license text and per-font copyright notices live at backend/assets/fonts/LICENSE-OFL.txt and are publicly served at /fonts/LICENSE-OFL.txt.

If you redistribute the PicPeak Docker image, you redistribute these fonts too — you must keep the LICENSE-OFL.txt file accessible. The default static handler does this for you.

Deployed from docs/fonts.md at 2026-05-29 20:07:55 UTC.

← Back to documentation home