mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-03 05:10:25 +03:00
refactor: bundle fonts (#1569)
This commit is contained in:
@@ -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:
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user