Self-hosted virtual tabletop - forked from CheekyChinchilla/CozyVTT
  • TypeScript 98.5%
  • CSS 0.7%
  • Python 0.4%
  • Shell 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
JPSariz451 4428afec40
Some checks failed
CI / Frontend (push) Has been cancelled
CI / Backend (push) Has been cancelled
CI / Docs (push) Has been cancelled
Extensions
2026-10-28 10:01:18 -06:00
.github Check the nginx stamp, the database client version and the OpenAPI file, and run the doc checks in CI 2026-09-27 03:58:05 -06:00
assets Navidrome and branding 2026-10-25 20:38:46 -06:00
backend Extensions 2026-10-28 10:01:18 -06:00
docs Extensions 2026-10-28 10:01:18 -06:00
Examples Extensions 2026-10-28 10:01:18 -06:00
frontend Extensions 2026-10-28 10:01:18 -06:00
nginx Give campaign imports their own nginx location and find a recreated backend 2026-10-06 21:00:29 -06:00
scripts Match the documented gates to CI and call the doc scripts with python3 2026-10-10 10:54:58 -06:00
.dockerignore v1.0.0 initial release 2026-05-17 12:03:03 -06:00
.env.example Correct the 1.5.1 release notes and docs against the code 2026-10-07 12:08:10 -06:00
.gitattributes v1.0.0 initial release 2026-05-17 12:03:03 -06:00
.gitignore Group the upgrade-rehearsal ignore rule and fix the backups comment 2026-09-30 22:51:20 -06:00
.nvmrc Release 1.1.0: modernization overhaul + hardening 2026-07-13 20:04:24 -06:00
CHANGELOG.md Date the 1.5.1 changelog and list its API changes for scripts 2026-10-10 08:49:30 -06:00
docker-compose.dev.yml Limit campaign archive imports, previews and exports per user 2026-10-06 19:45:23 -06:00
docker-compose.override.example.yml Docs: fix the external reverse proxy instructions 2026-08-21 20:32:52 -06:00
docker-compose.yml Add Seafile integration, branding, and customizations 2026-10-26 00:39:16 +01:00
FORK.md Extensions 2026-10-28 10:01:18 -06:00
LICENSE v1.0.0 initial release 2026-05-17 12:03:03 -06:00
README.md Navidrome and branding 2026-10-25 20:38:46 -06:00
SECURITY.md Check the remaining documentation against the code 2026-09-01 06:52:41 -06:00
SRD_ATTRIBUTION.md Attribute the SRD under CC BY 4.0, and credit Open5e 2026-09-01 07:12:23 -06:00
SRD_LICENSE.txt Attribute the SRD under CC BY 4.0, and credit Open5e 2026-09-01 07:12:23 -06:00
THIRD_PARTY_LICENSES.md Upgrade multer to 2.4.0 and cap upload form fields 2026-10-06 18:46:13 -06:00
THIRD_PARTY_NOTICES.txt Extensions 2026-10-28 10:01:18 -06:00

Typo VTT

cozyvtt.com

A self-hosted, browser-based Virtual Tabletop (VTT) platform. Designed for ease of use and narrative-driven tabletop RPG campaigns where atmosphere matters more than mechanics.

Self-hosted — you own your data. One instance can host multiple concurrent campaigns run by different GMs for different player groups.


⚠️ Self-Hosted Reality Check

CozyVTT is a self-hosted, community-maintained project run by you on your hardware. It is provided as-is, with no warranty, no SLA, and no central support — see the AGPL-3.0 License for the legal version of this.

You are responsible for the security and uptime of your instance. We do our best (Argon2id passwords, MFA, magic-byte file validation, per-endpoint rate limiting, security headers on the app page, non-root Docker containers — the full list is under Features → Security), but the operating environment is yours.

Recommended deployment posture for a public-facing instance:

  • Run on a small VPS rather than your home network
  • Front it with a Cloudflare Tunnel (free, hides your origin IP, no open ports needed, automatic DDoS protection) or a similar reverse proxy / WAF
  • Keep the instance updated as security patches land — watch this repo
  • Set a strong SESSION_SECRET (32+ char random) and your own DATABASE_PASSWORD — the production build refuses to start while either is still the placeholder
  • Use the built-in MFA on the admin account at minimum
  • Configure regular database backups (backend/scripts/backup.sh + cron — see DEPLOYMENT.md)
  • Review the Hardening Checklist in docs/DEPLOYMENT.md before flipping public

If those words mean nothing to you, run CozyVTT only on your local network (e.g. via a Tailscale node, ZeroTier, or just LAN-accessible) until you've leveled up your sysadmin chops. That's a perfectly valid way to play — your campaigns aren't worse for being LAN-only, and you skip the whole attack-surface conversation.

