Members and readiness
Member records, status, membership type and medical validity dates without storing diagnoses or unnecessary sensitive data.
A self-hosted panel for volunteer fire brigades to manage members, equipment, vehicles, deadlines, operations and photographic records.
N3X Station moves everyday volunteer fire department records into a modern web panel. Every person uses an individual account while members, equipment, deadlines and activities remain in a private PostgreSQL database on the department's server.
Data on the brigade's server · no public PostgreSQL port · no application telemetry
Managed hosting by N3X
N3X can deploy and maintain this application, from initial setup and SSL to updates, monitoring and backups.
Member records, status, membership type and medical validity dates without storing diagnoses or unnecessary sensitive data.
Inventory, ownership, location, asset numbers, readiness status and inspection dates in one register.
Fires, local hazards, false alarms, exercises, training and administrative trips with a clear history.
A shared calendar combines events with medical and inspection dates, while ready-to-use PDF and CSV reports use the current records.
Private photos and PDF files can be linked to an activity or event, described, downloaded and verified with a SHA-256 checksum.
A responsive interface and PWA manifest make the panel usable at the station, in a vehicle and away from a desktop.
Individual accounts, secure HttpOnly sessions, team-ready roles and an audit trail for the most important operations.
DOCKER COMPOSE
One configuration starts the panel, worker and PostgreSQL. The database password and materials remain in private volumes and only the application port is exposed.
DOCKER CONFIGURATOR
Set the domain, bind address, port and image version. The configurator prepares a ready-to-use Docker Compose file and startup commands — without an .env file.
The domain must point to the brigade's reverse proxy. Do not include https:// or a path.
0.0.0.0 provides LAN and proxy access. Use 127.0.0.1 when the proxy runs on the same host and the port should remain local.
The panel port available to the LAN or reverse proxy. The default is 8791.
Keep latest for the newest release or pin a specific version.
name: n3xremiza
x-app-environment: &app-environment
N3XREMIZA_DATABASE_PASSWORD_FILE: /run/n3xremiza/database_password
N3XREMIZA_GEOCODING_BASE_URL: ${N3XREMIZA_GEOCODING_BASE_URL:-https://photon.komoot.io}
N3XREMIZA_GEOCODING_BBOX: ${N3XREMIZA_GEOCODING_BBOX:-14.122,49.002,24.145,54.835}
N3XREMIZA_TRUST_PROXY_HOPS: ${N3XREMIZA_TRUST_PROXY_HOPS:-0}
N3XREMIZA_AUTH_AUDIT_RETENTION_DAYS: ${N3XREMIZA_AUTH_AUDIT_RETENTION_DAYS:-365}
TZ: Europe/Warsaw
x-app-security: &app-security
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
tmpfs:
- /tmp:size=64m,mode=1777
- /app/.next/cache:size=128m,mode=0700,uid=1001,gid=1001
services:
bootstrap:
image: alpine:3.22
restart: "no"
command:
- /bin/sh
- -ec
- |
umask 077
if [ ! -s /run/n3xremiza/database_password ]; then
od -An -N32 -tx1 /dev/urandom | tr -d ' \n' > /run/n3xremiza/database_password
fi
chmod 0444 /run/n3xremiza/database_password
volumes:
- runtime_secrets:/run/n3xremiza
networks:
- backend
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
web:
image: ghcr.io/nexitpl/n3xremiza:latest
pull_policy: always
restart: unless-stopped
depends_on:
bootstrap:
condition: service_completed_successfully
postgres:
condition: service_healthy
environment: *app-environment
volumes:
- runtime_secrets:/run/n3xremiza:ro
- attachments_data:/app/data/attachments
ports:
# Keep this port behind a host firewall until the owner account exists.
# For Internet access, place the app behind an HTTPS reverse proxy.
- "0.0.0.0:8791:3000"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
networks:
- frontend
- backend
<<: *app-security
worker:
image: ghcr.io/nexitpl/n3xremiza:latest
pull_policy: always
restart: unless-stopped
depends_on:
bootstrap:
condition: service_completed_successfully
postgres:
condition: service_healthy
web:
condition: service_healthy
environment: *app-environment
volumes:
- runtime_secrets:/run/n3xremiza:ro
command: ["node", "dist/worker.mjs"]
networks:
- backend
<<: *app-security
postgres:
image: postgres:17-alpine
restart: unless-stopped
depends_on:
bootstrap:
condition: service_completed_successfully
environment:
POSTGRES_DB: n3xremiza
POSTGRES_USER: n3xremiza
POSTGRES_PASSWORD_FILE: /run/n3xremiza/database_password
volumes:
- postgres_data:/var/lib/postgresql/data
- runtime_secrets:/run/n3xremiza:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n3xremiza -d n3xremiza"]
interval: 5s
timeout: 5s
retries: 12
networks:
- backend
networks:
frontend:
backend:
internal: true
volumes:
postgres_data:
runtime_secrets:
attachments_data:
mkdir -p n3xremiza
cd n3xremiza
# Save the copied configuration as docker-compose.yml
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8791/api/health