Pinned release install:
curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/v1.2.0/install.sh | VERSION=v1.2.0 shMoving latest-release installer, convenient for test deployments:
curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/main/install.sh | shDownload 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- 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 -fEnvironment variables:
# Change port
sudo systemctl edit tnt
# Add:
[Service]
Environment="PORT=3333"
sudo systemctl restart tntThe 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.
To generate a reviewable environment file with an interactive terminal setup wizard:
scripts/install_wizard.sh --output tnt.env
sudo install -m 600 tnt.env /etc/default/tnt
sudo systemctl restart tntThe wizard can choose a core-only deployment, scan a module root, select
individual modules, or validate a manually entered module path list. It never
downloads modules, edits systemd units, or restarts TNT by itself. See
docs/INSTALL_LIFECYCLE.md for the full operator lifecycle.
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
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.mdwithscripts/module_check.sh. - Develop and publish community modules in the public companion repository:
https://github.com/m1ngsama/tnt-modules.
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-moduleUnset TNT_MODULE_PATHS and restart TNT to return to the plain core server.
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.txtNo restart required — TNT reads the file on each new connection.
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 tntThe 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.
# Ubuntu/Debian
sudo ufw allow 2222/tcp
# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload# Stop service
sudo systemctl stop tnt
# Re-run the pinned installer for the version you want
curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/v1.2.0/install.sh | VERSION=v1.2.0 sh
# Start service
sudo systemctl start tntsudo 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/tntFROM 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