Skip to content

home / selfhost / install / systemd

Installation via Systemd

Install Tux directly on your system without Docker. This guide covers both quick start for development and production deployment with systemd.

Quick Start (Development)

For quick testing or development, you can run Tux directly:

Bash
# Clone repository
git clone https://github.com/allthingslinux/tux.git
cd tux

# Install dependencies
uv sync

# Generate configuration files
uv run config generate

# Copy and edit .env
cp .env.example .env
nano .env

# Run migrations
uv run db push

# Start bot
uv run tux start

For production deployment, continue with the systemd setup below.

Production Deployment with Systemd

Prerequisites

Before deploying with systemd, ensure you have:

  • Linux system with systemd (most modern distributions)
  • Python 3.13+ installed
  • uv package manager installed
  • PostgreSQL 13+ database running
  • Discord bot token from Discord Developer Portal
  • Root or sudo access for systemd service creation

Installation Steps

1. Create System User

Create a dedicated user for running Tux (recommended for security):

Bash
sudo useradd -r tux

2. Clone Repository to /opt/tux

Clone the Tux repository directly to the installation directory:

Bash
# Clone repository as tux user
sudo -u tux git clone https://github.com/allthingslinux/tux.git /opt/tux

# Set ownership (ensure tux user owns everything)
sudo chown -R tux:tux /opt/tux

# Set appropriate permissions
sudo chmod 755 /opt/tux

3. Install Dependencies

Install Tux dependencies using uv:

Bash
# Switch to tux user and install dependencies
sudo -u tux bash -c "cd /opt/tux && uv sync"

# Generate configuration files
sudo -u tux bash -c "cd /opt/tux && uv run config generate"

# Create and protect .env file
sudo -u tux cp /opt/tux/.env.example /opt/tux/.env
sudo chmod 600 /opt/tux/.env
sudo chown tux:tux /opt/tux/.env

4. Configure Environment

Edit the .env file and setup necessary environment variables:

Bash
# Create or edit .env file
sudo -u tux nano /opt/tux/.env

Alternative: Systemd Environment File

You can also use a separate systemd environment file at /etc/tux/environment if you prefer to separate system-level configuration from application configuration. If using this approach, add EnvironmentFile=/etc/tux/environment to the systemd service file.

5. Configure Database

Ensure PostgreSQL is configured and accessible:

Bash
# Create database user (if not exists)
sudo -u postgres createuser -P tux_user

# Create database
sudo -u postgres createdb -O tux_user tux

# Run migrations
cd /opt/tux
sudo -u tux uv run db push

6. Find uv Installation Path

Before creating the service file, find where uv is installed:

Bash
# Find uv executable
which uv

# Common locations:
# - /usr/local/bin/uv (standalone installer)
# - /usr/bin/uv (package manager)
# - ~/.cargo/bin/uv (cargo installation)
# - ~/.local/bin/uv (pip --user)

If uv is not in a system path, you can either:

  1. Create a symlink (recommended):
Bash
sudo ln -s $(which uv) /usr/local/bin/uv
  1. Use full path in the service file (replace /usr/local/bin/uv with your path)

7. Create Systemd Service File

Create the systemd service unit:

Bash
sudo nano /etc/systemd/system/tux.service

Use this configuration (adjust the uv path if needed):

INI
[Unit]
Description=Tux Discord Bot
Documentation=https://tux.atl.dev
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=tux
Group=tux
WorkingDirectory=/opt/tux
ExecStart=/usr/local/bin/uv run tux start
Restart=always
RestartSec=10

# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=tux

[Install]
WantedBy=multi-user.target

8. Enable and Start Service

Bash
# Reload systemd to recognize new service
sudo systemctl daemon-reload

# Enable service to start on boot
sudo systemctl enable tux

# Start the service
sudo systemctl start tux

# Check status
sudo systemctl status tux

Configuration Updates

Updating Environment Variables

Bash
# Edit .env file
sudo -u tux nano /opt/tux/.env

# Reload service to apply changes
sudo systemctl daemon-reload
sudo systemctl restart tux

Updating Tux Code

Bash
# Stop service
sudo systemctl stop tux

# Backup current installation
sudo cp -r /opt/tux /opt/tux.backup.$(date +%Y%m%d)

# Update code
cd /opt/tux
sudo -u tux git pull origin main

# Update dependencies
sudo -u tux uv sync

# Run database migrations
sudo -u tux uv run db push

# Start service
sudo systemctl start tux

