# OpenMesh ISP

OpenMesh ISP is a community-operated internet service platform for building resilient neighborhood mesh networks. It connects member-owned routers over wireless or wired links, automatically routes traffic around failures, and provides shared gateway access to the public internet.

The project is designed for cooperatives, rural communities, apartment buildings, event networks, and disaster-response deployments. It uses WireGuard for secure node-to-node tunnels, Babel for dynamic routing, and a lightweight controller for node enrollment, monitoring, and configuration distribution.

## Features

- Automatic mesh discovery and route selection
- Encrypted WireGuard tunnels between nodes
- Multi-gateway failover and load balancing
- IPv4 and IPv6 support
- Member and device bandwidth policies
- Captive portal with voucher or account-based access
- DNS caching and optional content filtering
- Prometheus metrics and health checks
- Web-based network topology view
- Configuration backups and signed updates
- Support for OpenWrt, Debian, and Ubuntu gateways
- Offline operation when upstream internet access is unavailable

## Architecture

A typical deployment contains:

- **Controller:** Manages enrollment, configuration, topology, and authentication.
- **Gateway nodes:** Provide upstream internet connectivity and NAT where required.
- **Relay nodes:** Forward traffic and extend mesh coverage.
- **Access nodes:** Provide Wi-Fi or Ethernet service to community members.
- **Client devices:** Connect to an access node without running mesh software.

The controller is not part of the packet-forwarding path. Existing nodes continue routing traffic if the controller becomes unavailable.

## Requirements

### Controller

- Linux server with Docker 24 or later
- Docker Compose v2
- 2 CPU cores
- 2 GB RAM
- 10 GB available storage
- A stable hostname or IP address

### Mesh nodes

- OpenWrt 23.05 or later, Debian 12, or Ubuntu 24.04
- WireGuard kernel support
- At least one network interface
- Accurate system time
- Outbound HTTPS access to the controller during enrollment

For wireless backhaul, use radios and channels permitted by your local regulator.

## Installation

Clone the repository and create a local configuration file:

```sh
git clone https://github.com/example-community/openmesh-isp.git
cd openmesh-isp
cp config.example.yaml config.yaml
```

Generate controller secrets:

```sh
./bin/openmesh secrets generate --output .env
```

Start the controller:

```sh
docker compose up -d
```

Verify that the services are healthy:

```sh
docker compose ps
curl http://localhost:8080/health
```

The administration interface is available at `http://localhost:8080` by default. On first login, create the network administrator account and record the recovery codes.

For production deployments, place the controller behind a TLS-enabled reverse proxy and restrict administrative access to trusted networks.

## Enrolling a Node

Create a single-use enrollment token:

```sh
docker compose exec controller \
  openmeshctl token create --role relay --expires 30m
```

On the node, install the agent:

```sh
curl -fsSL https://controller.mesh.example/install.sh | sudo sh
```

Enroll it using the generated token:

```sh
sudo openmesh-agent enroll \
  --controller https://controller.mesh.example \
  --token TOKEN
```

Start and enable the service:

```sh
sudo systemctl enable --now openmesh-agent
```

The node should appear in the administration interface within one minute. Assign its location, interfaces, and operating role before enabling client access.

## Usage

### Check network status

```sh
docker compose exec controller openmeshctl status
```

### List enrolled nodes

```sh
docker compose exec controller openmeshctl nodes list
```

### Inspect routes from a node

```sh
sudo openmesh-agent routes
```

### Test connectivity between nodes

```sh
sudo openmesh-agent ping node-07
```

### Promote a node to gateway

```sh
docker compose exec controller \
  openmeshctl nodes update node-07 \
  --role gateway \
  --uplink eth0
```

### Drain a node for maintenance

```sh
docker compose exec controller openmeshctl nodes drain node-07
```

Draining stops new client sessions and gradually reduces the node's routing preference without immediately disconnecting active users.

### View logs

```sh
docker compose logs -f controller
sudo journalctl -u openmesh-agent -f
```

## Configuration

The controller reads `config.yaml` at startup. Environment variables may be used for secrets and deployment-specific overrides.

```yaml
network:
  name: Riverside Community Mesh
  domain: mesh.riverside.example
  region: ca-on
  timezone: America/Toronto

controller:
  public_url: https://controller.mesh.riverside.example
  listen: 0.0.0.0:8080
  enrollment_enabled: true
  token_ttl: 30m

mesh:
  protocol: babel
  address_pool_v4: 10.42.0.0/16
  address_pool_v6: fd42:6d65:7368::/48
  wireguard_port: 51820
  keepalive_seconds: 25
  route_metric: 100

gateways:
  selection: latency
  health_check_interval: 15s
  failure_threshold: 3
  nat_ipv4: true
  advertise_default_ipv6: true

access:
  ssid: Riverside Mesh
  client_isolation: true
  captive_portal: true
  session_timeout: 24h
  default_download_mbps: 25
  default_upload_mbps: 10

dns:
  listen: 10.42.0.1
  upstream:
    - 1.1.1.1
    - 9.9.9.9
  cache_size: 10000
  blocklists: []

monitoring:
  prometheus_enabled: true
  metrics_path: /metrics
  retention_days: 30
  node_offline_after: 2m

logging:
  level: info
  format: json
```

Apply controller configuration changes with:

```sh
docker compose restart controller
```

Node-specific changes made through the administration interface or CLI are signed and distributed automatically. Agents validate the signature before applying an update and retain the previous configuration for rollback.

### Environment Variables

| Variable | Description | Default |
|---|---|---|
| `OPENMESH_DATABASE_URL` | PostgreSQL connection string | Required |
| `OPENMESH_SECRET_KEY` | Controller signing and session secret | Required |
| `OPENMESH_ADMIN_EMAIL` | Initial administrator email | None |
| `OPENMESH_CONFIG` | Path to the YAML configuration | `/etc/openmesh/config.yaml` |
| `OPENMESH_LOG_LEVEL` | Logging verbosity | `info` |
| `OPENMESH_METRICS_TOKEN` | Bearer token for metrics access | None |

Do not commit `.env`, enrollment tokens, WireGuard private keys, or database backups to version control.

## Operations

Back up the controller database and signing keys regularly:

```sh
./bin/openmesh backup create --output ./backups
```

Restore a backup into a stopped deployment:

```sh
docker compose down
./bin/openmesh backup restore ./backups/openmesh-2026-07-31.tar.zst
docker compose up -d
```

Before upgrading, review the release notes and create a backup:

```sh
git pull --ff-only
docker compose pull
docker compose run --rm controller openmeshctl migrate
docker compose up -d
```

Upgrade relay nodes in small groups so the mesh retains redundant paths.

## Security

Treat controller signing keys and gateway credentials as critical infrastructure. Use TLS, enable multi-factor authentication for administrators, rotate enrollment tokens, and keep node operating systems updated.

A mesh network does not make user traffic inherently anonymous or private. Gateway operators may still observe connection metadata, and application traffic without end-to-end encryption may be readable. Publish a clear privacy policy and comply with applicable telecommunications, spectrum, and data-protection laws.

Report suspected vulnerabilities privately to `security@mesh.example`. Do not open a public issue containing credentials, private keys, or exploitable details.

## Contributing

Community contributions are welcome. Before submitting a pull request:

1. Open an issue describing the problem or proposed change.
2. Add tests for behavior changes.
3. Run `make lint test`.
4. Update documentation when configuration or deployment steps change.

Please follow the project code of conduct and avoid including real subscriber data in issues, fixtures, or logs.

## License

OpenMesh ISP is licensed under the GNU Affero General Public License v3.0. See `LICENSE` for details.