<div align="center">

# 🐋 Synapse-iDOCK

**Enterprise-grade, self-hosted Docker orchestration & monitoring — part of the Synapse ecosystem.**

Dark-themed, agent-first multi-host container management with real-time metrics,
webhook automation and a token-secured REST API.

</div>

---

## Overview

Synapse-iDOCK is a single self-hosted service that monitors and controls Docker
containers across **many networked hosts** from one dashboard.

The primary way to bring hosts in is the **agent**: install it on a host and it
reads the local Docker socket and pushes inventory + live metrics over outbound
HTTPS — no Docker API port is exposed, and no per-host approval step is needed.
The **Deploy Agent** page gives you the exact one-line install command per OS.

### Feature highlights

| Area | Capability |
|------|-----------|
| **Auth** | Session-based login; first-run *Initial Admin Setup* redirect |
| **Deploy Agent** | Copy-paste one-line installers (Docker / Linux / Windows) with token pre-filled |
| **Host agent** | Outbound push of inventory + CPU/RAM/Net/Disk metrics; executes queued control commands |
| **Host management** | Manual *Add Host* with **None / TLS / SSH** security toggles + credential upload |
| **Dashboard** | High-density grid with Online/Offline pills; inline **Start / Stop / Update** |
| **Container Insight** | Modal with live CPU / RAM / Net I/O / Disk I/O charts, searchable + downloadable logs, full metadata |
| **Webhooks** | JSON push to Slack / IronNode SOAR on *Container Down / Recovered / High CPU / Restart Loop* |
| **REST API** | Token-authenticated `/api/v1` for hosts, containers, actions & logs |

---

## Architecture

```
                          ┌──────────────────────────────────────────┐
                          │              synapse-idock                 │
  Browser  ── session ──▶ │  FastAPI  ──▶  SQLite (persistent volume)  │
  SOAR/CI  ── Bearer ───▶ │    │                                       │
                          │    ├─ Discovery thread (probe + reconcile) │
                          │    ├─ Metric collector (ring-buffer)       │
                          │    ├─ Webhook engine (async dispatch)      │
                          │    └─ Static React SPA (Vite build)        │
                          └────────────┬───────────────┬──────────────┘
                                       │ unix socket   │ tcp/tls/ssh
                                  local Docker      remote Docker hosts
```

* **Backend** — FastAPI + official Docker SDK (`docker-py`), SQLAlchemy 2.0 over SQLite.
* **Frontend** — React 18 + Vite + Tailwind CSS + Chart.js, compiled and served by the backend.
* **Persistence** — one Docker volume (`/data`) holds the database, the auto-generated
  session secret and any uploaded TLS/SSH credential files.

```
Synapse-iDOCK/
├── docker-compose.yml
├── Dockerfile                 # multi-stage: build SPA → python runtime
├── .env.example
├── backend/
│   ├── requirements.txt
│   └── app/
│       ├── main.py            # app factory, middleware, SPA serving
│       ├── config.py          # env-driven settings
│       ├── database.py        # engine / session
│       ├── models.py          # ← staging state machine lives here
│       ├── schemas.py
│       ├── security.py        # password + API-token hashing
│       ├── deps.py            # session / admin / token auth
│       ├── docker_manager.py  # connection handling (none/tls/ssh) + ops
│       ├── discovery.py       # background sweep, metrics, triggers
│       ├── webhooks.py        # webhook engine
│       └── routers/           # auth, hosts, staging, containers, webhooks, tokens, api
└── frontend/
    └── src/                   # pages/, components/, api.js, auth.jsx
```

---

## Quick start

```bash
git clone <repo> synapse-idock && cd synapse-idock
cp .env.example .env            # optional — sane defaults apply
docker compose up -d --build
```

Open **http://localhost:8800** → you are redirected to **Initial Admin Setup**.
Create the administrator, then sign in.

Go to **Deploy Agent**, generate a token, and run the one-line installer it shows on
each host you want to manage. Containers stream onto the dashboard within ~20s — no
approval step.

### Local development (hot reload)

