Skip to main content
Fluxer is designed as a modular platform that can run as a single monolith or scale to a distributed microservices architecture. This guide explains the system components and how they interact.

Deployment Modes

Fluxer supports two deployment architectures:

Core Components

HTTP Services (Node.js + Hono)

All HTTP-based services are built with TypeScript, Node.js, and the Hono web framework.
Package: fluxer_api
Purpose: REST API for all application logic
Handles:
  • User authentication and registration
  • Guild (community) and channel management
  • Message creation and history
  • File uploads and CDN operations
  • Search indexing
  • Admin operations
Endpoints:
  • /api/v1/* - Public REST API
  • /_health - Health check endpoint
Port: 8080 (default in monolith)
Package: fluxer_media_proxy
Purpose: Image and video processing, CDN proxying
Features:
  • Dynamic image resizing and optimization
  • Video thumbnail generation (ffmpeg)
  • Signed URL verification
  • Optional NSFW detection (ONNX model)
  • External URL proxying with caching
Port: 8080/media (monolith) or dedicated port
Package: fluxer_admin
Purpose: Web-based administration interface
Features:
  • User management and moderation
  • Guild administration
  • System configuration
  • LiveKit voice region management
  • Analytics dashboard
Endpoint: /admin (monolith) or dedicated service
Authentication: OAuth2 with session tokens
Package: fluxer_marketing
Purpose: Optional public landing page
Features:
  • Instance homepage
  • Public guild directory
  • Terms of service and privacy policy
Endpoint: /marketing or root path
Can be disabled in configuration.
Package: @fluxer/s3
Purpose: S3-compatible object storage
Built-in filesystem-backed S3 implementation for self-hosted deployments. Supports:
  • Multipart uploads
  • Presigned URLs
  • Bucket management
  • Compatible with AWS SDK clients
Endpoint: /s3 (monolith)
Can be replaced with external S3 (AWS, MinIO, Garage, etc.).
Package: @fluxer/queue
Purpose: Background job processing
Handles:
  • Email delivery
  • Search indexing
  • Image processing jobs
  • Data exports
  • Scheduled tasks
Uses NATS JetStream in microservices mode, or in-process queue in monolith.

WebSocket Gateway (Erlang/OTP)

Package: fluxer_gateway
Language: Erlang/OTP
Purpose: Real-time WebSocket connections and message routing

Why Erlang?

Erlang excels at managing millions of concurrent connections with minimal resource overhead. The BEAM VM provides:
  • Lightweight processes - Each WebSocket connection runs in an isolated Erlang process
  • Hot code reloading - Update gateway code without disconnecting users
  • Fault tolerance - Supervisor trees automatically restart failed connections
  • Built-in distribution - Native clustering across multiple nodes
Gateway Responsibilities:
  • Connection management - Handles WebSocket lifecycle (identify, resume, heartbeat)
  • Message routing - Delivers events to connected clients
  • Presence tracking - Maintains online/offline status and activity
  • Push notifications - Sends Web Push to offline users
  • Rate limiting - Per-connection and per-user limits
Configuration:
"services": {
  "gateway": {
    "port": 8082,
    "presence_shards": 4,
    "guild_shards": 4,
    "push_enabled": true
  }
}
Sharding allows distributing load across multiple Erlang processes. Increase shard counts for high-concurrency deployments.

Frontend Application (React + Electron)

Package: fluxer_app
Technologies: React, TypeScript, Rust (WASM), Vite
The web and desktop clients are built from the same React codebase:
  • Web App - Served at / by fluxer_server
  • Desktop App - Electron wrapper with native OS integration
Rust WebAssembly Modules:
  • Voice codec processing (Opus)
  • Encryption primitives
  • Performance-critical operations
The compiled app is included in the fluxer_server Docker image at /usr/src/app/assets.

Data Layer

Database Options

Best for: Single-node deployments, < 10,000 usersFluxer uses SQLite in WAL mode with optimizations:
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -64000;  -- 64MB cache
PRAGMA busy_timeout = 5000;
File Location: Configured in database.sqlite_path
Backups: Simple file copy (use PRAGMA wal_checkpoint(TRUNCATE) first)
Limitations:
  • Single-writer (multiple readers OK)
  • No geographic replication
  • Limited to single server’s disk I/O

Caching & Coordination (Valkey/Redis)

Image: valkey/valkey:8.0.6-alpine
Purpose: High-speed cache and distributed coordination
Use cases:
  • Session storage
  • Rate limiting counters
  • Cached API responses
  • Distributed locks
  • Ephemeral data (typing indicators, presence)
Deployment:
services:
  valkey:
    image: valkey/valkey:8.0.6-alpine
    command: [
      'valkey-server',
      '--appendonly', 'yes',
      '--save', '60', '1'
    ]
    volumes:
      - valkey_data:/data
For high availability, deploy Redis Cluster or use managed Redis (AWS ElastiCache, etc.).

Search Engines

Fluxer supports two search backends: Indexed content:
  • Messages (with filters for channels, authors, dates)
  • Guilds (for discovery)
  • Users (for mentions and DMs)

Voice & Video Infrastructure

LiveKit SFU

Image: livekit/livekit-server:v1.9.11
Purpose: Selective Forwarding Unit for WebRTC media
LiveKit handles:
  • WebRTC signaling (via WebSocket)
  • Media routing between participants
  • TURN/STUN for NAT traversal
  • Recording and egress
  • Simulcast and adaptive bitrate
Architecture: Fluxer API generates JWT tokens for LiveKit access. Clients connect directly to LiveKit for media. Port Requirements:
PortProtocolPurpose
7880TCPHTTP/WebSocket API (internal)
7881TCPRTC over TCP (fallback)
3478UDPTURN/STUN
50000-50100UDPRTP/RTCP media streams
UDP ports must be directly accessible from the internet. They cannot be proxied through Cloudflare Tunnels or similar HTTP-only services.
See Voice Setup Guide for detailed LiveKit configuration.

Message Queue (Microservices Mode)

NATS

Image: nats:2-alpine
Purpose: Inter-service communication and job queuing
NATS provides:
  • Core NATS - Request/reply RPC between services
  • JetStream - Persistent message queues for background jobs
Only required in microservices mode. The monolith uses in-process communication.
nats_core:
  image: nats:2-alpine
  command: ['-c', '/etc/nats/nats.conf']
  ports:
    - '4222:4222'

nats_jetstream:
  image: nats:2-alpine
  command: ['-c', '/etc/nats/jetstream.conf', '--jetstream']
  ports:
    - '4223:4222'

Request Flow

Here’s how a typical message send request flows through Fluxer:

Resource Requirements

Monolith Deployment

ComponentCPUMemoryStorage
fluxer_server2-4 cores4-8 GB-
Valkey1 core2 GB1 GB
Meilisearch1 core1 GB5-50 GB
SQLite--10-500 GB
Total4-6 cores8-12 GB20-600 GB

Microservices Deployment (per service)

ServiceCPUMemoryNotes
API Server2-4 cores4 GBScale horizontally
Gateway4-8 cores8 GBConnection-heavy
Media Proxy2 cores4 GBCPU for image/video
Admin Panel1 core1 GBLow traffic
Cassandra (per node)4-8 cores32-64 GBSee Scaling
NATS2 cores2 GBJetStream needs disk

Security Considerations

Use Docker networks to isolate services:
  • Public: Only reverse proxy and LiveKit
  • Internal: All other services
networks:
  public:
  internal:
    internal: true
Never commit secrets to version control. Use:
  • Environment variables for containers
  • Docker secrets or Kubernetes secrets
  • External secret managers (Vault, AWS Secrets Manager)
Always terminate TLS at the reverse proxy:
  • Use Let’s Encrypt for free certificates
  • Set "public_scheme": "https" in config
  • Set "cookie.secure": true
Restrict access:
# Allow only necessary ports
ufw allow 80/tcp    # HTTP (redirect to HTTPS)
ufw allow 443/tcp   # HTTPS
ufw allow 3478/udp  # TURN
ufw allow 7881/tcp  # RTC TCP fallback
ufw allow 50000:50100/udp  # RTC media

Monitoring & Observability

Health Checks

All services expose health check endpoints:
# Fluxer server
curl http://localhost:8080/_health

# Valkey
valkey-cli ping

# Meilisearch
curl http://localhost:7700/health

# LiveKit
curl http://localhost:7880/

Logs

Fluxer uses structured JSON logging in production:
{
  "level": "info",
  "timestamp": "2026-03-04T12:00:00.000Z",
  "service": "api",
  "message": "Request completed",
  "request_id": "req_123",
  "method": "POST",
  "path": "/api/v1/messages",
  "status": 201,
  "duration_ms": 45
}
Centralize logs with:
  • Loki + Grafana
  • ELK Stack
  • Cloud logging (AWS CloudWatch, GCP Cloud Logging)

Metrics (OpenTelemetry)

Enable telemetry in config:
{
  "telemetry": {
    "enabled": true,
    "otlp_endpoint": "http://otel-collector:4318",
    "service_name": "fluxer",
    "trace_sampling_ratio": 0.1
  }
}
Exported metrics:
  • HTTP request rates and latencies
  • Database query performance
  • Cache hit/miss ratios
  • WebSocket connection counts
  • Message delivery times

Next Steps

Configuration

Explore all configuration options in detail

Voice Setup

Set up LiveKit for voice and video

Scaling

Scale to distributed deployments

Upgrading

Learn about upgrade procedures

Build docs developers (and LLMs) love