Files
proxmox-lxc-shell-commands/proxmox-lxc-outline.sh
DevOps 8c67ae01f3 feat: Immich, Outline, Gitea LXC 설치 스크립트 추가
- proxmox-lxc-immich.sh: 사진/동영상 관리 (Google Photos 대안)
- proxmox-lxc-outline.sh: 팀 위키/문서 관리 (Notion 대안)
- proxmox-lxc-gitea.sh: 경량 Git 서버 (GitHub/GitLab 대안)

모든 스크립트: Docker-in-LXC, PostgreSQL, systemd 서비스 등록

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 23:46:52 +09:00

313 lines
9.7 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Outline LXC Installation Script
# Description: Modern team knowledge base and wiki (Notion alternative)
# OS: Debian 12 (Bookworm) - Auto-detected latest version
# Ports: Web UI: 3000
# Repository: https://github.com/outline/outline
# Last Updated: 2026-01-05
set -euo pipefail
#################################################################
# Configuration Variables
#################################################################
CT_ID=${CT_ID:-24005}
CT_HOSTNAME=${CT_HOSTNAME:-"outline"}
CT_CORES=${CT_CORES:-2}
CT_MEMORY=${CT_MEMORY:-4096}
CT_SWAP=${CT_SWAP:-1024}
CT_DISK_SIZE=${CT_DISK_SIZE:-20}
CT_IP=${CT_IP:-"dhcp"}
CT_GATEWAY=${CT_GATEWAY:-""}
CT_BRIDGE=${CT_BRIDGE:-"vmbr0"}
CT_NAMESERVER=${CT_NAMESERVER:-"8.8.8.8"}
CT_STORAGE=${CT_STORAGE:-"local-lvm"}
TEMPLATE_STORAGE=${TEMPLATE_STORAGE:-"local"}
DEBIAN_VERSION="12"
TEMPLATE_NAME=""
# Application Configuration
OUTLINE_PORT=${OUTLINE_PORT:-3000}
SECRET_KEY=${SECRET_KEY:-"$(openssl rand -hex 32)"}
UTILS_SECRET=${UTILS_SECRET:-"$(openssl rand -hex 32)"}
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-"$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 20)"}
# Container Options
CT_ONBOOT=${CT_ONBOOT:-1}
CT_UNPRIVILEGED=${CT_UNPRIVILEGED:-0}
CT_FEATURES=${CT_FEATURES:-"keyctl=1,nesting=1"}
#################################################################
# Color Output Functions
#################################################################
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
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"; }
#################################################################
# Functions
#################################################################
check_root() {
[[ $EUID -ne 0 ]] && error "This script must be run as root" && exit 1
}
check_proxmox() {
command -v pct &> /dev/null || { error "Run on Proxmox VE host"; exit 1; }
}
check_container_exists() {
pct status "$CT_ID" &> /dev/null && { error "Container $CT_ID exists"; exit 1; }
}
detect_and_download_template() {
info "Updating template database..."
pveam update 2>&1 || true
local available_template
available_template=$(pveam available --section system 2>/dev/null | grep "debian-${DEBIAN_VERSION}" | grep "standard" | tail -1 | awk '{print $2}')
[[ -z "$available_template" ]] && error "No Debian ${DEBIAN_VERSION} template found" && exit 1
TEMPLATE_NAME="$available_template"
info "Found template: $TEMPLATE_NAME"
pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE_NAME" || pveam download "$TEMPLATE_STORAGE" "$TEMPLATE_NAME" 2>&1
success "Template ready"
}
create_container() {
info "Creating LXC container $CT_ID ($CT_HOSTNAME)..."
local net_config="name=eth0,bridge=${CT_BRIDGE},ip=${CT_IP}"
[[ "$CT_IP" != "dhcp" ]] && [[ -n "$CT_GATEWAY" ]] && net_config="${net_config},gw=${CT_GATEWAY}"
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 || exit 1
success "Container created"
}
start_container() {
info "Starting container..."
pct start "$CT_ID" && sleep 5
success "Container started"
}
install_docker() {
info "Installing Docker..."
pct exec "$CT_ID" -- bash -c "apt-get update -qq"
pct exec "$CT_ID" -- bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ca-certificates curl gnupg"
pct exec "$CT_ID" -- bash -c "install -m 0755 -d /etc/apt/keyrings"
pct exec "$CT_ID" -- bash -c "curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc"
pct exec "$CT_ID" -- bash -c "chmod a+r /etc/apt/keyrings/docker.asc"
pct exec "$CT_ID" -- bash -c 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null'
pct exec "$CT_ID" -- bash -c "apt-get update -qq"
pct exec "$CT_ID" -- bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin"
pct exec "$CT_ID" -- bash -c "systemctl enable docker && systemctl start docker"
sleep 3
success "Docker installed"
}
install_outline() {
info "Installing Outline..."
pct exec "$CT_ID" -- bash -c "mkdir -p /opt/outline/{data,postgres,redis}"
# Create docker-compose.yml
pct exec "$CT_ID" -- bash -c "cat > /opt/outline/docker-compose.yml << 'EOF'
services:
outline:
image: docker.getoutline.com/outlinewiki/outline:latest
container_name: outline
restart: always
env_file: ./.env
ports:
- \"${OUTLINE_PORT}:3000\"
volumes:
- ./data:/var/lib/outline/data
depends_on:
- postgres
- redis
networks:
- outline-network
postgres:
image: postgres:15-alpine
container_name: outline-postgres
restart: always
environment:
POSTGRES_USER: outline
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD}
POSTGRES_DB: outline
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: [\"CMD-SHELL\", \"pg_isready -U outline -d outline\"]
interval: 10s
timeout: 5s
retries: 5
networks:
- outline-network
redis:
image: redis:7-alpine
container_name: outline-redis
restart: always
volumes:
- ./redis:/data
healthcheck:
test: [\"CMD\", \"redis-cli\", \"ping\"]
interval: 10s
timeout: 5s
retries: 5
networks:
- outline-network
networks:
outline-network:
driver: bridge
EOF"
# Create .env file
pct exec "$CT_ID" -- bash -c "cat > /opt/outline/.env << 'EOF'
# REQUIRED
NODE_ENV=production
SECRET_KEY=${SECRET_KEY}
UTILS_SECRET=${UTILS_SECRET}
# Database
DATABASE_URL=postgres://outline:\${POSTGRES_PASSWORD}@postgres:5432/outline
DATABASE_CONNECTION_POOL_MIN=1
DATABASE_CONNECTION_POOL_MAX=10
PGSSLMODE=disable
# Redis
REDIS_URL=redis://redis:6379
# URL (update this for production)
URL=http://localhost:${OUTLINE_PORT}
PORT=3000
FORCE_HTTPS=false
# Storage
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
FILE_STORAGE_UPLOAD_MAX_SIZE=26214400
# Authentication (configure at least one)
# For testing, you can use username/password
# SMTP is required for email login
# OIDC_CLIENT_ID=
# OIDC_CLIENT_SECRET=
# OIDC_AUTH_URI=
# OIDC_TOKEN_URI=
# OIDC_USERINFO_URI=
# Optional
DEFAULT_LANGUAGE=ko_KR
ENABLE_UPDATES=true
DEBUG=
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
EOF"
info "Starting Outline containers..."
pct exec "$CT_ID" -- bash -c "cd /opt/outline && docker compose up -d"
info "Waiting for Outline to start (1-2 minutes)..."
local max_attempts=30
local attempt=1
while [[ $attempt -le $max_attempts ]]; do
if pct exec "$CT_ID" -- bash -c "curl -s -o /dev/null -w '%{http_code}' http://localhost:${OUTLINE_PORT}/" | grep -q "200\|302"; then
success "Outline is running!"
break
fi
echo -n "."
sleep 5
((attempt++))
done
echo ""
success "Outline installed"
}
create_outline_service() {
pct exec "$CT_ID" -- bash -c 'cat > /etc/systemd/system/outline.service << EOF
[Unit]
Description=Outline Wiki
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/outline
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=180
[Install]
WantedBy=multi-user.target
EOF'
pct exec "$CT_ID" -- bash -c "systemctl daemon-reload && systemctl enable outline"
success "Outline service created"
}
verify_installation() {
local container_ip
container_ip=$(pct exec "$CT_ID" -- bash -c "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "unknown")
echo ""
echo "================================================================"
echo -e "${GREEN}Outline Installation Complete!${NC}"
echo "================================================================"
echo "Container ID: $CT_ID | Hostname: $CT_HOSTNAME | IP: $container_ip"
echo ""
echo "Web UI: http://${container_ip}:${OUTLINE_PORT}"
echo ""
echo -e "${YELLOW}IMPORTANT: Configure authentication before use!${NC}"
echo ""
echo "Authentication options:"
echo " 1. OIDC (Keycloak, Auth0, etc.)"
echo " 2. SAML"
echo " 3. Google/GitHub OAuth"
echo ""
echo "Edit /opt/outline/.env to configure authentication,"
echo "then restart: docker compose restart outline"
echo ""
echo "Commands:"
echo " pct exec $CT_ID -- docker compose -f /opt/outline/docker-compose.yml logs -f"
echo " pct exec $CT_ID -- docker compose -f /opt/outline/docker-compose.yml ps"
echo ""
echo "Data location: /opt/outline/data"
echo "================================================================"
}
main() {
echo "================================================================"
echo "Outline LXC Installation Script"
echo "================================================================"
check_root
check_proxmox
check_container_exists
detect_and_download_template
create_container
start_container
install_docker
install_outline
create_outline_service
verify_installation
}
main "$@"