██████╗ ██╗██╗ ██╗██╗ ██████╗███████╗
██╔════╝ ██║██║ ██║██║██╔════╝██╔════╝
██║ ██║██║ ██║██║██║ ███████╗
██║ ██║╚██╗ ██╔╝██║██║ ╚════██║
╚██████╗ ██║ ╚████╔╝ ██║╚██████╗███████║
╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝╚══════╝
Civilian ICS node software — private mesh messaging for teams, communities, and organizations
Built by @mrdulasolutions
CivICS is the civilian node and operator console for closed ICS networks. Each device holds its own cryptographic identity. Teams message one-to-one or in groups after they join a private hub — a path your organization issues, not a public chat network.
CivICS does not ship a public hub and does not pin a vendor endpoint. You host the hub (LAN, VPS, or cloud) and issue Mesh + Dest yourself.
Device ──TCP 4242──► Private hub (yours)
Operator UI Mesh + Dest you issue
(localhost:8080) Console stays on loopback
| Requirement | Notes |
|---|---|
| Docker | Desktop or engine with Compose v2 |
| ICS | Transport daemon (Apache-2.0). Docker build context. |
| MMF | Message format (Apache-2.0). Docker build context. |
| A hub card | Mesh host:port + Dest (32 hex) from your administrator |
git clone https://github.com/mrdulasolutions/CivICS.git
cd CivICS
cp .env.example .env # optional
docker compose up --build -dPoint ICS_CONTEXT and MMF_CONTEXT at your ICS and MMF checkouts if they are not the default nested paths (../../ICS, ../../MMF). A sibling clone (~/mesh/CivICS next to ICS and MMF) uses ICS_CONTEXT=../ICS MMF_CONTEXT=../MMF. Continue on a Linux host: docs/LINUX-BOX.md.
| Surface | Address |
|---|---|
| Operator console | http://127.0.0.1:8080 |
| Second local node | http://127.0.0.1:8081 |
| Third local node | http://127.0.0.1:8082 |
| Mesh TCP | host port 4242 (lab bind defaults to 127.0.0.1) |
- Open the console → This device. Set name, unit, device type, and station. Save identity.
- Join a hub (recommended) or call a peer.
- Click Make visible on every device that should appear to others.
- Open Messages. A spoke can message a dest the hub has heard even if those two spokes never called each other on TCP. The third console on 8082 is for that hub-relay check.
Full walkthrough: wiki · Getting started.
Your administrator issues a hub card. CivICS never hardcodes a hub.
Mesh: hub.example.com:4242
Dest: <32 hex characters>
On the device:
- Setup → Hosted hub.
- Paste the card, or fill Mesh and Dest. Directory is optional.
- Call that hub, then Make visible.
For a nearby peer without a hub: Setup → Call a device → paste their TCP address (port 4242 unless specified) → Make visible on both sides.
Direct calls are for lab, local, or point-to-point use. They are not a substitute for a private hub in operational traffic.
- Each node has a dest (32-hex message address) that persists with its Docker volume
- Profile fields (name, unit, device type, station) are what others see
docker compose downkeeps identity;docker compose down -vmints a new device
- ICS TCP (HDLC framing, port 4242) plus AutoInterface UDP 29716 on the compose network (
ICS_AUTO_PORT=0to disable). Lab compose setsICS_IFAC=civics-lab. Real LAN, USB radio, and BlueZ: docs/LINUX-BOX.md - Share cards: Mesh + Dest for onboarding
- Public community meshes (
*.reticulum.networkand listed public hubs) are blocked
- Home / Messages / Setup
- Operator UI bound to localhost by default
- Groups are created on Messages. ICS rooms are 1:1 dest send, not MeshChat rooms.
- Join any private hub your organization operates
- Self-host with
compose.hub.yaml - Example AWS automation under
infra/aws/— not a hosted tenant
Keep the operator console on loopback. Issue Mesh + Dest from that hub’s share card.
cp .env.hub.example .env.hub
docker compose -f compose.hub.yaml --env-file .env.hub up --build -dHost production hubs on a network you control. Operator checklist: docs/PRIVATE-HUB.md. Also wiki · Self-hosting.
- ICS identity (
ICS_HOME,/var/lib/civics/ics) plus hub lists, channels, and messages (/var/lib/civics/civics) live on the Docker volume - Publish TCP 4242 (and UDP 29716 on Linux LAN) only to networks you intend to peer with. Lab compose binds 4242 to loopback;
compose.hub.yaml/compose.lan.yamlopen the host. Keep 8080 and 7850 on loopback. - Report vulnerabilities: SECURITY.md
./scripts/backup.sh
./scripts/restore.sh backups/<stamp>
CIVICS_DRILL_YES=1 ./scripts/backup-drill.sh # backup → down -v → restore; same dest
./scripts/drop-saved-peer.sh <host> 4242 # leftover ICS peers.json entrycivics-hub / civics-spoke
├── icsd ICS daemon (TCP 4242, AutoInterface 29716, RPC 7850, ICS_HOME=/var/lib/civics/ics)
├── status_server Operator console + API (HTTP 8080)
├── mesh.py Peers, dest, MMF messages, hosted hubs
├── ui/ Home, Messages, Setup
└── volume /var/lib/civics (not /var/lib/reticulum)
Transport is ICS (Apache-2.0). Messages are MMF (Apache-2.0). CivICS is not TAK Server and does not ship Python rns or lxmf.
See ARCHITECTURE.md and the wiki.
Copy .env.example to .env.
| Variable | Purpose |
|---|---|
CIVICS_CALLSIGN |
Default display name until identity is saved |
CIVICS_HOME |
Data root inside the container (/var/lib/civics; ICS_HOME is $CIVICS_HOME/ics) |
CIVICS_ADVERTISE_HOST |
Host on the share card (LAN, Tailscale, or hub DNS — not 127.0.0.1 for remote peers) |
CIVICS_TCP_BIND |
Host bind for published mesh TCP (lab default 127.0.0.1) |
CIVICS_TCP_PORT |
Published mesh port (container listens on 4242) |
ICS_IFAC |
Shared AutoInterface secret (civics-lab on compose.yaml; unset on hub-only) |
ICS_LORA_DEV |
Optional boot TTY (compose.lora.yaml). Empty = Home → Radio picker. |
CIVICS_HTTP_BIND / CIVICS_HTTP_PORT |
Operator console bind |
Hub-only deployments use .env.hub.example. Details: wiki · Configuration.
| Wiki | Operator handbook |
| ARCHITECTURE.md | How the node is put together |
| docs/PRIVATE-HUB.md | Example private-hub runbook |
| docs/LINUX-BOX.md | Continue on Linux: real LAN AutoInterface, then RNode / BlueZ |
| VERSIONS.md | Pinned ICS and MMF SHAs for image rebuilds |
| ROADMAP.md | Later tracks |
| CONTRIBUTING.md | How to change the code |
| SECURITY.md | Vulnerability reporting |
| CODE_OF_CONDUCT.md | Community standards |
Apache License 2.0. ICS and MMF are Apache-2.0. This image does not ship Python rns or lxmf.
CivICS is provided AS IS, without warranties or conditions of any kind. See LICENSE.
What this software is. A Docker node and operator console. Transport is ICS. Messages are MMF. Data lives under ICS_HOME / /var/lib/civics, not a Reticulum/rns tree.
What it is not. TAK Server, ATAK, MeshChat, Python rns/lxmf, or a public Reticulum community client. ICS implements the public-domain Reticulum protocol. MMF follows the public LXMF layout. Neither is a fork of those reference packages.
Affiliation. Not affiliated with, endorsed by, or certified by Amazon Web Services, Microsoft, unsigned.io, or TAK product vendors. Reticulum, LXMF, TAK, AWS, and Azure are names of their respective owners.
“Private hub.” A hub you host or procure, reached by Mesh + Dest you issue. It is not a hosted tenant in this repository.
You own the deployment. Hub cards, peering, backups, radio/spectrum, and lawful use are the operator’s. Device types in the console describe the platform a node is on. Contracts can add duties a README cannot waive.
Built by @mrdulasolutions