372 lines
11 KiB
Bash
372 lines
11 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Gotify LXC Installation Script
|
|
# Description: Self-hosted push notification server
|
|
# OS: Debian 12 (Bookworm) - Auto-detected latest version
|
|
# Ports: Web UI/API: 8080
|
|
# Repository: https://github.com/gotify/server
|
|
# Last Updated: 2026-01-05
|
|
|
|
set -euo pipefail
|
|
|
|
#################################################################
|
|
# Configuration Variables
|
|
#################################################################
|
|
|
|
# Container Configuration
|
|
CT_ID=${CT_ID:-11001} # Container ID
|
|
CT_HOSTNAME=${CT_HOSTNAME:-"gotify"} # Container hostname
|
|
CT_CORES=${CT_CORES:-1} # CPU cores
|
|
CT_MEMORY=${CT_MEMORY:-512} # RAM in MB
|
|
CT_SWAP=${CT_SWAP:-256} # Swap in MB
|
|
CT_DISK_SIZE=${CT_DISK_SIZE:-8} # Root disk size in GB
|
|
|
|
# Network Configuration
|
|
CT_IP=${CT_IP:-"dhcp"} # IP address (dhcp or static like 192.168.1.100/24)
|
|
CT_GATEWAY=${CT_GATEWAY:-""} # Gateway (required for static IP)
|
|
CT_BRIDGE=${CT_BRIDGE:-"vmbr0"} # Network bridge
|
|
CT_NAMESERVER=${CT_NAMESERVER:-"8.8.8.8"} # DNS server
|
|
|
|
# Storage Configuration
|
|
CT_STORAGE=${CT_STORAGE:-"local-lvm"} # Storage pool for container
|
|
TEMPLATE_STORAGE=${TEMPLATE_STORAGE:-"local"} # Storage pool for templates
|
|
|
|
# Debian Template (will be auto-detected)
|
|
DEBIAN_VERSION="12" # Debian version
|
|
TEMPLATE_NAME="" # Auto-detected
|
|
|
|
# Application Configuration
|
|
GOTIFY_PORT=${GOTIFY_PORT:-8080} # Web UI/API port
|
|
GOTIFY_ADMIN_USER=${GOTIFY_ADMIN_USER:-"admin"} # Admin username
|
|
GOTIFY_ADMIN_PASS=${GOTIFY_ADMIN_PASS:-"admin"} # Admin password (change this!)
|
|
GOTIFY_VERSION=${GOTIFY_VERSION:-"2.6.1"} # Gotify version
|
|
|
|
# Container Options
|
|
CT_ONBOOT=${CT_ONBOOT:-1} # Start on boot (1=yes, 0=no)
|
|
CT_UNPRIVILEGED=${CT_UNPRIVILEGED:-1} # Unprivileged container
|
|
CT_FEATURES=${CT_FEATURES:-"nesting=1"} # Container features
|
|
|
|
#################################################################
|
|
# Color Output Functions
|
|
#################################################################
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
#################################################################
|
|
# Validation Functions
|
|
#################################################################
|
|
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_proxmox() {
|
|
if ! command -v pct &> /dev/null; then
|
|
error "This script must be run on a Proxmox VE host"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_container_exists() {
|
|
if pct status "$CT_ID" &> /dev/null; then
|
|
error "Container ID $CT_ID already exists"
|
|
info "Please choose a different CT_ID or remove the existing container"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
detect_and_download_template() {
|
|
info "Updating template database..."
|
|
|
|
if ! pveam update 2>&1 | grep -q "update successful\|already up to date"; then
|
|
warn "Template database update encountered issues, continuing anyway..."
|
|
fi
|
|
|
|
info "Detecting available Debian ${DEBIAN_VERSION} template..."
|
|
|
|
local available_template
|
|
available_template=$(pveam available --section system 2>/dev/null | grep "debian-${DEBIAN_VERSION}" | grep "standard" | tail -1 | awk '{print $2}')
|
|
|
|
if [[ -z "$available_template" ]]; then
|
|
error "No Debian ${DEBIAN_VERSION} template found in available templates"
|
|
exit 1
|
|
fi
|
|
|
|
TEMPLATE_NAME="$available_template"
|
|
info "Found template: $TEMPLATE_NAME"
|
|
|
|
if pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE_NAME"; then
|
|
success "Template already downloaded"
|
|
return 0
|
|
fi
|
|
|
|
warn "Downloading Debian template (this may take a few minutes)..."
|
|
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE_NAME" 2>&1; then
|
|
success "Template downloaded successfully"
|
|
else
|
|
error "Failed to download template"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
#################################################################
|
|
# Container Creation Functions
|
|
#################################################################
|
|
|
|
create_container() {
|
|
info "Creating LXC container $CT_ID ($CT_HOSTNAME)..."
|
|
|
|
local net_config="name=eth0,bridge=${CT_BRIDGE},ip=${CT_IP}"
|
|
|
|
if [[ "$CT_IP" != "dhcp" ]] && [[ -n "$CT_GATEWAY" ]]; then
|
|
net_config="${net_config},gw=${CT_GATEWAY}"
|
|
fi
|
|
|
|
pct create "$CT_ID" \
|
|
"${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE_NAME}" \
|
|
--hostname "$CT_HOSTNAME" \
|
|
--cores "$CT_CORES" \
|
|
--memory "$CT_MEMORY" \
|
|
--swap "$CT_SWAP" \
|
|
--rootfs "${CT_STORAGE}:${CT_DISK_SIZE}" \
|
|
--net0 "$net_config" \
|
|
--nameserver "$CT_NAMESERVER" \
|
|
--onboot "$CT_ONBOOT" \
|
|
--unprivileged "$CT_UNPRIVILEGED" \
|
|
--features "$CT_FEATURES" \
|
|
--ostype debian || {
|
|
error "Failed to create container"
|
|
exit 1
|
|
}
|
|
|
|
success "Container $CT_ID created successfully"
|
|
}
|
|
|
|
start_container() {
|
|
info "Starting container $CT_ID..."
|
|
pct start "$CT_ID" || {
|
|
error "Failed to start container"
|
|
exit 1
|
|
}
|
|
|
|
info "Waiting for container to boot..."
|
|
sleep 5
|
|
|
|
success "Container started successfully"
|
|
}
|
|
|
|
configure_autologin() {
|
|
info "Configuring automatic console login..."
|
|
|
|
pct exec "$CT_ID" -- bash -c "mkdir -p /etc/systemd/system/container-getty@1.service.d"
|
|
|
|
pct exec "$CT_ID" -- bash -c 'cat > /etc/systemd/system/container-getty@1.service.d/override.conf << EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
|
|
EOF'
|
|
|
|
pct exec "$CT_ID" -- bash -c "systemctl daemon-reload"
|
|
pct exec "$CT_ID" -- bash -c "systemctl restart container-getty@1.service" 2>/dev/null || true
|
|
|
|
success "Automatic console login configured"
|
|
}
|
|
|
|
#################################################################
|
|
# Gotify Installation
|
|
#################################################################
|
|
|
|
install_gotify() {
|
|
info "Installing Gotify in container $CT_ID..."
|
|
|
|
info "Updating package list..."
|
|
pct exec "$CT_ID" -- bash -c "apt-get update -qq"
|
|
|
|
info "Installing required packages..."
|
|
pct exec "$CT_ID" -- bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
|
|
wget \
|
|
unzip \
|
|
ca-certificates \
|
|
curl"
|
|
|
|
info "Creating Gotify directories..."
|
|
pct exec "$CT_ID" -- bash -c "mkdir -p /opt/gotify/data"
|
|
|
|
info "Downloading Gotify ${GOTIFY_VERSION}..."
|
|
pct exec "$CT_ID" -- bash -c "cd /opt/gotify && wget -q https://github.com/gotify/server/releases/download/v${GOTIFY_VERSION}/gotify-linux-amd64.zip"
|
|
pct exec "$CT_ID" -- bash -c "cd /opt/gotify && unzip -o gotify-linux-amd64.zip && rm gotify-linux-amd64.zip"
|
|
pct exec "$CT_ID" -- bash -c "chmod +x /opt/gotify/gotify-linux-amd64"
|
|
|
|
info "Creating Gotify configuration..."
|
|
pct exec "$CT_ID" -- bash -c "cat > /opt/gotify/config.yml << 'EOF'
|
|
server:
|
|
port: ${GOTIFY_PORT}
|
|
keepaliveperiodseconds: 0
|
|
listenaddr: \"\"
|
|
ssl:
|
|
enabled: false
|
|
redirecttohttps: false
|
|
listenaddr: \"\"
|
|
port: 443
|
|
certfile: \"\"
|
|
certkey: \"\"
|
|
letsencrypt:
|
|
enabled: false
|
|
accepttos: false
|
|
cache: data/certs
|
|
hosts:
|
|
- domain.tld
|
|
responseheaders: {}
|
|
cors:
|
|
alloworigins:
|
|
- \".+\"
|
|
allowmethods:
|
|
- GET
|
|
- POST
|
|
allowheaders:
|
|
- Authorization
|
|
- content-type
|
|
stream:
|
|
allowedorigins:
|
|
- \".+\"
|
|
pingperiodseconds: 45
|
|
database:
|
|
dialect: sqlite3
|
|
connection: data/gotify.db
|
|
defaultuser:
|
|
name: ${GOTIFY_ADMIN_USER}
|
|
pass: ${GOTIFY_ADMIN_PASS}
|
|
passstrength: 10
|
|
uploadedimagesdir: data/images
|
|
pluginsdir: data/plugins
|
|
registration: false
|
|
EOF"
|
|
|
|
success "Gotify installed successfully"
|
|
}
|
|
|
|
create_gotify_service() {
|
|
info "Creating Gotify systemd service..."
|
|
|
|
pct exec "$CT_ID" -- bash -c 'cat > /etc/systemd/system/gotify.service << EOF
|
|
[Unit]
|
|
Description=Gotify Push Notification Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=/opt/gotify
|
|
ExecStart=/opt/gotify/gotify-linux-amd64
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF'
|
|
|
|
pct exec "$CT_ID" -- bash -c "systemctl daemon-reload"
|
|
pct exec "$CT_ID" -- bash -c "systemctl enable gotify"
|
|
pct exec "$CT_ID" -- bash -c "systemctl start gotify"
|
|
|
|
sleep 3
|
|
|
|
if pct exec "$CT_ID" -- bash -c "systemctl is-active gotify" &>/dev/null; then
|
|
success "Gotify service started successfully"
|
|
else
|
|
warn "Gotify service may not be running, please check logs"
|
|
fi
|
|
}
|
|
|
|
#################################################################
|
|
# Verification Functions
|
|
#################################################################
|
|
|
|
verify_installation() {
|
|
info "Verifying Gotify installation..."
|
|
|
|
sleep 3
|
|
|
|
local container_ip
|
|
container_ip=$(pct exec "$CT_ID" -- bash -c "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "unknown")
|
|
|
|
if pct exec "$CT_ID" -- bash -c "curl -s -o /dev/null -w '%{http_code}' http://localhost:${GOTIFY_PORT}/" | grep -q "200\|302"; then
|
|
success "Gotify is running and accessible!"
|
|
else
|
|
warn "Gotify may not be fully ready yet. Please wait a moment and try again."
|
|
fi
|
|
|
|
echo ""
|
|
echo "================================================================"
|
|
echo -e "${GREEN}Gotify Installation Complete!${NC}"
|
|
echo "================================================================"
|
|
echo ""
|
|
echo "Container Information:"
|
|
echo " - Container ID: $CT_ID"
|
|
echo " - Hostname: $CT_HOSTNAME"
|
|
echo " - IP Address: $container_ip"
|
|
echo ""
|
|
echo "Access Information:"
|
|
echo " - Web UI: http://${container_ip}:${GOTIFY_PORT}"
|
|
echo " - Admin User: ${GOTIFY_ADMIN_USER}"
|
|
echo " - Admin Password: ${GOTIFY_ADMIN_PASS}"
|
|
echo ""
|
|
echo "Service Management:"
|
|
echo " - pct exec $CT_ID -- systemctl status gotify"
|
|
echo " - pct exec $CT_ID -- systemctl restart gotify"
|
|
echo ""
|
|
echo "Data Directory: /opt/gotify/data"
|
|
echo "Config File: /opt/gotify/config.yml"
|
|
echo "================================================================"
|
|
}
|
|
|
|
#################################################################
|
|
# Main Script Execution
|
|
#################################################################
|
|
|
|
main() {
|
|
echo "================================================================"
|
|
echo "Gotify LXC Installation Script"
|
|
echo "================================================================"
|
|
echo ""
|
|
|
|
check_root
|
|
check_proxmox
|
|
check_container_exists
|
|
|
|
detect_and_download_template
|
|
create_container
|
|
start_container
|
|
configure_autologin
|
|
|
|
install_gotify
|
|
create_gotify_service
|
|
|
|
verify_installation
|
|
}
|
|
|
|
main "$@"
|