Skip to content

Instantly share code, notes, and snippets.

@ElliotGluck
Last active October 22, 2025 10:10
Show Gist options
  • Select an option

  • Save ElliotGluck/89d8d4416f165974e185430ad0f3a116 to your computer and use it in GitHub Desktop.

Select an option

Save ElliotGluck/89d8d4416f165974e185430ad0f3a116 to your computer and use it in GitHub Desktop.
Installs n8n+ollama on Linode stackscript
#!/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