```bash
# backend
cd backend
pip install -r requirements.txt
IDOCK_DATA_DIR=./data uvicorn app.main:app --reload

# frontend (separate shell) — proxies /api to :8000
cd frontend
npm install
npm run dev        # http://localhost:5173
```

---

## Bringing hosts in — the agent

Most Docker daemons **only listen on the local Unix socket** — exposing the API on
`2375`/`2376` is rare and insecure, so scanning the network finds nothing on a
normally-configured host. The **agent** is the answer: install it on each host and
it reads the local socket and **pushes** inventory + live metrics to iDOCK over
outbound HTTPS — no inbound Docker port required. It also executes queued
Start/Stop/Restart/Update/Logs commands.

The **Deploy Agent** page generates a token and shows **one pre-authenticated
command** to run on the host — server URL and token already filled in. By default
iDOCK **builds and serves the agent image itself** (via its Docker socket), so the
host needs no registry and no extra setup:

```bash
curl -fsSL https://idock.example.com/agent/image.tar.gz | docker load && \
docker run -d --name idock-agent --restart unless-stopped \
  -e IDOCK_URL="https://idock.example.com" -e IDOCK_TOKEN="idk_xxxx" \
  -e IDOCK_AGENT_NAME="$(hostname)" -e IDOCK_AGENT_ID_FILE=/state/agent_id \
  -v /var/run/docker.sock:/var/run/docker.sock -v idock_agent_state:/state \
  synapse-idock-agent:1.0.0
```

Prefer a registry? Publish the image and set `IDOCK_AGENT_IMAGE=ghcr.io/org/…` — the
command becomes a plain `docker run <ref>` that `docker` auto-pulls. There's also a
`docker compose` file ([`agent/docker-compose.yml`](agent/docker-compose.yml)) and a
Python one-liner for hosts without Docker.

Agent-reported hosts and their containers **appear on the dashboard automatically**
(the token is the trust boundary — revoke it under **API Tokens** to disconnect a
host instantly). Registered agents are listed under **Hosts → Connected Agents**.
See [`agent/README.md`](agent/README.md) for all options.

> **Manual & TCP hosts** are still supported via **Hosts → Add Host** (None / TLS /
> SSH) for daemons you *do* expose over the network; their containers surface on the
> dashboard automatically too. A background subnet scanner also remains available via
> the API for TCP-exposed daemons.

---

## Secure host integration (manual TCP/TLS/SSH hosts)

For daemons exposed over the network, add them under **Hosts → Add Host**:

### None
Plain `unix://` socket or an unauthenticated `tcp://host:2375`. Use only on trusted,
isolated networks.

### TLS (recommended for remote hosts)
Point the daemon at a TLS-enabled port (`2376`) and upload:
* **CA certificate** — verifies the daemon
* **Client certificate** + **Client key** — authenticates iDOCK to the daemon

Base URL example: `tcp://10.0.0.10:2376`. Leave *Verify* on in production. Uploaded
material is stored (mode `600`) under the `/data/certs` volume; only file paths are
persisted in the database.

### SSH
Base URL `ssh://user@host`. Provide the SSH username and upload the private key, or
mount `~/.ssh` read-only into the container (see the commented volume in
`docker-compose.yml`). iDOCK shells out to the system `ssh` client, honouring
`~/.ssh/config` and key permissions.

> **Least privilege:** agents authenticate with a revocable token and mount the
> socket read-only by default; grant read-write (or manual host control) only where
> you actually need lifecycle actions.

---

## REST API (`/api/v1`)

Generate a token under **API Tokens** (shown once). Authenticate with
`Authorization: Bearer idk_…` (or `X-API-Key: idk_…`).

| Method | Path | Description |
|--------|------|-------------|
| `GET`  | `/api/v1/hosts` | List approved hosts |
| `GET`  | `/api/v1/containers` | List approved containers |
| `POST` | `/api/v1/containers/{id}/start` | Start container |
| `POST` | `/api/v1/containers/{id}/stop` | Stop container |
| `POST` | `/api/v1/containers/{id}/restart` | Restart container |
| `POST` | `/api/v1/containers/{id}/pull` | Pull latest image |
| `GET`  | `/api/v1/containers/{id}/logs?tail=100` | Fetch logs |

