BinktermPHP is a modern web-based BBS that combines classic FTN packet processing with a full multi-user online experience. It supports native BinkP TCP/IP connectivity for echomail and netmail across multiple simultaneous FTN networks, while delivering a browser-accessible bulletin board where users can read and post messages, chat, play door games, and earn credits — just like on a traditional BBS, no terminal client required. For those who prefer the authentic experience, BinktermPHP also includes a built-in telnet and SSH server.
BinktermPHP's mobile-responsive interface makes netmail and echomail comfortably accessible from phones and tablets while preserving the familiar feel of a classic BBS. ANSI art renders inline, links are detected and hyperlinked automatically, messages are full-text searchable, and built-in address books help users track their contacts. Users can also share individual messages via secure, expiring web links — with public or private access controls and revocation — making it easy to point someone at a great thread without requiring a login. The result is a Fidonet messaging experience that blends traditional FTN communication with practical modern conveniences, even on modest hardware.
Whether you're setting up a lean point or a full BBS node, BinktermPHP comes loaded with the features sysops care about:
- Built-in BinkP mailer — connect to multiple Fidonet-style networks simultaneously, sending and receiving echomail and netmail without third-party software
- Full door support — native Linux/Windows programs, classic DOS doors via DOSBox, and browser-based doors with auto-discovery
- Telnet & SSH server — offer classic terminal access alongside the web interface
- Credits economy — reward logins and participation, or charge for door games and premium features
- Message webshare — let users share posts via secure, expiring links with public or private access
- Nodelist browser — search and reference FTN nodes without leaving the interface
- Full admin interface — manage users, echo areas, doors, credits, and system settings from the browser
- Themeable UI — ships with multiple themes including ANSI-inspired and cyberpunk styles
- ...and more
binkterm-php was largely written by Anthropic's Claude with prompting by awehttam. It was meant to be a fun little excercise to see what Claude would come up with for an older technology mixed up with a modern interface.
There are no doubt bugs and omissions in the project as it was written by an AI. "Your Mileage May Vary". This code is released under the terms of a BSD License.
awehttam operates a full instance of BinktermPHP over at https://claudes.lovelybits.org - Claude's very own BBS, and a point system @ https://mypoint.lovelybits.org.
- Screenshots
- Features
- Installation
- Configuration — see also docs/CONFIGURATION.md
- Upgrading
- Command Line Scripts
- Operation
- Joining LovlyNet Network
- Customization
- Security Considerations
- Echo Areas
- File Areas
- Optional Features
- Developer Guide
- Contributors Wanted
- Contributing
- License
- Support
- Acknowledgments
BinktermPHP runs beautifully in any browser — here's a look at the interface across different features and themes.
Echomail List![]() |
Echomail Reader![]() |
Netmail![]() |
Cyberpunk Theme![]() |
ANSI Decoder![]() |
Nodelist Browser![]() |
Mobile Echoread![]() |
Mobile Echolist![]() |
Doors![]() |
User Settings![]() |
Admin Menu![]() |
Telnet Server![]() |
Activity Stats![]() |
Gemini Home![]() |
Markdown![]() |
- Modern Bootstrap 5 UI - Clean, responsive interface accessible from any device including mobile phones.
- Netmail Management - Send and receive private network mail messages
- Echomail Support - Participate in public discussion areas (forums). Sortable and threaded view available.
- Address Book Support A handy address book to keep track of your netmail contacts
- Message Sharing - Share echomail messages via secure web links with privacy controls
- Message Saving - Ability to save messages
- Search Capabilities - Full-text search across messages and echo areas
- Web Terminal - SSH terminal access through the web interface with configurable proxy support
- Installable PWA - Installable both on mobile and desktop for a more seamless application experience
- Gateway Tokens - Provides remote and third party services a means to authenticate a BinktermPHP user for access
- MRC Chat - Real-time multi-BBS chat via the MRC (Multi Relay Chat) network; connects users across BBSes in shared rooms with private messaging support (see docs/MRC_Chat.md)
- WebDoors - PHP/HTML5/JavaScript game integration with storage and leaderboards
- Gemini Browser - Built-in Gemini protocol browser for exploring Geminispace
- Gemini Capsule Hosting - Users can publish personal Gemini capsules accessible via
gemini:// - DOS Door support - Integration with dosbox-x for running DOS based doors
- File Areas - Networked and local file areas with optional automation rules (see
docs/FileAreas.md) - ANSI Support - Support for ANSI escape sequences and pipe codes (BBS color codes) in message readers. See ANSI Support and Pipe Code Support for details.
- Credit System - Support for credits and rewards (details)
- Voting Booth - Voting Booth supports multiple polls. Users can submit new polls for credits
- Shoutbox - Shoutbox support
- Nodelist Browsers - Integrated nodelist updater and browser
- BBS Directory - Public directory of known BBS systems, automatically populated from echomail announcements and supplementable with manual or user-submitted entries reviewed by the sysop
- Echomail Robots - Generic rule-based framework that watches echo areas for matching messages and dispatches them to configurable processors. Ships with a built-in processor for FSXNet
ibbslastcall-dataannouncements that auto-populates the BBS Directory. Custom processors can be added insrc/Robots/Processors/. See docs/Robots.md. - Markup Support - Echomail and netmail can be composed and rendered using Markdown or StyleCodes formatting on compatible networks
- Localization - Full multi-language support across the web interface, admin panel, and API error messages. The active locale is resolved automatically from user preferences, browser settings, or a cookie — no configuration required for users. Sysops can add new languages by dropping catalog files in place with no code changes. Ships with English and Spanish out of the box.
- FTS-1026 Compliant - binkp/1.0 protocol implementation
- TCP/IP Connectivity - Direct connections over internet (port 24554)
- Automated Scheduling - Cron-style polling with configurable intervals
- Password Authentication - Plaintext and Crypt-MD5 Uplink authentication
- Connection Management - Multiple concurrent connections with limits
- Message Posting - CLI tool for automated netmail/echomail posting
- Connection Testing - Debug and test binkp connections
- Server Management - Start/stop binkp server daemon (Linux/UNIX only)
- Status Monitoring - Real-time system and connection status
- Scheduling Control - Manage automated polling schedules
- Weather Reports - Configurable weather forecast generator for posting to echomail areas (details)
- Echomail Maintenance - Purge old messages by age or count limits to manage database size (details)
- Move Messages - Move messages between echo areas for reorganization and consolidation
BinktermPHP provides a shared terminal server experience for text-mode access. After login, Telnet and SSH users get the same core functionality:
- Netmail + Echomail - Browse, read, compose, and reply in terminal mode
- File Areas - Browse file areas and transfer files via ZMODEM
- Doors, Polls, Shoutbox - Access enabled interactive features from the menu
- Full-Screen Editor - Cursor-aware editing with message quoting and shortcuts
- Screen-Aware ANSI UI - Terminal-dimension-aware rendering and ANSI color support
See docs/TerminalServer.md for full terminal feature documentation.
The Telnet daemon is one access method for the shared Terminal Server.
- Classic BBS Access - Traditional telnet-based terminal connection
- Multi-Platform - Works with PuTTY, SyncTERM, ZOC, and standard telnet clients
- Optional TLS Listener - Encrypted telnet access available when enabled
See telnet/README.md for daemon setup, configuration, and troubleshooting.
The built-in pure-PHP SSH server is another access method for the same Terminal Server.
- Encrypted Transport - SSH-2 encryption for terminal sessions
- Direct Login Path - Valid SSH credentials can skip the BBS login menu
- No External SSH Daemon Required - Runs from BinktermPHP directly
See docs/SSHServer.md for daemon setup, configuration, and troubleshooting.
BinktermPHP includes an integrated credits economy that rewards user participation and allows charging for certain actions. Credits can be used to encourage quality content, manage resource usage, and gamify the BBS experience. Configuration is done in config/bbs.json under the credits section, or via Admin → BBS Settings → Credits System Configuration.
See docs/CreditSystem.md for default values, configuration options, transaction types, and the developer API.
BinktermPHP supports rich text formatting in echomail and netmail messages on networks that allow it. When enabled for an uplink, users can compose messages using Markdown or StyleCodes and have them rendered with full formatting in the message reader.
How it works:
Markup support is opt-in per uplink via the allow_markup flag in the Binkp configuration. When a user sends a message with a markup format selected, BinktermPHP adds a \x01MARKUP: <Format> 1.0 kludge line to the outbound packet per LSC-001 Draft 2. Readers that recognise the kludge render the message body with formatting. Readers that don't see the raw text, which remains human-readable as plain text.
Enabling markup for an uplink:
In your Binkp configuration, add "allow_markup": true to the uplink definition:
{
"uplinks": [
{
"address": "1:123/456",
"domain": "lovlynet",
"allow_markup": true
}
]
}Composing messages with markup:
When a user composes a message to a markup-enabled network, a Markup Format selector appears below the message body with three options:
- Plain text — no markup kludge added (default)
- Markdown — activates the split-pane Markdown editor with toolbar and live preview
- StyleCodes — adds the
^AMARKUP: StyleCodes 1.0kludge; use inline codes directly in the plain text editor
Markdown editor features:
- Formatting toolbar — buttons for bold, italic, headings (H1–H3), inline code, code blocks, links, bullet lists, ordered lists, blockquotes, and horizontal rules
- Keyboard shortcuts — Ctrl+B (bold), Ctrl+I (italic), Ctrl+K (link), Tab (indent)
- Edit / Preview tabs — switch between raw Markdown editing and a rendered preview that uses the same server-side renderer as the message reader
Supported Markdown syntax:
| Syntax | Result |
|---|---|
**bold** |
bold |
*italic* |
italic |
`code` |
inline code |
# Heading |
H1 heading |
[text](url) |
hyperlink |
- item |
bullet list |
1. item |
numbered list |
> text |
blockquote |
``` |
fenced code block |
--- |
horizontal rule |
| col | col | |
table |
Supported StyleCodes syntax:
StyleCodes (also known as GoldEd Rich Text, SemPoint Rich Text, or Synchronet Message Markup) use single-character delimiters around words or phrases:
| Syntax | Result |
|---|---|
*bold* |
bold |
/italics/ |
italics |
_underlined_ |
underlined |
#inverse# |
inverse video |
Rendering:
Incoming messages are rendered based on the ^AMARKUP kludge in the message. Markdown messages are rendered server-side by MarkdownRenderer; StyleCodes messages are rendered by StyleCodesRenderer. Messages without a markup kludge are displayed as plain text. The legacy ^AMARKDOWN: kludge (Draft 1) is still recognised for backwards compatibility.
BinktermPHP can be installed using two methods: Git-based installation, or the installer.
- PHP 8.1+ with extensions: PDO, PostgreSQL, Sockets, JSON, DOM, Zip, OpenSSL, GMP
- NodeJS for DOS Doors support (optional)
- PostgreSQL - Database server
- Web Server - Apache, Nginx, or PHP built-in server
- Composer - For dependency management
- Operating System - Designed with Linux in mind, should also run on MacOS, Windows (with some caveats)
- Operating User - It is recommended to run BinktermPHP out of its own user account
sudo apt-get update
sudo apt-get install libapache2-mod-php apache2 php-zip php-mcrypt php-iconv php-mbstring php-pdo php-pgsql php-dom postgresql composer
sudo apt-get install -y unzip p7zip-fullThe unzip and p7zip-full packages are required for Fidonet bundle extraction.
First, decide on a database name, username, and password. These will be used in your .env file later.
Connect to PostgreSQL as the superuser:
sudo -u postgres psqlThen run the following commands, replacing your_username, your_password, and your_database with your chosen values:
CREATE USER your_username WITH PASSWORD 'your_password';
CREATE DATABASE your_database OWNER your_username;
\qVerify the connection works with the new credentials:
psql -U your_username -d your_database -h 127.0.0.1If the connection succeeds, update your .env file with the corresponding values:
DB_HOST=127.0.0.1
DB_PORT=5432
DB_NAME=your_database
DB_USER=your_username
DB_PASS=your_password
Note: Using
127.0.0.1instead oflocalhostforces a TCP connection, which avoids peer authentication issues on some systems.
The installer provides an automated setup process that downloads, configures, and installs BinktermPHP.
# Download the installer
wget https://raw.githubusercontent.com/awehttam/binkterm-php-installer/main/binkterm-installer.phar
# Run the installer
php binkterm-installer.phar [options]
# Or make it executable (Linux/macOS)
chmod +x binkterm-installer.phar
./binkterm-installer.phar [options]The installer will:
- Check system requirements (PHP version, extensions)
- Download the latest release from GitHub
- Configure the database and environment
- Set up initial admin user
- Configure FidoNet settings
This is the standard installation method currently in use while the installer is being developed.
git clone https://github.com/awehttam/binkterm-php
cd binkterm-phpcomposer installCopy the example environment file and configure your settings:
cp .env.example .env
cp binkp.json.example binkp.jsonEdit .env to configure your database connection, SMTP settings, and other options. At minimum, set the PostgreSQL database credentials. Once the system is up you can adjust your BBS settings and BinkP configuration through the administration interface.
First, use the installation script for automated setup:
# Interactive installation (prompts for admin credentials)
php scripts/install.php
# Non-interactive installation (creates admin/admin123 - CHANGE IMMEDIATELY!)
php scripts/install.php --non-interactiveAlternatively, use the setup script which auto-detects whether to install or upgrade:
php scripts/setup.phpThen run the schema upgrader to ensure all schemas are up to date:
php scripts/upgrade.php<VirtualHost *:80>
ServerName binktest.local
DocumentRoot /path/to/binktest/public_html
<Directory /path/to/binktest/public_html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>server {
listen 80;
server_name binktest.local;
root /path/to/binktest/public_html;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}cd public_html
php -S localhost:8080Start the core long-running services at boot and keep cron for periodic maintenance tasks. If you enable optional features such as telnet, Gemini, or DOS doors, see the Operation section for the additional @reboot entries for those daemons.
# Start admin daemon on boot
@reboot /usr/bin/php /path/to/binkterm/scripts/admin_daemon.php --daemon
# Start scheduler on boot
@reboot /usr/bin/php /path/to/binkterm/scripts/binkp_scheduler.php --daemon
# Start binkp server on boot (Linux/macOS)
@reboot /usr/bin/php /path/to/binkterm/scripts/binkp_server.php --daemon
# Update nodelists daily at 3am
#0 3 * * * /usr/bin/php /path/to/binkterm/scripts/update_nodelists.php --quietDirect cron usage of binkp_poll.php and process_packets.php is deprecated but still supported. See the Operation section for the full daemon list and additional cron examples.
update_nodelists can be used if you have URL's to update from. Otherwise nodelists can be updated using file area actions.
# Fresh installation with admin user
php scripts/install.php # Interactive mode
php scripts/install.php --non-interactive # Uses defaults (admin/admin123)
# Auto-detect install vs upgrade
php scripts/setup.php # Smart setup
php scripts/setup.php status # Show system status
# Apply pending migrations
php scripts/upgrade.php # Run migrations
php scripts/upgrade.php status # Show migration status
# Create a new migration (for developers)
php scripts/upgrade.php create 1.3.0 "add feature"Database changes are managed through versioned SQL migration files stored in database/migrations/:
- Filename format:
vX.Y.Z_description.sql(e.g.,v1.1.0_add_user_preferences.sql) - Automatic tracking: Migration status is recorded in
database_migrationstable - Safe execution: Each migration runs in a transaction with rollback on failure
- Comment support: SQL comments are automatically stripped during execution
| Service | Default Port | Protocol | Direction | Configured In |
|---|---|---|---|---|
| Web interface (Apache/Caddy/Nginx) | 80, 443 |
HTTP/HTTPS | Inbound | Web server / reverse proxy |
| BinkP daemon | 24554 |
TCP | In + Out | config/binkp.json → binkp.port |
| Telnet daemon (plain) | 2323 |
TCP | Inbound | .env TELNET_PORT |
| Telnet daemon (TLS) | 8023 |
TCP/TLS | Inbound | .env TELNET_TLS_PORT |
| SSH daemon | 2022 |
SSH-2/TCP | Inbound | .env SSH_PORT |
| Gemini capsule daemon | 1965 |
Gemini/TLS | Inbound | .env GEMINI_PORT |
| DOS door WebSocket bridge | 6001 |
WebSocket | Inbound | .env DOSDOOR_WS_PORT |
| DOSBox bridge session range | 5000–5100 |
TCP | Internal | Between bridge and emulator |
| Admin daemon (TCP fallback) | 9065 |
TCP | localhost | .env ADMIN_DAEMON_SOCKET |
| PostgreSQL | 5432 |
TCP | Internal | .env DB_PORT |
| MRC relay (remote) | 5000 / 5001 |
TCP / TLS | Outbound | config/mrc.json |
- Expose only the services you actually run.
- Bind internal services (admin daemon, DOSBox bridge, PostgreSQL) to
127.0.0.1. - Publish user-facing services through a reverse proxy with TLS.
Full configuration reference: docs/CONFIGURATION.md
To get started, two critical files must be configured before first run:
If you are installing manually from Git, these are the initial two files that must be set up by hand before the first run. If you use the installer, it creates and populates these files for you during setup.
.env— database, SMTP, daemon ports, and feature flags. Copy.env.exampleto.envand fill in values before first run.config/binkp.json— your FTN system identity, uplinks, binkp daemon, security, and crashmail. Copyconfig/binkp.json.exampleas a starting point.
Additional configuration files cover nodelists, file areas, WebDoors, appearance, and more — see docs/CONFIGURATION.md for the full reference.
After those two files are configured and the system is installed, ongoing BBS settings are generally managed through the Admin web interface rather than by manually editing configuration files. In particular, day-to-day feature settings are typically handled through Admin -> BBS Settings.
After editing any config file, restart services:
bash scripts/restart_daemons.shSee docs/CONFIGURATION.md for the complete reference covering all .env variables, binkp.json fields, nodelists, nodelist URL macros, and welcome text files.
In general, you can follow these general steps when upgrading BinktermPHP however individual versions may have their own requirements.
Review version-specific upgrade notes - Check for any UPGRADING_x.x.x.md documents that apply to your upgrade path BEFORE upgrading as there may be specific steps you must take. This applies to both git and installer methods of upgrading!
The general steps are:
- Pull the latest code -
git pull - Run setup -
php scripts/setup.php(handles database migrations automatically) - Update configurations - Review and update
config/binkp.jsonand.envas needed for new features - Restart daemons (admin_daemon, binkd_scheduler, binkd_server) -
bash scripts/restart_daemons.shor restart using your preferred system service tool
If you previously installed BinktermPHP using the installer, re-run the installer to perform an upgrade.
# Download the installer
wget https://raw.githubusercontent.com/awehttam/binkterm-php-installer/main/binkterm-installer.phar
# Run the installer
php binkterm-installer.pharIndividual versions with specific upgrade documentation:
| Version | Date | Highlights |
|---|---|---|
| 1.8.6 | Mar 2026 | i18n/localization, SSH daemon, file areas terminal, ZMODEM, telnet ANSI auto-detect, echomail/netmail reader keyboard shortcuts |
| 1.8.5 | Mar 4 2026 | Native doors (PTY), StyleCodes rendering, LSC-001 Draft 2 MARKUP kludge, markup format composer selector, allow_markup uplink config key |
| 1.8.4 | Mar 1 2026 | Username/real name cross-collision check, MRC room list fix, collapsible compose sidebar, echolist new-tab support |
| 1.8.3 | Feb 27 2026 | Appearance system & shells, Gemini Capsule Hosting, Gemini echo area exposure, Markdown compose editor, netmail file attachments, file share links, friendly share URLs, address book crashmail preference, crashmail DNS fallback & immediate delivery, scrollable message reader, echomail bulk mark-as-read, MRC Chat WebDoor |
| 1.8.2 | Feb 23 2026 | Gemini Browser WebDoor, CSRF protection, telnet anti-bot, security fixes |
| 1.8.0/1.8.1 | Feb 15 2026 | DOS door integration, activity tracking & stats, referral system, WebDoor SDK, UTC timestamp normalisation |
| 1.7.9 | Feb 8 2026 | LovlyNet, telnet user registration, ANSI AD generator, misc updates |
| 1.7.8 | Feb 6 2026 | NetMail enhancements, auto feed RSS poster, sysop notifications to email, echomail cross posting |
| 1.7.7 | Feb 4 2026 | Nodelist import fix for ZC/NC, WebDoor updates, signatures and taglines, file area action processing |
| 1.7.5 | Feb 2 2026 | Echomail loader optimisations, Bink fixes, file areas, forum-style echoarea list |
| 1.7.2 | Jan 30 2026 | Maintenance release |
| 1.7.1 | Jan 29 2026 | Online config editing for BinkP, system config, and WebDoors |
| 1.7.0 | Jan 28 2026 | New daemon/scheduler cron model |
| 1.6.7 | Jan 24 2026 | Multi-network support (FidoNet, FSXNet, etc.) |
BinktermPHP includes a full suite of CLI tools for managing your system from the terminal.
System Daemons — long-running services started at boot:
| Script | Description |
|---|---|
binkp_server.php |
BinkP server — accepts inbound FTN connections |
binkp_scheduler.php |
Automated polling scheduler |
admin_daemon.php |
Control socket for backend task management |
telnet/telnet_daemon.php |
Telnet server daemon |
ssh/ssh_daemon.php |
SSH server daemon |
scripts/gemini_daemon.php |
Gemini capsule server daemon |
mrc/mrc_daemon.php |
MRC chat relay daemon |
scripts/dosbox-bridge/multiplexing-server.js |
DOS door multiplexing bridge |
Utility Scripts — run on demand or via cron:
| Script | Description |
|---|---|
admin_client.php |
Send commands to the admin daemon from the command line |
backup_database.php |
PostgreSQL database backup via pg_dump |
binkp_poll.php |
Manually poll uplinks |
binkp_status.php |
View connection and queue status |
crashmail_poll.php |
Process the crashmail queue for direct delivery |
create_translation_catalog.php |
Generate i18n translation catalogs using AI |
echomail_maintenance.php |
Purge old messages by age or count |
echomail_robots.php |
Run echomail robot processors |
generate_ad.php |
Generate ANSI ads from current system settings |
logrotate.php |
Rotate and archive log files in data/logs |
lovlynet_setup.php |
Automated LovlyNet network registration |
move_messages.php |
Move messages between echo areas |
post_ad.php |
Post an ANSI ad to an echomail area |
post_message.php |
Post netmail or echomail from the command line |
process_packets.php |
Process inbound packets manually |
restart_daemons.sh |
Stop and restart all running daemons |
send_activityreport.php |
Generate and send an activity digest as netmail |
subscribe_users.php |
Bulk subscribe users to echo areas |
update_nodelists.php |
Download and import nodelists from configured URL feeds (optional — the recommended method is file area rules with the import_nodelist tool) |
user-manager.php |
Manage user accounts |
weather_report.php |
Generate weather forecasts for echomail posting |
who.php |
Show currently active users |
Run any script with --help for full usage. See docs/CLI.md for documentation on scripts including usage examples, options, and cron job examples.
- Start Web Server: Ensure Apache/Nginx is running, or use PHP built-in server
- Start Admin Daemon:
php scripts/admin_daemon.php --daemon - Start Scheduler:
php scripts/binkp_scheduler.php --daemon - Start Binkp Server:
php scripts/binkp_server.php --daemon(Linux/macOS; Windows should run in foreground) - Optional Service Daemons: start these only if you use the related features:
php telnet/telnet_daemon.php --daemonphp scripts/gemini_daemon.php --daemonnode scripts/dosbox-bridge/multiplexing-server.js --daemon
- Polling + Packet Processing: handled by the scheduler via the admin daemon
- Navigate to your binktest URL
- Login with your credentials
- Use the Binkp tab to monitor connections and manage uplinks
- Send/receive messages via Netmail and Echomail tabs
- Monitor status:
php scripts/binkp_status.php - Manual poll:
php scripts/binkp_poll.php --all - Post messages:
php scripts/post_message.php [options] - Chat cleanup:
php scripts/chat_cleanup.php --limit=500 --max-age-days=30
ANSI ads can be placed in the bbs_ads/ directory (files ending in .ans). A random ad will be displayed on the main dashboard and can be viewed full-screen via /ads/random.
Post a random ad to an echoarea using:
php scripts/post_ad.php --echoarea=BBS_ADS --domain=fidonet --subject="BBS Advertisement"
php scripts/post_ad.php --echoarea=BBS_ADS --domain=fidonet --ad=claudes1.ans --subject="BBS Advertisement"Weekly cron example (every Tuesday at 6:00 AM):
0 6 * * 2 /usr/bin/php /path/to/binkterm/scripts/post_ad.php --echoarea=BBS_ADS --domain=fidonet --subject="BBS Advertisement"Generate ANSI ads from current system settings:
php scripts/generate_ad.php --stdoutFor extended usage and examples, see docs/ANSI_Ads_Generator.md.
The recommended approach is to start the core services at boot (systemd or @reboot cron). If you use telnet, Gemini, or DOS doors, add the optional daemon entries below as needed. Direct cron usage of binkp_poll.php and process_packets.php is deprecated but still supported.
# Start admin daemon on boot (pid defaults to data/run/admin_daemon.pid)
@reboot /usr/bin/php /path/to/binktest/scripts/admin_daemon.php --daemon
# Start scheduler on boot (pid defaults to data/run/binkp_scheduler.pid)
@reboot /usr/bin/php /path/to/binktest/scripts/binkp_scheduler.php --daemon
# Start binkp server on boot (Linux/macOS; pid defaults to data/run/binkp_server.pid)
@reboot /usr/bin/php /path/to/binktest/scripts/binkp_server.php --daemon
# Optional: start telnet daemon on boot
@reboot /usr/bin/php /path/to/binktest/telnet/telnet_daemon.php --daemon
# Optional: start SSH daemon on boot
@reboot /usr/bin/php /path/to/binktest/ssh/ssh_daemon.php --daemon
# Optional: start Gemini daemon on boot
@reboot /usr/bin/php /path/to/binktest/scripts/gemini_daemon.php --daemon
# Optional: start DOS door multiplexing bridge on boot
@reboot /usr/bin/node /path/to/binktest/scripts/dosbox-bridge/multiplexing-server.js --daemon
# Rotate logs weekly
0 0 * * 0 find /path/to/binktest/data/logs -name "*.log" -mtime +7 -delete
# For passive nodes with no binkp_scheduler or binkp_server running (passive node/no incoming connections)
# */3 * * * * /usr/bin/php /path/to/binktest/scripts/process_packets.php
# */5 * * * * /usr/bin/php /path/to/binktest/scripts/binkp_poll.php --all- Increase
max_connectionsin configuration - Use faster storage for inbound/outbound directories
- Consider SSD storage for database
- Monitor system resources during peak times
- Optimize PHP opcache settings
For deployed systems where you need lightweight backend profiling, you can enable slow request logging. This logs slow
requests to the PHP error log via error_log() so you can identify bottlenecks without external tooling.
Add to .env:
PERF_LOG_ENABLED=true
PERF_LOG_SLOW_MS=500PERF_LOG_ENABLED: Set totrueto enable logging.PERF_LOG_SLOW_MS: Minimum duration in milliseconds before a request is logged.
- Monitor PHP memory usage
- Process packets more frequently to avoid large queues
- Clean up old log files regularly
- Consider increasing PHP memory limit
LovlyNet is a FidoNet Technology Network (FTN) operating in Zone 227 with automated registration. You can join and get an FTN address assigned automatically:
php scripts/lovlynet_setup.phpSee docs/LovlyNet.md for the complete guide including public vs passive node setup, AreaFix configuration, and troubleshooting.
BinktermPHP provides several ways to customize the look and feel without modifying core files:
The easiest way to customize your BBS is through Admin → Appearance, which provides a point-and-click interface for:
- Shells — Choose between the modern
webshell (Bootstrap 5) or the retrobbs-menushell. The BBS menu shell offers three variants: card grid, text menu, and ANSI art display. You can allow users to choose their own shell or lock everyone to a single choice. - Branding — Set a custom accent color, logo URL, default theme, and footer text.
- Announcements — Post a dismissible site-wide announcement with an optional expiry date.
- System News — Write dashboard content in Markdown, managed through the admin panel.
- Navigation — Add custom links to the navigation bar.
- SEO — Set a site description and Open Graph image for search engine and social sharing metadata.
All appearance settings are stored in data/appearance.json and take effect immediately.
- Custom Stylesheet: Set
STYLESHEET=/css/mytheme.cssin.env(includes built-in dark theme at/css/dark.css) - Template Overrides: Copy any template to
templates/custom/to override it without touching core files - Shell Templates: Add a
templates/shells/<name>/directory with abase.twigto create a new shell - Custom Routes: Create
routes/web-routes.local.phpto add new pages - Header Insertions: Add CSS/JS via
templates/custom/header.insert.twig - Welcome Messages: Customize login page via
config/welcome.txt
All customizations are upgrade-safe and won't be overwritten when updating BinktermPHP.
For detailed instructions including the full appearance configuration reference, shell template structure, Twig variables, and code examples, see docs/CUSTOMIZING.md.
- Binkp server listens on all interfaces by default
- Consider firewall rules to restrict access
- Monitor connection logs for unauthorized attempts
- Use strong passwords for uplink authentication
- Inbound directory should not be web-accessible
- Set appropriate file permissions (755 for directories, 644 for files)
- Regular backup of database and configuration files
- Monitor disk space to prevent DoS via large files
- Use HTTPS in production environments
- Implement proper session management
- Regular security updates of dependencies
- Consider rate limiting for API endpoints
The Gateway Token system allows remote components (such as Door servers, external modules, or automatic login scripts) to securely verify a user's identity without requiring the user to share their primary BBS credentials with the remote system.
- Handshake Initiation: A user visits the BBS and hits (for example).
- Redirect: The BBS generates a temporary, single-use token and redirects the user to the remote gateway URL (e.g.,
https://remote-door.com/login?userid=123&token=abc...). - Back-Channel Validation: The remote gateway receives the user. Before granting access, it makes a server-to-server POST request back to the BBS with its API Key, the UserID, and the Token.
- Verification: The BBS validates the request. If successful, the gateway receives the user's profile information and initiates a local session.
Endpoint: POST /auth/verify-gateway-token
| Header | Value | Description |
|---|---|---|
Content-Type |
application/json |
Required |
X-API-Key |
YOUR_BBS_API_KEY |
Must match the BBSLINK_API_KEY in the BBS .env |
The server accepts either userid or user_id as the key.
{
"userid": 1,
"token": "78988029a8385f9..."
}{
"valid": true,
"userInfo": {
"id": 1,
"username": "Sysop",
"email": "admin@example.com"
}{
"valid": false,
"error": "Invalid or expired token"
}<?php
/**
* Example function to verify a token against the BBS
*/
function verifyWithBBS($userId, $token) {
$bbsUrl = '[https://your-bbs-domain.com/auth/verify-gateway-token](https://your-bbs-domain.com/auth/verify-gateway-token)';
$apiKey = 'your_configured_api_key';
$payload = json_encode([
'userid' => $userId,
'token' => $token
]);
$ch = curl_init($bbsUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-API-Key: ' . $apiKey
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
if ($data['valid']) {
return $data['userInfo']; // Token is valid!
}
}
return false; // Invalid token or API key
}
// --- Usage in a landing page ---
$userIdFromUrl = $_GET['userid'] ?? null;
$tokenFromUrl = $_GET['token'] ?? null;
if ($userIdFromUrl && $tokenFromUrl) {
$user = verifyWithBBS($userIdFromUrl, $tokenFromUrl);
if ($user) {
echo "Welcome, " . htmlspecialchars($user['username']);
// Proceed to log the user into the local system...
} else {
die("Authentication failed.");
}
}Echo areas are public message forums distributed across FidoNet-compatible (FTN) networks. Each area is identified by a tag (e.g., GENERAL) and a domain (e.g., fidonet), allowing the same tag to exist independently in multiple networks. Areas marked Local Only are stored purely on the local system and never transmitted to uplinks — useful for internal discussion boards or testing.
Inbound echomail arrives in .pkt packets or FTN day-of-week bundles, is validated and deduplicated by MSGID, then stored in the database. If a packet references an area that doesn't exist yet, BinktermPHP creates it automatically. Outbound messages composed through the web interface or terminal server are bundled into packets at the next binkp poll.
New users are automatically subscribed to areas marked as default subscriptions. Users can manage their own subscriptions, and areas can be restricted to admins only (Sysop Access Only) or exposed to Gemini protocol readers (Public Gemini Access).
Areas are managed at Admin → Echo Areas and support bulk import via CSV. For full configuration details, see docs/EchoAreas.md.
File areas are organized collections of downloadable files, similar to echo areas but for file distribution. Each area is identified by a tag and a domain (e.g., NODELIST in fidonet or localnet). File areas can be local‑only or networked for distribution to uplinks, and they support controls like maximum file size, upload permissions, and virus scanning.
Files uploaded or received via TIC are stored under a directory specific to the file area, and the web UI at /fileareas lets sysops manage area settings and browse files. This makes it easy to distribute nodelists, archives, and other content across FTN networks while keeping local areas isolated when needed.
BinktermPHP supports optional ClamAV virus scanning for uploaded and TIC-received files, configurable per area. See docs/AntiVirus.md for installation and configuration instructions.
BinktermPHP supports file area automation rules to run scripts and apply post-processing actions after uploads or TIC imports. Rules are configured in config/filearea_rules.json and can be edited in the admin UI at /admin/filearea-rules. Each rule matches filenames with a regex, runs a script with macro substitutions, and then performs success/fail actions like delete, move, or notify. Rules can be scoped by area tag and domain and are applied in order (global rules first, then area-specific rules). For full configuration details, see docs/FileAreas.md.
The following features are optional and can be enabled based on your needs. Each has its own configuration and may require additional setup.
Doors are external programs or games that run within the BBS, launched on demand for individual users. BinktermPHP supports three types of doors: native Linux and Windows programs that run directly via PTY, classic DOS games running under DOSBox emulation, and browser-based doors that run as web applications in the user's browser. All door types are managed from the admin interface and can integrate with the credits economy.
BinktermPHP supports running native Linux binaries and Windows executables as BBS doors. Native doors run directly via PTY (pseudo-terminal) with no emulator overhead, making them suitable for modern programs, shell scripts, or compiled binaries.
- Browser Terminal - xterm.js terminal in the web browser
- Multiplexing Bridge - Same Node.js bridge used by DOS doors; spawns the door executable via
node-pty - PTY Execution - Door runs in a pseudo-terminal with full ANSI/VT100 support
- Drop Files & Environment Variables - DOOR.SYS written to
native-doors/drops/NODE{n}/; user data also injected as environment variables
- No Emulator Required - Doors launch instantly with no DOSBox overhead
- Multi-Node Support - Isolated sessions per node with DOOR.SYS drop files written per-session, same as DOS doors
- Environment Variable Injection -
DOOR_USER_NAME,DOOR_NODE,DOOR_BBS_NAME,DOOR_DROPFILE,TERM, and more - Cross-Platform - Supports Linux shell scripts, compiled binaries, and Windows
.bat/.exefiles
- Create a subdirectory under
native-doors/doors/for your door. - Add a
nativedoor.jsonmanifest (seeUPGRADING_1.8.3.mdfor the full format). - Place your executable in the same directory.
- Go to Admin → Native Doors and click Sync Doors, then enable the door.
- Node.js with
node-pty— already required by the DOS door bridge
See docs/NativeDoors.md for complete documentation including:
- Manifest format reference
- Creating and installing doors
- Environment variables and drop file details
- Platform notes (Linux and Windows)
- Troubleshooting
BinktermPHP supports running classic DOS door games through DOSBox-X emulation. This brings authentic retro BBS door games like Legend of the Red Dragon (LORD), Trade Wars, and other DOS classics to your web-based BBS.
The DOS door system uses a multiplexing bridge architecture that connects browser terminals to DOSBox-X instances via WebSockets:
- Browser Terminal - xterm.js terminal in the web browser
- Multiplexing Bridge - Node.js server managing WebSocket connections and DOSBox instances
- DOSBox-X - Emulator running the actual DOS door game with FOSSIL driver support
- Node-Specific Drop Files - DOOR.SYS generated per-session for proper multi-user support
- Multi-Node Support - Multiple users can play simultaneously with isolated sessions
- Automatic Session Management - Bridge handles entire lifecycle (config generation, DOSBox launch, cleanup)
- Carrier Detection - Realistic BBS behavior with graceful shutdown on disconnect
- Drop File Generation - DOOR.SYS files generated from user data for proper door game integration
- DOSBox-X - Required for DOS emulation
- Node.js - Required for the multiplexing bridge server
- FOSSIL Driver Support - Built into DOSBox-X serial port configuration
- Door Games - Classic DOS door game files (LORD, BRE, etc.)
See docs/DOSDoors.md for complete documentation including:
- Installation and configuration
- Adding door games
- Multi-node setup
- WebSocket configuration (SSL/proxy support)
- Troubleshooting and debugging
BinktermPHP implements the WebDoors - HTML5/JavaScript games that integrate with the BBS.
BinktermPHP ships with the following WebDoors out of the box:
Games:
- Blackjack - Classic casino card game against the dealer
- Hangman - Word guessing game with category selection
- Klondike Solitaire - Traditional solitaire with save/load support
- Reverse Polarity - Reverse Polarity BBS
- Wordle - Popular five-letter word guessing game
Utilities:
- MRC Chat - Real-time multi-BBS chat connecting to the MRC network (see docs/MRC_Chat.md)
- Community Wireless Node List - Interactive map for discovering and sharing community wireless networks, mesh networks, and grassroots infrastructure
- Source Games - Live server browser for Source engine games (TF2, CS:GO) with real-time stats
- Terminal - Web-based SSH terminal for system access
- Game Library - Browse and launch available games from the web interface
- Save/Load Support - Games can persist user progress via the BBS API
- Leaderboards - Global and time-scoped high score tracking
- Multiplayer - Real-time multiplayer support via WebSocket connections (not yet implemented)
- Lobby System - Create and join game rooms for multiplayer sessions
By default the webdoor system is not activated and requires webdoors.json to be installed. You may do so through the Admin -> >Webdoors interface or by copying config/webdoors.json.example to config/webdoors.json.
The example configuration enables a number of webdoors by default.
WebDoors supports two hosting approaches:
| Model | Location | Authentication | Use Case | Status |
|---|---|---|---|---|
| Local | Same server (/webdoor/games/) |
Session cookie | Self-hosted games | In use |
| Third-Party | External server | Token + CORS | Community games | Not yet implemented |
Each game includes a webdoor.json manifest describing its capabilities:
{
"webdoor_version": "1.0",
"game": {
"id": "space-trader",
"name": "Space Trader",
"version": "1.0.0",
"entry_point": "index.html"
},
"requirements": {
"features": ["storage", "leaderboard"]
},
"storage": {
"max_size_kb": 100,
"save_slots": 3
},
"config": {
"enabled": "true,",
"play_cost": 10
}
}Games interact with the BBS through REST endpoints:
| Endpoint | Purpose |
|---|---|
GET /api/webdoor/session |
Get authenticated session |
GET/PUT/DELETE /api/webdoor/storage/{slot} |
Save game management |
GET/POST /api/webdoor/leaderboard/{board} |
Leaderboard access |
WS /api/webdoor/multiplayer |
Real-time multiplayer (not yet implemented) |
For the WebDoor documentation as used by BinktermPHP see docs/WebDoors.md.
BinktermPHP includes first-class support for the Gemini protocol — a lightweight, privacy-focused alternative to the web that uses a simple text format called gemtext.
A built-in Gemini browser WebDoor lets users explore Geminispace without leaving the BBS. It includes:
- Address bar with history navigation (back/forward)
- Bookmark management per user
- Gemtext rendering with headings, links, lists, blockquotes, and preformatted blocks
- Redirect following and configurable request timeouts
- SSRF protection (private/reserved address blocking for public deployments)
The browser opens to a curated start page with links to popular Geminispace destinations. The start page can be overridden in Admin → WebDoors → Gemini Browser.
BBS users can publish personal Gemini capsules directly from the web interface. The Gemini Capsule WebDoor provides:
- Split-pane gemtext editor with live preview
- Per-file publish/draft controls (only published files are publicly accessible)
- Gemtext syntax cheat sheet
- Multiple
.gmifiles per user
Published capsules are accessible at:
gemini://yourdomain.com/home/username/
A directory page at gemini://yourdomain.com/ lists all users with published capsules and links to the BBS website.
The capsule server is a separate opt-in daemon (scripts/gemini_daemon.php) that operators start only if they want to expose Gemini. It generates a self-signed TLS certificate automatically (Gemini uses a Trust On First Use model), or can be configured to use a CA-signed certificate such as one from Let's Encrypt.
See docs/GeminiCapsule.md for full setup instructions, TLS configuration, and Let's Encrypt integration.
For developers working on BinktermPHP or integrating with the system, see the comprehensive Developer Guide which covers:
- Project Architecture - Overview of the dual web+mailer system
- Core Concepts - FidoNet terminology, message types, network routing
- Development Workflow - Code conventions, database migrations, best practices
- Credits System - In-world currency implementation and API
- URL Construction - Centralized site URL generation for reverse proxy support
- WebDoor Integration - Game/application API for BBS integration
The Developer Guide is essential reading for anyone contributing code, developing WebDoors, or extending the system.
BinktermPHP uses key-based localization for Twig templates, JavaScript UI, and API errors. For a full technical reference see docs/Localization.md.
- Translation files live in:
config/i18n/en/common.phpconfig/i18n/en/errors.phpconfig/i18n/es/common.phpconfig/i18n/es/errors.php
- UI keys should use the
ui.*prefix (for exampleui.settings.*). - API error keys should use the
errors.*prefix.
- Use the Twig
t()helper instead of hardcoded literals:
{{ t('ui.settings.title', {}, 'common') }}
{{ t('ui.polls.create.submit', {'cost': poll_cost}, 'common') }}- Use
window.t(key, params, fallback)(or a localuiTwrapper). - Always provide a fallback string for resilience.
- Example:
window.t('ui.polls.create.submit', { cost: 25 }, 'Create Poll ({cost} credits)');JavaScript catalogs are loaded on demand from:
GET /api/i18n/catalog?ns=common,errors&locale=<locale>
- API responses should include both:
error_code(translation key)error(human fallback text)
- Routes should emit errors through
apiError(errorCode, message, status, extra). - Frontend should resolve display text through
window.getApiErrorMessage(payload, fallback).
This keeps UI text translatable and avoids coupling frontend logic to raw server English strings.
Run both checks before committing:
php scripts/check_i18n_hardcoded_strings.php
php scripts/check_i18n_error_keys.phpWe're looking for experienced PHP developers interested in contributing to BinktermPHP. Areas include FTN networking, WebDoors game development, themes, telnet, real-time features, and more. See HELP_WANTED.md for details.
We welcome contributions to BinktermPHP! Before contributing, please review:
- Developer Guide - Essential reading for understanding the codebase
- Help Wanted - Current areas where contributions are especially needed
- Contributing Guide - Detailed information on:
- Development setup and code conventions
- Pull request workflow
- Database migrations
- Testing guidelines
- Security considerations
All contributions must be submitted via pull request and will be reviewed by project maintainers.
This project is licensed under a BSD License. See LICENSE.md for more information.
- Documentation: This README and inline code comments
- Issues: GitHub issue tracker
- Community: Fidonet echo areas and developer forums
Problem: Cannot connect to uplink Solutions:
- Check network connectivity:
ping uplink.hostname.com - Verify port is open:
telnet uplink.hostname.com 24554 - Run debug script:
php scripts/debug_binkp.php 1:153/149 - Check logs in
data/logs/directory - Verify password in configuration
Problem: Password mismatch errors Solutions:
- Verify password in
config/binkp.jsonmatches uplink configuration - Check that uplink address is correct
- Ensure uplink has your address and password configured
- Run debug script to see exact authentication flow
Problem: Files not transferring properly Solutions:
- Check file permissions on inbound/outbound directories
- Verify disk space availability
- Check for firewall blocking data transfer
- Review transfer logs for specific error messages
- Test with smaller files first
Problem: Cannot access web interface Solutions:
- Check web server error logs
- Verify PHP extensions are installed
- Check file permissions on web directory
- Test PHP configuration:
php -m - Verify database file permissions
Monitor these log files for troubleshooting:
data/logs/binkp_server.log- Server daemon logsdata/logs/binkp_poll.log- Polling activitydata/logs/binkp_scheduler.log- Automated schedulingdata/logs/binkp_debug.log- Debug connection issuesdata/logs/binkp_web.log- Web interface API calls
Enable detailed logging for troubleshooting:
# Start server with debug logging
php scripts/binkp_server.php --log-level=DEBUG
# Debug specific connection
php scripts/debug_binkp.php 1:153/149
# Monitor logs in real-time
tail -f data/logs/binkp_server.logYou can inject analytics tracking code into the page header by creating a template named templates/custom/header.insert.twig.
See templates/custom/header.insert.twig.example for reference with Google Analytics and other tracking examples.
If you encounter issues not covered here:
- Check the debug logs with maximum verbosity
- Test with minimal configuration (one uplink)
- Verify your FTN address is correct and authorized
- Contact your uplink administrator to verify connectivity
- Create issues on the project GitHub repository with:
- Full error messages
- Configuration details (remove passwords)
- Debug log excerpts
- System information (OS, PHP version)
See FAQ.md for Frequently (or infrequently) Asked Questions
- Fidonet Technical Standards Committee for protocol specifications
- Original binkd developers for reference implementation
- Bootstrap and jQuery communities for web interface components
- PHP community for excellent documentation and tools














