Skip to content

jaybill/anemoia

Repository files navigation

Anemoia

IRC community server with a web chat client and API-backed authentication. Ergo IRCd + Node.js API + Preact client. Users register on the web; their account is created in both the API DB and Ergo (via oper). The web client connects to IRC through the API bouncer; traditional IRC clients connect directly to Ergo. No SASL required — connect then identify with NickServ.

Prerequisites

  • Node.js 20+ (for local scripts: migrate, seed)
  • Docker and Docker Compose
  • Yarn (or npm)

Note: These instructions target Ubuntu 24.04. Other distros may need different setup.

Ubuntu 24.04: Docker

Use the default Ubuntu packages:

sudo apt install docker.io docker-compose-v2 docker-buildx-plugin
sudo usermod -aG docker $USER

Debian 13

Use the default Debian packages (names differ from Ubuntu):

sudo apt install docker.io docker-cli docker-compose docker-buildx
sudo usermod -aG docker $USER

Use the docker-compose command (with hyphen) for Compose; the rest of this doc uses docker compose (space), which is equivalent.

Log out and back in after adding yourself to the docker group. If you see permission denied connecting to the Docker socket, add your user: sudo usermod -aG docker $USER, then log out and back in (or run newgrp docker in your shell).


Production

Not used for local development — use Development (yarn dev, docker-compose.dev.yml). setup.sh is only for deploying the Caddy + production stack on a server.

Recommended: run the interactive installer from the repo root (requires Node + Yarn on the host):

chmod +x setup.sh update.sh   # once
./setup.sh

That writes .env, TLS material, ergo/ircd.yaml (via yarn generate-config), builds the chat client into srv/client/ and the admin app into srv/admin/, writes Caddyfile from deploy/Caddyfile.template, and brings up docker-compose.yml (Caddy, API, Ergo, cert-sync). Updates: ./update.sh.

Full operator notes (DNS, firewall, first-boot order, manual deploy without setup.sh): docs/deployment.md.

AWS: optional deploy/aws/ CloudFormation stack (EC2 + Elastic IP + security group); see deploy/aws/README.md.

Development

Local development does not use setup.sh or root docker-compose.yml. Use yarn dev (or docker compose -f docker-compose.dev.yml …) and .env.dev — see Quick start below.

Follow-ups and polish backlog: docs/polish-list.md.

Quick start

# 1. Install dependencies
yarn install

# 2. Create .env.dev (copy from template, edit ADMIN_NICK to your preferred first-admin nick)
cp .env.dev.example .env.dev
# Edit .env.dev: set ADMIN_NICK=yournick (the nick you'll register with)

# 3. Generate self-signed TLS certs and oper client cert
yarn dev:certs
# Copy the printed SHA-256 fingerprint into ergo/ircd.dev.yaml:
#   opers.anemoia-api.certfp = "YOUR_FINGERPRINT_HERE"

# 4. Start Ergo + API
yarn dev:infra

# 5. Open the web chat at http://localhost:5173 and register (use the nick you set in ADMIN_NICK)

# 6. Restart the dev stack so the admin bootstrap runs
#    (Ctrl+C, then yarn dev:infra again — or: docker compose -f docker-compose.dev.yml restart dev)

Alternative: seed test users — If you prefer seeded accounts instead of registering:

yarn seed:docker   # Creates admin, alice, bob, charlie (password: password)

Then set ADMIN_NICK=admin in .env.dev and restart. The seed creates admin with role=admin, so ADMIN_NICK bootstrap won't run — but you'll have an admin account ready.

First admin via ADMIN_NICK: If you register (not seed), set ADMIN_NICK=yournick in .env.dev before step 4. After registering, restart the dev container so the bootstrap promotes your user to admin.

Ports

Port Service
3000 API
5173 Web chat client (Vite dev server)
6667 IRC (plaintext)
6697 IRC (TLS, self-signed)

API docs: With the API running, OpenAPI + Swagger UI are at http://localhost:3000/api/docs (machine JSON: /api/docs/json). The listed server URL uses DOMAIN, OPENAPI_SERVER_URL, or http://127.0.0.1:$PORT — set OPENAPI_SERVER_URL if “Try it out” should hit a different origin.

SMTP (e.g. Gmail + app password for email_code): docs/smtp.md.

IRC client setup

Server: localhost (or 127.0.0.1)
Port: 6667 (plaintext) or 6697 (TLS)
Auth: No SASL. Connect with your nick, then identify: /msg NickServ IDENTIFY yourpassword

