Files
homelab-optimized/scripts/setup-stoatchat.sh
Gitea Mirror Bot d6893f4a93
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m3s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-04 11:24:58 UTC
2026-04-04 11:24:58 +00:00

480 lines
12 KiB
Bash
Executable File

#!/bin/bash
# Stoatchat Setup Script
# Automated deployment of Revolt chat backend for st.vish.gg
set -euo pipefail
# Configuration
STOATCHAT_DIR="/opt/stoatchat"
DOMAIN="st.vish.gg"
REPO_URL="https://github.com/stoatchat/stoatchat.git"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if running as root
check_root() {
if [[ $EUID -eq 0 ]]; then
log_error "This script should not be run as root"
exit 1
fi
}
# Check system requirements
check_requirements() {
log_info "Checking system requirements..."
# Check OS
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot determine OS version"
exit 1
fi
source /etc/os-release
if [[ "$ID" != "ubuntu" && "$ID" != "debian" ]]; then
log_warning "This script is designed for Ubuntu/Debian. Proceeding anyway..."
fi
# Check available memory
local mem_gb=$(free -g | awk '/^Mem:/{print $2}')
if [[ $mem_gb -lt 4 ]]; then
log_warning "Less than 4GB RAM detected. Stoatchat may not perform well."
fi
# Check available disk space
local disk_gb=$(df -BG / | awk 'NR==2{print $4}' | sed 's/G//')
if [[ $disk_gb -lt 20 ]]; then
log_error "Less than 20GB free disk space. Cannot proceed."
exit 1
fi
log_success "System requirements check passed"
}
# Install system dependencies
install_dependencies() {
log_info "Installing system dependencies..."
sudo apt update
sudo apt install -y \
curl \
wget \
git \
build-essential \
pkg-config \
libssl-dev \
ca-certificates \
gnupg \
lsb-release \
jq
# Install Docker if not present
if ! command -v docker &> /dev/null; then
log_info "Installing Docker..."
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
rm get-docker.sh
log_success "Docker installed"
else
log_info "Docker already installed"
fi
# Install Docker Compose if not present
if ! command -v docker-compose &> /dev/null; then
log_info "Installing Docker Compose..."
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
log_success "Docker Compose installed"
else
log_info "Docker Compose already installed"
fi
# Install mise (Rust toolchain manager)
if ! command -v mise &> /dev/null; then
log_info "Installing mise..."
curl https://mise.run | sh
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
log_success "mise installed"
else
log_info "mise already installed"
fi
log_success "Dependencies installed"
}
# Clone and setup stoatchat
setup_stoatchat() {
log_info "Setting up Stoatchat..."
# Create directory
sudo mkdir -p $STOATCHAT_DIR
sudo chown $USER:$USER $STOATCHAT_DIR
# Clone repository
if [[ ! -d "$STOATCHAT_DIR/.git" ]]; then
log_info "Cloning Stoatchat repository..."
git clone $REPO_URL $STOATCHAT_DIR
else
log_info "Updating Stoatchat repository..."
cd $STOATCHAT_DIR
git pull origin main
fi
cd $STOATCHAT_DIR
# Setup LiveKit configuration
if [[ ! -f "livekit.yml" ]]; then
log_info "Creating LiveKit configuration..."
cp livekit.example.yml livekit.yml
# Update LiveKit config with domain
sed -i "s/localhost:7880/voice.$DOMAIN/g" livekit.yml
sed -i "s/redis_host: localhost/redis_host: localhost/g" livekit.yml
sed -i "s/redis_port: 6379/redis_port: 6380/g" livekit.yml
fi
# Create production configuration
log_info "Creating production configuration..."
cat > Revolt.overrides.toml << EOF
[api]
url = "https://api.$DOMAIN"
[events]
url = "wss://events.$DOMAIN"
[autumn]
url = "https://files.$DOMAIN"
[january]
url = "https://proxy.$DOMAIN"
[livekit]
url = "wss://voice.$DOMAIN"
[database]
mongodb = "mongodb://localhost:27017/revolt"
[redis]
url = "redis://localhost:6380"
[s3]
endpoint = "http://localhost:14009"
access_key_id = "minioadmin"
secret_access_key = "minioadmin"
bucket = "revolt-files"
region = "us-east-1"
[rabbitmq]
url = "amqp://guest:guest@localhost:5672"
[email]
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "your-email@example.com"
smtp_password = "REDACTED_PASSWORD"
from_address = "your-email@example.com"
smtp_tls = true
[features]
registration = true
email_verification = false
invite_only = false
EOF
log_success "Stoatchat setup completed"
}
# Start supporting services
start_infrastructure() {
log_info "Starting supporting services..."
cd $STOATCHAT_DIR
# Start Docker services
docker-compose up -d
# Wait for services to be ready
log_info "Waiting for services to be ready..."
sleep 30
# Check service health
local services=("database" "redis" "minio" "rabbitmq")
for service in "${services[@]}"; do
if docker-compose ps | grep -q "stoatchat-$service.*Up"; then
log_success "$service is running"
else
log_error "$service failed to start"
docker-compose logs stoatchat-$service
exit 1
fi
done
log_success "Infrastructure services started"
}
# Build stoatchat
build_stoatchat() {
log_info "Building Stoatchat..."
cd $STOATCHAT_DIR
# Activate mise environment
export PATH="$HOME/.local/bin:$PATH"
eval "$(mise activate bash)"
# Build the project
if mise run build; then
log_success "Stoatchat built successfully"
else
log_error "Failed to build Stoatchat"
exit 1
fi
}
# Start stoatchat services
start_stoatchat_services() {
log_info "Starting Stoatchat services..."
cd $STOATCHAT_DIR
# Create logs directory
mkdir -p logs
# Start services in background
export PATH="$HOME/.local/bin:$PATH"
eval "$(mise activate bash)"
mise service:api > logs/api.log 2>&1 &
echo $! > logs/api.pid
mise service:events > logs/events.log 2>&1 &
echo $! > logs/events.pid
mise service:files > logs/files.log 2>&1 &
echo $! > logs/files.pid
mise service:proxy > logs/proxy.log 2>&1 &
echo $! > logs/proxy.pid
mise service:gifbox > logs/gifbox.log 2>&1 &
echo $! > logs/gifbox.pid
mise service:pushd > logs/pushd.log 2>&1 &
echo $! > logs/pushd.pid
mise service:crond > logs/crond.log 2>&1 &
echo $! > logs/crond.pid
# Wait for services to start
sleep 10
# Check if services are running
local ports=(14702 14703 14704 14705 14706)
for port in "${ports[@]}"; do
if ss -tlnp | grep -q ":$port "; then
log_success "Service on port $port is running"
else
log_warning "Service on port $port may not be ready yet"
fi
done
log_success "Stoatchat services started"
}
# Test the installation
test_installation() {
log_info "Testing installation..."
# Test API endpoint
if curl -s http://localhost:14702/0.8/ | jq -e '.revolt' > /dev/null; then
log_success "API is responding correctly"
else
log_error "API is not responding"
return 1
fi
# Test file service
if curl -s http://localhost:14704/ | jq -e '.autumn' > /dev/null; then
log_success "File service is responding correctly"
else
log_error "File service is not responding"
return 1
fi
log_success "Installation test passed"
}
# Create systemd services
create_systemd_services() {
log_info "Creating systemd services..."
# Create stoatchat user service
sudo tee /etc/systemd/system/stoatchat.service > /dev/null << EOF
[Unit]
Description=Stoatchat (Revolt Chat Backend)
After=network.target docker.service
Requires=docker.service
[Service]
Type=forking
User=$USER
WorkingDirectory=$STOATCHAT_DIR
Environment=PATH=$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=$STOATCHAT_DIR/scripts/start-services.sh
ExecStop=$STOATCHAT_DIR/scripts/stop-services.sh
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Create start script
cat > $STOATCHAT_DIR/scripts/start-services.sh << 'EOF'
#!/bin/bash
cd /opt/stoatchat
export PATH="$HOME/.local/bin:$PATH"
eval "$(mise activate bash)"
# Start infrastructure
docker-compose up -d
# Wait for infrastructure
sleep 30
# Start stoatchat services
mkdir -p logs
mise service:api > logs/api.log 2>&1 &
echo $! > logs/api.pid
mise service:events > logs/events.log 2>&1 &
echo $! > logs/events.pid
mise service:files > logs/files.log 2>&1 &
echo $! > logs/files.pid
mise service:proxy > logs/proxy.log 2>&1 &
echo $! > logs/proxy.pid
mise service:gifbox > logs/gifbox.log 2>&1 &
echo $! > logs/gifbox.pid
mise service:pushd > logs/pushd.log 2>&1 &
echo $! > logs/pushd.pid
mise service:crond > logs/crond.log 2>&1 &
echo $! > logs/crond.pid
EOF
# Create stop script
cat > $STOATCHAT_DIR/scripts/stop-services.sh << 'EOF'
#!/bin/bash
cd /opt/stoatchat
# Stop stoatchat services
if [[ -f logs/api.pid ]]; then kill $(cat logs/api.pid) 2>/dev/null || true; fi
if [[ -f logs/events.pid ]]; then kill $(cat logs/events.pid) 2>/dev/null || true; fi
if [[ -f logs/files.pid ]]; then kill $(cat logs/files.pid) 2>/dev/null || true; fi
if [[ -f logs/proxy.pid ]]; then kill $(cat logs/proxy.pid) 2>/dev/null || true; fi
if [[ -f logs/gifbox.pid ]]; then kill $(cat logs/gifbox.pid) 2>/dev/null || true; fi
if [[ -f logs/pushd.pid ]]; then kill $(cat logs/pushd.pid) 2>/dev/null || true; fi
if [[ -f logs/crond.pid ]]; then kill $(cat logs/crond.pid) 2>/dev/null || true; fi
# Stop infrastructure
docker-compose down
EOF
# Make scripts executable
chmod +x $STOATCHAT_DIR/scripts/*.sh
# Enable service
sudo systemctl daemon-reload
sudo systemctl enable stoatchat.service
log_success "Systemd services created"
}
# Print final instructions
print_final_instructions() {
log_success "Stoatchat installation completed!"
echo ""
echo "🎉 Installation Summary:"
echo " • Stoatchat installed in: $STOATCHAT_DIR"
echo " • Domain configured for: $DOMAIN"
echo " • Services running on ports: 14702-14706"
echo ""
echo "🔧 Next Steps:"
echo " 1. Set up Gmail App Password:"
echo " - Go to Google Account settings"
echo " - Enable 2-Factor Authentication"
echo " - Generate App Password for 'Mail'"
echo " - Update GMAIL_APP_PASSWORD_REQUIRED in Revolt.overrides.toml"
echo ""
echo " 2. Configure Cloudflare Tunnel for external access:"
echo " - api.$DOMAIN → localhost:14702"
echo " - events.$DOMAIN → localhost:14703"
echo " - files.$DOMAIN → localhost:14704"
echo " - proxy.$DOMAIN → localhost:14705"
echo ""
echo " 3. Set up the web client at $DOMAIN"
echo ""
echo " 4. Configure LiveKit for voice chat (optional)"
echo ""
echo "📊 Service Management:"
echo " • Start: sudo systemctl start stoatchat"
echo " • Stop: sudo systemctl stop stoatchat"
echo " • Status: sudo systemctl status stoatchat"
echo " • Logs: journalctl -u stoatchat -f"
echo ""
echo "🔍 Manual Service Management:"
echo " • View logs: tail -f $STOATCHAT_DIR/logs/*.log"
echo " • Test API: curl http://localhost:14702/0.8/"
echo " • Check ports: ss -tlnp | grep revolt"
echo ""
echo "📚 Documentation: $STOATCHAT_DIR/README.md"
echo ""
}
# Main execution
main() {
log_info "Starting Stoatchat installation for $DOMAIN"
check_root
check_requirements
install_dependencies
setup_stoatchat
start_infrastructure
build_stoatchat
start_stoatchat_services
if test_installation; then
create_systemd_services
print_final_instructions
else
log_error "Installation test failed. Please check the logs."
exit 1
fi
}
# Run main function
main "$@"