# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=binktest
DB_USER=binktest
DB_PASS=binktest
DB_SSL=false
# Optional SSL Configuration (uncomment if needed)
#DB_SSL_CA=/path/to/ca-cert.pem
#DB_SSL_CERT=/path/to/client-cert.pem
#DB_SSL_KEY=/path/to/client-key.pem
# Admin daemon (Unix socket by default, TCP on Windows).
ADMIN_DAEMON_SECRET=change_me
ADMIN_DAEMON_SOCKET=tcp://127.0.0.1:9065
# Unix sockets require care for their permissions and group ownership
# ADMIN_DAEMON_SOCKET=unix:///path/to/binkterm/data/run/admin_daemon.sock
# ADMIN_DAEMON_SOCKET_PERMS=0660
# Telnet Daemon Configuration
# TELNET_BIND_HOST=0.0.0.0
# TELNET_PORT=2323
# TLS is enabled by default on port 8023 with an auto-generated self-signed cert.
# Set TELNET_TLS=false to disable TLS entirely.
# TELNET_TLS=true
# TELNET_TLS_PORT=8023
# TELNET_TLS_CERT=/etc/ssl/certs/your-cert.pem
# TELNET_TLS_KEY=/etc/ssl/private/your-key.pem
# Shared secret the terminal daemons send when bypassing browser-only registration anti-spam checks.
# Defaults to Chang3Me when omitted. Change this in production.
# TERMINAL_REGISTRATION_SECRET=Chang3Me
# PubTerm Native Door Configuration
# Host and port the PubTerm door connects to via telnet (defaults to BBS localhost telnet port)
# PUBTERM_HOST=127.0.0.1
# PUBTERM_PORT=2323
# Path to telnet binary if not on PATH (Linux)
# PUBTERM_TELNET_BIN=/usr/bin/telnet
# Windows: PubTerm uses PuTTY plink in telnet mode (no escape character trap).
# Install PuTTY: winget install PuTTY.PuTTY
# PUBTERM_PLINK_BIN=C:\Program Files\PuTTY\plink.exe
# Gemini Capsule Server Configuration (optional ? only needed if running the daemon)
# GEMINI_BIND_HOST=0.0.0.0
# GEMINI_PORT=1965
# GEMINI_CERT_PATH=/etc/letsencrypt/live/yourdomain.com/fullchain.pem
# GEMINI_KEY_PATH=/etc/letsencrypt/live/yourdomain.com/privkey.pem
# Site URL Configuration (used for generating sharing URLs)
SITE_URL=https://example.com
# BBS Directory geocoding (used for the public map tab)
# Enabled by default. Set to false to disable location lookups entirely.
# BBS_DIRECTORY_GEOCODING_ENABLED=true
# BBS_DIRECTORY_GEOCODER_URL=https://nominatim.openstreetmap.org/search
# BBS_DIRECTORY_GEOCODER_USER_AGENT=
# BBS_DIRECTORY_GEOCODER_EMAIL=
# SMTP Email Configuration
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURITY=tls
SMTP_USER=your-email@example.com
SMTP_PASS=your-email-password
SMTP_FROM_EMAIL=noreply@example.com
SMTP_FROM_NAME=BinktermPHP
SMTP_ENABLED=true
#SMTP_NOVERIFYCERT=true
# Whether to allow terminal access (grants ssh/telnet access to remote hosts).
# This setting is used by the 'Terminal' web door.
TERMINAL_ENABLED=false
# Experimental FREQ UI controls.
# false = hide file-area FREQ controls and nodelist file-request actions
# true = expose file-area FREQ controls and sysop-only nodelist file requests
ENABLE_FREQ_EXPERIMENTAL=false
# Interests system ? admin-defined topic groups that users can subscribe to.
# Subscribing to an interest auto-subscribes the user to all member echo areas.
ENABLE_INTERESTS=true
# AI assistant feature flag (defaults to false)
# AI_ASSISTANT_ENABLED=false
# AI provider configuration
# AI_DEFAULT_PROVIDER=openai
# AI_DEFAULT_MODEL=gpt-4o-mini
# AI_MESSAGE_AI_ASSISTANT_PROVIDER=openai
# AI_MESSAGE_AI_ASSISTANT_MODEL=gpt-4o-mini
# AI_TRANSLATION_CATALOG_PROVIDER=openai
# AI_TRANSLATION_CATALOG_MODEL=gpt-4o-mini
# AI_INTEREST_GENERATION_PROVIDER=anthropic
# AI_INTEREST_GENERATION_MODEL=claude-haiku-4-5-20251001
# OPENAI_API_KEY=
# OPENAI_API_BASE=https://api.openai.com/v1
# ANTHROPIC_API_KEY=
# ANTHROPIC_API_BASE=https://api.anthropic.com/v1
# Pricing is optional but recommended for accurate cost estimates.
# Values are USD per 1,000,000 tokens.
# AI_PRICE_OPENAI_INPUT_PER_MILLION_USD=0
# AI_PRICE_OPENAI_OUTPUT_PER_MILLION_USD=0
# AI_PRICE_ANTHROPIC_INPUT_PER_MILLION_USD=0
# AI_PRICE_ANTHROPIC_OUTPUT_PER_MILLION_USD=0
# The first host listed will be this host, and could be your BBS or other favourite system
TERMINAL_HOST=your.ssh.server.com
TERMINAL_PORT=22
TERMINAL_TYPE=ssh
# The proxy server the terminal client will use. You could use a system like http://github.com/awehttam/terminalgateway
TERMINAL_PROXY_HOST=your.proxy.server.com
TERMINAL_PROXY_PORT=443
# Virus scanning with ClamAV (optional - will auto-detect if not set)
# CLAMDSCAN=/usr/bin/clamdscan
# Backend profiling (logs slow requests to error_log)
PERF_LOG_ENABLED=false
PERF_LOG_SLOW_MS=500
# Archive extractor commands for Fidonet bundles (JSON array).
# Use {archive} and {dest} placeholders.
# ARCMAIL_EXTRACTORS=["7z x -y -o{dest} {archive}","unzip -o {archive} -d {dest}"]
# BinkP socket tuning
# Disable Nagle's algorithm by default to reduce latency for small handshake/control frames.
# Set to false only if you need to troubleshoot interoperability with a specific peer/network stack.
# BINKP_TCP_NODELAY=true
# Retain binkp_session_log rows for this many days in scripts/database_maintenance.php.
# Default: 30
# BINKP_SESSION_LOG_RETENTION_DAYS=30
# PID File locations (defaults to data/run)
# ADMIN_DAEMON_PID_FILE=data/run/admin_daemon.pid
# BINKP_SCHEDULER_PID_FILE=data/run/binkp_scheduler.pid
# BINKP_SERVER_PID_FILE=data/run/binkp_server.pid
# Move stale unprocessed inbound files to data/inbound/unprocessed/ by default
# Set to true to delete stale unprocessed files instead (after 24 hours untouched)
# BINKP_DELETE_UNPROCESSED_FILES=false
# UI Customization
# STYLESHEET=/css/style.css
# ANSI renderer options
# ANSI_RENDERER_MODE controls how ANSI art HTML is emitted:
# grouped = default, merges runs of identical styling into larger spans and enables URL hyperlinking
# perchar = one span per character, closer to the older renderer behavior
# ANSI_RENDERER_MODE=grouped
#
# Debug font overrides for troubleshooting ANSI rendering differences across browsers/themes.
# DEBUG_ANSI_NOT_PERFECT=true forces ANSI blocks to inherit the page font instead of the ANSI font.
# DEBUG_ANSI_USE_CONSOLAS=true forces ANSI blocks to use Consolas.
# Leave both false in normal use.
# DEBUG_ANSI_NOT_PERFECT=false
# DEBUG_ANSI_USE_CONSOLAS=false
# favicon in SVG format
# Binkterm uses three formats for favicon. SVG, PNG and ICO. This is for platform support across browser technologies
# and Progressive Web Apps.
#FAVICONSVG=/robot_favicon.svg
#FAVICONPNG=/robot_favicon.png
#FAVICONICO=/robot_favicon.ico
# File area rule logging
FILEAREA_RULE_ACTION_LOG=data/logs/filearea_rules.log
# Maximum file size (in bytes) for listing non-ZIP archive contents via 7z.
# ZIP archives are always listed regardless of size (fast index read).
# Default: 20971520 (20 MB). Set to 0 to disable the limit.
# ARCHIVE_LIST_MAX_SIZE=20971520
# File action debugging (writes data/logs/file_action_debug.log)
# FILE_ACTION_DEBUG=true
# Echomail message date ordering field used by backend sorting and echomail UI date display.
# received = use date_received (default), written = use date_written
# ECHOMAIL_ORDER_DATE=received
# Licensing
# Path to the license file (default: data/license.json)
# LICENSE_FILE=data/license.json
# Log invalid license states to PHP error_log (useful for troubleshooting)
# LICENSE_LOG_INVALID=false
# i18n missing key logging (QA hardening)
# Set to true to log translation keys that are missing from catalogs.
# I18N_LOG_MISSING_KEYS=false
# Optional explicit log file path. If unset, messages go to PHP error_log.
# I18N_MISSING_KEYS_LOG_FILE=data/logs/i18n_missing_keys.log
# DOS Emulator Selection (defaults to DOSBox)
# dosbox = DOSBox (default, reliable, ~180MB RAM, works on Windows and Linux) - RECOMMENDED
# dosemu = DOSEMU (EXPERIMENTAL, NOT RECOMMENDED, Linux only, requires dosemu2 package)
# DOSEMU has console I/O conflicts and complex configuration - only for adventurous users
# DOOR_EMULATOR=dosbox
# DOSBox-X executable path (auto-detects if not specified)
# Prefers vanilla DOSBox (lighter: ~30MB RAM) over DOSBox-X (~256MB RAM)
# Auto-detection order: dosbox-x, dosbox
# DOSBOX_EXECUTABLE=/usr/bin/dosbox-x
# DOSBOX_EXECUTABLE=/usr/local/bin/dosbox-x
# DOSEMU executable path (auto-detects if not specified)
# Linux only - much lighter than DOSBox (10-30MB vs 180MB RAM)
# DOSEMU_EXECUTABLE=/usr/bin/dosemu
# DOS Door Configuration
# Specify which DOSBox config to use (defaults to dosbox-bridge-production.conf)
# Create a custom config (e.g., dosbox-bridge-custom.conf) to prevent overwriting on upgrades
# DOSDOOR_CONFIG=dosbox-bridge-production.conf
# DOSDOOR_CONFIG=dosbox-bridge-test.conf
# DOSDOOR_CONFIG=dosbox-bridge-custom.conf
# DOS Door disconnect behavior (in minutes)
# 0 = Immediately close door when WebSocket disconnects (traditional BBS "lost carrier" behavior - DEFAULT)
# >0 = Wait X minutes for reconnection before closing door
DOSDOOR_DISCONNECT_TIMEOUT=0
# 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
# DOS Door WebSocket Configuration (Multiplexing Bridge)
# Single WebSocket port for all door connections
DOSDOOR_WS_PORT=6001
# WebSocket bind address (server-side)
# 127.0.0.1 = Localhost only (DEFAULT - for production behind SSL proxy like Caddy)
# 0.0.0.0 = All interfaces (for development/direct access without proxy)
DOSDOOR_WS_BIND_HOST=127.0.0.1
# WebSocket URL for browser (client-side)
# If not set, auto-detects: ws://hostname:6001 or wss://hostname:6001 based on page protocol
# Production examples:
# DOSDOOR_WS_URL=wss://bbs.example.com:6001 (separate WebSocket port)
# DOSDOOR_WS_URL=wss://bbs.example.com/dosdoor (proxied through main HTTPS)
# Development: Leave empty for auto-detection (ws://localhost:6001)
DOSDOOR_WS_URL=
# Debug mode - keep session files for inspection (default: false)
# Set to 'true' to disable cleanup of DOOR.SYS and session directories
# Useful for debugging drop file generation and DOSBox config issues
DOSDOOR_DEBUG_KEEP_FILES=false
# Carrier loss timeout (in milliseconds)
# How long to wait for door to exit gracefully after simulating carrier loss (socket close)
# before force-killing the process (default: 5000ms = 5 seconds)
DOSDOOR_CARRIER_LOSS_TIMEOUT=5000
# BinkStream transport strategy (currently supported: auto, sse, ws)
# auto = normal default; on Apache, if SSE_WINDOW_SECONDS is not set explicitly,
# BinktermPHP uses an implicit 2-second SSE window as an interim mitigation
# for Apache + php-fpm buffering behavior.
# sse = force the standard SSE behavior and default to a 60-second window unless
# SSE_WINDOW_SECONDS is explicitly overridden.
# ws = use the standalone PHP WebSocket realtime daemon instead of SSE.
BINKSTREAM_TRANSPORT_MODE=auto
# BinkStream WebSocket server (used when BINKSTREAM_TRANSPORT_MODE=ws)
# Bind host and port for scripts/realtime_server.php.
BINKSTREAM_WS_BIND_HOST=127.0.0.1
BINKSTREAM_WS_PORT=6010
# Comma-separated list of proxy IPs whose X-Forwarded-For header is trusted
# for real client IP logging in scripts/realtime_server.php.
# Default: 127.0.0.1
# BINKSTREAM_TRUSTED_PROXIES=127.0.0.1
# Public WebSocket URL the browser connects to. In production this is usually
# proxied through the main HTTPS vhost, e.g. wss://bbs.example.com/ws
BINKSTREAM_WS_PUBLIC_URL=/ws
# Standalone FTP daemon served by scripts/ftp_daemon.php.
# This is a passive-mode FTP server that exposes a virtual filesystem:
# anonymous login - public file areas only
# /qwk/download/<BBSID>.QWK - generate/download QWK packets
# /qwk/upload/*.REP|*.ZIP - upload REP reply packets
# /incoming/<AREA>/... - upload files into pending approval
# /fileareas/... - browse and download approved file-area files
FTPD_ENABLED=false
FTPD_BIND_HOST=0.0.0.0
FTPD_PORT=2121
# Optional public IPv4 address/hostname to advertise in PASV replies.
# Set this when the FTP service is behind NAT or bound to 0.0.0.0.
# FTPD_PUBLIC_HOST=203.0.113.10
FTPD_PASSIVE_PORT_START=2122
FTPD_PASSIVE_PORT_END=2149
# Set to true to allow anonymous FTP logins (default: false)
FTPD_ALLOW_ANONYMOUS=false
# SSE back-channel window duration (seconds)
# How long the /api/stream endpoint holds an Apache/PHP-FPM worker while
# polling for new events before sending event:reconnect. The SharedWorker
# reconnects immediately, so messages still arrive within one poll interval.
# How long each SSE connection is held open before the client is asked to reconnect.
# A keepalive comment is sent every 15 seconds to prevent proxy timeouts.
# Increase pm.max_children in php-fpm proportionally ? each active browser tab
# holds one worker for the full duration of the window.
# On the PHP built-in dev server this is always 0 (immediate reconnect).
# Default: 60
# Apache + BINKSTREAM_TRANSPORT_MODE=auto implicit default: 2
SSE_WINDOW_SECONDS=60
# Sixel image rendering (terminal inline images)
# Absolute path to the img2sixel binary. Leave unset to auto-detect from PATH.
# IMG2SIXEL_PATH=/usr/bin/img2sixel
# Windows example:
# IMG2SIXEL_PATH=C:\tools\img2sixel.exe
SIXEL_FETCH_TIMEOUT=10
SIXEL_CONVERT_TIMEOUT=15
SIXEL_WRITE_TIMEOUT=15
SIXEL_IMAGE_MAX_BYTES=5242880
SIXEL_PIXELS_PER_COL=9
SIXEL_PIXELS_PER_ROW=16
|