If you find a security issue, please report it privately per SECURITY.md rather than filing a public issue.


Features

Platform

  • Multi-campaign — one server, unlimited campaigns, isolated from each other
  • Role-based access control — Platform Admin, Campaign DM, Player, and Spectator roles; the DM seat can be handed to another member without losing ownership of the campaign
  • Setup wizard — guided first-run initialization; no manual database seeding required
  • Admin dashboard — user management, system settings, activity logs, database backups

Campaign Tools

  • Interactive map canvas — upload map images, place tokens, drag to move in real time
  • Token system — player, NPC, and object token types with disposition (friendly/neutral/hostile), HP bars, conditions, stat blocks, and notes; three display modes (pog, top-down, full-art); colored-letter placeholders for tokens without images; the DM can hide a token from players or obscure what it is, and players are sent only what they may see of each token
  • Creature library — browse, search, and place creatures from the SRD bestiary (auto-imported from Open5e) or custom campaign-specific templates; per-campaign favorites with star toggle; duplicate SRD creatures to customize; edit custom creatures in-place; save token images back to templates
  • Token templates — save reusable token configurations (image, stats, HP, size, disposition, full NPC stat block); place from library or save from map context menu; copy templates between campaigns the DM owns
  • NPC right-click rolls — DMs right-click any NPC token to roll abilities, saves, skills, attacks, and damage parsed from its stat block; advantage/disadvantage selector for d20 systems; free-form custom roll fallback for non-5e systems
  • Campaign export/import — export campaigns as portable .cozyvtt archives; import on any CozyVTT instance; includes maps, tokens, creatures, templates, and assets; multi-step preview flow; optional audio toggle; secured against path traversal, zip bombs, and malicious files
  • Walls & dynamic lighting — DM-drawn wall segments (walls, doors, windows) with raycasting visibility; draw, polygon, and brush drawing modes; snap-to-grid and snap-to-endpoint; split, select, erase, and merge point tools; multi-select with Shift, a drag-box or Ctrl+A, then move or delete the lot together; snap-to-wall door/window placement (auto-splits existing walls); players only see what their character can: bright light clearly, dim light and the token's darkvision at half, nothing beyond, and light never reveals through a wall — a lit room is visible only to someone with line of sight into it; per-map Global Illumination lights everything in line of sight for tables that prefer it; explored areas are remembered per player and shown in grey until seen again; door interactions for both DM and players; bright/dim light radii matching D&D 5e and PF2e rules; named light presets (Candle, Torch, Lamp, Lantern, Campfire); overlapping dim zones combine to bright
  • Universal VTT import/export — bring in a .uvtt, .dd2vtt or .df2vtt map from Dungeondraft, Dungeon Alchemist, Czepeku and others, with its walls, doors and lights already placed, and export any map back out. One file is one map, as the format intends; if a file's walls reach outside its own picture, CozyVTT says so before importing rather than leaving you to wonder
  • Fog of war — drag a box to reveal or hide chunks of the map; the selection snaps to whole grid squares, with animated fade transitions
  • Spirit layer — a second canvas layer for ethereal / astral / out-of-body scenes, hidden from players by default
  • Initiative tracker — real-time combat turn order that follows each token; the DM runs it and players roll their own initiative. Players see every combatant the DM has not hidden, on the map the table is looking at and on their own plane, even one they cannot yet find in the dark or under fog, and a creature's hit points only when the DM turns its HP bar on. The acting token is ringed on the map for everyone, and hovering a name highlights its token (and vice versa)
  • Map pings — press Tab to mark a spot for the whole table; a dot with radiating rings in your own colour, labelled with your name
  • Vibe tracker — time-of-day periods (dawn, day, dusk and night by default, all editable) that tint the map with a colour filter
  • Ambient atmosphere — six visual effects (rain, mist, leaves, sparkles, snow, wind) and ambient audio independently per campaign
  • Session management — start, pause, resume, and end sessions with full state capture (token positions, map, vibe)
  • Resizable session workspace — drag to resize or collapse the roster, map, and side panels; a tabbed sidebar keeps Chat, Dice, Initiative, Notes and Session full-height, with an unread-message badge; layout persists per browser

Character Sheets

  • D&D 5th Edition — full sheet with stats, skills, saving throws, attacks, spells, inventory
  • Pathfinder 2nd Edition — attributes, saves, perception, skills, lore skills, strikes
  • Call of Cthulhu 7th Edition — characteristics, skills, weapons, sanity, luck
  • Flexible / Custom — JSON-based freeform character sheets for any system

Dice System

  • Full dice notation — 1d20+5, 2d6, 4d6kh3 (keep highest), advantage/disadvantage
  • Real-time results — rolls appear in the Dice panel for the whole table
  • Secret rolls — hidden from the other players; your DM can still see them, and they stay in your own list marked as secret
  • Dice history — a running log of the session's rolls that survives a refresh, filtered per person by the server
  • Saved rolls — name a dice expression and it becomes a one-click button in the dice panel; private to you and scoped to one campaign, with the expression checked when you save it so a saved roll always works

Communication

  • Campaign chat — in-session messaging between all members
  • System messages — automatic notices when a session starts, pauses, resumes or ends, when the DM changes the time of day, and when the spirit layer is revealed or hidden
  • Personal notes — private per-campaign notes in Markdown, with a rendered preview and autosave; readable only by their author, enforced server-side
  • Documents — upload a PDF, plain text or Markdown rulebook or handout, or write one in the app, and read it without leaving CozyVTT; a DM shares documents with a campaign, and every member reads them from inside the session; text and Markdown documents can be edited by their uploader
  • Session history — every finished session with its date, length and the recap the DM wrote; the DM can edit or clear any past recap

Theming & Customization

  • 16 built-in color themes — warm, cool, dark, neutral, and vibrant palettes
  • Per-user themes — each account picks its own theme and font from the profile page; preferences persist across logout/login
  • Custom theme — pick primary, accent, background, and text colors to create a unique look
  • 8 font families — open-source Google Fonts including medieval, elegant, modern, handwritten, and scholarly options
  • Live preview — theme and font changes preview instantly before saving
  • Default theme — admin selects the theme shown on the login page and applied to brand-new users
  • Custom branding — the instance logo, mascot, and favicon can be replaced (swap the images in frontend/public/ before building; an admin upload UI is planned)

Security

  • Argon2id password hashing (64 MB memory cost, timeCost 3)
  • TOTP multi-factor authentication with hashed backup codes
  • Session-based authentication with rolling expiry and "remember me"
  • Password reset via email (SMTP configurable)
  • Admin-approval registration (optional)
  • File upload validation — magic-byte content checks (not just MIME header), size limits by type; text uploads must genuinely be text, and documents are served as plain text or PDF, never as a web page
  • Per-endpoint rate limiting — global API limit, strict auth limit, asset upload limit (configurable via ASSET_UPLOAD_RATE_LIMIT), and per-account limits on everything sent to the live table, set far above what a game sends
  • Security headers on the app page — a Content-Security-Policy that allows script only from your own instance, plus X-Frame-Options, nosniff, Referrer-Policy and Permissions-Policy. Injected script cannot run, the app cannot be framed by another site, and the browser will not send data to an address CozyVTT does not use
  • WebSocket campaign isolation — server-authenticated campaign membership; no client-spoofing
  • The backend runs as an unprivileged user — the container starts as root only long enough to fix ownership on your mounted folders, then drops to appuser before the app itself runs
  • Production refuses to start with a placeholder SESSION_SECRET or DATABASE_PASSWORD
  • See SECURITY.md for the vulnerability disclosure policy

Game Systems

System Character Sheet Status
D&D 5th Edition Full Available
Pathfinder 2nd Edition Full Available
Call of Cthulhu 7th Edition Full Available
Flexible / Custom JSON freeform Available
Shadowrun 6th Edition — Planned

Tech Stack

Backend

  • Node.js + Express + TypeScript (strict mode)
  • PostgreSQL 15 + Prisma ORM
  • Socket.io for real-time WebSocket events
  • Argon2id password hashing
  • Multer + Sharp for file uploads and thumbnail generation
  • Nodemailer for transactional email
  • Zod for runtime request validation
  • Jest for testing

Frontend

  • React 18 + TypeScript (strict mode)
  • Vite build tooling
  • Tailwind CSS with custom design tokens
  • Zustand for live session state; TanStack Query (React Query) for REST data
  • Socket.io client
  • Axios for REST API calls
  • react-resizable-panels for the session workspace
  • Framer Motion for animations (reduced-motion aware)
  • Vitest + Testing Library

Quick Start

Requirements

  • Node.js 20+
  • PostgreSQL 14+
  • A modern browser (Chrome, Firefox, Edge, Safari)
  • SMTP server (optional — required for password reset and invitation emails)
git clone https://github.com/CheekyChinchilla/CozyVTT.git
cd CozyVTT

# Copy it, then set at least DATABASE_PASSWORD and SESSION_SECRET (see docs/DEPLOYMENT.md)
cp .env.example .env

# Production stack (hardened, what end-users run)
docker compose up -d --build

Navigate to http://localhost and complete the setup wizard.

Local Development

If you've cloned the repo to hack on CozyVTT itself, use the dev compose file instead — it enables hot reload, exposes the backend port directly, and runs NODE_ENV=development:

docker compose -f docker-compose.dev.yml up

See docs/DEVELOPMENT.md for the full dev setup (including running outside Docker).

See docs/DEPLOYMENT.md for production deployment with Nginx and SSL.


Configuration

Most runtime configuration is managed through the Admin dashboard after setup. Email (SMTP) and upload limits are set in .env; the dashboard shows them and can send a test email:

Tab Setting Description
Users Invite User Email someone a link to join and choose their own password (needs SMTP; link valid 7 days)
Users Create User Generate a temporary password to hand over yourself — for instances without email
Settings Instance Name Displayed in the browser title and emails
Settings Allow Registration Whether new users can self-register
Settings Require Admin Approval New registrations must be approved before login
Settings Timezone Server timezone for session timestamps
Settings SMTP Shows the email settings from .env, with Send Test Email
Settings Upload Limits Shows the per-type file size limits from .env (maps, tokens, audio, avatars, documents)
Appearance Default Theme Theme shown on the login page and used for new users (each user can override from their profile)
Appearance Default Font Default font family applied alongside the default theme
Appearance Custom Theme Build a palette from primary, accent, background, and text colors, with a live readability check

However an account is added, its first sign-in ends with the person choosing their own password — an admin-issued temporary password cannot be used for anything else.

Instance branding (logo, mascot, favicon) is not set from the dashboard yet — see Appearance & Theming for how to change it today.

Default Upload Limits

Type Default Environment variable
Map images 50 MB MAX_MAP_SIZE_MB
Token images 5 MB MAX_TOKEN_SIZE_MB
Audio files 20 MB MAX_AUDIO_SIZE_MB
Avatar images 2 MB MAX_AVATAR_SIZE_MB
Documents (PDF, text, Markdown) 50 MB MAX_DOCUMENT_SIZE_MB

Set these in .env and apply them with docker compose up -d; no rebuild is needed, but docker compose restart keeps the old values. If you raise one, raise your reverse proxy's body limit to match (NGINX_MAX_BODY_SIZE for the bundled Nginx). See Upload Size Limits.


User Roles

Platform Roles

Role Description
ADMIN Full platform access — manage users, campaigns, system settings
USER Can create and join campaigns

Campaign Roles

Role Description
DM Full campaign control — manage maps, tokens, sessions, members
PLAYER Can view maps, move their own tokens, roll dice, chat
SPECTATOR Watches the map, chats and pings; keeps private notes and dice macros; cannot roll dice or initiative, move or edit tokens, or edit a character

Documentation

Document Description
User Guide End-user guide for all platform features
DM Guide DM-specific features and workflows
Player Guide Quick-start guide for players
Development Setup Local development guide
Architecture System architecture and design decisions
Deployment Production deployment guide
Contributing How to contribute to CozyVTT
Game Systems How to add new game system support
API Reference REST API and WebSocket event reference
WebSocket Events Detailed Socket.io event schema
Future Features Backlog of planned work
Security Policy How to report vulnerabilities
Changelog Release history
Third-Party Licenses Font and content license attributions

Community Projects

Built by other people, on their own terms. They are not part of CozyVTT, are not maintained by this project, and are listed because they are useful — check their own documentation and licence before running them.

Project What it does
cozyvtt-mcp An MCP bridge that lets an AI assistant act in a campaign — post to chat, roll dice, move tokens, change maps and run initiative. MIT licensed, independent of this codebase.

A note on building things like this. CozyVTT's HTTP and WebSocket surfaces are not a public API: they are what the web client calls, they are not versioned, and they carry no compatibility promise, so they can change in any release. They can be driven by a program — signing in with your own email and password returns a session cookie that authenticates both, and a script can do exactly what the web client does, as that user with that user's permissions. Unsupported is the honest word for it, not impossible.

That is why cozyvtt-mcp pins to a CozyVTT version and keeps a compatibility table. Check that table before pairing the two: the surface it builds on is unversioned and can change in any release.


Asset Storage

Uploaded files are stored in backend/uploads/ organized by type:

uploads/
  maps/        Map images and thumbnails
  tokens/      Token images and thumbnails
  audio/       Ambient audio files
  avatars/     User profile avatars
  documents/   PDF, text and Markdown documents

Backups made from the Admin Panel are not kept here: they go in backend/backups/.


License

GNU Affero General Public License v3.0 — see LICENSE for details.

CozyVTT is free to use, self-host, and fork. The AGPLv3 requires that any modified version you run as a network service must also make its source code available under the same license.

For third-party font and content licenses, see THIRD_PARTY_LICENSES.md.