A MUD code base in the style of the last millennium, written in the new millennium.
- Introduction
- Features
- Build Requirements
- Building
- Releases
- Deploying
- Local Configuration (.env)
- Database Tools
- Running the Server
- Development
- Support
- Contributing
- License
Cyberspace. A consensual hallucination experienced daily by billions of legitimate operators, in every nation, by children being taught mathematical concepts... A graphic representation of data abstracted from the banks of every computer in the human system. Unthinkable complexity. Lines of light ranged in the nonspace of the mind, clusters and constellations of data. Like city lights, receding. -- William Gibson
Boris MUD is a text-based virtual reality that allows multiple people to engage in roleplaying, adventuring, and story-telling.
- MTH (Mud Telopt Handler) - standardized handling of TELNET protocol.
- LMDB back-end database for objects and user accounts.
- Room navigation: look, go, enter, and direction aliases (north/n, south/s, etc.).
- SSE-based web client with output buffering and multipart framing.
- ColdFire machine programs -- objects can have ColdFire V4e programs (ELF binaries) attached that post messages to the game world via hypercalls.
- TODO ability to host multiple independent worlds from a single server.
- TODO On-Line Creation: interactive wizard provides menu-based building.
- GNU Make 4.2.1 (or later)
- GCC or Clang
- zlib development headers
Optional (for rebuilding machine programs in sdk/machine/):
- m68k-linux-gnu-gcc cross-compiler (
apt install gcc-m68k-linux-gnuon Debian/Ubuntu)
Debian / Ubuntu:
sudo apt update
sudo apt install build-essential zlib1g-devgit clone --recurse-submodules https://github.com/OrangeTide/boris
cd borisBuild using all available CPU cores:
make -j$(nproc)To use Clang instead of GCC:
make -j$(nproc) USE_CLANG=1To specify a cross-compiler directly:
make -j$(nproc) CC=arm-linux-gnueabihf-gccBuild output is bin/boris, bin/mkpass, and bin/muddb-tool. Object files go to
build/<triplet>/ (e.g. build/x86_64-linux-gnu/) so cross-compiled
object files don't clobber native ones.
To install the web client (to bin/www/ by default):
make installEnable the arm64 architecture and install the cross toolchain with libraries:
sudo dpkg --add-architecture arm64
sudo apt update
sudo apt install gcc-aarch64-linux-gnu zlib1g-dev:arm64Note: On Ubuntu and derivatives, the default apt mirrors only carry amd64/i386
packages. arm64 and armhf packages are served from ports.ubuntu.com. If apt update
fails with 404 errors for arm64, you need to add a ports source and pin
your existing sources to amd64 only. Create
/etc/apt/sources.list.d/arm64-cross.list:
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble main universe
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-updates main universe
Then add [arch=amd64,i386] to each deb line in your existing
/etc/apt/sources.list (or files under sources.list.d/) so they stop
trying to fetch arm64 from the wrong mirror. Then run sudo apt update again.
Build with the cross-compiler:
make -j$(nproc) CC=aarch64-linux-gnu-gccFor a fully static binary (no runtime dependencies on the Pi):
make -j$(nproc) CC=aarch64-linux-gnu-gcc LDFLAGS="-static"Follow the same ports.ubuntu.com setup as above (substituting [arch=armhf]
for [arch=arm64], or [arch=arm64,armhf] if you want both) if needed, then:
sudo dpkg --add-architecture armhf
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf zlib1g-dev:armhfmake -j$(nproc) CC=arm-linux-gnueabihf-gccCopy bin/boris, bin/mkpass, boris.cfg, and the data/ directory to the Raspberry Pi to run.
make clean # Remove object files and dependency files
make distclean # Remove objects, binaries, and installed web assetsBuild a release tarball containing stripped binaries, web client, sample
config, and game data. Pass all build flags in the same command -- release
chains through the full build so CC, LDFLAGS, and RELEASE_ARCH must
all be present:
make -j$(nproc) release # native x86-64
make -j$(nproc) release CC=aarch64-linux-gnu-gcc LDFLAGS="-static" RELEASE_ARCH=linux-arm64
make -j$(nproc) release CC=arm-linux-gnueabihf-gcc LDFLAGS="-static" RELEASE_ARCH=linux-arm32Output is a file like boris-0.7-linux-arm64.tar.xz in the project root.
Deploy a release to a remote server via SSH. Include the same build flags
as you would for make release:
make -j$(nproc) deploy [email protected]:mud
make -j$(nproc) deploy CC=arm-linux-gnueabihf-gcc LDFLAGS="-static" RELEASE_ARCH=linux-arm32 [email protected]:mudThis builds a release tarball and uploads it to the remote host. The deploy script uses versioned releases with symlinks:
~/mud/
releases/boris-0.7-linux-arm64/ # each release unpacked here
shared/boris.cfg # persistent config (survives upgrades)
shared/data/chars/ # persistent game data
shared/data/users/
current -> releases/... # symlink to active release
On first deploy, boris.cfg is copied to shared/ for editing. Game data
directories (chars/, users/) are symlinked from each release into
shared/ so they persist across upgrades.
You can also deploy directly without the Makefile:
./scripts/deploy.sh [email protected]:mud [tarball]Per-checkout settings go in a .env file (not committed to git). The
Makefile reads it automatically. Copy the example to get started:
cp doc/env.example .envAvailable settings:
| Variable | Description | Example |
|---|---|---|
DEPLOY_DEST |
Deploy target for make deploy (user@host[:dir]) |
[email protected]:mud |
RELEASE_ARCH |
Override release architecture label | linux-arm32 |
CC |
C compiler (useful for cross-compilation) | arm-linux-gnueabihf-gcc |
LDFLAGS |
Linker flags | -static |
Boris stores game objects (rooms, characters, users) in an LMDB database
(data/muddb/). The muddb-tool utility exports and imports this data as
plain-text JSON files organized by domain.
Dump the entire database to a directory tree:
./bin/muddb-tool export data/muddb dump/This creates dump/<domain>/<key>.json for every object. To export a
single domain:
./bin/muddb-tool export data/muddb dump/ roomsLoad JSON files into the database:
./bin/muddb-tool import data/muddb dump/To import only specific domains:
./bin/muddb-tool import data/muddb dump/ rooms charsA sample/ directory ships with the source (and binary releases) containing
a starter world with a handful of connected rooms. To set up a fresh
database:
mkdir -p data/muddb
./bin/muddb-tool import data/muddb sample/Then start the server normally with ./bin/boris.
The export/import format is a flat directory hierarchy:
sample/
rooms/
town-square.json # {"id":"town-square","name.short":"Town Square", ...}
east-gates.json
...
Each .json file contains a single JSON object. The filename (minus .json)
is the database key.
The server runs unattended on hobby hardware, so regular backups are important. Two approaches:
JSON export (portable, human-readable)
./bin/muddb-tool export data/muddb backup/This creates one .json file per record. The export can be inspected,
edited, diffed, or version-controlled. To restore from a JSON export, stop
the server, then:
rm -rf data/muddb
mkdir -p data/muddb
./bin/muddb-tool import data/muddb backup/LMDB file copy with mdb_copy (fast, compact)
mdb_copy creates a consistent snapshot even while the server is running.
Install it from the system LMDB package (apt install lmdb-utils on
Debian/Ubuntu).
mdb_copy data/muddb /path/to/backup/muddbAdd -c to compact free pages during copy:
mdb_copy -c data/muddb /path/to/backup/muddbTo restore, stop the server and replace the database directory:
rm -rf data/muddb
cp -r /path/to/backup/muddb data/muddbAutomated daily backup (cron)
Back up with muddb-tool, keep 14 days of snapshots. Adjust MUD_DIR to
match your installation:
MUD_DIR=/home/mud/boris
# daily database export, 04:00, keep 14 days
0 4 * * * d=$MUD_DIR/backups/$(date +\%F); mkdir -p "$d" && $MUD_DIR/bin/muddb-tool export $MUD_DIR/data/muddb "$d" && find $MUD_DIR/backups -maxdepth 1 -mindepth 1 -mtime +14 -exec rm -rf {} +
Or with mdb_copy for a faster binary snapshot:
MUD_DIR=/home/mud/boris
# daily LMDB snapshot, 04:00, keep 14 days
0 4 * * * d=$MUD_DIR/backups/muddb-$(date +\%F); mkdir -p "$d" && mdb_copy -c $MUD_DIR/data/muddb "$d" && find $MUD_DIR/backups -maxdepth 1 -name 'muddb-*' -mtime +14 -exec rm -rf {} +
Edit configuration file (boris.cfg) with your preferred MUD port (server.port, default 4444) and web port (webserver.port, default 8080).
Initialize the database with the sample world (optional but recommended):
mkdir -p data/muddb
./bin/muddb-tool import data/muddb sample/Start the server:
./bin/borisLogin and create your account.
When running the server the web client will be hosted at http://localhost:8080 (or your configured webserver.port).
Press Ctrl+C to shut down the server gracefully.
TODO: provide instructions on how to manually set administrator privileges on an account
CRITICAL:telnetserver:telnet server error: could not bind socket (Address already in use)
Another process is already listening on the configured port. Find it with:
lsof -i tcp:4444Either stop the other process or change server.port in boris.cfg to an unused port.
ERROR:muddb:mdb_env_open(data/muddb): No such file or directory
The LMDB database directory does not exist. Create it:
mkdir -p data/muddbClients cannot connect (firewall blocking ports)
If ufw is active on the server, open the telnet and web ports:
sudo ufw allow 4444/tcp
sudo ufw allow 8080/tcpReplace the port numbers if you changed server.port or webserver.port in
boris.cfg. Check status with sudo ufw status.
Objects can have ColdFire V4e programs attached to them. Pre-built ELF
binaries ship in data/machine/ and are loaded automatically when the
object enters the cache.
Source code for machine programs lives in sdk/machine/. To rebuild:
cd sdk/machine
makeThis cross-compiles with m68k-linux-gnu-gcc and writes ELF files to
data/machine/. The SDK header sdk/machine/include/machine_hc.h provides
inline wrappers for all available hypercalls (sleep, message post, exit, etc.).
See DEV.md for the machine program architecture details.
See DEV.md for architecture, build system internals, code patterns, and contributor information.
Please open an issue for support.
Please contribute using Github Flow. Create a branch, add commits, and open a pull request.
Boris includes the following third-party libraries:
- tiny-AES-c -- Small portable AES128/192/256 in C. Public domain (Unlicense). Used for scrypt password encryption.
- LMDB -- Lightning Memory-Mapped Database.
- jsmn -- Minimalistic JSON parser.
- MTH -- MUD Telopt Handler.
Copyright (c) 2008-2025, Jon Mayo
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the Boris MUD project.