A free, open-source browser strategy game: grow a settlement from a hut to a castle, raise an army, raid and conquer.
▶ Play now in your browser — no download, no sign-up
Website · Development · Self-hosting · Contributing
LibreHold is a multiplayer village strategy game that runs in the browser. Every world lives on the server, so your villages keep growing and your armies keep marching while you are away. Bots fill the map, so a world is never empty, even with a handful of friends.
Alpha: the rules and balance still change, and worlds or accounts may be reset between updates.
- Instant games — one-hour matches on a small map at ×100 speed. Press Play now, get a guest nickname and a developed village, and make your first conquest within minutes. No sign-up needed.
- Private worlds — host a short game for friends with an invite link and a QR code, and tune its length, seats, bots, pace and rules.
- Long worlds — persistent worlds created by the server admin, played over days.
- Real strategy — 15 buildings, 12 unit types, scouting, supports, field battles between marching armies, loyalty and conquest, a market and a farm assistant.
- Bots that play — computer players that build, farm barbarians, save for hetmans and wage war on each other and on you.
- Own pixel art and a layout that works on phones from 360 px.
- Easy to host — one Go binary, Postgres and Valkey in Docker Compose, with optional HTTPS through Caddy and nightly backups.
Open librehold.org and press Play now.
You need a machine with Docker (amd64 or arm64). Save this as docker-compose.yml:
services:
db:
image: postgres:18.6
restart: unless-stopped
environment:
POSTGRES_USER: librehold
POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "librehold"]
interval: 5s
server:
image: ghcr.io/librehold-game/librehold:latest
restart: unless-stopped
environment:
LH_DATABASE_URL: postgres://librehold:${DB_PASSWORD}@db:5432/librehold?sslmode=disable
LH_COOKIE_SECURE: "false"
LH_ADMIN_USERNAME: admin
LH_ADMIN_PASSWORD: ${ADMIN_PASSWORD:?set ADMIN_PASSWORD in .env}
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
volumes:
pgdata:Next to it, create .env with two passwords of your own (letters and digits; the admin one at least 8 characters) and start the game:
DB_PASSWORD=
ADMIN_PASSWORD=docker compose up -dThe game is then at http://<server>:8080/; log in as admin to reach the admin panel. Update with
docker compose pull && docker compose up -d. This is enough for friends or a LAN party; before you open the game
to the internet, use the full setup in deploy/: HTTPS, nightly backups and limits shared through Valkey.
Requirements: Node.js 24+, Go 1.27+ and Docker (for Postgres, Valkey and the database tests).
npm install
cd server && make db && cd .. # Postgres on localhost:5433, Valkey on localhost:6380
npm run dev:all # API on :8080, account site on :5173, game on :5174; Ctrl+C stops all threeOpen the account site at http://localhost:5173/ (admin: admin / adminadmin); the game runs at
http://localhost:5174/game/game.html?world=<id>. Run the tests with npm test (client) and npm run server:test
(server). The full guide, including running the parts separately, the environment variables and the end-to-end tests,
is in docs/development.md.
The Go server owns every rule and every balance value, and the Postgres database is the single source of truth: each
order and each scheduled event is one transaction under a per-world lock, so a restart loses nothing. The React client
only displays the state and sends orders. It reads the balance tables generated from the Go rules (npm run gen), so
the two never drift apart.
server/ Go game server (hexagonal)
internal/game game rules, balance and bots; no I/O
internal/app use cases: accounts, lobby, orders, views, event worker
internal/adapters Postgres, HTTP API, WebSocket, file gate
cmd/ server, bot simulator, archive export, generator
src/ React client (account site and game)
tests/ client tests (Vitest)
deploy/ Docker Compose, Caddy, backups
| Document | Contents |
|---|---|
docs/development.md |
running locally, server layout, environment variables, time model, scripts |
docs/gameplay.md |
instant games, player worlds, world settings, bots, quests |
docs/balance.md |
balance formulas, where to change them, pacing tests |
docs/interface.md |
village view, map, art layers, phone layout |
deploy/README.md |
production deployment, HTTPS, backups and restore |
ASSETS.md |
origin and licence of every art and font file |
CHANGELOG.md |
changes per version, written from the git history by scripts/release.sh |
Bug reports, ideas and pull requests are welcome. Please read CONTRIBUTING.md and the
Code of Conduct first. There is nothing to sign: contributions are
accepted under the project's licence. Artwork is not open, so please ask before sending any graphics.
Please do not report security problems in public issues. Follow SECURITY.md instead.
You are free to play, self-host, study, change and share LibreHold.
- Code — GNU AGPL 3.0, with a few additional terms in
LICENSING.md: keep the credits, and give a modified version its own name. If you run a modified version for other people, share its source code. - Artwork (
src/assets/pixel/,public/account/og/,docs/media/) — free to use, unchanged, on any LibreHold server that is not commercial (LICENSE-ART.md). - Fonts — their authors' licence (SIL OFL 1.1), described in
ASSETS.md.
Made by Szymon Kocur and contributors, hosted by TomcatFlow.