HexChat: Add server localhost/6697 (SSL). Do not enable SASL. After connect, send /msg NickServ IDENTIFY password (or your password).

WeeChat: /server add anemoia localhost/6667 (or -ssl for 6697) → /connect anemoia/msg NickServ IDENTIFY password

New users: Register on the web app first; your nick and password are created in both the API and Ergo. Then connect to IRC and /msg NickServ IDENTIFY yourpassword.

Command is IDENTIFY (with a Y), not IDENTITY. Use one argument (your password); your current nick is used automatically.

"Account does not exist"? The seeded users must be created in Ergo. With the stack running, run yarn seed:docker so the seed script creates admin, alice, bob, charlie in both the DB and Ergo.

Can join/speak without identifying? If you had Ergo running before Phase 3, default channels may have been created without +R/+M. Reset the Ergo data volume so channels are recreated with the correct modes, then re-seed:

docker compose -f docker-compose.dev.yml down
docker volume rm anemoia_ergo_data
docker compose -f docker-compose.dev.yml up -d
# Wait for Ergo to start, then:
yarn seed:docker

Web chat client

The Preact chat client runs at http://localhost:5173 (Vite dev server; proxies API and WebSocket to port 3000).

  • Register — Create an account (display name, email, password). Your nick is derived from your display name.
  • Login — Use your nick and password.
  • Chat — Select a channel from the sidebar (#general by default), type messages. You’re connected to IRC via the API bouncer; messages sync with traditional IRC clients.
  • Settings — Change password (synced to IRC).

Seeded logins (if you ran yarn seed:docker): nicks admin, alice, bob, charlie — password: password

API endpoints

Full request/response contracts (registration modes, verify-email, rate limits, error code fields) live in docs/api-protocol.md.

Method Path Purpose
POST /api/auth/register Register (nick, email, password)
POST /api/auth/login Login (nick, password) → token + cookie
POST /api/auth/verify-email Email verification (email_code mode); see protocol doc
POST /api/auth/resend-code Resend verification code
PATCH /api/auth/password Change password (Bearer); syncs to Ergo
GET /api/auth/me Current user (Bearer)
POST /api/auth/logout Invalidate session
GET /ws WebSocket (IRC bouncer; ?token=... + credential cookie)
GET /api/health API + Ergo health
GET /api/server/info Community name, channels, user count
GET /api/channels Channel list (name, topic)
GET /~:nick User profile

Admin API (Bearer token, role=admin): POST/GET/DELETE /api/admin/channels, POST/GET/DELETE /api/admin/channels/:name/ops, POST/GET/DELETE /api/admin/super-ops, POST /api/admin/kick-from-all, and (approval registration) GET/POST …/pending-registrations — see docs/api-protocol.md.

Useful commands

yarn dev:certs        # Generate self-signed TLS certs + oper client cert
yarn dev:certs:force  # Same, overwriting existing PEMs (or: yarn dev:certs -- --force)
yarn dev              # Start Ergo + API (foreground; same as dev:infra)
yarn dev:infra        # Start Ergo + API (foreground)
yarn dev:infra:down   # Stop containers (keeps volumes and ./data)
yarn dev:teardown     # Full tear-down: stop, remove volumes, delete ./data
yarn dev:reset        # Teardown everything, then start fresh
yarn seed:docker      # Seed users (run with stack up)

Troubleshooting

  • Port 3000 in use: kill $(lsof -t -i :3000) or stop whatever is using it.
  • ADMIN_NICK not promoting: Ensure the user exists (register first), set ADMIN_NICK in .env.dev, then restart the dev container. The bootstrap runs only at API startup.
  • Oper cert fingerprint mismatch: After yarn dev:certs, copy the printed SHA-256 fingerprint into ergo/ircd.dev.yamlopers.anemoia-api.certfp. To regenerate everything, yarn dev:certs:force (then update the fingerprint again).

Development notes

  • Environment: Copy .env.dev.example to .env.dev and edit. Dev scripts load .env.dev first, then .env if present. For production, copy .env.example to .env.
  • Registration modes: REGISTRATION_MODE (open, email_code, approval), SMTP, PENDING_REGISTRATION_KEY, rate limits, and TRUST_PROXY are documented in .env.example / .env.dev.example and docs/api-protocol.md. Default local dev is open with rate limits disabled (*_MAX=0).
  • Docker dev: The Ergo container uses a custom image (ergo/Dockerfile.dev) that adds curl so the auth-wrapper can call the API. The API container is built with ERGO_HOST=ergo and ERGO_PORT=6667 in the image so the bouncer connects to Ergo by service name; if those env vars are missing at runtime, the API still uses ergo when it detects it is running inside Docker (/.dockerenv).
  • IRC credential key (dev): In development, if IRC_CREDENTIAL_KEY is not set in .env.dev, a built-in fallback key is used so login and the web client work without generating one. Production must set IRC_CREDENTIAL_KEY (e.g. openssl rand -base64 32).
  • Admin email (dev): Seeded admin uses ADMIN_EMAIL from .env.dev; the default is admin@localhost.localdomain so it is a valid email format.

Deployment (Production)

For most servers, use ./setup.sh (see Production above) instead of following these manual steps.

1. Environment

cp .env.example .env

Edit .env and set:

  • COMMUNITY_NAME, DOMAIN, ADMIN_EMAIL, ADMIN_PASSWORD
  • REGISTRATION_MODEopen (default), email_code, or approval; non-open requires PENDING_REGISTRATION_KEY and (for email_code) SMTP — see comments in .env.example
  • TRUST_PROXY1 if the API is behind a reverse proxy (rate limits use forwarded client IP)
  • Rate limit vars (RATE_LIMIT_*) — 0 for *_MAX disables that limiter
  • ERGO_API_TOKENopenssl rand -base64 32
  • IRC_CREDENTIAL_KEYopenssl rand -base64 32 (encrypts IRC password cookie for bouncer)
  • SESSION_SECRETopenssl rand -base64 32
  • NETWORK_NAME, SERVER_NAME (for Ergo)
  • BUFFER_MAX_MESSAGES — optional; default 500 (in-memory replay per user)

See docs/api-protocol.md for HTTP status codes and admin pending-registration routes.

Values with spaces (e.g. COMMUNITY_NAME) must be quoted.

2. Generate Ergo config

yarn generate-config

Writes ergo/ircd.yaml from ergo/ircd.yaml.template using values from .env (tokens, oper fingerprint, server name, etc.). That file is gitignored — it is not in the repository, so you must run this after a fresh clone or whenever .env changes. ./setup.sh runs it for you.

3. TLS certificates

For production, use real certs (e.g. Let's Encrypt). Place:

  • certs/fullchain.pem
  • certs/privkey.pem

For local/testing only, use self-signed:

yarn dev:certs

4. Start services

docker compose up -d

5. Create first admin

Option A — ADMIN_NICK bootstrap: Register a user on the web app, set ADMIN_NICK=thatnick in .env, then restart the API. On startup, if no admins exist, that user is promoted.

Option B — Seed script: yarn seed:docker (or docker compose run --rm dev node /app/scripts/seed.js). Creates admin, alice, bob, charlie (password: password). Uses ADMIN_EMAIL and ADMIN_PASSWORD from .env for the admin account.

Production checklist

  • .env filled with production values
  • ERGO_API_TOKEN, IRC_CREDENTIAL_KEY, and SESSION_SECRET generated (not dev defaults)
  • Real TLS certs in certs/ (not self-signed)
  • yarn generate-config run after any .env change (creates ergo/ircd.yaml, which is not committed)
  • Firewall: 80, 443 (HTTP/S + ACME), 6697 (IRC TLS), and 6667 only if you use plaintext IRC — with Caddy, the API is not published on 3000 (see docs/deployment.md)

Project structure

├── packages/
│   ├── api/          # Fastify API, auth, WebSocket bouncer, Ergo client
│   ├── client/       # Preact chat client (Vite)
│   └── common/       # Validation, shared protocol (nick, display name, WS message types)
├── ergo/             # Ergo: ircd.yaml.template (source), ircd.dev.yaml (dev); ircd.yaml generated (gitignored)
├── scripts/          # gen-dev-certs, generate-config, seed, migrate
├── .env.example      # Production env template
├── .env.dev.example  # Dev env template
├── setup.sh          # Production interactive setup (see above)
├── update.sh         # Rebuild/restart production stack
├── deploy/
│   ├── aws/          # Optional CloudFormation (EC2 + VPC + Elastic IP)
│   ├── Caddyfile.template
│   └── cert-sync.Dockerfile
├── docker-compose.yml
└── docker-compose.dev.yml

About

anemoia package

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors