Skip to content
New1DirectionPublic

About

A free, self-hostable, end-to-end-encrypted Discord alternative — Signal-level privacy, Discord-level everything. Rust + React + Tauri.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Ohiyo

Builder fees earned on repo.ing

A private-by-design chat app with Discord-like ease — servers, channels, DMs, and real-time voice / video / screen-share, with end-to-end encryption you can turn on for DMs and group chats, a sandboxed plugin system, and a brand of its own. Rust on the backend, React 19 + Tauri on the desktop. No subscriptions, no paywalled features, no telemetry. And launch your own server in one tap — Realms-style hosting with export ownership and self-host always one click away. Encrypted DMs and group chats stay ciphertext on the box; server channels are stored like any chat server's.

Ohiyo on the Daybreak light theme — cream and coral, with channels, chat, and member list Ohiyo on the Dusk dark theme — the same client in dark mode

Kikka, the coral chinchilla mascot

Status: v0.3.0 public beta — early but real. The hosted app is live at app.ohiyo.gg, the public site is live at ohiyo.gg, and the end-to-end suite runs in CI on every pull request. Desktop apps for Mac and Linux are on ohiyo.gg and in Releases; the Mac build is a beta that Apple has not verified yet.


Highlights

  • End-to-end encryption, per conversation — turn on the lock in a DM or group chat and messages are encrypted on your device with the Signal Protocol before they leave it; for those messages the server relays only ciphertext. It is opt-in today, not the default, and server channels are not end-to-end encrypted. Multi-device, with disappearing messages, safety numbers, padded plaintext, encrypted attachments, and Privacy Mode for quieter metadata. Encrypted messages show no link previews and cannot be forwarded, so their content stays off the server. (A YouTube link or a post on X there gets a play button, which loads nothing until you press it.) Group encryption is experimental and can miss messages sent while you were offline. Ohiyo is not anonymous or SimpleX-level metadata privacy; it keeps Discord-like convenience while reducing avoidable leaks. See Known limits of the encryption below. (e2e suites 19-e2e-dm, 20-disappearing, 21-multidevice, 22-group-e2e, 26-privacy-mode, 27-private-dm-links, 35-recovery-restore, 36-new-device-alert, 37-change-password, 38-contact-new-device, 39-delete-account.)
  • Two-factor sign-in — an authenticator app's code after your password, with single-use recovery codes for a lost phone. It also guards changing the password and deleting the account. (e2e suite 59-two-factor.)
  • Instant Servers — launch your own community server in one tap. We host it (Minecraft-Realms-style): encrypted DMs and group chats are ciphertext on the box, while server channels are stored in the clear like any chat server's. Export anytime, or graduate to your own box, or self-host for $0. Free servers can sleep; the optional paid plan (about $8 a month per community, less than one Discord Nitro) keeps one running, paid by card through Stripe and cancellable in the app. (Control plane, provisioning and the paid plan are built; they're off on the hosted service until Fly and Stripe are set up — see GO-LIVE.md. Design in docs/superpowers/.)
  • One-command Discord template migration — give Ohiyo a Discord Server Template link and it reconstructs categories, channels, roles, best-effort permission bits, overwrite snapshots, server icon, and custom emoji assets. See docs/discord-template-migration.md.
  • Text — servers, channels, threads, DMs, reactions, edits/deletes, attachments, read receipts / delivered state on DMs.
  • Voice & video — WebRTC voice, video, and screen-share, with Discord-like live voice rows, a pre-join roster, and a “Ready to join?” preview with Join muted, so you can see who is already in a room before hopping in. Voice participation is honest: joining reveals you to the room/channel audience even when media is encrypted. Peer-to-peer with STUN on LAN; optional coturn (infra/coturn/) for symmetric-NAT users, or an optional LiveKit SFU (infra/livekit/) for larger rooms.
  • Plugins — third-party plugins run in a Web Worker sandbox with no DOM and no token access. Network APIs are removed inside the worker and the web build's CSP limits what remains; on desktop the sandbox is the only barrier, so install only plugins you trust. See client/src/plugins/.
  • Design — the Daybreak light theme (cream + coral, Quicksand + Inter) and a Dusk dark theme, with a real motion system and reduced-motion support.
  • Desktop-native — Tauri app with native notifications, deep links, and an encrypted local vault for sensitive cache namespaces; the web build runs anywhere.
  • Webhooks — let another service post to a space's text channel (Space menu → Webhooks, for people who manage channels). The URL is shown once; post Discord-style JSON to it and the message appears under the webhook's name, marked APP: curl -X POST -H 'Content-Type: application/json' -d '{"content":"Deploy finished"}' https://<server>/api/v1/webhooks/<id>/<token>. {"text": …} (Slack style) works too; ?wait=true returns the message. A post's username/avatar_url are ignored, so a webhook can't pose as someone, and @everyone/@here ping nobody. GitHub's own webhook payload isn't Discord's format, so point GitHub at a relay or an Action that posts {"content": …} for now.
  • Fast private actions — Ctrl/⌘K jumps to channels and also exposes quick actions for Privacy Mode, one-time private DM links, and joining an active voice room.

Tech stack

