#!/usr/bin/env bash # ============================================================================ # OpenClaw Mattermost Installer # Deploys Mattermost (Team Edition) via Docker with Nginx + Let's Encrypt SSL # Compatible with OpenClaw gateway via localhost # # Usage: sudo bash install.sh # GitHub: https://github.com/openclaw/mattermost-installer # ============================================================================ set -euo pipefail # ── Colors ─────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # ── Helpers ────────────────────────────────────────────────────────────────── info() { echo -e "${CYAN}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[ OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } banner() { echo "" echo -e "${BOLD}${CYAN}" echo " ┌──────────────────────────────────────────────┐" echo " │ 🦞 OpenClaw Mattermost Installer 🦞 │" echo " │ Docker + Nginx + Let's Encrypt │" echo " └──────────────────────────────────────────────┘" echo -e "${NC}" echo "" } # ── Pre-flight checks ─────────────────────────────────────────────────────── preflight() { if [[ $EUID -ne 0 ]]; then fail "This script must be run as root (sudo bash install.sh)" fi if ! grep -qiE 'ubuntu|debian' /etc/os-release 2>/dev/null; then fail "This installer supports Ubuntu/Debian only." fi if ss -tlnp | grep -qE ':80\b' 2>/dev/null; then warn "Port 80 is already in use. Nginx/Certbot may conflict." read -rp "Continue anyway? (y/N): " cont [[ "$cont" =~ ^[Yy]$ ]] || exit 1 fi if ss -tlnp | grep -qE ':443\b' 2>/dev/null; then warn "Port 443 is already in use. Nginx/Certbot may conflict." read -rp "Continue anyway? (y/N): " cont [[ "$cont" =~ ^[Yy]$ ]] || exit 1 fi success "Pre-flight checks passed." } # ── Interactive prompts ────────────────────────────────────────────────────── gather_input() { echo -e "${BOLD}Step 1: Configuration${NC}" echo "" # Domain while true; do read -rp " Enter your Mattermost domain (e.g. chat.example.com): " MM_DOMAIN if [[ -z "$MM_DOMAIN" ]]; then warn "Domain cannot be empty." elif [[ "$MM_DOMAIN" == *" "* ]]; then warn "Domain cannot contain spaces." else break fi done # Email for SSL while true; do read -rp " Enter your email (for Let's Encrypt SSL certificate): " MM_EMAIL if [[ -z "$MM_EMAIL" ]]; then warn "Email cannot be empty." elif [[ "$MM_EMAIL" != *"@"* ]]; then warn "Please enter a valid email address." else break fi done # Internal port read -rp " Internal proxy port [8000]: " MM_PORT MM_PORT=${MM_PORT:-8000} # Install directory read -rp " Installation directory [~/mattermost-docker]: " INSTALL_DIR INSTALL_DIR=${INSTALL_DIR:-"$HOME/mattermost-docker"} # Expand tilde INSTALL_DIR="${INSTALL_DIR/#\~/$HOME}" echo "" echo -e "${BOLD} Summary:${NC}" echo " Domain: https://${MM_DOMAIN}" echo " Email: ${MM_EMAIL}" echo " Port: 127.0.0.1:${MM_PORT} → :8065" echo " Directory: ${INSTALL_DIR}" echo "" read -rp " Proceed? (Y/n): " confirm [[ "$confirm" =~ ^[Nn]$ ]] && { info "Aborted."; exit 0; } } # ── Install dependencies ──────────────────────────────────────────────────── install_deps() { echo "" echo -e "${BOLD}Step 2: Installing dependencies${NC}" echo "" info "Updating package index..." apt-get update -qq # Docker if command -v docker &>/dev/null; then success "Docker already installed: $(docker --version)" else info "Installing Docker..." apt-get install -y -qq ca-certificates curl gnupg lsb-release install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null || true chmod a+r /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update -qq apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin success "Docker installed." fi # Docker Compose (detect v2 plugin vs v1 standalone) if docker compose version &>/dev/null; then COMPOSE_CMD="docker compose" success "Docker Compose (v2 plugin) available." elif command -v docker-compose &>/dev/null; then COMPOSE_CMD="docker-compose" success "Docker Compose (v1 standalone) available." else info "Installing Docker Compose plugin..." apt-get install -y -qq docker-compose-plugin COMPOSE_CMD="docker compose" success "Docker Compose installed." fi # Nginx if command -v nginx &>/dev/null; then success "Nginx already installed." else info "Installing Nginx..." apt-get install -y -qq nginx systemctl enable nginx systemctl start nginx success "Nginx installed and started." fi # Certbot if command -v certbot &>/dev/null; then success "Certbot already installed." else info "Installing Certbot..." apt-get install -y -qq certbot python3-certbot-nginx success "Certbot installed." fi # UFW (optional — configure if present) if command -v ufw &>/dev/null; then info "Configuring firewall (UFW)..." ufw allow 'Nginx Full' >/dev/null 2>&1 || true ufw allow OpenSSH >/dev/null 2>&1 || true success "Firewall rules updated." fi success "All dependencies ready." } # ── Generate secure password ──────────────────────────────────────────────── generate_password() { openssl rand -base64 24 | tr -d '/+=' | head -c 32 } # ── Create Docker stack ────────────────────────────────────────────────────── create_docker_stack() { echo "" echo -e "${BOLD}Step 3: Creating Docker stack${NC}" echo "" DB_PASS=$(generate_password) mkdir -p "${INSTALL_DIR}" cat > "${INSTALL_DIR}/docker-compose.yml" < "${INSTALL_DIR}/.env" < "${NGINX_CONF}" </dev/null || true nginx -t || fail "Nginx configuration test failed!" systemctl reload nginx success "Nginx proxy configured for ${MM_DOMAIN}" } # ── Obtain SSL certificate ─────────────────────────────────────────────────── obtain_ssl() { echo "" echo -e "${BOLD}Step 5: Obtaining SSL certificate${NC}" echo "" info "Requesting Let's Encrypt certificate for ${MM_DOMAIN}..." info "Make sure your DNS A record points to this server's IP!" echo "" certbot --nginx \ -d "${MM_DOMAIN}" \ --non-interactive \ --agree-tos \ --email "${MM_EMAIL}" \ --redirect \ || { warn "Certbot failed. This usually means:" warn " 1. DNS is not yet pointing to this server" warn " 2. Ports 80/443 are blocked by a firewall" warn "" warn "You can retry later with:" warn " sudo certbot --nginx -d ${MM_DOMAIN}" warn "" warn "Continuing without SSL..." } success "SSL certificate obtained (or skipped)." } # ── Start the stack ────────────────────────────────────────────────────────── start_stack() { echo "" echo -e "${BOLD}Step 6: Starting Mattermost${NC}" echo "" info "Pulling Docker images (this may take a few minutes)..." cd "${INSTALL_DIR}" $COMPOSE_CMD pull info "Starting containers..." $COMPOSE_CMD up -d # Wait for Mattermost to boot info "Waiting for Mattermost to start (up to 60s)..." for i in $(seq 1 12); do if curl -sI "http://127.0.0.1:${MM_PORT}" >/dev/null 2>&1; then success "Mattermost is responding on port ${MM_PORT}!" break fi sleep 5 done # Show container status echo "" $COMPOSE_CMD ps echo "" } # ── Print summary ─────────────────────────────────────────────────────────── print_summary() { echo "" echo -e "${BOLD}${GREEN}" echo " ┌──────────────────────────────────────────────┐" echo " │ ✅ Installation Complete! ✅ │" echo " └──────────────────────────────────────────────┘" echo -e "${NC}" echo "" echo -e "${BOLD} Access your Mattermost:${NC}" echo " 🌐 https://${MM_DOMAIN}" echo "" echo -e "${BOLD} Internal (localhost) access:${NC}" echo " 📡 http://127.0.0.1:${MM_PORT}" echo "" echo -e "${BOLD} Credentials:${NC}" echo " 📄 ${INSTALL_DIR}/.env" echo "" echo -e "${BOLD} Management commands:${NC}" echo " Start: cd ${INSTALL_DIR} && ${COMPOSE_CMD} up -d" echo " Stop: cd ${INSTALL_DIR} && ${COMPOSE_CMD} down" echo " Logs: cd ${INSTALL_DIR} && ${COMPOSE_CMD} logs -f" echo " Status: cd ${INSTALL_DIR} && ${COMPOSE_CMD} ps" echo "" echo -e "${BOLD}${CYAN} ── OpenClaw Integration ──${NC}" echo "" echo " 1. Create a Bot Account in Mattermost:" echo " System Console → Integrations → Bot Accounts → Add Bot" echo " (Enable bot creation first, grant 'post:all')" echo "" echo " 2. Configure OpenClaw to connect:" echo -e " ${YELLOW}openclaw config set channels.mattermost.accounts.default.baseUrl \"https://${MM_DOMAIN}\"${NC}" echo -e " ${YELLOW}openclaw config set channels.mattermost.accounts.default.botToken \"\"${NC}" echo "" echo " OpenClaw will connect to Mattermost internally via localhost:${MM_PORT}" echo " for maximum speed and security. 🦞" echo "" } # ── Main ───────────────────────────────────────────────────────────────────── main() { banner preflight gather_input install_deps create_docker_stack configure_nginx obtain_ssl start_stack print_summary } main "$@"