#!/bin/bash ############################################################# #### Mattermost Server Install Script #### #### Bare-metal deployment with PostgreSQL and nginx #### #### #### #### Author: Phil Connor #### #### Contact: contact@mylinux.work #### #### License: MIT #### #### Version: 1.0 #### #### #### #### Usage: sudo ./install-mattermost.sh #### #### sudo ./install-mattermost.sh --help #### ############################################################# set -euo pipefail # ============================================================================ # CONFIGURATION (edit these before running) # ============================================================================ MATTERMOST_VERSION="10.6.1" DOMAIN="mattermost.example.com" DB_NAME="mattermost" DB_USER="mmuser" DB_PASS="" MM_USER="mattermost" MM_DIR="/opt/mattermost" DATA_DIR="/opt/mattermost/data" NGINX_CONF=true # ============================================================================ # INTERNAL # ============================================================================ readonly VERSION="1.0" readonly SCRIPT_NAME="${0##*/}" OS_ID="" OS_FAMILY="" PKG_MGR="" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # ============================================================================ # HELPER FUNCTIONS # ============================================================================ log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } log_step() { echo -e "${CYAN}[STEP]${NC} $*"; } show_usage() { cat </dev/null; then PKG_MGR="yum" fi ;; *) log_error "Unsupported OS: $OS_ID" exit 1 ;; esac log_info "Detected OS: $PRETTY_NAME (package manager: $PKG_MGR)" } # ============================================================================ # STEP 1: INSTALL DEPENDENCIES # ============================================================================ install_dependencies() { log_step "Installing dependencies..." case "$OS_FAMILY" in debian) apt-get update -qq apt-get install -y -qq postgresql postgresql-contrib nginx curl jq ;; rhel) $PKG_MGR install -y -q postgresql-server postgresql nginx curl jq # Initialize PostgreSQL if not already done if [[ ! -d /var/lib/pgsql/data ]] || [[ -z "$(ls -A /var/lib/pgsql/data 2>/dev/null)" ]]; then log_info "Initializing PostgreSQL database..." postgresql-setup --initdb fi # Enable and start PostgreSQL systemctl enable postgresql systemctl start postgresql ;; esac # Ensure PostgreSQL is running on Debian-based as well if [[ "$OS_FAMILY" == "debian" ]]; then systemctl enable postgresql systemctl start postgresql fi log_info "Dependencies installed" } # ============================================================================ # STEP 2: CONFIGURE POSTGRESQL # ============================================================================ configure_database() { log_step "Configuring PostgreSQL database..." # Generate random password if not provided if [[ -z "$DB_PASS" ]]; then DB_PASS=$(openssl rand -base64 24 | tr -d '/+=') log_info "Generated random database password" fi # Create user if not exists if sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then log_warn "PostgreSQL user '$DB_USER' already exists — updating password" sudo -u postgres psql -c "ALTER USER $DB_USER WITH PASSWORD '$DB_PASS';" else sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASS';" log_info "Created PostgreSQL user: $DB_USER" fi # Create database if not exists if sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1; then log_warn "Database '$DB_NAME' already exists" else sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" log_info "Created database: $DB_NAME" fi sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;" # Ensure md5/scram-sha-256 auth for local connections on RHEL if [[ "$OS_FAMILY" == "rhel" ]]; then local pg_hba pg_hba=$(sudo -u postgres psql -tAc "SHOW hba_file;") if [[ -f "$pg_hba" ]] && grep -q 'ident' "$pg_hba"; then log_info "Updating pg_hba.conf to allow password authentication..." sed -i 's/^\(local.*all.*all.*\)ident/\1md5/' "$pg_hba" sed -i 's/^\(host.*all.*all.*127\.0\.0\.1\/32.*\)ident/\1md5/' "$pg_hba" sed -i 's/^\(host.*all.*all.*::1\/128.*\)ident/\1md5/' "$pg_hba" systemctl restart postgresql fi fi log_info "PostgreSQL configured" } # ============================================================================ # STEP 3: CREATE SYSTEM USER # ============================================================================ create_system_user() { log_step "Creating system user..." if id "$MM_USER" &>/dev/null; then log_warn "System user '$MM_USER' already exists" else useradd --system --no-create-home --shell /usr/sbin/nologin "$MM_USER" log_info "Created system user: $MM_USER" fi } # ============================================================================ # STEP 4: DOWNLOAD AND EXTRACT MATTERMOST # ============================================================================ download_mattermost() { log_step "Downloading Mattermost v${MATTERMOST_VERSION}..." local download_url="https://releases.mattermost.com/${MATTERMOST_VERSION}/mattermost-${MATTERMOST_VERSION}-linux-amd64.tar.gz" local tmp_file="/tmp/mattermost-${MATTERMOST_VERSION}.tar.gz" if [[ -d "$MM_DIR" ]] && [[ -f "$MM_DIR/bin/mattermost" ]]; then local existing_version existing_version=$("$MM_DIR/bin/mattermost" version 2>/dev/null | grep -oP 'Version:\s*\K[\d.]+' || echo "unknown") log_warn "Mattermost already installed at $MM_DIR (version: $existing_version)" log_warn "Skipping download — remove $MM_DIR to reinstall" return 0 fi curl -fSL -o "$tmp_file" "$download_url" log_info "Downloaded: $download_url" # Extract to /opt (creates /opt/mattermost) tar -xzf "$tmp_file" -C /opt/ rm -f "$tmp_file" # Create data directory mkdir -p "$DATA_DIR" # Set ownership chown -R "$MM_USER:$MM_USER" "$MM_DIR" log_info "Mattermost extracted to $MM_DIR" } # ============================================================================ # STEP 5: CONFIGURE MATTERMOST # ============================================================================ configure_mattermost() { log_step "Configuring Mattermost..." local config_file="$MM_DIR/config/config.json" if [[ ! -f "$config_file" ]]; then log_error "Config file not found: $config_file" exit 1 fi local dsn="postgres://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}?sslmode=disable&connect_timeout=10" # Use jq to update configuration local tmp_config tmp_config=$(mktemp) jq \ --arg dsn "$dsn" \ --arg siteurl "https://${DOMAIN}" \ --arg datadir "$DATA_DIR" \ ' .SqlSettings.DriverName = "postgres" | .SqlSettings.DataSource = $dsn | .ServiceSettings.SiteURL = $siteurl | .ServiceSettings.ListenAddress = ":8065" | .FileSettings.Directory = $datadir ' "$config_file" > "$tmp_config" mv "$tmp_config" "$config_file" chown "$MM_USER:$MM_USER" "$config_file" chmod 600 "$config_file" log_info "Configuration updated: $config_file" } # ============================================================================ # STEP 6: CREATE SYSTEMD SERVICE # ============================================================================ create_service() { log_step "Creating systemd service..." cat > /etc/systemd/system/mattermost.service < "$nginx_config" <<'NGINXEOF' upstream mattermost_backend { server localhost:8065; keepalive 32; } server { listen 80; server_name DOMAIN_PLACEHOLDER; client_max_body_size 100M; location ~ /api/v[0-9]+/(users/)?websocket$ { proxy_pass http://mattermost_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Frame-Options SAMEORIGIN; proxy_buffers 256 16k; proxy_buffer_size 16k; proxy_read_timeout 600s; } location / { proxy_pass http://mattermost_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Frame-Options SAMEORIGIN; proxy_buffers 256 16k; proxy_buffer_size 16k; } } NGINXEOF # Replace domain placeholder sed -i "s/DOMAIN_PLACEHOLDER/$DOMAIN/" "$nginx_config" # Enable site on Debian-based systems if [[ "$OS_FAMILY" == "debian" ]]; then mkdir -p /etc/nginx/sites-enabled ln -sf "$nginx_config" /etc/nginx/sites-enabled/mattermost fi # Test and reload nginx if nginx -t 2>/dev/null; then systemctl enable nginx systemctl reload nginx log_info "Nginx configured and reloaded" else log_error "Nginx configuration test failed" nginx -t exit 1 fi } # ============================================================================ # STEP 8: SUMMARY # ============================================================================ print_summary() { echo "" echo "============================================" echo " Mattermost Installation Complete" echo "============================================" echo "" log_info "Database credentials:" echo " User: $DB_USER" echo " Password: $DB_PASS" echo " Database: $DB_NAME" echo "" log_info "Mattermost:" echo " URL: https://$DOMAIN" echo " Service: mattermost.service" echo " Config: $MM_DIR/config/config.json" echo " Data: $DATA_DIR" echo "" log_info "Next steps:" echo " 1. Set up TLS: sudo certbot --nginx -d $DOMAIN" echo " 2. Visit https://$DOMAIN to create the admin account" echo " 3. View logs: sudo journalctl -u mattermost -f" echo "" } # ============================================================================ # MAIN # ============================================================================ main() { parse_args "$@" echo "" echo "============================================" echo " Mattermost Install Script v${VERSION}" echo " https://mylinux.work" echo "============================================" echo "" check_root detect_os install_dependencies configure_database create_system_user download_mattermost configure_mattermost create_service configure_nginx print_summary } main "$@"