Skip to content

nerdy-dav/ruki

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ruki

A self-hosted wiki with Spaces → Documents → Pages hierarchy, inspired by Confluence but lightweight. Content is stored as Markdown files; metadata lives in SQLite (or Postgres). The backend is a JSON API served by Axum; the frontend is a Leptos WASM SPA.

Quick Start

cp .env.example .env          # edit SESSION_SECRET
cargo run                     # builds + runs the API server on :3000

Then open http://localhost:3000. The first run creates an admin user automatically — see Administration.

Configuration

All configuration is via environment variables (or .env):

Variable Default Description
DATABASE_URL sqlite:ruki.db SQLite path or Postgres connection string
CONTENT_DIR ./content Directory for Markdown page files
SESSION_SECRET Key for signing session cookies
PORT 3000 HTTP listen port
ADMIN_USERNAME admin Initial admin username (first run only)
ADMIN_PASSWORD admin Initial admin password (first run only)
RUST_LOG Log level (ruki=info, tower_sessions=debug)

Database

SQLite (default)

DATABASE_URL=sqlite:ruki.db?mode=rwc

PostgreSQL

cargo run --features postgres --no-default-features
DATABASE_URL=postgres://user:pass@localhost:5432/ruki

Migrations run automatically on server start.

Frontend

The frontend is a Leptos WASM SPA. Pre-built files in frontend/dist/ are served automatically by the backend at /.

Development (hot-reload)

cd frontend
trunk serve              # http://localhost:8080, proxies /api → :3000

The API server must be running separately on port 3000. CORS is configured to allow localhost:8080.

Production build

cd frontend && trunk build

Output goes to frontend/dist/. Restart the backend to pick up the new build.

Systemd Service

sudo useradd -r -s /bin/false ruki
sudo mkdir -p /opt/ruki
sudo cp -r . /opt/ruki
cd /opt/ruki && cargo build --release
sudo cp contrib/ruki.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ruki

See contrib/ruki.service for the unit file.

Architecture

Spaces → Documents → Pages
  • Spaces — top-level sections (e.g. "Engineering", "HR")
  • Documents — groupings within a space (e.g. "Playbooks")
  • Pages — individual wiki pages written in Markdown

Page content is stored as .md files at:

content/{space_slug}/{doc_slug}/{page_slug}.md

The frontend has a light/dark theme toggle in the sidebar, persisted to localStorage (defaults to system prefers-color-scheme).

Access Control

Ruki uses a hierarchical permission model. Each permission level inherits the capabilities of the levels below it:

Level Can view Can create/edit content Can manage ACLs
read
write
admin

Resolution order (highest wins):

  1. Space-specific user ACL
  2. Space-specific group ACL (any of the user's groups)
  3. Global user ACL
  4. Global group ACL
  5. If none match → no access

Admin group: members of the admin group always have admin permission on every space, regardless of other ACLs.

Space creator: the user who created a space always retains ACL management access for that space.

When no ACLs exist at all, only admin group members can see or do anything. Anonymous (unauthenticated) users have no access.

Managing ACLs

Per-space: visit the space's Settings page (visible when you have admin permission on that space). Add or remove entries by user ID or group ID.

Global defaults: Admin → Global Access Control. These apply to all spaces unless overridden by a space-specific ACL.

Backup & Restore

Available to global admins at Admin → Backup & Restore.

  • Backup — downloads a .tar.gz containing a clean copy of the database (VACUUM INTO) and all content files
  • Restore — upload a previous .tar.gz, replaces the database and content files atomically

API

All endpoints are at /api/ and accept/produce JSON. Authentication is via cookie-based sessions (set by login, sent automatically by the browser).

Auth

Method Path Description
GET /api/auth/me Current user, or null
POST /api/auth/login Login — {"username","password"}
POST /api/auth/logout Clear session

Spaces

Method Path Description
GET /api/spaces List accessible spaces
POST /api/spaces Create space (admin group only)
GET /api/spaces/{slug} Get space with user's effective permission
PUT /api/spaces/{slug} Update space (admin permission)
DELETE /api/spaces/{slug} Delete space (admin permission)

Documents

Method Path Description
GET /api/spaces/{slug}/documents List documents in space
POST /api/spaces/{slug}/documents Create document (write permission)
GET /api/spaces/{space}/{doc} Get document
PUT /api/spaces/{space}/{doc} Update document (write permission)
DELETE /api/spaces/{space}/{doc} Delete document (write permission)

Pages

Method Path Description
GET /api/spaces/{s}/{d}/pages List pages in document
POST /api/spaces/{s}/{d}/pages Create page (write permission)
GET /api/spaces/{s}/{d}/{p} Get page (includes rendered HTML)
PUT /api/spaces/{s}/{d}/{p} Update page (write permission)
DELETE /api/spaces/{s}/{d}/{p} Delete page (write permission)

Space ACLs (space admin or global admin)

Method Path Description
GET /api/spaces/{slug}/acls List space ACLs
POST /api/spaces/{slug}/acls Create space ACL entry
DELETE /api/spaces/{slug}/acls/{id} Delete space ACL entry

Global ACLs (global admin only)

Method Path Description
GET /api/admin/acls List global ACLs
POST /api/admin/acls Create global ACL entry
DELETE /api/admin/acls/{id} Delete global ACL entry

Admin (global admin only)

Method Path Description
GET /api/admin/users List users
POST /api/admin/users Create user
GET /api/admin/users/{id} Get user with groups
PUT /api/admin/users/{id} Update user
DELETE /api/admin/users/{id} Delete user
GET /api/admin/groups List groups
POST /api/admin/groups Create group
GET /api/admin/groups/{id} Get group
PUT /api/admin/groups/{id} Update group
DELETE /api/admin/groups/{id} Delete group
GET /api/admin/backup Download backup archive
POST /api/admin/restore Upload and restore backup

Administration

First run

When the database is empty the server creates an initial admin user using the ADMIN_USERNAME / ADMIN_PASSWORD env vars (defaults: admin / admin).

Change the password on first login.

Admin panel

Logged-in admin users see an Admin link in the sidebar. From there you can:

  • Users — create, edit, delete users and assign group memberships
  • Groups — create and delete groups
  • Global Access Control — set default permissions for users/groups
  • Backup & Restore — download and restore full backups

The admin group is seeded automatically. Users in this group have full administrative access.

Managing users

Only admins can create users. There is no public registration. To add a user:

  1. Log in as an admin
  2. Go to Admin → Manage Users → + New User
  3. Set username, display name, password, and optionally assign groups

Content storage

All page content is stored as plain Markdown files on disk. You can:

  • Edit files directly in content/ (changes reflect on next page load)
  • Version control them with git
  • Back them up independently from the database

Development

# Backend
cargo build
cargo run

# Frontend (separate terminal)
cd frontend
trunk serve

# Run both at once
RUST_LOG=ruki=info cargo run & cd frontend && trunk serve

About

Small lightweight Wiki

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages