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.
- Overview
- System Architecture
- Prerequisites
- Initial Setup
- Configuration
- Adding New Door Games
- Sysop DOS Maintenance Shell
- Door Manifest Format
- Troubleshooting
- Advanced Configuration
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)
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:
-
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)
-
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
-
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:
- User clicks door game link
- PHP allocates node, generates unique token
- PHP creates database record with session info (token, node, door_id, user data for drop file)
- PHP returns session data with WebSocket URL and token to browser
- Browser connects to multiplexing bridge with token:
wss://bbs.com:6001?token=abc123... - Bridge validates token against database, retrieves session details including user data
- Bridge allocates dynamic TCP port from available pool (no port conflicts!)
- Bridge generates drop file (DOOR.SYS) using user data from session record
- Bridge generates DOSBox config with allocated port and door-specific settings
- Bridge creates TCP listener on allocated port
- Bridge launches DOSBox which connects back to bridge's TCP listener
- Bridge updates database with allocated port and DOSBox PID
- User input flows: Browser → WebSocket → Bridge → TCP → DOSBox → Door Game
- Game output flows: Door Game → DOSBox → TCP → Bridge → WebSocket → Browser
- 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
-
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-xor 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-xin.envto 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
- DOSBox-X is strongly recommended due to better serial port stability and features:
-
Node.js 18.x or newer and bridge dependencies — see Doors.md for installation instructions.
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
Windows:
- Download DOSBox-X from https://dosbox-x.com/
- Install to
C:\DOSBox-X\(recommended) - 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 --versionSee Doors.md — Prerequisites for Node.js installation and bridge dependency setup.
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=falseThe door system requires these tables (created by scripts/setup.php):
door_sessions- Active session trackingdoor_session_logs- Session event logging
Run setup if needed:
php scripts/setup.phpStart the multiplexing bridge — see Doors.md — Running the Bridge for instructions.
Then visit your BBS and try launching a door game. The bridge will:
- Authenticate your WebSocket connection
- Allocate a TCP port dynamically (e.g., 5000)
- Generate a DOSBox config for your session
- Launch DOSBox which connects back to the bridge
- Multiplex data between your browser and the door game
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
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.confIn 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 1Sessions 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 sessionsSession Expiration:
- Default: 2 hours per session
- Configurable in
startSession()method (line 101) - Enforced by cleanup script
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, andLordall 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 thedosbox-bridge/dos/directory tree is managed from Linux:
- If you create a directory named
testfrom Linux and later createTEST, 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/:
- Use UPPERCASE for all filenames and directory names — e.g.
DOORS,LORD,START.BAT- Stick to 8.3 format — maximum 8 characters for the name, 3 for the extension
- 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 changever=to7.0or higher in the DOSBox config, LFN support activates and the case-sensitivity problem returns.
-
Obtain the door game files
- Download from archives such as the Internet Archive BBS Door Game Collection or My Abandonware
- Must be DOS-compatible (16-bit DOS executable or batch file)
-
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.shto 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
-
Create door directory (use UPPERCASE — Linux is case-sensitive):
mkdir dosbox-bridge/dos/DOORS/YOURDOOR
-
Copy door files:
cp -r /path/to/door/files/* dosbox-bridge/dos/DOORS/YOURDOOR/ -
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
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 usersexecutable: Main executable or batch filelaunch_command: Full command with {node} and {dropfile} macrosdrop_file_format: Currently only "DOOR.SYS" is supportedmax_nodes: Maximum concurrent players (1-100)require_ansi: Whether door requires ANSI supportfossil_required: Load FOSSIL driver (default:true). Set tofalsefor doors with internal comm routines (faster)
-
Scan for new doors: The system automatically scans
dosbox-bridge/dos/DOORS/fordosdoor.jsnfiles -
Enable via admin panel:
- Login as admin
- Navigate to Games → DOS Doors
- Find your door in the list
- Click "Enable"
- Adjust settings if needed
-
Or enable manually:
Edit
config/dosdoors.json:{ "yourdoor": { "enabled": true, "name": "Your Door Game", "max_nodes": 10 } }
-
Launch the door from the games menu
-
Check for issues:
- Does it display properly?
- Does input work correctly?
- Does it save game state?
- Does it exit cleanly?
-
Review logs:
# Filter for DOSDOOR-prefixed logs tail -f data/logs/php-errors.log | grep DOSDOOR
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 menuBinktermPHP 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.
The DOS shell door is restricted to admin accounts and will not appear in the games list for regular users.
- Log in as an admin
- Navigate to Games in the main menu
- The "DOSDoor DOS shell" door will be listed (admin-only doors are only visible to admins)
- 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:.
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.
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.
{
"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
}
}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}/iconendpoint - 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}/screenshotendpoint - 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
falseonly if you've verified the door works with internal comm routines
- Memory impact: FOSSIL driver uses ~30-50KB RAM per session
| Placeholder | Replaced with |
|---|---|
{node} |
Node number (e.g. 1) |
{dropfile} |
Drop file name (e.g. DOOR.SYS) |
{user_number} |
BBS user ID (numeric) |
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"
}The system supports custom icons and screenshots for each door game.
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
-
Place asset files in door directory:
dosbox-bridge/dos/DOORS/LORD/ ├── dosdoor.jsn ├── icon.gif # Your icon file └── screenshot.png # Your screenshot file
-
Declare in manifest:
{ "game": { "name": "Legend of the Red Dragon", "icon": "icon.gif", "screenshot": "screenshot.png" } } -
Supported formats:
- GIF, PNG, JPG/JPEG, SVG, BMP, ICO
- Recommended icon size: 64x64 pixels
- Recommended screenshot size: 640x400 pixels
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→ Servesicon.gif(declared in LORD's manifest)/door-assets/bre/screenshot→ Servesscreenshot.png(declared in BRE's manifest)
Assets are served with 24-hour cache headers for performance:
Cache-Control: public, max-age=86400
Symptoms: Clicking door does nothing, or shows "Connecting..." forever
Check:
- Is the multiplexing bridge running?
ps aux | grep multiplexing-serveror check Task Manager - Is Node.js installed?
node --version - Are npm dependencies installed? Check
node_modules/wsandnode_modules/iconv-lite - Is DOSBox-X installed? Check
DOSBOX_EXECUTABLEin.env - Is WebSocket port available? Check for conflicts on port 6001 (TCP ports 5000-5100 are allocated dynamically)
Symptoms: Terminal connects but shows blank screen
Check:
- Is the door executable correct in
dosdoor.jsn? - Does the door exist in
dosbox-bridge/dos/DOORS/? - 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 windowSymptoms: Player progress is lost between sessions
Check:
-
Does the door directory have write permissions?
# Windows - Right click folder → Properties → Security # Linux chmod -R 775 dosbox-bridge/dos/DOORS/YOURDOOR
-
Is the door configured for multi-node operation?
- Some doors need separate data files per node
- Check door documentation for multi-node setup
-
Are drop files being generated correctly?
# After launching, check: ls dosbox-bridge/dos/DROPS/NODEX/DOOR.SYS
Symptoms: "Connection closed" right after connecting
Check:
-
Disconnect timeout setting:
# In .env: DOSDOOR_DISCONNECT_TIMEOUT=0 # Change to 5 for 5-minute grace period
-
Bridge server logs:
# Bridge logs to console - check for errors # Look for [WS] messages
-
Firewall blocking WebSocket ports (6001-6100)
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.confCommon 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=ENABLEDThe 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=5000Flow:
- User closes browser → WebSocket disconnects
- Immediately close TCP socket (simulate carrier loss)
- Wait 5 seconds for door to detect carrier loss and exit
- 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=5000Flow:
- User closes browser → WebSocket disconnects
- Wait 5 minutes for user to reconnect
- If reconnected → Resume session seamlessly
- If not reconnected → Close TCP socket (carrier loss)
- Wait 5 seconds for door to exit gracefully
- 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
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 hoursChange 7200 to your desired duration in seconds:
- 1800 = 30 minutes
- 3600 = 1 hour
- 7200 = 2 hours (default)
- 14400 = 4 hours
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 sessionsNote: After changing ports, update firewall rules if needed.
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.
For production deployments with HTTPS, use a reverse proxy (Caddy or nginx) to handle SSL termination.
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
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/dosdoorIf 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;
}
}- Start bridge:
sudo systemctl start dosdoor-bridge- Reload Caddy:
sudo systemctl reload caddy- 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.
- 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 - Never create directories or files that differ only by case (e.g.,
lord/andLORD/) — the DOSBox-X config usesver=6.22(MS-DOS 6.22) to disable long filename support and force 8.3 uppercase handling; do not change this tover=7.xas that re-enables LFN and the case problem returns - 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
- Validate door files before installing - only install doors from trusted sources
- Limit door execution to the
dosbox-bridge/dos/DOORS/directory - Review door configs for potentially dangerous DOS commands
- Monitor logs for suspicious activity
- Keep DOSBox-X updated for security patches
- Run cleanup script regularly (every 10 minutes recommended)
- Monitor active sessions - adjust
DOSDOOR_MAX_SESSIONSin.envbased on server capacity - Set reasonable session timeouts (2 hours default)
- Use immediate disconnect mode (
DOSDOOR_DISCONNECT_TIMEOUT=0) to free resources quickly - Optimize FOSSIL loading for faster door response:
- Test if doors work without FOSSIL (internal comm routines)
- Set
fossil_required: falsein manifest for doors that support it - Example: LORD performs significantly faster without FOSSIL
- Result: Faster startup, lower memory usage, better user experience
- Test doors before making them public
- Document door-specific requirements (memory, special configs)
- Keep backups of working door installations
- Monitor bridge server for crashes or errors
- Set up automated cleanup via Task Scheduler or cron
- Review this documentation thoroughly
- Check door game documentation for specific requirements
# 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 :500Last updated: February 2026