Before the web, there were BBSes: bulletin board systems you dialed into directly, one caller at a time, to read messages, play door games, and trade files. As part of FlameNet I wanted a real one back. Here's the setup.

ENiGMA½

The modern BBS of choice is ENiGMA½, a Node.js BBS package supporting message networks, door games, file areas, and ANSI art, accepting connections over both telnet and SSH. Actively maintained and surprisingly full-featured.

Dockerizing it

I run it as a container with a bind-mounted config so the board survives rebuilds:

services:
  enigma:
    image: enigmabbs/enigma-bbs:latest
    ports:
      - "8888:8888"   # telnet
      - "8889:8889"   # ssh
    volumes:
      - ./enigma/config:/enigma-bbs/config
      - ./enigma/db:/enigma-bbs/db

Everything, themes, message areas, login servers, the SSH host key, is defined in a single config.hjson. HJSON rather than JSON, which means comments and trailing commas are legal, and that matters a lot in a config file this size. The two volumes are the whole state of the board: config holds how it behaves, db holds the SQLite databases with your users, messages and file catalog. Back up both or you are backing up neither.

The SSH listener has a specific trap. ENiGMA wants an RSA host key in the old PEM encoding, and a modern ssh-keygen writes the newer OpenSSH format by default, so the key generates fine and the SSH server refuses to start with an error that looks nothing like an encoding problem. Generate it with -m PEM and it works first time.

(If you ever publish your config, scrub the private-key passphrase first. Ask me how I know.)

Connecting

Any telnet or SSH client works. The board greets you with ANSI art, a login prompt, and the unmistakable feeling that it's 1996 again.

One thing to set on your side: the art is CP437, the IBM PC character set, not UTF-8. A terminal that assumes UTF-8 renders the box-drawing characters as garbage, which is a disappointing first impression of a board somebody spent hours theming. Most modern clients have a setting for it, and SyncTERM exists precisely because this is a solved problem nobody wants to solve twice.

The full Docker setup is on my GitLab. More FlameNet writeups soon.