deploy.sh: update for new auth structure (lib/, data/, better-sqlite3, pm2 reload)

This commit is contained in:
Vadym Samoilenko 2026-05-05 12:46:57 +01:00
parent 8e98b3974a
commit 596bf0bce0

116
deploy.sh
View file

@ -7,11 +7,11 @@
# Apache (port 80) → reverse proxy → Node.js (port 3000)
#
# Prerequisites (do these manually before running this script):
# git clone git@bitbucket.org:zlalani/3m-portal.git /opt/3m-portal
# Upload new code to the server (rsync or git pull), then:
#
# Usage:
# sudo bash /opt/3m-portal/deploy.sh # first-time install
# sudo bash /opt/3m-portal/deploy.sh --update # reload after git pull
# sudo bash /opt/3m-portal/deploy.sh --update # reload after code update
# =============================================================
set -euo pipefail
@ -32,7 +32,8 @@ UPDATE_ONLY=false
# ── 0. Checks ─────────────────────────────────────────────────
[[ $EUID -ne 0 ]] && error "Run as root: sudo bash deploy.sh"
[[ ! -f "$APP_DIR/server.js" ]] && error "Code not found at $APP_DIR. Clone the repo first:\n git clone git@bitbucket.org:zlalani/3m-portal.git $APP_DIR"
[[ ! -f "$APP_DIR/server.js" ]] && error "Code not found at $APP_DIR. Upload the code first."
[[ ! -d "$APP_DIR/lib" ]] && error "lib/ directory missing — make sure the full codebase is uploaded."
# ── 1. Node.js + build tools ──────────────────────────────────
if ! $UPDATE_ONLY; then
@ -44,7 +45,7 @@ if ! $UPDATE_ONLY; then
fi
info "Node.js $(node -v), npm $(npm -v)"
section "Build tools (for better-sqlite3 native module)"
section "Build tools (required for better-sqlite3 native module)"
apt-get install -y build-essential python3 make g++
info "Build tools installed"
fi
@ -75,7 +76,7 @@ section "Data directory"
mkdir -p "$APP_DIR/data"
chown "$APP_USER":"$APP_USER" "$APP_DIR/data"
chmod 700 "$APP_DIR/data"
info "Data directory: $APP_DIR/data"
info "Data directory: $APP_DIR/data (owner: $APP_USER, mode: 700)"
# ── 4. .env ───────────────────────────────────────────────────
section ".env"
@ -93,15 +94,15 @@ COOKIE_SECURE=true
SESSION_TTL_MS=28800000
INITIAL_ADMINS=[{"email":"CHANGE_ME","one2editUsername":"CHANGE_ME","password":"CHANGE_ME"}]
MAILGUN_API_KEY=CHANGE_ME
MAILGUN_DOMAIN=CHANGE_ME
MAILGUN_FROM=CHANGE_ME
MAILGUN_DOMAIN=mg.oliver.solutions
MAILGUN_FROM=noreply@mg.oliver.solutions
EOF
warn "──────────────────────────────────────────────────"
warn "Edit all values now: nano $ENV_FILE"
warn "──────────────────────────────────────────────────"
read -rp "Press Enter after updating .env to continue..."
else
info ".env already exists — skipping"
info ".env exists"
fi
if grep -q "CHANGE_ME" "$ENV_FILE"; then
@ -110,32 +111,51 @@ fi
# ── 5. Permissions ────────────────────────────────────────────
section "Permissions"
# Own all app files as nodeapp, then lock down .env and data
chown -R "$APP_USER":"$APP_USER" "$APP_DIR"
chmod 600 "$ENV_FILE"
info "Owner: $APP_USER, .env: 600"
# Re-apply data dir restriction (chown -R sets ownership but not mode)
chmod 700 "$APP_DIR/data"
info "Owner: $APP_USER, .env: 600, data/: 700"
# ── 5a. npm install ───────────────────────────────────────────
section "npm install"
cd "$APP_DIR" && sudo -u "$APP_USER" npm install --omit=dev
info "Dependencies installed"
cd "$APP_DIR" && HOME="$APP_DIR" sudo -u "$APP_USER" npm install --omit=dev
info "Dependencies installed (including better-sqlite3 native build)"
# ── 6. PM2 process ────────────────────────────────────────────
section "PM2 process"
pm2 stop 3m-portal 2>/dev/null || true
pm2 delete 3m-portal 2>/dev/null || true
if $UPDATE_ONLY; then
# Reload picks up new code + fresh .env without dropping existing sessions
if pm2 describe 3m-portal &>/dev/null; then
pm2 reload 3m-portal --update-env
info "PM2 reloaded with updated env"
else
warn "PM2 process not found — starting fresh"
pm2 start "$APP_DIR/server.js" \
--name 3m-portal \
--user "$APP_USER" \
--log /var/log/3m-portal.log \
--restart-delay 3000 \
--max-restarts 10
fi
else
pm2 stop 3m-portal 2>/dev/null || true
pm2 delete 3m-portal 2>/dev/null || true
pm2 start "$APP_DIR/server.js" \
--name 3m-portal \
--user "$APP_USER" \
--log /var/log/3m-portal.log \
--restart-delay 3000 \
--max-restarts 10
pm2 start "$APP_DIR/server.js" \
--name 3m-portal \
--user "$APP_USER" \
--log /var/log/3m-portal.log \
--restart-delay 3000 \
--max-restarts 10
env PATH="$PATH:/usr/bin" pm2 startup systemd -u "$APP_USER" --hp "$APP_DIR" \
| tail -1 | bash || warn "Run 'pm2 startup' manually if autostart is needed"
fi
pm2 save
info "PM2 process started"
env PATH="$PATH:/usr/bin" pm2 startup systemd -u "$APP_USER" --hp "$APP_DIR" \
| tail -1 | bash || warn "Run 'pm2 startup' manually if autostart is needed"
info "PM2 state saved"
# ── 7. Apache modules ─────────────────────────────────────────
if ! $UPDATE_ONLY; then
@ -145,23 +165,20 @@ if ! $UPDATE_ONLY; then
fi
# ── 8. Apache virtual host ────────────────────────────────────
section "Apache vhost"
if ! $UPDATE_ONLY; then
section "Apache vhost"
if [ -f "$APACHE_CONF" ]; then
cp "$APACHE_CONF" "${APACHE_CONF}.bak.$(date +%Y%m%d%H%M%S)"
info "Backed up existing config"
fi
if [ -f "$APACHE_CONF" ]; then
cp "$APACHE_CONF" "${APACHE_CONF}.bak.$(date +%Y%m%d%H%M%S)"
info "Backed up existing config"
fi
cat > "$APACHE_CONF" << EOF
cat > "$APACHE_CONF" << EOF
# 3M OMG Portal — Apache reverse proxy to Node.js
#
# SSL is terminated at the load balancer.
# This server receives plain HTTP on port 80 from the LB
# and proxies it to Node.js on port ${NODE_PORT}.
#
# App: ${APP_DIR}
# Note: /var/vhosts/${DOMAIN}/htdocs exists (created by DevOps)
# but is intentionally unused — all traffic goes to Node.js.
<VirtualHost *:80>
ServerName ${DOMAIN}
@ -181,17 +198,18 @@ cat > "$APACHE_CONF" << EOF
</VirtualHost>
EOF
info "Apache config written: $APACHE_CONF"
info "Apache config written: $APACHE_CONF"
# ── 9. Enable site & reload Apache ────────────────────────────
section "Apache reload"
a2ensite "${DOMAIN}.conf" 2>/dev/null || true
# ── 9. Enable site & reload Apache ────────────────────────────
section "Apache reload"
a2ensite "${DOMAIN}.conf" 2>/dev/null || true
if apache2ctl configtest 2>&1; then
systemctl reload apache2
info "Apache reloaded"
else
error "Apache config test failed — check $APACHE_CONF"
if apache2ctl configtest 2>&1; then
systemctl reload apache2
info "Apache reloaded"
else
error "Apache config test failed — check $APACHE_CONF"
fi
fi
# ── 10. Smoke test ────────────────────────────────────────────
@ -203,10 +221,12 @@ else
error "Node.js not responding. Check logs: pm2 logs 3m-portal"
fi
if curl -sf "http://127.0.0.1/" -o /dev/null; then
info "Apache proxy responding on port 80"
else
warn "Apache not responding on port 80 — check: systemctl status apache2"
if ! $UPDATE_ONLY; then
if curl -sf "http://127.0.0.1/" -o /dev/null; then
info "Apache proxy responding on port 80"
else
warn "Apache not responding on port 80 — check: systemctl status apache2"
fi
fi
# ── Done ──────────────────────────────────────────────────────
@ -216,7 +236,7 @@ echo -e "${GREEN}║ Deploy complete! ║${N
echo -e "${GREEN}║ ║${NC}"
echo -e "${GREEN}║ Portal: https://${DOMAIN}${NC}"
echo -e "${GREEN}║ Admin: https://${DOMAIN}/admin.html ║${NC}"
echo -e "${GREEN}║ App: ${APP_DIR}${NC}"
echo -e "${GREEN}║ Logs: pm2 logs 3m-portal ║${NC}"
echo -e "${GREEN}║ Update: git pull && sudo bash deploy.sh --update ║${NC}"
echo -e "${GREEN}║ DB: sqlite3 ${APP_DIR}/data/portal.db ║${NC}"
echo -e "${GREEN}║ Update: upload code → sudo bash deploy.sh --update ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"