TNT/docs/DEPLOYMENT.md
m1ngsama 2402c70d6f feat: add module foundation runtime
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
2026-06-04 22:48:21 +08:00

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

  1. Create user and directory:
sudo useradd -r -s /bin/false tnt
  1. Install service file:
sudo cp tnt.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable tnt
sudo systemctl start tnt
  1. 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
  1. 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 ceiling
  • TNT_MAX_CONN_PER_IP: concurrent sessions allowed from one IP
  • TNT_MAX_CONN_RATE_PER_IP: new connection attempts allowed per IP per 60 seconds
  • TNT_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