Last active
October 22, 2025 10:10
-
-
Save ElliotGluck/89d8d4416f165974e185430ad0f3a116 to your computer and use it in GitHub Desktop.
Installs n8n+ollama on Linode stackscript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # <UDF name="domain_name" label="Domain Name" example="example.com" /> | |
| # <UDF name="subdomain" label="Subdomain" default="n8n" example="n8n" /> | |
| # <UDF name="ssl_email" label="Email for SSL Certificate" example="[email protected]" /> | |
| ########################################### | |
| # n8n + Ollama GPU Stack (SSL Required) | |
| # Ubuntu 22.04/24.04 LTS - NVIDIA GPU Required | |
| ########################################### | |
| set -euo pipefail | |
| exec 1> >(tee -a /var/log/stackscript.log) | |
| exec 2>&1 | |
| # Configuration | |
| readonly REPO_URL="https://github.com/ElliotGluck/n8n-gpu-swarm.git" | |
| readonly REPO_DIR="/opt/n8n-gpu-swarm" | |
| readonly LOG_FILE="/var/log/stackscript.log" | |
| readonly STAGE_FILE="/root/.stackscript_stage_complete" | |
| log() { | |
| echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | |
| } | |
| error() { | |
| echo "[ERROR] $*" >&2 | |
| exit 1 | |
| } | |
| # Generate random string | |
| generate_random_string() { | |
| local length=${1:-32} | |
| openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length" | |
| } | |
| # ============ STAGE 1: GPU DRIVERS ONLY ============ | |
| stage1_gpu_install() { | |
| log "=== STAGE 1: Installing NVIDIA GPU Drivers ===" | |
| # Check for GPU | |
| if ! lspci | grep -qi nvidia; then | |
| error "No NVIDIA GPU detected - this stack requires GPU" | |
| fi | |
| # Set hostname | |
| hostnamectl set-hostname "n8n-ai" | |
| echo "127.0.0.1 n8n-ai" >> /etc/hosts | |
| # Update system | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get update -qq | |
| apt-get upgrade -y -qq | |
| # Install NVIDIA drivers | |
| log "Installing NVIDIA drivers (580-server)..." | |
| apt-get install -y -qq ubuntu-drivers-common --no-install-recommends | |
| ubuntu-drivers install --gpgpu nvidia:580-server | |
| apt-get install -y -qq nvidia-utils-580-server --no-install-recommends | |
| # Install NVIDIA container toolkit | |
| log "Installing NVIDIA container toolkit..." | |
| apt-get install -y -qq curl gnupg --no-install-recommends | |
| curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \ | |
| gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg | |
| curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ | |
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ | |
| tee /etc/apt/sources.list.d/nvidia-container-toolkit.list >/dev/null | |
| apt-get update -qq | |
| apt-get install -y -qq nvidia-container-toolkit --no-install-recommends | |
| # Save environment variables for stage 2 | |
| cat >/root/.stackscript_env <<EOF | |
| export DOMAIN_NAME="${DOMAIN_NAME}" | |
| export SUBDOMAIN="${SUBDOMAIN}" | |
| export SSL_EMAIL="${SSL_EMAIL}" | |
| EOF | |
| # Create stage 2 service | |
| cat >/etc/systemd/system/stackscript-stage2.service <<EOF | |
| [Unit] | |
| Description=StackScript Stage 2 - Complete Installation | |
| After=multi-user.target network-online.target | |
| Wants=network-online.target | |
| ConditionPathExists=!/root/.stackscript_stage_complete | |
| [Service] | |
| Type=oneshot | |
| ExecStart=/bin/bash /root/stage2.sh | |
| RemainAfterExit=yes | |
| StandardOutput=journal+console | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| # Create stage 2 script | |
| cat >/root/stage2.sh <<'STAGE2_SCRIPT' | |
| #!/bin/bash | |
| set -euo pipefail | |
| exec 1> >(tee -a /var/log/stackscript.log) | |
| exec 2>&1 | |
| # Load environment | |
| source /root/.stackscript_env | |
| # Configuration | |
| readonly REPO_URL="https://github.com/ElliotGluck/n8n-gpu-swarm.git" | |
| readonly REPO_DIR="/opt/n8n-gpu-swarm" | |
| log() { | |
| echo "[$(date +'%Y-%m-%d %H:%M:%S')] STAGE2: $*" | |
| } | |
| error() { | |
| echo "[STAGE2 ERROR] $*" >&2 | |
| exit 1 | |
| } | |
| generate_random_string() { | |
| local length=${1:-32} | |
| openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length" | |
| } | |
| log "=== STAGE 2: Completing n8n Stack Installation ===" | |
| # Verify GPU is working | |
| if ! nvidia-smi &>/dev/null; then | |
| error "GPU drivers not loaded properly after reboot" | |
| fi | |
| log "GPU drivers verified and working" | |
| # Install remaining packages | |
| log "Installing required packages..." | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get update -qq | |
| apt-get install -y -qq \ | |
| wget git lsb-release ca-certificates \ | |
| software-properties-common ufw fail2ban \ | |
| --no-install-recommends | |
| # Setup firewall | |
| log "Configuring firewall..." | |
| ufw allow 22/tcp | |
| ufw allow 80/tcp | |
| ufw allow 443/tcp | |
| ufw --force enable | |
| # Install Docker | |
| log "Installing Docker..." | |
| install -m 0755 -d /etc/apt/keyrings | |
| curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc | |
| chmod a+r /etc/apt/keyrings/docker.asc | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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 \ | |
| --no-install-recommends | |
| systemctl enable docker --now | |
| # Configure NVIDIA runtime for Docker (per Ollama instructions) | |
| log "Configuring Docker NVIDIA runtime..." | |
| nvidia-ctk runtime configure --runtime=docker | |
| systemctl restart docker | |
| sleep 5 | |
| # Setup n8n stack | |
| log "Setting up n8n stack..." | |
| cd /opt | |
| git clone --quiet "$REPO_URL" "$REPO_DIR" | |
| cd "$REPO_DIR" | |
| # Create Caddyfile | |
| docker volume create caddy_data | |
| log "Creating Caddyfile..." | |
| cat >${REPO_DIR}/caddy_config/Caddyfile <<CADDY_EOF | |
| ${SUBDOMAIN}.${DOMAIN_NAME} { | |
| reverse_proxy n8n:5678 { | |
| flush_interval -1 | |
| } | |
| } | |
| CADDY_EOF | |
| # Generate credentials | |
| log "Generating credentials..." | |
| ENCRYPTION_KEY=$(generate_random_string 32) | |
| JWT_SECRET=$(generate_random_string 40) | |
| DB_PASSWORD=$(generate_random_string 24) | |
| # Create .env file | |
| cat >.env <<EOF | |
| POSTGRES_USER=root | |
| POSTGRES_DB=n8n | |
| N8N_DEFAULT_BINARY_DATA_MODE=filesystem | |
| N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY} | |
| N8N_USER_MANAGEMENT_JWT_SECRET=${JWT_SECRET} | |
| POSTGRES_PASSWORD=${DB_PASSWORD} | |
| WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME} | |
| DATA_FOLDER=${REPO_DIR} | |
| EOF | |
| # Save credentials | |
| cat >/root/credentials.txt <<EOF | |
| n8n Credentials | |
| =============== | |
| Date: $(date) | |
| Database Password: ${DB_PASSWORD} | |
| Encryption Key: ${ENCRYPTION_KEY} | |
| JWT Secret: ${JWT_SECRET} | |
| URL: https://${SUBDOMAIN}.${DOMAIN_NAME} | |
| EOF | |
| chmod 600 /root/credentials.txt | |
| # Start services with GPU profile (per official instructions) | |
| log "Starting Docker Compose services with GPU profile..." | |
| docker compose up -d | |
| # Setup systemd service | |
| cat >/etc/systemd/system/n8n-stack.service <<SERVICE_EOF | |
| [Unit] | |
| Description=n8n AI Stack | |
| Requires=docker.service | |
| After=docker.service network-online.target | |
| [Service] | |
| Type=oneshot | |
| RemainAfterExit=yes | |
| WorkingDirectory=${REPO_DIR} | |
| ExecStartPre=/bin/sleep 10 | |
| ExecStart=/usr/bin/docker compose up -d | |
| ExecStop=/usr/bin/docker compose down | |
| StandardOutput=journal | |
| [Install] | |
| WantedBy=multi-user.target | |
| SERVICE_EOF | |
| systemctl daemon-reload | |
| systemctl enable n8n-stack.service | |
| # Mark completion | |
| touch /root/.stackscript_stage_complete | |
| # Cleanup | |
| rm -f /root/.stackscript_env | |
| systemctl disable stackscript-stage2.service | |
| rm -f /etc/systemd/system/stackscript-stage2.service | |
| log "=== Stage 2 Complete - System Fully Configured ===" | |
| # Display final message | |
| cat <<FINAL_EOF | |
| ========================================= | |
| n8n GPU Stack Installation Complete | |
| ========================================= | |
| Access URL: https://${SUBDOMAIN}.${DOMAIN_NAME} | |
| Credentials: /root/credentials.txt | |
| GPU Status: Active and Working | |
| All Ollama models have been loaded. | |
| Service Management: | |
| - View logs: docker compose -f ${REPO_DIR}/docker-compose.yml logs -f | |
| - Restart: systemctl restart n8n-stack | |
| - Status: systemctl status n8n-stack | |
| ========================================= | |
| FINAL_EOF | |
| STAGE2_SCRIPT | |
| chmod +x /root/stage2.sh | |
| systemctl daemon-reload | |
| systemctl enable stackscript-stage2.service | |
| log "Stage 1 complete - GPU drivers installed" | |
| log "System will reboot in 10 seconds to activate GPU..." | |
| log "Stage 2 will run automatically after reboot" | |
| sleep 10 | |
| shutdown -r now | |
| } | |
| # ============ MAIN EXECUTION ============ | |
| main() { | |
| log "=== n8n GPU Stack Installation Starting ===" | |
| # Validate required parameters | |
| [[ -z "${DOMAIN_NAME}" ]] && error "DOMAIN_NAME is required" | |
| [[ -z "${SUBDOMAIN}" ]] && error "SUBDOMAIN is required" | |
| [[ -z "${SSL_EMAIL}" ]] && error "SSL_EMAIL is required" | |
| # Check if this is stage 2 (after reboot) | |
| if [[ -f "$STAGE_FILE" ]]; then | |
| log "Installation already complete" | |
| exit 0 | |
| fi | |
| # Check if GPU drivers are already loaded | |
| if nvidia-smi &>/dev/null; then | |
| log "GPU already active - running full installation" | |
| # If GPU is already working, run stage 2 directly | |
| bash /root/stage2.sh | |
| else | |
| # Run stage 1 - GPU installation and reboot | |
| stage1_gpu_install | |
| fi | |
| } | |
| # Run | |
| main "$@" 2>&1 | tee -a "$LOG_FILE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment