Skip to content

Latest commit

 

History

History
1187 lines (920 loc) · 38.5 KB

File metadata and controls

1187 lines (920 loc) · 38.5 KB

DOS Door Games - Sysop Documentation

This document was generated by AI and may contain errors. Report issues on Github.

See also: Doors.md for an overview of all door types and shared multiplexing bridge setup.

Table of Contents


Overview

BinktermPHP supports classic DOS door games through a DOSBox-X bridge system. This allows users to play traditional BBS door games like Legend of the Red Dragon (LORD), Trade Wars 2002, and others directly in their web browser.

Key Features:

  • Multi-user support (up to 100 concurrent sessions; default 10)
  • Automatic node allocation
  • Session management with expiration
  • Configurable disconnect and carrier loss behavior
  • Drop file generation (DOOR.SYS format)
  • ANSI/CP437 encoding support
  • Custom icons and screenshots per door
  • Secure asset serving (manifest-declared assets only)

System Architecture

The DOS door system uses a multiplexing bridge architecture where a single long-running bridge process manages the entire session lifecycle:

[Browser 1] ─┐
[Browser 2] ─┼─→ wss://bbs.com:6001 ─→ [Multiplexing Bridge] ─┬─→ 127.0.0.1:5000 ←─ DOSBox 1 → LORD
[Browser 3] ─┘      (WebSocket)           (Node.js Process)     ├─→ 127.0.0.1:5001 ←─ DOSBox 2 → TW2002
                                                                 └─→ 127.0.0.1:5002 ←─ DOSBox 3 → LORD

Components:

  1. Multiplexing Bridge (scripts/dosbox-bridge/multiplexing-server.js):

    • Single long-running Node.js process
    • Listens on one WebSocket port (default: 6001)
    • Authenticates clients using tokens
    • Dynamically allocates TCP ports from pool (5000-5100)
    • Generates DOSBox configs with session-specific settings
    • Launches DOSBox processes when WebSocket connects
    • Creates TCP listeners for DOSBox connections
    • Multiplexes data between WebSocket clients and DOSBox TCP ports
    • Handles up to 100 concurrent sessions efficiently (60-100MB RAM per dosbox-x session on x64)
  2. DOSBox-X: Runs the actual DOS door game in headless mode

    • Each session gets its own DOSBox process (launched by bridge)
    • Connects TO bridge via TCP on dynamically allocated port
    • Built-in FOSSIL emulation for door compatibility
  3. Session Manager (src/DoorSessionManager.php):

    • Allocates nodes (1-100)
    • Generates authentication tokens
    • Stores user data in session record (for drop file generation)
    • Creates session record in database
    • Bridge handles everything else (port allocation, drop file creation, config generation, DOSBox launch)

Data Flow:

  1. User clicks door game link
  2. PHP allocates node, generates unique token
  3. PHP creates database record with session info (token, node, door_id, user data for drop file)
  4. PHP returns session data with WebSocket URL and token to browser
  5. Browser connects to multiplexing bridge with token: wss://bbs.com:6001?token=abc123...
  6. Bridge validates token against database, retrieves session details including user data
  7. Bridge allocates dynamic TCP port from available pool (no port conflicts!)
  8. Bridge generates drop file (DOOR.SYS) using user data from session record
  9. Bridge generates DOSBox config with allocated port and door-specific settings
  10. Bridge creates TCP listener on allocated port
  11. Bridge launches DOSBox which connects back to bridge's TCP listener
  12. Bridge updates database with allocated port and DOSBox PID
  13. User input flows: Browser → WebSocket → Bridge → TCP → DOSBox → Door Game
  14. Game output flows: Door Game → DOSBox → TCP → Bridge → WebSocket → Browser
  15. When done, DOSBox exits, bridge detects disconnect and cleans up

Advantages of This Architecture:

  • No Port Conflicts: Dynamic allocation from pool, only binds ports for active sessions
  • Efficient: One Node.js process manages all sessions
  • Scalable: Handles many concurrent sessions with minimal overhead
  • Easy SSL: Works seamlessly behind reverse proxy (Caddy, nginx)
  • Centralized: All WebSocket connections through single port
  • Reliable: Long-running daemon with full lifecycle control
  • Simple: PHP just creates database record, bridge does the heavy lifting

Prerequisites

