Add validated input buffering, shared JSON helpers, the tnt.module.v1 protocol helpers, and an opt-in external-process module runtime behind TNT_MODULE_PATHS. Closes #52
5.6 KiB
DEPLOYMENT
Quick Install
One-line install (latest release):
curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/main/install.sh | sh
Specific version:
VERSION=vX.Y.Z curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/main/install.sh | sh
Manual Install
Download binary for your platform from releases:
# Linux AMD64
curl -LO https://github.com/m1ngsama/TNT/releases/latest/download/tnt-linux-amd64
chmod +x tnt-linux-amd64
sudo mv tnt-linux-amd64 /usr/local/bin/tnt
# macOS ARM64 (Apple Silicon)
curl -LO https://github.com/m1ngsama/TNT/releases/latest/download/tnt-darwin-arm64
chmod +x tnt-darwin-arm64
sudo mv tnt-darwin-arm64 /usr/local/bin/tnt
systemd Service
- Create user and directory:
sudo useradd -r -s /bin/false tnt
- Install service file:
sudo cp tnt.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable tnt
sudo systemctl start tnt
- Optional runtime overrides:
sudo tee /etc/default/tnt >/dev/null <<'EOF'
PORT=2222
TNT_BIND_ADDR=0.0.0.0
TNT_STATE_DIR=/var/lib/tnt
TNT_MAX_CONNECTIONS=200
TNT_MAX_CONN_PER_IP=30
TNT_MAX_CONN_RATE_PER_IP=60
TNT_RATE_LIMIT=1
TNT_SSH_LOG_LEVEL=0
TNT_PUBLIC_HOST=chat.example.com
EOF
sudo systemctl restart tnt
- Check status:
sudo systemctl status tnt
sudo journalctl -u tnt -f
Configuration
Environment variables:
# Change port
sudo systemctl edit tnt
# Add:
[Service]
Environment="PORT=3333"
sudo systemctl restart tnt
The service uses StateDirectory=tnt, so systemd creates /var/lib/tnt automatically.
Use TNT_STATE_DIR or tnt -d DIR when running outside systemd to avoid depending on the current working directory.
Recommended interpretation:
TNT_MAX_CONNECTIONS: global connection ceilingTNT_MAX_CONN_PER_IP: concurrent sessions allowed from one IPTNT_MAX_CONN_RATE_PER_IP: new connection attempts allowed per IP per 60 secondsTNT_RATE_LIMIT=0: disables rate-based blocking and auth-failure IP blocking, but not the explicit capacity limits
Edge Module Production Profile
Some deployments intentionally track the newest TNT builds and newest module integrations to exercise the full product surface. Treat these as edge production environments: user-facing, but optimized for fast integration and fast rollback.
For that profile:
- Deploy TNT and modules as separate artifacts so a module can be disabled without replacing the core server.
- Keep module permissions explicit and minimal. Do not grant private-message access unless the module exists for that purpose.
- Keep a known-good TNT binary and module manifest set on disk for immediate rollback.
- Log module startup failures, invalid JSONL, protocol errors, and timeouts separately from chat history.
- Prefer plain-text fallbacks for every module-created message, even when the module also targets richer terminal renderers.
- Before promoting a module, test its manifest and JSONL handshake against the
protocol in
docs/MODULE_PROTOCOL.md.
Enable modules explicitly with TNT_MODULE_PATHS, using a colon-separated
list of module directories:
TNT_MODULE_PATHS=/opt/tnt-modules/echo-module:/opt/tnt-modules/other-module
Unset TNT_MODULE_PATHS and restart TNT to return to the plain core server.
MOTD (Message of the Day)
Place a motd.txt file in the state directory. TNT displays it to each user on connect; they press any key to enter the chat.
# Systemd deployment (state dir is /var/lib/tnt)
sudo tee /var/lib/tnt/motd.txt <<'EOF'
Welcome! Be respectful. No spam.
Type :help for a concise manual, or ? for the full key reference.
EOF
sudo chown tnt:tnt /var/lib/tnt/motd.txt
# Remove to disable
sudo rm /var/lib/tnt/motd.txt
No restart required — TNT reads the file on each new connection.
Manual Log Maintenance
TNT stores public chat history in messages.log under the state directory.
Use the maintenance script from a source checkout when the service is stopped
or during a quiet maintenance window:
sudo systemctl stop tnt
sudo scripts/logrotate.sh /var/lib/tnt/messages.log 100 10000
sudo systemctl start tnt
The arguments are LOG_FILE MAX_SIZE_MB KEEP_LINES. The script archives the
full log, compacts the active log to the last KEEP_LINES records, compresses
the archive when gzip is available, and keeps the newest five archives by
default. Use --dry-run to preview actions, or --keep-archives N to change
archive retention.
Before replacing a suspicious log, inspect and recover it offline:
tnt --log-check /var/lib/tnt/messages.log
tnt --log-recover /var/lib/tnt/messages.log > /var/lib/tnt/messages.recovered.log
--log-recover writes valid records to stdout and reports skipped records to
stderr. Review the recovered file before replacing the active log.
Firewall
# Ubuntu/Debian
sudo ufw allow 2222/tcp
# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
Update
# Stop service
sudo systemctl stop tnt
# Re-run install script
curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/main/install.sh | sh
# Start service
sudo systemctl start tnt
Uninstall
sudo systemctl stop tnt
sudo systemctl disable tnt
sudo rm /etc/systemd/system/tnt.service
sudo systemctl daemon-reload
sudo rm /usr/local/bin/tnt
sudo userdel tnt
sudo rm -rf /var/lib/tnt
Docker (Alternative)
FROM alpine:latest
RUN apk add --no-cache libssh
COPY tnt /usr/local/bin/tnt
EXPOSE 2222
CMD ["/usr/local/bin/tnt"]
Build and run:
docker build -t tnt .
docker run -d -p 2222:2222 --name tnt tnt