```bash
curl -H "Authorization: Bearer idk_XXXX" http://localhost:8800/api/v1/containers
```

Interactive docs (session-protected mutations aside) are available at `/docs`.

---

## Webhooks

Configure under **Webhooks**. Each fires a JSON payload to your URL when a subscribed
trigger occurs during a discovery sweep:

```json
{
  "source": "synapse-idock",
  "trigger": "container_down",
  "timestamp": "2026-07-10T12:00:00+00:00",
  "host": "prod-01",
  "container": "billing-api",
  "container_id": "a1b2c3d4e5",
  "state": "exited"
}
```

Triggers: `container_down`, `container_up`, `high_cpu` (per-webhook threshold),
`restart_loop`. Add custom headers (JSON) for authenticated targets such as
IronNode SOAR. Use **Send test** to validate connectivity.

---

## Configuration

All settings are environment variables (prefix `IDOCK_`). See [`.env.example`](.env.example).

| Variable | Default | Purpose |
|----------|---------|---------|
| `IDOCK_PORT` | `8800` | Published host port |
| `IDOCK_SECRET_KEY` | *(auto)* | Session signing secret; auto-generated & persisted if unset |
| `IDOCK_SESSION_HTTPS_ONLY` | `false` | Mark session cookie `Secure` (set behind HTTPS) |
| `IDOCK_PUBLIC_URL` | *(auto)* | Externally-reachable URL baked into the Deploy Agent command; blank auto-detects the LAN IP |
| `IDOCK_DISCOVERY_ENABLED` | `true` | Enable background discovery/metrics thread |
| `IDOCK_DISCOVERY_INTERVAL` | `30` | Seconds between sweeps |
| `IDOCK_DISCOVERY_INCLUDE_LOCAL` | `true` | Stage the mounted local socket |
| `IDOCK_DISCOVERY_TARGETS` | *(empty)* | Comma-separated remote endpoints to probe |
| `IDOCK_METRIC_RETENTION` | `720` | Samples kept per container |
| `IDOCK_AGENT_IMAGE` | *(empty)* | Registry ref for the agent image; blank = iDOCK builds & serves it |
| `IDOCK_AGENT_AUTOBUILD` | `true` | Build the agent image on demand via the Docker socket |
| `IDOCK_SCAN_INTERVAL_MINUTES` | `60` | Default auto-scan interval (overridable in UI) |
| `IDOCK_SCAN_PORTS` | `2375,2376,2374,2377,4243` | Default Docker ports (popular ports are always probed regardless) |
| `IDOCK_SCAN_MAX_HOSTS` | `4096` | Hard cap on addresses probed per scan |
| `IDOCK_SCAN_CONNECT_TIMEOUT` | `0.6` | Per-address TCP connect timeout (seconds) |
| `IDOCK_SCAN_CONCURRENCY` | `128` | Parallel probe workers |

> Subnets, ports, interval and the enable toggle are stored in the database and
> managed from the UI; the variables above only set the defaults / safety bounds.

---

## Security notes

* Passwords hashed with **bcrypt**; API tokens stored only as SHA-256 hashes.
* Sessions are signed cookies (`SameSite=Lax`); set `IDOCK_SESSION_HTTPS_ONLY=true`
  and terminate TLS at a reverse proxy for production.
* The Docker socket is mounted **read-only** by default in compose; iDOCK still issues
  lifecycle commands over the API — mount `:rw` only if your workflow requires it and
  understand that socket access is root-equivalent on the host.
* Agent access is gated by a bearer token — revoke it under **API Tokens** to cut a
  host off instantly. Keep the agent's socket mount read-only unless you need control.

---

## Roadmap

* WebSocket log streaming (currently 5 s polled tail)
* Container re-create on `pull` (image pull is implemented; redeploy is left to the operator)
* RBAC beyond the single admin role
* Prometheus metrics exporter

---

<div align="center">
<sub>Synapse-iDOCK · Synapse security & infrastructure ecosystem</sub>
</div>
