deploy: production deploy script + path alignment to /opt/nextworkspace/
- Add deploy.sh: idempotent production deploy (scaffold, build, systemd, health check) - Fix update.sh: align all paths from /opt/nextwks/ to /opt/nextworkspace/ (blueprint-compliant) - deploy.sh safe for first-time setup and subsequent updates - Creates full blueprint directory tree: config/, data/, logs/, src/core/
This commit is contained in:
parent
3560e9b5b6
commit
1efeb05f4f
2 changed files with 219 additions and 3 deletions
216
deploy.sh
Executable file
216
deploy.sh
Executable file
|
|
@ -0,0 +1,216 @@
|
|||
#!/bin/bash
|
||||
# ============================================================
|
||||
# NextWks — Production Deploy Script
|
||||
# Idempotent: safe for first-time setup and subsequent updates.
|
||||
# Run: sudo bash deploy.sh
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
|
||||
info() { echo -e "${BLUE}[+]${NC} $1"; }
|
||||
ok() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||
die() { echo -e "${RED}[✗]${NC} $1"; exit 1; }
|
||||
header(){ echo -e "\n${BOLD}${CYAN}── $1 ──${NC}"; }
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
INSTALL_DIR="/opt/nextworkspace"
|
||||
SRC_DIR="${INSTALL_DIR}/src/core"
|
||||
CONFIG_DIR="${INSTALL_DIR}/config/nextworkspace"
|
||||
DATA_DIR="${INSTALL_DIR}/data/core"
|
||||
CERTS_DIR="${INSTALL_DIR}/data/certs"
|
||||
LOGS_DIR="${INSTALL_DIR}/logs"
|
||||
STATIC_DIR="${INSTALL_DIR}/static"
|
||||
BIN_PATH="${INSTALL_DIR}/core"
|
||||
CONFIG_PATH="${CONFIG_DIR}/config.yaml"
|
||||
SERVICE_FILE="/etc/systemd/system/nextwks.service"
|
||||
SVC_USER="nextwks"
|
||||
REPO_URL="https://git.lohmar.co.uk/lexton-it/NextWks.git"
|
||||
|
||||
# Must be root
|
||||
[ "${EUID:-$(id -u)}" -ne 0 ] && die "Run as root: sudo bash deploy.sh"
|
||||
|
||||
# ============================================================
|
||||
# PHASE 1: DIRECTORY SCAFFOLD + SERVICE USER
|
||||
# ============================================================
|
||||
header "Phase 1: Directory Structure"
|
||||
|
||||
if ! id "$SVC_USER" &>/dev/null; then
|
||||
useradd -r -s /usr/sbin/nologin -d /nonexistent "$SVC_USER"
|
||||
ok "Created service user: $SVC_USER"
|
||||
else
|
||||
info "Service user exists: $SVC_USER"
|
||||
fi
|
||||
|
||||
mkdir -p "$SRC_DIR" "$CONFIG_DIR/apps.d" "$DATA_DIR" "$CERTS_DIR" "$LOGS_DIR" "$STATIC_DIR"
|
||||
chown -R "$SVC_USER:$SVC_USER" "$DATA_DIR" "$CERTS_DIR" "$LOGS_DIR" "$STATIC_DIR"
|
||||
ok "Directory tree created at $INSTALL_DIR/"
|
||||
|
||||
# ============================================================
|
||||
# PHASE 2: FETCH + BUILD
|
||||
# ============================================================
|
||||
header "Phase 2: Build"
|
||||
|
||||
if [ -d "$SRC_DIR/.git" ]; then
|
||||
info "Pulling latest from origin..."
|
||||
cd "$SRC_DIR"
|
||||
git fetch origin main --quiet
|
||||
git reset --hard origin/main --quiet
|
||||
ok "Repo updated"
|
||||
else
|
||||
info "Cloning repository..."
|
||||
git clone --depth 1 "$REPO_URL" "$SRC_DIR" --quiet
|
||||
cd "$SRC_DIR"
|
||||
ok "Repo cloned"
|
||||
fi
|
||||
|
||||
VERSION=$(cat "$SRC_DIR/VERSION" 2>/dev/null || echo "dev")
|
||||
COMMIT_SHA=$(cd "$SRC_DIR" && git rev-parse --short HEAD)
|
||||
BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
if ! command -v go &>/dev/null; then
|
||||
die "Go is not installed. Run: apt install golang-go"
|
||||
fi
|
||||
|
||||
info "Building v${VERSION} (${COMMIT_SHA})..."
|
||||
cd "$SRC_DIR/src"
|
||||
|
||||
go build -ldflags="-s -w \
|
||||
-X git.lohmar.co.uk/lexton-it/NextWks/core/version.Version=${VERSION} \
|
||||
-X git.lohmar.co.uk/lexton-it/NextWks/core/version.BuildTime=${BUILD_TIME} \
|
||||
-X git.lohmar.co.uk/lexton-it/NextWks/core/version.CommitSHA=${COMMIT_SHA}" \
|
||||
-o "$BIN_PATH" .
|
||||
|
||||
chmod 755 "$BIN_PATH"
|
||||
chown "$SVC_USER:$SVC_USER" "$BIN_PATH"
|
||||
ok "Binary: $BIN_PATH"
|
||||
|
||||
# ============================================================
|
||||
# PHASE 3: CONFIG + ASSETS
|
||||
# ============================================================
|
||||
header "Phase 3: Configuration"
|
||||
|
||||
if [ ! -f "$CONFIG_PATH" ]; then
|
||||
ADMIN_TOKEN=$(openssl rand -hex 32 2>/dev/null || head -c32 /dev/urandom | xxd -p -c32)
|
||||
SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || head -c32 /dev/urandom | xxd -p -c32)
|
||||
|
||||
cat > "$CONFIG_PATH" << CONFIGEOF
|
||||
# NextWks — Production Configuration
|
||||
# Generated: $(date)
|
||||
server:
|
||||
host: "0.0.0.0"
|
||||
port: 8080
|
||||
|
||||
admin:
|
||||
secret_token: "${ADMIN_TOKEN}"
|
||||
|
||||
database:
|
||||
type: "sqlite"
|
||||
path: "${DATA_DIR}/nextwks.db"
|
||||
|
||||
authelia:
|
||||
host: "http://127.0.0.1:9091"
|
||||
config_path: "/opt/authelia/configuration.yml"
|
||||
users_db_path: "/opt/authelia/users_database.yml"
|
||||
|
||||
oidc:
|
||||
issuer_url: "https://app.nextwks.eu/auth"
|
||||
client_id: "nextwks"
|
||||
client_secret: ""
|
||||
redirect_url: "https://app.nextwks.eu/access"
|
||||
|
||||
smtp:
|
||||
host: ""
|
||||
port: 587
|
||||
username: ""
|
||||
password: ""
|
||||
from: "noreply@nextwks.local"
|
||||
|
||||
session:
|
||||
secret: "${SESSION_SECRET}"
|
||||
expiry_minutes: 60
|
||||
|
||||
tls:
|
||||
enabled: false
|
||||
domain: ""
|
||||
email: ""
|
||||
storage_path: "${CERTS_DIR}"
|
||||
staging: false
|
||||
CONFIGEOF
|
||||
|
||||
chmod 600 "$CONFIG_PATH"
|
||||
chown "$SVC_USER:$SVC_USER" "$CONFIG_PATH"
|
||||
ok "Config: $CONFIG_PATH"
|
||||
warn "IMPORTANT: Edit $CONFIG_PATH with your domain, email, and SMTP settings!"
|
||||
else
|
||||
ok "Config exists (not overwritten): $CONFIG_PATH"
|
||||
fi
|
||||
|
||||
if [ -d "$SRC_DIR/app/static" ]; then
|
||||
cp -r "$SRC_DIR/app/static/"* "$STATIC_DIR/" 2>/dev/null || true
|
||||
chown -R "$SVC_USER:$SVC_USER" "$STATIC_DIR"
|
||||
ok "Static assets copied"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# PHASE 4: SYSTEMD
|
||||
# ============================================================
|
||||
header "Phase 4: Systemd"
|
||||
|
||||
cat > "$SERVICE_FILE" << SERVICEEOF
|
||||
[Unit]
|
||||
Description=Next Workspace (NextWks) Core
|
||||
Documentation=https://git.lohmar.co.uk/lexton-it/NextWks
|
||||
After=network-online.target authelia.service
|
||||
Wants=network-online.target authelia.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${SVC_USER}
|
||||
Group=${SVC_USER}
|
||||
WorkingDirectory=${INSTALL_DIR}
|
||||
ExecStart=${BIN_PATH} -config ${CONFIG_PATH}
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ReadWritePaths=${DATA_DIR} ${LOGS_DIR} ${CERTS_DIR}
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICEEOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable nextwks 2>/dev/null || true
|
||||
systemctl restart nextwks
|
||||
ok "Systemd unit installed and service restarted"
|
||||
|
||||
# ============================================================
|
||||
# PHASE 5: HEALTH CHECK
|
||||
# ============================================================
|
||||
header "Phase 5: Health Check"
|
||||
|
||||
sleep 2
|
||||
if curl -s --max-time 5 http://localhost:8080/api/health 2>/dev/null | grep -q '"status":"ok"'; then
|
||||
ok "Health check passed — NextWks v${VERSION} (${COMMIT_SHA}) is running"
|
||||
else
|
||||
warn "Health check failed — check logs: journalctl -u nextwks -n 30"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN} NextWks v${VERSION} deployed${NC}"
|
||||
echo -e "${GREEN}════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
info " Binary: ${BIN_PATH}"
|
||||
info " Config: ${CONFIG_PATH}"
|
||||
info " Data: ${DATA_DIR}"
|
||||
info " Logs: journalctl -u nextwks -f"
|
||||
info " Version: ${VERSION} (${COMMIT_SHA})"
|
||||
echo ""
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
# Pulls latest code, rebuilds, restarts NextWks only.
|
||||
# Users & auth are managed by Authelia (untouched).
|
||||
#
|
||||
# Run: cd /opt/nextwks && sudo bash update.sh
|
||||
# cd /opt/nextwks && sudo bash update.sh --wipe-db
|
||||
# Run: cd /opt/nextworkspace && sudo bash update.sh
|
||||
# cd /opt/nextworkspace && sudo bash update.sh --wipe-db
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ error() { echo -e "${RED}$1${NC}"; }
|
|||
|
||||
REPO_URL="https://git.lohmar.co.uk/lexton-it/NextWks.git"
|
||||
REPO_DIR="/tmp/nextwks-update"
|
||||
INSTALL_DIR="/opt/nextwks"
|
||||
INSTALL_DIR="/opt/nextworkspace"
|
||||
BIN_DIR="${INSTALL_DIR}/bin"
|
||||
DATA_DIR="${INSTALL_DIR}/data"
|
||||
WIPE_DB=false
|
||||
|
|
|
|||
Loading…
Reference in a new issue