Layer Tech
Server Rust, axum 0.8, sqlx + SQLite, WebSocket gateway
Client React 19, TypeScript, Tailwind CSS v4, Vite
Desktop Tauri 2
Realtime WebRTC (voice/video/screen-share), WS gateway with one-time tickets
Deploy Docker on Railway or Fly.io (see DEPLOY.md)
Quality ESLint (hooks-as-error), tsc, unit tests, cargo test, end-to-end suite (dev and production-preview), GitHub Actions CI

Repo layout

server/        Rust axum + sqlx server (migrations/, src/, Dockerfile, railway.json, fly.toml)
client/        React + Vite app and Tauri shell (src/, src-tauri/)
e2e/           Node-driven end-to-end suites (NN-*.test.mjs + harness)
infra/coturn/  Optional TURN server for WebRTC behind strict NATs
brand/         Mascot (Kikka) + brand assets (Daybreak)
site/          Public landing page (deploys to ohiyo.gg)
docs/          Design specs & plans
CHANGELOG.md   Release notes (Keep a Changelog)
DEPLOY.md      Production deploy guide (Railway or Fly.io)
UX-GATES.md    UX acceptance gates

Quickstart (local dev)

Prerequisites: Rust (stable), Node 22+ (22.6+ for unit tests), and Bun 1.4+ (installs the client's packages and runs its scripts).

1. Server (http://localhost:3000)

cd server
cp .env.example .env          # set JWT_SECRET — `openssl rand -base64 48`
cargo run                     # migrations apply on startup

2. Client (Vite dev on http://localhost:1420, talks to :3000)

cd client
bun install
bun run dev

Open http://localhost:1420, register an account, create a space, and start talking.

Desktop build

cd client
bun run tauri build           # produces the platform bundle (.dmg on macOS)

The packaged app connects to the backend in client/.env.production (VITE_SERVER_URL, e.g. https://ohiyo-server-production.up.railway.app or your own server). The public beta uses the hosted Ohiyo backend; you can also point the app at your own Fly app, self-hosted server, or custom home. See DEPLOY.md to stand one up.

Testing

cd client
bun run test:unit     # unit tests (Node 22.6+)
KIKKA_ORIGIN=http://localhost:1420 bun run test:e2e   # full suite (27)
KIKKA_ORIGIN=http://localhost:1420 bun run test:e2e receipts   # filter by substring
bun run lint          # ESLint — react-hooks rules are errors
bun run typecheck     # tsc --noEmit

The server and Vite dev client (port 1420) must both be running for e2e. On every push, CI runs the full gate: ESLint, tsc, unit tests (test:unit), client build, cargo fmt --check, cargo clippy -D warnings, cargo build, and cargo test.

Deploy

The hosted service runs on Railway: the server from server/Dockerfile and the browser app from client/Dockerfile. The landing site is published to GitHub Pages. The full walkthrough — Docker image, volume-backed SQLite, secrets for JWT_SECRET/TURN, optional coturn, and the Fly.io and Railway specifics — is in DEPLOY.md.

Public privacy docs

Ohiyo's privacy boundary is documented publicly:

Known limits of the encryption

We would rather you know these than find them:

  • Opt-in. A conversation is encrypted only after someone turns on the lock. New DMs start unencrypted.
  • A contact's new device gets your message before you're told. When a contact adds a device, your client encrypts to it at once and then says so in the chat ("They added a new device"). If you had verified that contact, the warning is loud and the verified mark drops until you compare safety numbers again. So a malicious server, or someone holding the contact's stolen session, could read the message that reveals the new device. It can't add one you're never told about: your client encrypts only to the devices the directory lists, under the keys it lists, and a message from a device it never listed raises the same notice. Compare safety numbers out of band for conversations that matter. A device added to your own account is announced on your other devices at once, with a one-tap "Not me" that removes it and signs out every session.
  • Group encryption is experimental. It is Ohiyo's own sender-key design, not Signal's, and it can miss messages sent while a member was offline.
  • Not end-to-end encrypted: server channels, polls, and watch-party links.
  • Signing out removes readable history from that device. An encrypted message can be decrypted only once, so the app keeps a readable copy on the device. Signing out of your last account there removes those copies (after a confirmation), and they cannot be decrypted on that device again. Your other devices are not affected.
  • One account per browser profile. Encryption keys are stored per browser profile, not per account. Signing in to a second account in the same profile reuses the first account's keys and breaks its sessions; use a separate profile for each account.
  • No external audit yet. One-to-one chat uses a community TypeScript port of the Signal Protocol; the group scheme, voice keys, backup and desktop vault are our own constructions.

Closing the first three is on the roadmap.

License

AGPL-3.0. You're free to use, modify, self-host, and redistribute Ohiyo. The one obligation: if you run a modified version as a network service, you must offer your users its source. That's deliberate — it keeps every hosted fork of a free chat app free.


ohiyo.gg · github.com/New1Direction/ohiyo · Releases
Made with care (and one coral chinchilla named Kikka).

About

A free, self-hostable, end-to-end-encrypted Discord alternative — Signal-level privacy, Discord-level everything. Rust + React + Tauri.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages