This guide covers deploying BinktermPHP using Docker and Docker Compose.
Note: Docker is a best-effort deployment option, not the primary target — the bare-metal install (docs/INSTALL.md) receives the most testing. Docker support is improving as issues are reported; if you run into problems, please report them in the LVLY_BINKTERMPHP echo area or on GitHub.
- Prerequisites
- Quick Start
- Configuration
- Included Services
- First Run Setup
- Upgrading
- Managing the Application
- Volumes and Data Persistence
- Troubleshooting
- Production Considerations
- Docker Engine 20.10 or newer
- Docker Compose 2.0 or newer
- At least 2GB of available RAM
- 10GB of available disk space
git clone https://github.com/awehttam/binkterm-php.git
cd binkterm-php# Copy the example environment file
cp .env.docker.example .env
# Edit the .env file with your settings
nano .envImportant: Change at least these values:
DB_PASSWORD- Use a strong passwordSITE_URL- Your public URL (e.g., https://bbs.example.com)SITE_NAME- Your BBS nameSYSOP_NAME- Your nameFIDONET_ADDRESS- Your FidoNet address (if applicable)
# Set RUN_SETUP=true for first run only
RUN_SETUP=true docker-compose up -d
# Watch the logs to ensure setup completes
docker-compose logs -f binktermWait for the message "Initialization complete!" in the logs.
Open your browser to http://localhost (or the configured SITE_URL).
The default admin account must be created through the registration page on first use.
Edit the .env file to configure your deployment:
DB_NAME=binkterm # Database name
DB_USER=binkterm # Database username
DB_PASSWORD=changeme # CHANGE THIS!SITE_URL=http://localhost # Public URL of your BBS
SITE_NAME=BinktermPHP BBS # Name displayed on your BBS
SYSOP_NAME=Sysop # Your name/handle
FIDONET_ADDRESS=1:2/3.4 # Your FidoNet addressHTTP_PORT=80 # Web interface (default: 80)
BINKP_PORT=24554 # BinkP server (default: 24554)
DOSDOOR_WS_PORT=24555 # DOS Door WebSocket (default: 24555)
BINKSTREAM_WS_PORT=6010 # Realtime (BinkStream) WebSocket (default: 6010)If you need to use different ports (e.g., 8080 instead of 80):
HTTP_PORT=8080:80 # Map host port 8080 to container port 80DOSDOOR_DEBUG_KEEP_FILES=false # Set to true to keep session files for debuggingAPP_DEBUG=false # Set to true for verbose error messagesdocker/supervisord.conf only starts the basic set of services needed for the core web interface and FTN networking. It is not a complete list of everything BinktermPHP can run — several optional daemons documented elsewhere in the project are left out of the Docker image entirely so the default container stays small and focused.
- apache — the web interface
- admin_daemon — configuration/management daemon (writes
config/*.jsonon behalf of the web process) - realtime_server — BinkStream WebSocket server (live updates in the browser interface)
- binkp_scheduler — schedules periodic BinkP mail polls
- binkp_server — FidoNet mail server (BinkP protocol)
- dosdoor_bridge — DOS door game multiplexing server (Node.js)
- telnet_daemon — Telnet BBS server
- gemini_daemon — Gemini protocol server. Present in
supervisord.confwithautostart=false; enable it by changing that line toautostart=trueand rebuilding, or start it on demand withdocker exec -it binkterm-app supervisorctl start gemini_daemon. Also requires publishingGEMINI_PORTindocker-compose.yml.
These daemons exist in the project but have no supervisord.conf entry or exposed port in the default Docker setup:
- SSH daemon (
ssh/ssh_daemon.php, default port 2022) — shares terminal-side code with the Telnet daemon; seessh/CLAUDE.md - MCP server (
mcp-server/, default port 3740) — seedocs/MCPServer.md - Matterbridge daemon (
scripts/matterbridge_daemon.php) - MRC daemon (
scripts/mrc_daemon.php) - AI bot daemon (
scripts/ai_bot_daemon.php) - FTP daemon (
scripts/ftp_daemon.php)
If you want to run one of these under Docker, add a [program:...] block for it to docker/supervisord.conf (see Adding Services to Supervisor in docker/README.md for the block format), publish any port it needs in docker-compose.yml and EXPOSE it in the Dockerfile, then rebuild. These are ordinary PHP/Node scripts with no Docker-specific requirements, so wiring one in is the same as adding any other supervisor-managed process.
RUN_SETUP=true docker-compose up -d# Start containers
docker-compose up -d
# Run setup manually
docker exec -it binkterm-app php /var/www/html/scripts/setup.phpImportant: Only run setup once. After the initial setup, leave RUN_SETUP=false in your .env file.
docker-compose up -ddocker-compose down# All services
docker-compose logs -f
# Just the BinktermPHP app
docker-compose logs -f binkterm
# Just the database
docker-compose logs -f postgres# Restart everything
docker-compose restart
# Restart just the app
docker-compose restart binktermReview version-specific upgrade notes in docs/index.md before upgrading — individual versions may have specific steps you must take.
# Pull latest code
git pull
# Rebuild the image and recreate the container
docker-compose build
docker-compose up -d
# Run any new database migrations
docker exec -it binkterm-app php /var/www/html/scripts/setup.phpdocker-compose build followed by up -d is enough to pick up code changes — there's no need to docker-compose down first, since up -d recreates any container whose image changed and leaves the rest running. Use docker-compose build --no-cache instead if a change touched system packages or PHP extensions in the Dockerfile and you want a fully clean rebuild.
scripts/setup.php applies any pending database migrations and is safe to run every time you upgrade, even if there's nothing new to apply. Do not set RUN_SETUP=true for this — that variable is only meant for the very first up -d (see First Run Setup); running setup.php directly like this works against the already-running container without needing to touch .env.
docker exec -it binkterm-app bashDocker Compose creates three persistent volumes:
- postgres_data - PostgreSQL database files
- binkterm_data - Application data (logs, packets, uploads, etc.)
- binkterm_config - Configuration files (bbs.json, webdoors.json, etc.)
# Backup database
docker exec binkterm-postgres pg_dump -U binkterm binkterm > backup_$(date +%Y%m%d).sql
# Backup data volume
docker run --rm -v binkterm_data:/data -v $(pwd):/backup alpine tar czf /backup/binkterm_data_$(date +%Y%m%d).tar.gz -C /data .
# Backup config volume
docker run --rm -v binkterm_config:/config -v $(pwd):/backup alpine tar czf /backup/binkterm_config_$(date +%Y%m%d).tar.gz -C /config .# Restore database
cat backup.sql | docker exec -i binkterm-postgres psql -U binkterm binkterm
# Restore data volume
docker run --rm -v binkterm_data:/data -v $(pwd):/backup alpine tar xzf /backup/binkterm_data.tar.gz -C /data
# Restore config volume
docker run --rm -v binkterm_config:/config -v $(pwd):/backup alpine tar xzf /backup/binkterm_config.tar.gz -C /configCheck the logs:
docker-compose logs binktermCommon issues:
- Database not ready: Wait for PostgreSQL health check to pass
- Port already in use: Change
HTTP_PORTin.env - Permission issues: Ensure data directories are writable
Verify database is running:
docker-compose ps postgres
docker-compose logs postgresTest database connection:
docker exec -it binkterm-postgres psql -U binkterm -d binktermCheck DOSBox-X installation:
docker exec -it binkterm-app dosbox-x --versionCheck DOS door bridge logs:
docker exec -it binkterm-app cat /var/www/html/data/logs/dosdoor_bridge.logVerify SDL is configured for headless:
docker exec -it binkterm-app printenv | grep SDL
# Should show: SDL_VIDEODRIVER=dummyWARNING: This deletes all data!
docker-compose down -v
rm -rf data/ config/
docker-compose up -d-
Change Default Passwords: Always use strong passwords in
.env -
Use HTTPS: Put a reverse proxy (nginx, Caddy, Traefik) in front of BinktermPHP:
# Example nginx reverse proxy in docker-compose.yml
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- binkterm-
Firewall: Only expose necessary ports
- 80/443 for web access
- 24554 for BinkP (if accepting FidoNet connections)
-
Regular Updates: Keep Docker images and BinktermPHP up to date
- Resource Limits: Add resource constraints in docker-compose.yml:
binkterm:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 512M- PostgreSQL Tuning: Mount custom PostgreSQL config:
postgres:
volumes:
- ./postgresql.conf:/etc/postgresql/postgresql.conf:ro
command: postgres -c config_file=/etc/postgresql/postgresql.conf-
Health Checks: Already configured in docker-compose.yml
-
Logs: Use log aggregation (e.g., Loki, ELK stack)
-
Metrics: Consider adding Prometheus exporters
For high-traffic deployments:
- Use external PostgreSQL instance (remove postgres service from compose)
- Consider load balancing multiple binkterm containers
- Use shared storage (NFS, S3) for data volumes
- Separate DOS door bridge to dedicated server