ATO Doors Demo lobby open

Documentation

The manual

ATO Doors is a web launcher for 16-bit DOS door games. It runs on ordinary shared PHP hosting, gives your players accounts and a lobby, boots a small DOS machine inside each player's browser, and lets the classic games of the bulletin board era run exactly as they did in 1995: Legend of the Red Dragon, Usurper, TradeWars 2002, The Pit, Drakeville and the rest, several players at once, with a sysop panel to run the house.

This is the whole of it in one place: what it does and what it needs, how to install it and its doors, every page of the panel, what players see, where the files live, how it keeps you safe, and what to do when something goes wrong.

ATO Doors is free software under the MIT license. One build, no registered edition, no keys, no banner.

ATO Doors 1.0.0 · October 14, 2026

Chapter 01

#What it is

A door game was a program a bulletin board ran for a caller. The board answered the modem and took the caller's name, and when the caller picked a game from the menu, it handed the line to the door program along with a small text file saying who was calling. From there the door drew its screens down the modem line, and each caller played a few minutes a day against everyone else who called, until the game ended and the board took the line back.

The games kept their worlds in plain files beside the program.

ATO Doors is that board with only the doors left in it, the message bases gone and the file areas with them. No chat. What's left is a lobby full of games and an account to play them with, and everything that made a door game a door game is still here:

  • The game is the original program its author shipped, byte for byte. ATO never patches a door.
  • Each player gets a node and a daily allowance of minutes, and the door finds the player's name in a drop file, exactly as it expects.
  • Where a door was written for it, several players can be in at once, each on their own node, all sharing the one world the game keeps in its files.
  • The daily maintenance a door asks for runs once a day, the way a board's nightly event did.

You bring your own doors, as you always did. ATO ships none. Nothing installs on your computer or a player's, and no hosted service sits in the middle, since the site runs on hosting you already have.

Chapter 02

#How it works

The machine is the browser. When a player opens a door, their browser boots a small FreeDOS machine right there on the page: the v86 emulator, booting a 1.4 MB floppy. A network drive, D:, brings the door's files to that machine, and the server serves it file by file. The game runs on the player's own processor, and its screen is drawn into a terminal on the page, exactly as a caller's terminal drew it over a modem.

The server holds the files and keeps score. Nothing DOS ever runs on it: PHP serves the door's files to the machines, takes their writes back, holds the record locks that keep two players from writing the same record at once, hands out nodes and minutes, and keeps the books. That's why it runs on shared hosting: all it needs is PHP and a cron tick, and the database is one file.

One live world per door. The first time anyone enters a door, ATO copies the door's files into a live directory under data/, and from then on that directory is the world, read and written by every player's machine over the drive. Program files, the .EXE and the rest you declare as static, are cached in the browser and never written, while the data files flow both ways.

Nodes. Each door hands out node numbers from 1 up to the count you allow for it. A player's machine gets its node in the drop file and in %NODE% on the command line, so a door that keeps one file per node keeps them apart. Your own machine, run from the panel, is node 0, and it never counts against the players' seats.

Minutes. Every door has a daily allowance of minutes per player, from its manifest or from your override, counting the time a seat is open. When it runs out, that door won't open again for the player until the site's day turns at midnight in your time zone, though the sysop has no limit.

The day. The site has a time zone, set at install and changeable on the Site page. Midnight there is when the daily minutes reset and a door's daily maintenance falls due, and since the DOS machines keep that clock too, a game's own idea of “today” agrees with yours.

The daily maintenance. Some doors need a program run once a day: TradeWars' EXTERN, say, or Usurper's sweep. LORD runs its own, and since nothing DOS runs on the server, each of these programs runs in a browser. The first player of the day runs a short sweep on the way in, and you run a long one from the panel's Night page (chapter 9 has the whole story).

When a door ends. The game quits, the machine drains its last writes to the server, the seat closes, and the player lands back on the door's page. A player who closes the tab mid-game has simply dropped carrier. The seat and its locks are freed within a minute and a half, and the minutes go on the ledger.

Chapter 03

#What you need

On the host:

  • PHP 8.1 or newer, with four things almost every shared host has: the PDO SQLite driver, the usual string functions, JSON and the zip extension. The installer checks for each one and says what's missing.
  • A web server that serves .wasm files (the machine's CPU) as ordinary static files and honors the deny rule ATO plants in data/, which Apache with mod_rewrite, the common case, does as is.
  • An outgoing mail account (SMTP), since new players confirm their address by email and the site writes to you when a door misses its maintenance.
  • A cron job, every five minutes: every cPanel host has one, and the installer prints the exact line.
  • HTTPS, which is optional. Without it, passwords and session cookies travel in the clear, and the Full screen keyboard lock only works on a secure page.

For players: a current desktop browser (Chrome, Edge, Firefox, Safari) and a keyboard. A phone will do for a look around; for play, a door wants eighty columns and real keys.

Disk and memory are small. The site is about a megabyte, and the database is a single SQLite file. Doors add their own.

Chapter 04

#Installing

  1. Unzip the package and upload the contents of its one folder, atodoors/, to where the site should live, either the root of a domain or a folder such as /atodoors/; from here on, that folder, the one holding index.php, is “the install”.
  2. Check the two folders: data/ must be writable by PHP, which 755 or 775 does on nearly every host, and doors/ has to exist. The package carries both.
  3. Open install.php in the browser. The environment check comes first: the PHP version, the extensions, whether data/ can be written, and whether the machine's files are in place, each line green or saying what to fix.
  4. Name the site and its sysop: site name, tagline, your handle, your email and password, the time zone, and the site URL, which the installer guesses. Check it, since every link in every letter is built from it.
  5. Set up outgoing mail (SMTP server, port, security, login, password and the From address), and the installer sends a test letter before it goes on, since new players can't confirm their address without mail.
  6. Schedule the cron job. The last page gives the addresses of the lobby and the panel, with the cron line under them: paste that line into your host's scheduler now. It looks like this:
    */5 * * * * php /home/you/public_html/atodoors/cron.php key=...
    If your host's scheduler can only fetch a URL, the page shows the URL form too. The key is yours. The Site page shows it again.
  7. Bring a door: install one (chapter 6), then press Scan on the panel's Doors page.

Once it's installed, install.php refuses to run again, so to start over from nothing, delete data/config.php first.

If a page answers 500 where the installer should be, open check.php in the browser, next to index.php. Written in old PHP on purpose, it runs on any version a host might have, and it prints the PHP version, the extensions, who PHP runs as against who owns the files, and the permissions a shared host refuses. A Repair button sets every folder to 755 and every file to 644. The usual finding is a host still on PHP 5 or 7, so ask the host to switch the site to PHP 8.1 or newer. Once the site is installed, check.php answers only the logged-in sysop.
Chapter 05

#Updating

An update is an overlay. Unzip the new package and upload the contents of its atodoors/ folder over the install, replacing files. Nothing else to do.

  • data/ is yours: the database, every setting, your words and art, the live game worlds and the snapshots, none of it carried by the package except the deny rule, which is the same in every version.
  • doors/ is yours too. The package brings back only the README that lives in it.
  • The first page view after the upload brings the database up to the new version's schema by itself.
  • Every stylesheet and script is linked with its file time in the address, so browsers fetch the new ones and keep caching the rest. When the boot floppy changes, each player's first entry after the update fetches it again, once per browser.

The installer won't run again on an installed site, so uploading it again does no harm.

Chapter 06

#Installing doors

Where

Each door is its own folder in doors/, right off the install: doors/lord/ for Legend of the Red Dragon, say, or doors/usurper/ for Usurper. Never put a door anywhere under data/, because that's where ATO keeps the live worlds, and the Doors and Machine pages print that path only so you know where the live world is.

What

It holds two things:

doors/lord/
  dosdoor.json        the manifest
  files/              the game, exactly as it came

files/ is the door's own directory, exactly as you'd have installed it on a DOS board, with the program, its data files, its batch files and its configuration, plus anything you'd have written yourself for the board, such as a node file or a .CFG. ATO never changes a file in it.

The manifest

dosdoor.json is the same manifest ATDT BBS uses, so every door package made for ATDT installs here unchanged, and a manifest written here works there. A complete one:

{
  "api": 1,
  "slug": "lord",
  "title": "Legend of the Red Dragon",
  "command": "CALL START.BAT %NODE%",
  "dropfile": "DOOR.SYS",
  "static": ["*.EXE", "*.OVR", "*.DOC"],
  "session": ["TEMP*.*"],
  "max_nodes": 4,
  "minutes": 45,
  "maintenance": "",
  "jit": "on",
  "comport": 1,
  "blurb": "The dragon in the forest. Fight, flirt, and sleep in the inn.",
  "author": "Seth Able Robinson",
  "year": "1995",
  "maintenance_minutes": 0,
  "presets": [{"label": "LORDCFG", "command": "LORDCFG.EXE"}],
  "clear_when_empty": []
}

Key by key:

slugThe folder's name: 2 to 16 characters from a-z and 0-9, plus _ and -. It's the door's address on the site.
titleWhat players see.
commandWhat you'd type at the D:\> prompt to start the door for a caller. %NODE% becomes the player's node number. A batch file must be started with CALL, and it must stay relative. The game always runs with the door's folder as D:\, so START.BAT is right and D:\LORD\START.BAT is wrong.
dropfileWhich drop file the door reads: DOOR.SYS or DORINFO1.DEF. CHAIN.TXT works as well. ATO fills it in the way a board did, from the player's handle and node down to the minutes left. The record number is the player's account number. No real password ever rides in it.
staticPatterns for files that never change: the program, overlays, help, documentation. These are cached in the player's browser after the first fetch, and they're read-only to players. Declare them. A door with no static patterns reads every file over the wire on every open, and it feels slow.
sessionPatterns for scratch files that belong to one node only and are never shared between players.
max_nodesHow many players the door is written for. This is the starting value. Your override on the Doors page is the word that counts.
minutesThe daily allowance per player, 5 to 480. You can override this too.
maintenanceThe daily command, if the door has one: EXTERN MULTITASK=NO for TradeWars, USURPER.EXE /HMAINT /X for Usurper. Leave it out for doors that keep themselves.
jitoff runs the door on the emulator's interpreter, which is slower than its compiler. A few Turbo Pascal doors sit silent without it. Leave it out unless a door needs it.
comport, baudWhat the drop file tells the door about its line. COM1 is right for everything.

The rest are ATO's own. ATDT ignores them, and every one of them is easier to set on the Doors page.

blurbThe words on the card and the door's page, up to 400 characters.
author, yearThe card.
artThe name of an .ANS file in files/, drawn on the door's page.
maintenance_minutesHow long the daily sweep takes, so the Night page can budget.
presetsOne-click commands for the Machine page.
clear_when_emptyFiles that mean nothing once nobody is in the door. They're removed before the first seat of an empty door opens. Usurper's online list is the case that named it.

Scan

Once the folder is in place, open the panel's Doors page and press Scan, and every folder with a valid manifest is registered. The page lists the doors it found new or changed, and names any it refused, with the reason. New doors register open. If you don't want players in one while you set it up, Close it on the Doors page.

Sorting a door's files

The rule of thumb: anything the game only ever reads is static, which means the program, its overlays, text screens and documentation. Anything it writes is data, and it goes over the wire, while a file it writes for one node and never shares is a session file.

When in doubt, leave a file out of both the static and the session lists. It will just travel over the wire every time, which is correct, only slower.

Doors with several players

A door that lets several players in at once must use DOS record locking. Every multi-node door did. ATO holds the locks on the server, and closing a file releases them. Sharing modes on open (SHARE) aren't enforced, so a door that relied on SHARE alone to keep two writers apart needs a lower node count.

Start a new door at one or two players, and play it with a friend. Raise it once it holds.

Recipes

For the doors the project knows, a recipe ships with ATO: what to put in files/, the quirks, the proven node count, how long the maintenance takes, and the one-click commands for the Machine page. The Doors page shows the matching recipe's card beside a door's settings. Recipes are optional. A manifest is all Scan asks for, and ATO 1.0.0 ships two recipes, one for Legend of the Red Dragon 4.07 and one for Usurper 0.24 (chapter 13 has what each says).

The live world

The first time anyone enters a door, files/ is copied to data/doorstore/dos/<slug>/, and from then on that copy is the world. Edit a file in files/ after that, and the game won't see it until you press Reset on the Doors page, which wipes the world and copies files/ again, taking every player's progress with it.

To change one line of a live config file without a Reset, use the Files page, which edits the world directly and keeps a dated copy of what it changed.

Chapter 07

#The sysop panel

The panel is at admin/ under the install, and only the sysop account opens it.

The band across the top carries the site's name and the pages as tabs, with a strip of readouts under them that follow you from page to page. They show who's in the doors, the web lines in use, how many doors are open, the night's state, the cron job's last tick, and whether mail is set. Each readout is a lamp and a few words, and it links to its page. Green is live and red is a fault. Amber means it's waiting on someone.

7.1 Dashboard

What's happening now.

In the doors nowEvery open seat (door, node, player, since when), each with a Disconnect.
Web linesThe terminal sessions behind the seats, each with a Hang up. Hang up everyone does all of them at once.
The numbersCalls today and ever, members, accounts waiting for their confirmation letter, locked accounts, doors open of doors registered, the version, and the backup download.
The nightWhen cron last ran and which doors are due, with Run the scheduler now.
MailWhether outgoing mail is set, and the last letters sent.
The guardsWhether data/ is denied to the web, and whether the machine's CPU file downloads whole. To check the first, the dashboard fetches its own probe file and expects a refusal. A host that refuses .wasm files leaves every door unable to boot, which is why the second matters. Below those, the card shows the doors folder's full path and the last security rows from the log.

7.2 Doors

The table lists every registered door: title, slug, who may enter, nodes, minutes per day, the night's road and its last completed day, and whether it's open. Per row: arrows to reorder the lobby, Open or Close, edit, machine, files, and the door's public page.

Under the table, Scan doors/ registers what you dropped in, with a card beside it as a reminder of the manifest format.

Edit opens the door's drawer:

  • Who may enter. Everyone with an account; members at level 20 and up; trusted members at level 50 and up; the sysop only; or an access string in ATDT's grammar, where s50, for example, is level 50 and up.
  • Players at once. 0 keeps the manifest's number, and any other number is your word: lower it for a door you haven't watched two people play, and raise it once you have.
  • Minutes a day per player, with 0 again keeping the manifest's number.
  • Daily maintenance, when the manifest names one. Choose whether the first player of the day runs it on the way in (short sweeps) or only you run it from the Night or Machine page (long ones), and say how long it takes, so the Night page can budget. A sweep longer than the first-caller ceiling (on the Night page, 4 minutes by default) belongs on the sysop road, and the page says so.
  • The words. The blurb, your note on this door (signed with your handle on the door's page), the author and year for the card, and what a closed door's card says.
  • Art. An .ANS or .ASC file, 80 columns by up to 25 rows, drawn on the door's page in the VGA font and colors.
  • The recipe card, when a recipe matches: the care sheet in plain words.
  • Snapshots. Take one now. One is also taken by itself before every maintenance run, and the last three are kept, so Restore can put the world back to any of them, after a word about who's in the door.
  • Diagnostics. Turn debug on while you bring a new door up, and off once it plays: with it on, the last fifty file operations and their round-trip times are kept for you to read. A player whose door dies before it opens sees the machine's own DOS screen mirrored in the corner of the terminal, and a door that can't find its files says so there.
  • The machine and edit its files open the Machine and Files pages for this door.
  • Files compares the package's files/ with the live world: what grew or changed, and what the game created.
  • Reset game state wipes the live world and seeds it again from files/, and since every player's progress goes with it, you type the slug to confirm.
  • Remove this door unregisters it, and deletes its live world if you tick the box. The folder in doors/ is yours, and it stays.

7.3 Machine

It's the same FreeDOS machine players get, booted in your browser on the door's live world as D:\, running the command you give it, with the machine's own screen and keyboard right in the page. This is where a door's configuration program runs (LORDCFG.EXE, AASETUP.EXE), where an installer runs, where you drop to a DOS prompt and type DIR, and where you run a daily maintenance by hand.

Two screens share the page. The machine's own screen is the DOS screen: batch files, config tools, the prompt, and a door's maintenance program, which prints there. The door's line, folded under it, is what a caller would see, and a door game run by hand talks there, exactly as it does for a player.

Click a screen to type to it; the one with the keyboard wears a gold edge. Keys typed on the page go to the machine, so Ctrl+C interrupts a batch file as it would on DOS.

One-click commands come from the door's recipe or manifest. Boot the machine runs the command in the box, and a blank box runs DIR and leaves you at the prompt. Run the daily maintenance runs the manifest's maintenance command and stamps the day so players skip it. End session returns the seat, and a machine quiet for a minute dozes to spare your laptop until any key wakes it.

Changes land in the live game at once, and players keep their seats while you work, so on a busy door, close it first and wait for the seats to drain. To keep a change across a Reset, copy the changed file back into doors/<slug>/files/ on the server.

7.4 Files

A door's text files, read and edited in the browser with no FTP client needed: a config line, say, or a node file.

There are two roots. One is the live world, what the game runs on right now, and the other is the package, doors/<slug>/files/, which is what a Reset seeds from. The listing shows every file: text files open in an editor, while binaries and files over 256 KB are listed and left alone.

The editor keeps DOS line ends and the end-of-file mark exactly as the game wrote them, and every byte above 127 survives the round trip. Before every save, it keeps a dated copy of the old file under data/snapshots/<slug>/edits/, and a save into the live world tells the players' machines to fetch the new file. The page says when players are in the door, since the game may rewrite a file you're editing. You can create new files there, too.

7.5 Night

Every door's daily maintenance, in one place (chapter 9 has the full story). The table shows each door that has a maintenance command: the command, the road, how long it takes, when it last completed, and whether it's due today. On each row, Run now runs it on this tab's machine, and stamp marks today done without running it. A link beside them takes you to the door's Machine page.

Run everything due now runs the due doors one after another on this tab's machine. Night watch keeps the window on duty: every minute it looks for a door whose day has turned and that has nobody in it, and runs that door's maintenance. Leave the window open and visible, since the browser slows a hidden window, and the page warns you when it's hidden.

While a run is on, the machine's card comes up under the table, and the program prints its steps on the machine's own screen as it goes. The status line counts the minutes against the door's listed sweep, and if a program stops to ask something, click the screen and type your answer.

Settings: the first-caller road's ceiling, and whether the site writes to you when a door goes a day without its maintenance. A door whose sweep runs longer than the ceiling should be on the sysop road, and the table warns you when it isn't.

7.6 Accounts

Find an account by handle or email, or filter by status. Each one shows its email and status, which door the player is in, their calls and last login, and when they joined. Manage opens the account's row:

  • Pending accounts are registered, with the letter not yet answered, and you can open one by hand or send the confirmation letter again.
  • Active accounts can be locked out, which keeps the player from logging in and closes their seats. Locked ones can be unlocked.
  • Passwords and mail. Send a password reset letter, or set a new password directly. The mailbox can be changed here too.
  • A sysop note, visible only here.
  • The level, 0 to 254. 20 is a member and 50 is trusted, and a door's access string can ask for any number.
  • Where they've been. Today's minutes in each door. Where they say they're calling from, and the address of their last login.
  • Delete the account.

Your own account is the one at level 255, and there is exactly one sysop.

7.7 Look

Everything that makes your place look like yours, from its words to its colors.

Your words. Eight fields, each with its own limit in characters:

FieldWhere it showsUp to
Site nameThe masthead and the browser title. Every letter, too.60
TaglineOne line under the name80
WelcomeThe first paragraph of the lobby1200
AboutOn the About page6000
House rulesThe About page and the registration form3000
Footer lineEvery page, above the credit160
Letter signatureAt the end of every letter the site sends200
Offline messageWhat a visitor reads while the doors are offline400

The longer fields take a little markup: a blank line starts a paragraph, and *bold* is bold. A link is [label](https://link). Everything else is escaped, so nothing else turns into HTML.

News. Dated notes on the lobby, newest first. The last twenty are kept.

Masthead art. A piece of ANSI art drawn across the top of the lobby in place of the name, in the VGA font and the sixteen colors. It's an .ANS or .ASC file, 80 columns by up to 10 rows.

Colors. Five palettes (Midnight, Amber, Phosphor, Ice, Paper), and the nine colors each is made of (background, panel, line, ink, dim, gold, red, green, link), adjustable one by one with a live preview. Everything a player sees wears them, from the lobby to the account pages, except the terminal, which stays black. The panel keeps its own look.

7.8 Site

  • Site name, and the site URL that links in letters are built from.
  • The time zone. The doors' day turns at this zone's midnight, and the DOS machines keep its clock.
  • Whether new players may register, where off closes the door to new accounts and existing ones still log in.
  • Whether to play the modem ceremony when the terminal opens: the dial-and-connect theater before a door.
  • Web lines at once: players on the play page at the same time, across every door, while each door's own limit is on the Doors page.
  • Let go of a line whose door never opened after N minutes.
  • The offline switch. New callers are turned away with your offline message, and you can hang up everyone who's on right now. Every panel page says so until you flip it back.
  • Privacy: hide who's on, and the last callers, from visitors who aren't logged in.
  • Banned addresses, one per line, where a trailing * bans a prefix.
  • Outgoing mail: server, port, security, login, password, From address, and Send a test letter.
  • The cron job: the exact line for your host's scheduler and its URL form, with the key.

7.9 Log

Everything the site records, newest first: information, warnings, errors, security rows, the sysop's own actions, and mail. A security row is a refused path or a failed login, and a member knocking at the panel's door makes one too. Filter it by level. Search finds an actor or any text.

When a maintenance run dies, the machine's last screen is here as words, with the program's own error line if it printed one.

7.10 Backup

Download a backup takes a copy of the database: accounts, settings, words, door registrations, news, the log. The live game worlds are files under data/doorstore/dos/, so those travel by FTP, and a full backup of the site is all of data/ plus doors/.

Chapter 08

#The player's side

Registering. A visitor picks a handle and a password, with the house rules right there on the form. The site sends a confirmation letter to the email address they give, and the account stays pending until someone presses the button in it. A player who lost the letter can ask for another, and you can also open an account by hand on the Accounts page.

The lobby. It opens with the masthead (your art or the site's name) and your welcome, and the doors come next, as cards. A card shows the title, blurb, author and year, and who's in it right now, or else what a closed door's card says. Below them sit who's on the line now and the last callers (members only, and hidden from visitors when the privacy switch is on), with your news last of all. The About page carries your About text and the house rules.

A door's page. The door's art, its blurb, your signed note, the rules of the house, who's in it now, and Play. A door closed to this player says why.

Playing. The play page is a terminal with a status line that shows the door, the player's node, the minutes left today, and how many are in the door right now. When the line opens, with the modem ceremony if it's on, the machine boots. On the first entry the game fetches, and a big door can take half a minute, though later entries are quick, since the program is cached; then the door greets the player as it greeted a caller.

The Keys card says what the keys do:

  • Type as at a terminal. Arrow keys and Tab go to the door, but function keys don't, since none ever crossed a modem line.
  • Paste types what was pasted, and dragging on the screen copies.
  • Leave through the game's own quit so it saves. Ctrl+] three times drops carrier, the old-fashioned way, and the Hang up button does the same.
  • Full screen hands the browser's own chords (Ctrl+W, Ctrl+T) to the game. Hold Esc to leave it.
  • On a touch screen, a key row under the terminal carries Esc, the arrows, Tab and Enter, and the soft keyboard types into the door.

When the game ends, the page says it's saving, waits for the machine to finish its writes, says goodbye and returns to the door's page. One player can hold one line at a time, so opening a second door closes the first.

The account page. A player can change their password here, or their mailbox, which is confirmed by letter. The location the doors show for them is set here too, and so is the button that deletes the account.

Chapter 09

#The Night: daily maintenance

A door's daily maintenance is a console program that rewrites the game's world, aging the players and settling the day's events. It trims the logs, too. On a DOS board it ran as a nightly event at midnight, but ATO has no DOS on the server, so it runs in a browser, on one of two roads you choose for each door.

The first caller's road

The first player of the day to enter the door alone draws the duty. Their machine runs the maintenance command ahead of the game, with the machine's screen mirrored into their terminal so they can watch it and answer a stray prompt, and when the program finishes, the game starts as it always did.

It's right for sweeps of a minute or two, and the Night page's ceiling, 4 minutes by default and up to 60, is the longest sweep this road should carry.

The sysop's road

Only you run it: from the Night page, with Run now, Run everything due now or the Night watch left on duty, or from the Machine page's Run the daily maintenance.

Long sweeps go here. Usurper's takes ten to thirty minutes on a populated world, and TradeWars' EXTERN has no first-caller road at all in the original.

How a run is bracketed

Either way, a snapshot comes first. Then the program runs on the live world with a done sentinel after it, and when the sentinel crosses the line, the day is stamped for that door and the seat ends.

A run can end without the sentinel because the tab closed or the program died. Or the budget runs out. Any of those puts the snapshot back and counts a failure, and after two in a row the Night page says so until you clear it. The machine's last screen goes into the Log, so you can read what the program said before it died.

One machine runs a given door's maintenance at a time: the duty is leased for an hour, and released the moment the seat that holds it is gone.

Cron's part

Nothing DOS runs on the server, so cron never runs maintenance. It keeps the books. It sweeps dead seats and lines, arms the day, warns in the Log when a door has gone a day without its maintenance, and sends you the letter about it when that setting is on.

Without cron the site still plays, but nobody gets told when a door misses its maintenance.

A door that stays silent

A door that stays silent on the Machine page while its maintenance runs is almost always printing on the machine's own screen, which is where a maintenance program talks, and both the Night and Machine pages show it. A game run by hand talks on the door's line, folded under the screen. Open it.

Chapter 10

#Security, in plain words

The browser owns the machine

The game runs on the player's computer, so whatever the game can write to its shared files, a determined player can write with the seat's token. ATO fences that in:

  • The door's program and configuration files you declare as static are read-only to players.
  • Every path a machine asks for is jailed to the door's live directory, and a refusal is a security row in the Log.
  • Snapshots and a Reset put a world back.
  • The Doors page says all of this in plain words.

A door game's world was never a bank vault. ATO doesn't promise one.

Accounts

Passwords are stored only as hashes, and the letters that confirm an account or reset a password carry one-time links. Every form that changes anything carries a token against cross-site requests, and every terminal request carries a bearer token, issued to a logged-in browser. Logins are throttled after repeated failures, and after too many tries the panel locks for fifteen minutes.

The panel

Only the one account at level 255 opens it. A member who tries is turned away, and the attempt is logged with their address.

data/

Everything the site writes lives in data/, the game worlds included, and the package plants an Apache deny rule there, which the dashboard checks by fetching its own probe file and expecting a refusal.

If the dashboard says data/ is OPEN, deny it in the host's settings before anything else, because until you do, the database and the configuration are downloadable.

Drop files

None carries a real password. The game sees a stand-in, and the record number is the account's number.

Bans

Addresses and prefixes are banned on the Site page, and a banned address can't register or log in. It can't open a line.

Chapter 11

#Where things live

The install, folder by folder.

index.php, door.php, play.php, about.php     the lobby and the play page
account/                                      register, verify, login, settings, reset
admin/                                        the sysop panel
api.php                                       the terminal's and the machines' endpoint
cron.php                                      the scheduler's entry
install.php, check.php                        the installer and the host check
lib/                                          the site's code
assets/                                       stylesheets, scripts, fonts
machine/                                      the DOS machine: boot floppy, emulator, licenses
recipes/                                      what ATO knows about particular doors
doors/                                        your doors, one folder each
data/                                         yours, written by the site, denied to the web
  config.php                                  the database path and the site's keys
  <site>.sqlite                               the database
  doorstore/dos/<slug>/                       the live worlds
  snapshots/<slug>/                           world snapshots and the Files page's edit copies
  art/                                        the masthead and door art you uploaded
  logs/                                       the web server's view, when the host writes one
Chapter 12

#When something goes wrong

Every page answers 500.

Open check.php. Nine times in ten the host is running an old PHP, and the fix is to switch the site to 8.1 or newer in the host's panel. The rest is permissions. Repair sets them.

The installer says the machine's files are missing.

Upload the whole package. machine/ has to come along, all of it.

No door can boot, and the terminal says the runtime didn't load.

The host is refusing .wasm files or serving them with the wrong type, which the dashboard's guards card will confirm, so ask the host to serve application/wasm for .wasm, or add the type in .htaccess yourself:

AddType application/wasm .wasm

New players never get their letter.

Outgoing mail isn't set, or the host blocks the SMTP port. The Site page sends a test letter and says what the server answered, and until mail works, you can open accounts by hand on the Accounts page.

The panel keeps saying the cron job has never run.

Either the scheduler isn't calling cron.php, or it's calling it without the key, so copy the line from the Site page exactly, and if the host's scheduler can only fetch a URL, use the URL form.

A door sits silent after booting.

On the Machine page, open the door's line under the screen, since a game run by hand talks there. If a player reports it, turn diagnostics on for the door and enter it yourself: the machine's DOS screen appears in the corner and usually names a file the door couldn't find. A Turbo Pascal door that hangs with nothing on either screen may need "jit": "off" in its manifest.

The lobby shows no doors.

Nothing is registered, or every door is closed, so press Scan on the Doors page, then Open the ones you want seen.

A maintenance run ends early.

The Night page counts it and puts the snapshot back. The machine's last screen is in the Log as words, with a runtime error's own line if the program printed one.

A sweep longer than the first-caller ceiling belongs on the sysop road. When a sweep always dies at the same step, on a world that has run many nights, the world's data is usually the cause; a Reset from the package files clears it, players included, so take a snapshot first and read the Log before you decide.

A player is stuck “in the door” after closing the tab.

The seat is swept on its own within a minute and a half. The dashboard's Disconnect does it now.

F5 in the middle of a game.

Function keys stay with the page while a door runs, so F5 no longer reloads it and loses the seat the way it once did. When a seat does drop, the game has saved whatever it had written, and the rest of that visit is gone, as it always was when a modem dropped carrier.

Chapter 13

#Door packages the project vouches for

Every door package made for ATDT BBS installs here as is, and these two ship with a recipe, brought up on the project's own machines and proven with two players at once in a real browser.

Legend of the Red Dragon 4.07

  1. Install the contents of LORD.ZIP into files/.
  2. Lay the 4.07 FreeDOS patch over it, so that its LORD.EXE and LORD.OVR replace the originals already in files/.
  3. Run the patch's LORDCFG.EXE once from the Machine page: node 1, drop file DOOR.SYS, the path D:\, and Fossil as the port.
  4. The command is CALL START.BAT %NODE%, the same as in the manifest in chapter 6.

Two warriors in the forest at once, on nodes 1 and 2: proven.

Usurper 0.24

  • The files. The 0.20e full release, with the 0.24 upgrade's 16-bit EDITOR.EXE, EDITOR.OVR, USURPER.EXE, USURPER.OVR and EDITOR32.HLP (beside EDITOR.HLP).
  • USURP.CTL needs the FOSSIL keyword and BBSTYPE DOORSYS, or the door talks only to the local screen.
  • /X on every command line. It keeps the two-megabyte overlay in memory, and without it the door reads the overlay over the wire hundreds of times a second and never greets.
  • The daily maintenance is USURPER.EXE /HMAINT /X (never /FMAINT, which stays in the menu forever), and since it takes ten to thirty minutes, it belongs on the sysop's road.
  • Setup. Copy USUTEXT.DAT into DATA\ so the maintenance never stops at a picture prompt, then reset the world once in the Editor (Alt+R, every stage), so DATA\VERSION.DAT exists.
  • The online list. It's removed before the first seat of an empty door opens, so a player whose browser closed mid-game isn't told they're already online.

The demo board at atodoors.com runs these two and five more, each with its own art and notes: TradeWars 2002 with its EXTERN on the sysop road, The Pit, Drakeville, LORD II and Arrowbridge II. See what a finished board looks like before you build yours.

Chapter 14

#Licenses and credits

ATO Doors is MIT licensed: use it, change it, pass it on, keep the notice.

The DOS machine is built from free software whose licenses ship in machine/LICENSES.txt: the v86 emulator, FreeDOS, the EtherDFS network drive and its server, the Crynwr packet driver, and ATO's own FOSSIL driver.

Web437 by VileR (CC BY-SA 4.0) is the terminal font, and the panel's type is Archivo by Omnibus-Type (SIL Open Font License). The door kernel is ATDT BBS's, the same code that runs doors on a full board.

The door games themselves are their authors'. ATO ships none, and never changes one.

Chapter 15

#Glossary

DoorA game a bulletin board ran for a caller, handed the line through a drop file.
Drop fileThe small text file a board wrote for the door, naming the caller and giving their node and minutes. ATO writes DOOR.SYS or DORINFO1.DEF, whichever the door reads. CHAIN.TXT works too.
NodeOne line into the board. Each player in a door has one, and a door that lets several in keeps one per player.
SeatA player's place in a door right now: a node plus the minutes it has used.
LineA player's terminal session on the site. It carries at most one seat.
The worldA door's data files, shared by every player of that door, kept in the live directory under data/.
Static filesThe door's program and its other never-changing files, cached in the browser and read-only to players.
Session filesPer-node scratch files, never shared.
The dayFrom one midnight to the next in the site's time zone. When it turns, the minutes reset and maintenance falls due.
MaintenanceThe program a door asks to have run once a day.
FOSSILThe serial driver standard of the era. The machine ships one on COM1, and the door talks to the player through it.
SysopYou. System operator, the one who runs the house.