Required Software

  1. DOSBox-X (recommended) or vanilla DOSBox

    • DOSBox-X is strongly recommended due to better serial port stability and features:
      • Vanilla DOSBox has known issues with serial port handling
      • DOSBox-X provides better FOSSIL emulation and multiplexing support
      • Memory usage: ~60-100 MB RAM per instance in headless mode on x64
      • With 10 concurrent users: ~1 GB RAM (very reasonable)

    Installation:

    • Windows: Download from https://dosbox-x.com/
    • Linux: sudo apt install dosbox-x or compile from source
    • macOS: brew install dosbox-x

    Vanilla DOSBox (alternative, not recommended for production):

    • Similar memory usage (~60-100 MB per instance)
    • Known serial port stability issues
    • May work for testing but not recommended for production use (it didn't work well for me in testing!)
    • Linux: sudo apt install dosbox
    • Windows: Download from https://www.dosbox.com/
    • macOS: brew install dosbox

    Note: The bridge auto-detects and prefers vanilla DOSBox if both are installed. Set DOSBOX_EXECUTABLE=/usr/bin/dosbox-x in .env to specify a dosbox executable to use.

    DOSEMU Support (Experimental, Not Recommended):

    • The bridge includes experimental DOSEMU support via DOOR_EMULATOR=dosemu
    • NOT recommended for production use - numerous issues and requires further testing+development
    • Console I/O vs serial I/O conflicts with FOSSIL drivers
    • Complex configuration requirements
    • Only for adventurous sysops willing to troubleshoot and debug
    • DOSBox is proven, reliable, and recommended for all deployments
  2. Node.js 18.x or newer and bridge dependencies — see Doors.md for installation instructions.

File Structure

binkterm-php/
├── dosbox-bridge/                          # DOSBox configuration and DOS files
│   ├── dosbox-bridge-production.conf       # Headless config (default)
│   ├── dosbox-bridge-test.conf             # Visible window config (testing)
│   ├── maintenance.conf                    # Config for maintenance/admin mode
│   ├── dosdoor-maint.sh                    # Maintenance shell script (Linux)
│   ├── dosdoor-maint.cmd                   # Maintenance batch script (Windows)
│   └── dos/                                # DOS drive (mounted as C:)
│       ├── CONFIG.SYS                      # DOS system config
│       ├── DOORS/                          # Door game installations (UPPERCASE - Linux is case-sensitive)
│       │   ├── 8WAYSL/                     # 8-Way Shootout
│       │   ├── ADMIN/                      # Admin utilities door
│       │   ├── BRE/                        # Barren Realms Elite
│       │   ├── LORD/                       # Legend of the Red Dragon
│       │   │   ├── dosdoor.jsn             # Door manifest (required)
│       │   │   ├── START.BAT               # Launch script
│       │   │   └── ... (game files)
│       │   └── SKEL/                       # Skeleton door template
│       ├── DROPS/                          # Per-node drop file directories
│       │   ├── node1/                      # Drop files for node 1 (DOOR.SYS, etc.)
│       │   └── node2/                      # Drop files for node 2
│       └── TOOLS/                          # DOS utility tools
│           ├── EDIT.COM                    # DOS text editor
│           ├── EDIT.HLP                    # Editor help file
│           └── README.txt
└── scripts/
    └── cleanup_expired_dosdoor_sessions.php # Cleanup script

Initial Setup

1. Install DOSBox-X

Windows:

  1. Download DOSBox-X from https://dosbox-x.com/
  2. Install to C:\DOSBox-X\ (recommended)
  3. Verify installation: Open Start Menu → DOSBox-X

Linux (Debian/Ubuntu):

# Option 1: Package manager (if available)
sudo apt install dosbox-x

# Option 2: Compile from source
# Install build dependencies
sudo apt update
sudo apt install -y automake gcc g++ make libncurses-dev nasm \
    libsdl2-dev libsdl2-net-dev libpcap-dev libslirp-dev fluidsynth \
    libfluidsynth-dev libavformat-dev libavcodec-dev libswscale-dev \
    libfreetype-dev libxkbfile-dev libxrandr-dev libglu1-mesa-dev git

# Clone and build
git clone https://github.com/joncampbell123/dosbox-x.git
cd dosbox-x
./build
sudo make install

# Verify installation
dosbox-x --version

2. Install Node.js and Bridge Dependencies

See Doors.md — Prerequisites for Node.js installation and bridge dependency setup.

3. Configure Environment Variables

Edit .env and add/verify:

# DOS Emulator Selection (default: dosbox)
# dosbox = DOSBox or DOSBox-X (RECOMMENDED for stability)
# dosemu = DOSEMU (EXPERIMENTAL, Linux only, not recommended)
# DOOR_EMULATOR=dosbox

# DOSBox executable path (auto-detected if not specified)
# Auto-detection order: dosbox, dosbox-x
# DOSBOX_EXECUTABLE=/usr/bin/dosbox-x
DOSBOX_EXECUTABLE=/usr/local/bin/dosbox-x
#DOSBOX_EXECUTABLE=C:\DOSBox-X\dosbox-x.exe

# DOSEMU executable path (auto-detected if not specified)
# Linux only - experimental support, not recommended for production
# DOSEMU_EXECUTABLE=/usr/bin/dosemu

# DOSBox config file (default: dosbox-bridge-production.conf)
# DOSDOOR_CONFIG=dosbox-bridge-production.conf
# DOSDOOR_CONFIG=dosbox-bridge-test.conf
# DOSDOOR_CONFIG=dosbox-bridge-custom.conf

# WebSocket disconnect behavior (in minutes, default: 0 = immediate)
# 0 = Immediately simulate carrier loss when WebSocket disconnects
# >0 = Wait X minutes for user to reconnect before triggering carrier loss
DOSDOOR_DISCONNECT_TIMEOUT=0

# Carrier loss timeout (in milliseconds, default: 5000)
# How long to wait for door process to exit gracefully after carrier loss
# before force-killing the process
DOSDOOR_CARRIER_LOSS_TIMEOUT=5000

# WebSocket port for multiplexing bridge (default: 6001)
DOSDOOR_WS_PORT=6001

# WebSocket bind address (default: 127.0.0.1 for reverse proxy)
# 127.0.0.1 = Localhost only (production behind SSL proxy)
# 0.0.0.0 = All interfaces (development/direct access)
DOSDOOR_WS_BIND_HOST=127.0.0.1

# WebSocket URL for browser (optional, auto-detected if not set)
# If behind SSL proxy, configure proxy to forward /dosdoor or use separate port
# DOSDOOR_WS_URL=wss://bbs.example.com:6001
# DOSDOOR_WS_URL=wss://bbs.example.com/dosdoor

# Headless mode for DOSBox (default: true)
# true = Run DOSBox headless (production)
# false = Show DOSBox window (debugging)
# DOSDOOR_HEADLESS=true

# Maximum simultaneous door sessions (concurrent players)
# Limits how many users can play door games at the same time
# Each session uses one node number (1 to MAX_SESSIONS)
# Each dosbox instance may take upwards of 100 MB RAM each in headless mode
DOSDOOR_MAX_SESSIONS=10

# Debug mode - keep session files for inspection (default: false)
# Set to 'true' to disable cleanup of DOOR.SYS and session directories
# Useful for debugging drop file generation and DOSBox config issues
# DOSDOOR_DEBUG_KEEP_FILES=false

4. Verify Database Schema

The door system requires these tables (created by scripts/setup.php):

  • door_sessions - Active session tracking
  • door_session_logs - Session event logging

Run setup if needed:

php scripts/setup.php

5. Test the System

Start the multiplexing bridge — see Doors.md — Running the Bridge for instructions.

Then visit your BBS and try launching a door game. The bridge will:

  1. Authenticate your WebSocket connection
  2. Allocate a TCP port dynamically (e.g., 5000)
  3. Generate a DOSBox config for your session
  4. Launch DOSBox which connects back to the bridge
  5. Multiplex data between your browser and the door game

Starting the Multiplexing Bridge

See Doors.md — Running the Bridge for how to start the bridge in development and production (systemd, cron, Windows NSSM).

The bridge logs active session status every 60 seconds:

[STATUS] Active sessions: 3
  - door_1_node1_123: 45s, WS:true, DOS:true
  - door_2_node2_456: 120s, WS:true, DOS:true
  - door_3_node3_789: 30s, WS:false, DOS:true

Configuration

DOSBox Configuration Files

Production Config (dosbox-bridge-production.conf):

  • Headless mode (window positioned off-screen on Windows)
  • Serial port configured for TCP connection
  • Auto-exit when door closes
  • Used by default for live BBS

Test Config (dosbox-bridge-test.conf):

  • Visible window for debugging
  • Same serial port settings
  • Useful for testing door installations

Custom Config: Create dosbox-bridge-custom.conf for your own settings:

# In .env:
DOSDOOR_CONFIG=dosbox-bridge-custom.conf

Key DOSBox Settings

In your config file:

[sdl]
# Production: Window off-screen (Windows only)
windowposition=-2000,-2000

[serial]
# DOSBox connects TO bridge on dynamically allocated port
# Port number will be replaced by bridge with actual allocated port
# transparent:1 = Pass through control signals (required for FOSSIL)
# serial1_fossil=true = Enable built-in FOSSIL emulation
serial1=nullmodem server:127.0.0.1 port:5000 transparent:1
serial1_fossil=true

[autoexec]
# Mount DOS drive
mount c dosbox-bridge/dos
c:

# Door-specific commands will be appended here by the bridge
# The bridge reads the door manifest and generates:
# cd \DOORS\LORD
# call start.bat 1

Session Settings

Sessions are configured in src/DoorSessionManager.php:

private const TCP_PORT_BASE = 5000;  // DOSBox serial ports: 5001-5100
private const WS_PORT_BASE = 6000;   // WebSocket ports: 6001-6100
private const MAX_SESSIONS = 100;    // Maximum concurrent sessions

Session Expiration:

  • Default: 2 hours per session
  • Configurable in startSession() method (line 101)
  • Enforced by cleanup script

Adding New Door Games

Important Note: BinktermPHP includes sample dosdoor.jsn manifests and icons for popular door games (LORD, BRE, etc.) but does not include the actual door game files due to licensing restrictions. Sysops must download and install door game executables separately.

⚠ Warning: Linux Filesystem Case Sensitivity

DOS is case-insensitive — LORD, lord, and Lord all refer to the same file. Linux is case-sensitive — they are three different files or directories. This mismatch can cause subtle and hard-to-diagnose problems when the dosbox-bridge/dos/ directory tree is managed from Linux:

  • If you create a directory named test from Linux and later create TEST, DOS will see two different directories (because DOSBox-X's long filename support preserves the Linux case distinction). This can cause door games to fail to find their own files.
  • Filenames or directories that don't conform to the 8.3 format (max 8-character name, 3-character extension, no spaces or special characters) may display or behave inconsistently across DOS and Linux.

Rules to follow when creating or copying files from Linux into dosbox-bridge/dos/:

  1. Use UPPERCASE for all filenames and directory names — e.g. DOORS, LORD, START.BAT
  2. Stick to 8.3 format — maximum 8 characters for the name, 3 for the extension
  3. Use only alphanumeric characters, hyphens, and underscores — avoid spaces and special characters

DOSBox-X is configured to emulate MS-DOS 6.22 (ver=6.22), which does not include long filename (LFN/VFAT) support. This means DOS programs will only ever see uppercase 8.3 names, which eliminates the case-duplicate problem. If you change ver= to 7.0 or higher in the DOSBox config, LFN support activates and the case-sensitivity problem returns.

Step 1: Prepare the Door Game

  1. Obtain the door game files

  2. Test locally first

    • Extract to a test folder
    • Run in DOSBox manually to verify it works and to perform configuration. From within an X Terminal, run dosbox-bridge/dosdoor-maint.sh to run DOSBox-X with the door system mounted, or use the browser-based "DOSDoor DOS shell" admin door (see Sysop DOS Maintenance Shell).
    • Note the executable name and any configuration needed

Step 2: Install to BinktermPHP

  1. Create door directory (use UPPERCASE — Linux is case-sensitive):

    mkdir dosbox-bridge/dos/DOORS/YOURDOOR
  2. Copy door files:

    cp -r /path/to/door/files/* dosbox-bridge/dos/DOORS/YOURDOOR/
  3. Create launch script (optional but recommended):

    Create dosbox-bridge/dos/DOORS/YOURDOOR/START.BAT:

    @ECHO OFF
    REM %1 is the node number passed by BinktermPHP
    YOURDOOR.EXE DOOR%1.SYS

    Some doors may need different syntax:

    @ECHO OFF
    CALL YOURDOOR.BAT %1

Step 3: Create Door Manifest

Create dosbox-bridge/dos/DOORS/YOURDOOR/dosdoor.jsn:

{
    "version": "1.0",
    "type": "dosdoor",
    "game": {
        "name": "Your Door Game",
        "short_name": "YDG",
        "author": "Author Name",
        "version": "1.0",
        "release_year": 1995,
        "description": "A classic BBS door game",
        "genre": ["Adventure", "RPG"],
        "players": "Multi-player",
        "icon": "icon.gif",
        "screenshot": "screenshot.png"
    },
    "door": {
        "type": "dos",
        "executable": "START.BAT",
        "launch_command": "call start.bat {node}",
        "directory": "dosbox-bridge/dos/DOORS/YOURDOOR",
        "dropfile_format": "DOOR.SYS",
        "max_nodes": 10,
        "fossil_required": true
    },
    "config": {
        "enabled": false,
        "credit_cost": 0,
        "max_time_minutes": 30
    }
}

Manifest Field Reference:

  • id: Unique identifier (must match directory name)
  • name: Display name shown to users
  • executable: Main executable or batch file
  • launch_command: Full command with {node} and {dropfile} macros
  • drop_file_format: Currently only "DOOR.SYS" is supported
  • max_nodes: Maximum concurrent players (1-100)
  • require_ansi: Whether door requires ANSI support
  • fossil_required: Load FOSSIL driver (default: true). Set to false for doors with internal comm routines (faster)

Step 4: Enable the Door

  1. Scan for new doors: The system automatically scans dosbox-bridge/dos/DOORS/ for dosdoor.jsn files

  2. Enable via admin panel:

    • Login as admin
    • Navigate to Games → DOS Doors
    • Find your door in the list
    • Click "Enable"
    • Adjust settings if needed
  3. Or enable manually:

    Edit config/dosdoors.json:

    {
        "yourdoor": {
            "enabled": true,
            "name": "Your Door Game",
            "max_nodes": 10
        }
    }

Step 5: Test the Door

  1. Launch the door from the games menu

  2. Check for issues:

    • Does it display properly?
    • Does input work correctly?
    • Does it save game state?
    • Does it exit cleanly?
  3. Review logs:

    # Filter for DOSDOOR-prefixed logs
    tail -f data/logs/php-errors.log | grep DOSDOOR

Example: Installing LORD

Note: We ship a working dosdoor.jsn for LORD - the information below is for example only.

# 1. Create directory (UPPERCASE - Linux is case-sensitive)
mkdir dosbox-bridge/dos/DOORS/LORD

# 2. Copy LORD files (from archive or existing installation)
cp -r /path/to/lord/* dosbox-bridge/dos/DOORS/LORD/

# 3. Create START.BAT
cat > dosbox-bridge/dos/DOORS/LORD/START.BAT << 'EOF'
@ECHO OFF
REM Launch Legend of the Red Dragon
REM %1 = node number from BinktermPHP
LORD.EXE DOOR%1.SYS
EOF

# 4. Create manifest
cat > dosbox-bridge/dos/DOORS/LORD/dosdoor.jsn << 'EOF'
{
    "version": "1.0",
    "id": "lord",
    "name": "Legend of the Red Dragon",
    "author": "Seth Able Robinson",
    "description": "Classic fantasy adventure door game",
    "executable": "START.BAT",
    "launch_command": "call start.bat {node}",
    "drop_file_format": "DOOR.SYS",
    "max_nodes": 10,
    "require_ansi": true,
    "fossil_required": false,
    "category": "game",
    "notes": "LORD uses internal comm routines - FOSSIL not required (faster performance)"
}
EOF

# 5. Enable via admin panel or config file
# 6. Test by launching from games menu

Sysop DOS Maintenance Shell

BinktermPHP includes a built-in admin-only door called "DOSDoor DOS shell" that provides sysops with a live DOS command prompt directly in the browser. This is useful for configuring door games, editing configuration files, copying or reorganizing game data, and other maintenance tasks without needing direct server access.

Accessing the Maintenance Shell

The DOS shell door is restricted to admin accounts and will not appear in the games list for regular users.

  1. Log in as an admin
  2. Navigate to Games in the main menu
  3. The "DOSDoor DOS shell" door will be listed (admin-only doors are only visible to admins)
  4. Click Play to launch the door

The terminal will connect and drop you into a DOS command prompt with the BBS door file system (dosbox-bridge/dos/) mounted as drive C:.

What You Can Do

From the DOS shell you can:

  • Browse and edit files in C:\DOORS\ (door game installations)
  • Run door executables directly to test or configure them (e.g., run a door's setup utility)
  • Edit batch files and configuration text files
  • Copy, rename, or delete files within the DOS environment
  • Test that a door's launch sequence works correctly before enabling it for users

This is equivalent to running dosbox-bridge/dosdoor-maint.sh from a Linux terminal or dosdoor-maint.cmd on Windows, but accessible entirely through the browser interface.

Doorway Time Limit

The DOS shell uses Doorway for Unlimited Doors (Doorway) as its command-line environment. The copy of Doorway included with BinktermPHP is unregistered, which imposes a 10-minute time limit per session. When the limit is reached, Doorway will display a registration notice and exit, ending the session.

If you need longer sessions, you can register Doorway with the original shareware registration. A registered copy of Doorway removes the time limit entirely.

Workaround for the time limit: Simply close the tab and relaunch the DOS shell door to start a new 10-minute session. Your files and changes persist between sessions since they are stored on the server's dosbox-bridge/dos/ directory.


Door Manifest Format

Complete Manifest Specification

{
    "version": "1.0",
    "type": "dosdoor",
    "game": {
        "name": "Display Name",
        "short_name": "Short",
        "author": "Author Name",
        "version": "1.0",
        "release_year": 1995,
        "description": "Description shown to users",
        "genre": ["Genre1", "Genre2"],
        "players": "Single-player or Multi-player",
        "icon": "icon.gif",
        "screenshot": "screenshot.png"
    },
    "door": {
        "type": "dos",
        "executable": "FILENAME.EXE",
        "launch_command": "call start.bat {node}",
        "directory": "dosbox-bridge/dos/DOORS/DOORID",
        "dropfile_format": "DOOR.SYS",
        "dropfile_path": "\\DOORS\\DOORID",
        "node_support": true,
        "max_nodes": 10,
        "fossil_required": true,
        "notes": "Optional notes about this door"
    },
    "requirements": {
        "dosbox": "dosbox-x"
    },
    "config": {
        "enabled": false,
        "credit_cost": 0,
        "max_time_minutes": 30
    }
}

Field Descriptions

game.icon (string, optional):

  • Filename of the door's icon image (displayed on games page)
  • File must be placed in the door's directory alongside dosdoor.jsn
  • Supported formats: GIF, PNG, JPG, JPEG, SVG, BMP, ICO
  • Served securely via /door-assets/{doorid}/icon endpoint
  • Only assets declared in manifest can be accessed (security)
  • Example: "icon": "icon.gif"

game.screenshot (string, optional):

  • Filename of the door's screenshot image
  • File must be placed in the door's directory alongside dosdoor.jsn
  • Supported formats: GIF, PNG, JPG, JPEG, SVG, BMP, ICO
  • Served securely via /door-assets/{doorid}/screenshot endpoint
  • Example: "screenshot": "screenshot.png"

door.dropfile_path (string, optional):

  • Custom path where DOOR.SYS should be placed (for non-multi-node doors)
  • Overrides default per-node drop file location
  • Format: "\\DOORS\\DOORID" (DOS path format, uppercase)
  • Use for doors that expect DOOR.SYS in their own directory
  • Example: BRE expects DOOR.SYS in \DOORS\BRE\ not \DROPS\NODE1\

fossil_required (boolean, default: true):

  • Controls whether the FOSSIL driver (BNU.COM) is loaded before launching the door
  • true: Load FOSSIL driver (required for most DOS doors)
  • false: Skip FOSSIL loading (for doors with internal comm routines)
  • Performance impact:
    • FOSSIL loading adds ~100-200ms startup delay
    • Doors with internal routines (e.g., LORD) are noticeably faster without FOSSIL
    • Set to false only if you've verified the door works with internal comm routines
  • Memory impact: FOSSIL driver uses ~30-50KB RAM per session

Macro Replacements in launch_command

Placeholder Replaced with
{node} Node number (e.g. 1)
{dropfile} Drop file name (e.g. DOOR.SYS)
{user_number} BBS user ID (numeric)

Examples

Simple executable:

{
    "launch_command": "doorgame.exe {dropfile}"
}

Batch file with node:

{
    "launch_command": "call start.bat {node}"
}

Direct executable with node:

{
    "launch_command": "lord.exe DOOR{node}.SYS"
}

Door Assets (Icons & Screenshots)

The system supports custom icons and screenshots for each door game.

Asset Security

Important: Only assets explicitly declared in the door manifest can be accessed. This prevents arbitrary file access within door directories.

Allowed asset types:

  • icon - Door game icon (displayed on games page)
  • screenshot - Door game screenshot

Adding Assets

  1. Place asset files in door directory:

    dosbox-bridge/dos/DOORS/LORD/
    ├── dosdoor.jsn
    ├── icon.gif          # Your icon file
    └── screenshot.png    # Your screenshot file
  2. Declare in manifest:

    {
        "game": {
            "name": "Legend of the Red Dragon",
            "icon": "icon.gif",
            "screenshot": "screenshot.png"
        }
    }
  3. Supported formats:

    • GIF, PNG, JPG/JPEG, SVG, BMP, ICO
    • Recommended icon size: 64x64 pixels
    • Recommended screenshot size: 640x400 pixels

Asset URLs

Assets are served via secure endpoints that verify manifest declarations:

/door-assets/{doorid}/icon        → Serves icon file from manifest
/door-assets/{doorid}/screenshot  → Serves screenshot file from manifest

Examples:

  • /door-assets/lord/icon → Serves icon.gif (declared in LORD's manifest)
  • /door-assets/bre/screenshot → Serves screenshot.png (declared in BRE's manifest)

Browser Caching

Assets are served with 24-hour cache headers for performance:

Cache-Control: public, max-age=86400

Troubleshooting

Door Won't Launch

Symptoms: Clicking door does nothing, or shows "Connecting..." forever

Check:

  1. Is the multiplexing bridge running? ps aux | grep multiplexing-server or check Task Manager
  2. Is Node.js installed? node --version
  3. Are npm dependencies installed? Check node_modules/ws and node_modules/iconv-lite
  4. Is DOSBox-X installed? Check DOSBOX_EXECUTABLE in .env
  5. Is WebSocket port available? Check for conflicts on port 6001 (TCP ports 5000-5100 are allocated dynamically)

Door Launches But Nothing Displays

Symptoms: Terminal connects but shows blank screen

Check:

  1. Is the door executable correct in dosdoor.jsn?
  2. Does the door exist in dosbox-bridge/dos/DOORS/?
  3. Is the launch command correct?

Debug:

# Test DOSBox manually
# Edit dosbox-bridge-test.conf to add:
cd \DOORS\YOURDOOR
call start.bat 1

# Run DOSBox with visible window:
"C:\DOSBox-X\dosbox-x.exe" -conf dosbox-bridge-test.conf

# Watch for errors in DOSBox window

Door Doesn't Save Game State

Symptoms: Player progress is lost between sessions

Check:

  1. Does the door directory have write permissions?

    # Windows - Right click folder → Properties → Security
    # Linux
    chmod -R 775 dosbox-bridge/dos/DOORS/YOURDOOR
  2. Is the door configured for multi-node operation?

    • Some doors need separate data files per node
    • Check door documentation for multi-node setup
  3. Are drop files being generated correctly?

    # After launching, check:
    ls dosbox-bridge/dos/DROPS/NODEX/DOOR.SYS

WebSocket Disconnects Immediately

Symptoms: "Connection closed" right after connecting

Check:

  1. Disconnect timeout setting:

    # In .env:
    DOSDOOR_DISCONNECT_TIMEOUT=0  # Change to 5 for 5-minute grace period
  2. Bridge server logs:

    # Bridge logs to console - check for errors
    # Look for [WS] messages
  3. Firewall blocking WebSocket ports (6001-6100)


Advanced Configuration

Custom DOSBox Configurations

Create a custom config to preserve your changes across upgrades:

# 1. Copy production config
cp dosbox-bridge/dosbox-bridge-production.conf dosbox-bridge/dosbox-bridge-custom.conf

# 2. Edit your custom config
nano dosbox-bridge/dosbox-bridge-custom.conf

# 3. Set in .env
DOSDOOR_CONFIG=dosbox-bridge-custom.conf

Common customizations:

[cpu]
# Increase cycles for faster doors
cycles=20000

[serial]
# Adjust serial port settings if needed
serial1=nullmodem port:5001 transparent:1 telnet:1 rxdelay:0

[dos]
# Set XMS/EMS memory for doors that need it
xms=true
ems=true

[autoexec]
# Set DOS environment variables
set TEMP=C:\TEMP
set FOSSIL=ENABLED

Disconnect Behavior Modes

The door system uses a two-stage timeout process when users disconnect:

Stage 1: WebSocket Disconnect (DOSDOOR_DISCONNECT_TIMEOUT)

  • Controls whether to wait for user reconnection
  • Measured in minutes
  • Default: 0 (immediate carrier loss)

Stage 2: Carrier Loss (DOSDOOR_CARRIER_LOSS_TIMEOUT)

  • Controls graceful shutdown of door process
  • Measured in milliseconds
  • Default: 5000 (5 seconds)

Immediate Mode (Default):

DOSDOOR_DISCONNECT_TIMEOUT=0
DOSDOOR_CARRIER_LOSS_TIMEOUT=5000

Flow:

  1. User closes browser → WebSocket disconnects
  2. Immediately close TCP socket (simulate carrier loss)
  3. Wait 5 seconds for door to detect carrier loss and exit
  4. If still running, force-kill the process

Behavior:

  • Traditional BBS "lost carrier" behavior
  • Quick cleanup, frees resources immediately
  • Clean state, no confusion

Grace Period Mode:

DOSDOOR_DISCONNECT_TIMEOUT=5
DOSDOOR_CARRIER_LOSS_TIMEOUT=5000

Flow:

  1. User closes browser → WebSocket disconnects
  2. Wait 5 minutes for user to reconnect
  3. If reconnected → Resume session seamlessly
  4. If not reconnected → Close TCP socket (carrier loss)
  5. Wait 5 seconds for door to exit gracefully
  6. If still running, force-kill the process

Behavior:

  • Good for mobile users with spotty connections
  • Users can close/reopen browser without losing progress
  • Uses more resources (processes stay alive during wait)

Why Two Timeouts?

  • DISCONNECT_TIMEOUT: User convenience (reconnection grace period)
  • CARRIER_LOSS_TIMEOUT: Door compatibility (cleanup grace period)
  • Some doors need time to save state after carrier loss
  • Prevents data loss from abrupt termination

Session Duration

Edit src/DoorSessionManager.php:

// Line ~101 in startSession()
'time_remaining' => 7200,  // 2 hours in seconds

// Line ~114
$expiresAt = date('Y-m-d H:i:s', time() + 7200);  // 2 hours

Change 7200 to your desired duration in seconds:

  • 1800 = 30 minutes
  • 3600 = 1 hour
  • 7200 = 2 hours (default)
  • 14400 = 4 hours

Port Ranges

Edit src/DoorSessionManager.php:

// Lines ~27-29
private const TCP_PORT_BASE = 5000;  // DOSBox ports: 5001-5100
private const WS_PORT_BASE = 6000;   // WebSocket ports: 6001-6100
private const MAX_SESSIONS = 100;    // Maximum concurrent sessions

Note: After changing ports, update firewall rules if needed.

Credits System Integration

To charge credits for playing doors, edit the door manifest:

{
    "id": "yourdoor",
    "name": "Your Door Game",
    "credits_cost": 10
}

Users will be charged 10 credits each time they launch the door.

Configure credit costs in Admin Panel → BBS Settings → Credits System.


SSL/TLS and Reverse Proxy Configuration

For production deployments with HTTPS, use a reverse proxy (Caddy or nginx) to handle SSL termination.

Architecture

Browser → HTTPS (wss://bbs.com:443) → [Caddy] → WebSocket (ws://127.0.0.1:6001) → [Bridge]

The multiplexing bridge binds to 127.0.0.1:6001 (localhost only). Caddy handles:

  • SSL/TLS termination
  • WebSocket upgrade
  • Proxying to local bridge

Configuration

1. Set bind address to localhost:

In .env:

DOSDOOR_WS_BIND_HOST=127.0.0.1  # Localhost only (DEFAULT)

2. Configure WebSocket URL for browsers:

In .env:

# Let browsers know where to connect
DOSDOOR_WS_URL=wss://bbs.example.com/dosdoor

If not set, auto-detects based on page protocol and hostname.

3. Configure Caddy:

Add to your Caddyfile:

bbs.example.com {
    # DOS Door WebSocket endpoint
    handle /dosdoor {
        reverse_proxy 127.0.0.1:6001
    }

    # Main BBS traffic
    reverse_proxy 127.0.0.1:1244
}

Or use a separate port:

bbs.example.com {
    reverse_proxy 127.0.0.1:1244
}

bbs.example.com:6001 {
    reverse_proxy 127.0.0.1:6001
}

4. Configure nginx (alternative to Caddy):

upstream dosdoor_bridge {
    server 127.0.0.1:6001;
}

server {
    listen 443 ssl http2;
    server_name bbs.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # DOS Door WebSocket
    location /dosdoor {
        proxy_pass http://dosdoor_bridge;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    # Main BBS
    location / {
        proxy_pass http://127.0.0.1:1244;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Testing SSL Configuration

  1. Start bridge:
sudo systemctl start dosdoor-bridge
  1. Reload Caddy:
sudo systemctl reload caddy
  1. Test WebSocket connection:
# Install wscat if needed: npm install -g wscat
wscat -c "wss://bbs.example.com/dosdoor?token=test123"

You should see authentication error (expected - test token invalid) but connection should establish.


Best Practices

File Naming (Linux Hosts)

  1. Always use UPPERCASE 8.3 filenames when creating files or directories inside dosbox-bridge/dos/ from Linux — DOS is case-insensitive but Linux is not; mixed-case or duplicate-case names will appear as separate entries to DOS
  2. Never create directories or files that differ only by case (e.g., lord/ and LORD/) — the DOSBox-X config uses ver=6.22 (MS-DOS 6.22) to disable long filename support and force 8.3 uppercase handling; do not change this to ver=7.x as that re-enables LFN and the case problem returns
  3. Use the DOS shell maintenance door to create directories and files within the DOS environment itself — DOS will always create them with the correct uppercase 8.3 names

Security

  1. Validate door files before installing - only install doors from trusted sources
  2. Limit door execution to the dosbox-bridge/dos/DOORS/ directory
  3. Review door configs for potentially dangerous DOS commands
  4. Monitor logs for suspicious activity
  5. Keep DOSBox-X updated for security patches

Performance

  1. Run cleanup script regularly (every 10 minutes recommended)
  2. Monitor active sessions - adjust DOSDOOR_MAX_SESSIONS in .env based on server capacity
  3. Set reasonable session timeouts (2 hours default)
  4. Use immediate disconnect mode (DOSDOOR_DISCONNECT_TIMEOUT=0) to free resources quickly
  5. Optimize FOSSIL loading for faster door response:
    • Test if doors work without FOSSIL (internal comm routines)
    • Set fossil_required: false in manifest for doors that support it
    • Example: LORD performs significantly faster without FOSSIL
    • Result: Faster startup, lower memory usage, better user experience

Reliability

  1. Test doors before making them public
  2. Document door-specific requirements (memory, special configs)
  3. Keep backups of working door installations
  4. Monitor bridge server for crashes or errors
  5. Set up automated cleanup via Task Scheduler or cron

Support & Resources

Getting Help

  • Review this documentation thoroughly
  • Check door game documentation for specific requirements

Useful Commands Reference

# Check active sessions
php test/check-db-sessions.php

# Verify processes
php test/verify-session-procs.php

# Clean up expired sessions
php scripts/cleanup_expired_dosdoor_sessions.php

# Kill all door processes
kill-all-door-procs.cmd

# Check WebSocket port in use
netstat -ano | findstr :6001

# Check dynamically allocated TCP ports
netstat -ano | findstr :500

Last updated: February 2026