# Verify status
sudo systemctl status tux

Troubleshooting

Service Won't Start

Check service status:

Bash
sudo systemctl status tux

Common issues:

  1. Permission errors:
Bash
# Check file ownership
ls -la /opt/tux
sudo chown -R tux:tux /opt/tux
  1. Missing dependencies:
Bash
# Verify uv is installed
which uv

# Check Python version
python3 --version
  1. Database connection issues:
Bash
# Test database connection
sudo -u tux uv run db health

# Check PostgreSQL is running
sudo systemctl status postgresql
  1. Invalid bot token:
Bash
# Check .env file
sudo cat /opt/tux/.env | grep BOT_TOKEN

Service Crashes Repeatedly

Check logs for errors:

Bash
sudo journalctl -u tux -n 100 --no-pager

Common causes:

  • Invalid configuration
  • Database connection failures
  • Missing environment variables
  • Permission issues
  • Resource exhaustion

Check restart count:

Bash
systemctl show tux | grep NRestarts

Logs Not Appearing

Verify logging configuration:

Bash
# Check journald is working
sudo journalctl -u tux -n 10

# Check service output
sudo systemctl status tux

# Verify log directory permissions
ls -la /var/log/tux

Permission Denied Errors

Fix ownership:

Bash
sudo chown -R tux:tux /opt/tux
sudo chown tux:tux /var/log/tux

Check service user:

Bash
# Verify service runs as correct user
systemctl show tux | grep User

Database Connection Issues

Test connection manually:

Bash
# As tux user
sudo -u tux bash -c "cd /opt/tux && uv run db health"

# Check PostgreSQL is accessible
sudo -u postgres psql -c "SELECT version();"

Verify environment:

Bash
# Check DATABASE_URL or POSTGRES_* variables are set
sudo cat /opt/tux/.env | grep -E "DATABASE_URL|POSTGRES_"

Security Best Practices

File Permissions

Bash
# Protect .env file
sudo chmod 600 /opt/tux/.env
sudo chown tux:tux /opt/tux/.env

# Protect configuration files
sudo chmod 600 /opt/tux/config/config.toml
sudo chown tux:tux /opt/tux/config/config.toml

Network Security

Bash
# If using firewall, allow Discord connections
# Discord uses ports 443 (HTTPS) and 80 (HTTP)
# No special firewall rules needed for outbound connections

Advanced Configuration

Custom Working Directory

If installing to a different location:

INI
[Service]
WorkingDirectory=/home/tux/tux
ExecStart=/usr/local/bin/uv run tux start

Finding uv Path

Use which uv to find the correct path to the uv executable on your system.

Debug Mode

Enable debug logging:

Bash
# Edit .env file
sudo -u tux nano /opt/tux/.env

# Add or modify:
DEBUG=true
LOG_LEVEL=DEBUG

# Restart service
sudo systemctl restart tux

Resource Limits

Adjust resource limits in service file:

INI
[Service]
# Memory limit (512MB)
MemoryMax=512M

# CPU limit (50% of one core)
CPUQuota=50%

# I/O limits
IOWeight=100

Maintenance

Regular Updates

Create update script (/usr/local/bin/update-tux.sh):

Bash
#!/bin/bash
set -e

echo "Stopping Tux..."
sudo systemctl stop tux

echo "Backing up installation..."
sudo cp -r /opt/tux /opt/tux.backup.$(date +%Y%m%d)

echo "Updating Tux..."
cd /opt/tux
sudo -u tux git pull origin main

echo "Updating dependencies..."
sudo -u tux uv sync

echo "Running migrations..."
sudo -u tux uv run db push

echo "Starting Tux..."
sudo systemctl start tux

echo "Update complete!"

Make executable:

Bash
sudo chmod +x /usr/local/bin/update-tux.sh

Backup Strategy

Bash
# Backup script
#!/bin/bash
BACKUP_DIR=/backup/tux
DATE=$(date +%Y%m%d_%H%M%S)

# Stop service
sudo systemctl stop tux

# Backup database
sudo -u postgres pg_dump tux > $BACKUP_DIR/db_$DATE.sql

# Backup configuration
sudo tar -czf $BACKUP_DIR/config_$DATE.tar.gz /etc/tux /opt/tux/.env /opt/tux/config

# Start service
sudo systemctl start tux

echo "Backup complete: $BACKUP_DIR"

Next Steps: After deploying with systemd, verify your installation with the First Run Guide.