refactor: bundle fonts (#1569)

This commit is contained in:
Hampus
2026-08-12 13:21:50 +02:00
committed by GitHub
parent 03e6062ede
commit a9e6919713
1918 changed files with 39141 additions and 12841 deletions
+1 -70
View File
@@ -2,23 +2,6 @@
Run your own Fluxer instance with Docker Compose. This guide takes you from a fresh server to a working self-hosted instance with the web app, API, gateway, admin dashboard, media uploads, search, storage, and voice signaling behind one public hostname.
## What you'll run
The self-hosted stack is one Docker Compose project:
- **Caddy** terminates public HTTP(S) or receives traffic from a Cloudflare Tunnel.
- **App proxy** serves the Fluxer web client and injects instance bootstrap data.
- **API** handles accounts, auth, communities, messages, uploads, admin APIs, and instance discovery.
- **Admin dashboard** is required and is served at `/admin`.
- **Gateway** handles WebSocket sessions, presence, dispatch, push fanout, and realtime events.
- **Messages service** builds message responses and serves message history.
- **Media proxy** handles attachment upload relay, media metadata, thumbnails, and object reads.
- **Static proxy** serves Fluxer fonts, icons, emoji, badges, default avatars, and voice client assets from the same hostname.
- **LiveKit** handles voice and video signaling and WebRTC media.
- **Postgres**, **Valkey**, **NATS**, **Meilisearch**, and **SeaweedFS** provide data, cache, events, search, and S3-compatible object storage.
The app bundle is served by the self-host app-proxy image; shared static assets are served by the standalone `static-proxy` container. The stack does not depend on Fluxer's public static asset host.
## Requirements
- A Linux server or VM that can run Docker Engine.
@@ -204,59 +187,7 @@ docker compose logs -f api
The first start can take several minutes while images download and services initialize. `seaweedfs-init` exits after creating object-storage buckets; that is expected.
## Step 7: Verify the instance
Set your domain in the shell:
```bash
export FLUXER_DOMAIN=chat.example.com
```
Check every public HTTP entry point:
```bash
for path in /_health /api/_health /gateway/_health /media/_health /admin/_health; do
curl -fsS -o /tmp/fluxer-check -w "$path %{http_code}\n" "https://$FLUXER_DOMAIN$path"
done
```
Expected result:
```text
/_health 200
/api/_health 200
/gateway/_health 200
/media/_health 200
/admin/_health 200
```
Check instance discovery:
```bash
curl -fsS "https://$FLUXER_DOMAIN/api/.well-known/fluxer" | jq '.features.self_hosted, .endpoints.admin, .endpoints.gateway, .endpoints.media, .endpoints.static_cdn'
```
You should see `true`, an admin URL ending in `/admin`, a gateway URL ending in `/gateway`, a media URL ending in `/media`, and a static asset URL equal to the instance origin.
Check the web app, admin login page, app bundle, and static asset container:
```bash
curl -fsSI "https://$FLUXER_DOMAIN" | sed -n '1,8p'
curl -fsSI "https://$FLUXER_DOMAIN/admin/login" | sed -n '1,8p'
asset=$(curl -fsS "https://$FLUXER_DOMAIN" | grep -o 'src="[^"]*/assets/[^"]*"' | head -n1 | cut -d'"' -f2)
case "$asset" in
http*) curl -fsSI "$asset" | sed -n '1,8p' ;;
/*) curl -fsSI "https://$FLUXER_DOMAIN$asset" | sed -n '1,8p' ;;
esac
curl -fsSI "https://$FLUXER_DOMAIN/fonts/ibm-plex.css?v=3" | sed -n '1,8p'
curl -fsSI "https://$FLUXER_DOMAIN/web/favicon-32x32.png" | sed -n '1,8p'
```
If you are using Cloudflare Tunnel and see HTTP `530`, the tunnel connector is not currently connected or the public hostname route points at the wrong service.
## Step 8: Create the owner account
## Step 7: Create the owner account
Open the web app:
+10 -4
View File
@@ -1,8 +1,14 @@
:root {
--md-text-font: 'Fluxer Sans';
--md-code-font: 'Fluxer Mono';
--fluxer-display: 'Bricolage Grotesque', var(--md-text-font-family);
body {
--md-text-font-family:
system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--md-code-font-family:
ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', 'Roboto Mono', 'Courier New', monospace;
--fluxer-display: var(--md-text-font-family);
}
:root {
--md-primary-fg-color: #4641d9;
--md-primary-fg-color--light: #5b56e0;
--md-primary-fg-color--dark: #3832b8;
+7 -1
View File
@@ -22,12 +22,18 @@ server {
internal;
}
location ~* \.(?:css|js|mjs|svg|png|jpg|jpeg|gif|webp|avif|ico|woff2?)$ {
location ^~ /assets/ {
try_files $uri =404;
include /etc/nginx/conf.d/security-headers.conf;
add_header Cache-Control "public, max-age=31536000, immutable" always;
}
location ~* \.(?:css|js|mjs|svg|png|jpg|jpeg|gif|webp|avif|ico)$ {
try_files $uri =404;
include /etc/nginx/conf.d/security-headers.conf;
add_header Cache-Control "public, max-age=3600, must-revalidate" always;
}
location / {
try_files $uri $uri/ =404;
}
+3 -5
View File
@@ -16,9 +16,7 @@ class InlineScriptParser(html.parser.HTMLParser):
self._parts: list[str] = []
self.scripts: list[str] = []
def handle_starttag(
self, tag: str, attrs: list[tuple[str, str | None]]
) -> None:
def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
if tag.lower() != "script":
return
if any(name.lower() == "src" for name, _ in attrs):
@@ -63,9 +61,9 @@ def main() -> None:
[
"default-src 'self'",
f"script-src 'self' {script_sources}",
"style-src 'self' 'unsafe-inline' https://fluxerstatic.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"font-src 'self' data: https://fluxerstatic.com",
"font-src 'none'",
"connect-src 'self' https://api.github.com",
"worker-src 'self'",
"frame-src 'none'",
+1 -2
View File
@@ -105,8 +105,6 @@ nav = [
# Read more: https://zensical.org/docs/customization/#additional-css
#
extra_css = [
"https://fluxerstatic.com/fonts/ibm-plex.css?v=3",
"https://fluxerstatic.com/fonts/bricolage.css?v=3",
"stylesheets/fluxer.css",
]
@@ -145,6 +143,7 @@ extra_css = [
# - https://developer.mozilla.org/en-US/docs/Glossary/Favicon
#
favicon = "assets/favicon.svg"
font = false
# Zensical supports more than 60 different languages. This means that the