fixes deployment scripts
This commit is contained in:
440
scripts/resume-deploy.sh
Normal file
440
scripts/resume-deploy.sh
Normal file
@@ -0,0 +1,440 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# ETC PRS — Resume Deployment Script
|
||||
# Picks up a failed deploy.sh run by detecting what's already been done.
|
||||
# Usage: sudo bash scripts/resume-deploy.sh
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Colours ───────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
|
||||
|
||||
info() { echo -e "${CYAN}▸ $*${RESET}"; }
|
||||
success() { echo -e "${GREEN}✓ $*${RESET}"; }
|
||||
warn() { echo -e "${YELLOW}⚠ $*${RESET}"; }
|
||||
error() { echo -e "${RED}✗ $*${RESET}"; exit 1; }
|
||||
skip() { echo -e "${GREEN}✓ $* — already done, skipping${RESET}"; }
|
||||
header() { echo -e "\n${BOLD}${CYAN}══ $* ══${RESET}\n"; }
|
||||
divider() { echo -e "${CYAN}─────────────────────────────────────────────────${RESET}"; }
|
||||
|
||||
# ── Root check ────────────────────────────────────────────────────────────────
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
error "This script must be run as root (sudo bash scripts/resume-deploy.sh)"
|
||||
fi
|
||||
|
||||
# ── Constants (must match deploy.sh) ─────────────────────────────────────────
|
||||
APP_USER="prs"
|
||||
APP_DIR="/opt/etc-prs/app"
|
||||
DATA_DIR="/var/lib/etc-prs"
|
||||
LOG_DIR="/var/log/etc-prs"
|
||||
BACKUP_DIR="/var/backups/etc-prs"
|
||||
BACKUP_SCRIPT="/opt/etc-prs/backup.sh"
|
||||
NGINX_CONF="/etc/nginx/sites-available/etc-prs"
|
||||
ECOSYSTEM="${APP_DIR}/ecosystem.config.cjs"
|
||||
|
||||
# ── Banner ────────────────────────────────────────────────────────────────────
|
||||
clear
|
||||
echo -e "${BOLD}${CYAN}"
|
||||
echo " ███████╗████████╗ ██████╗ ██████╗ ██████╗ ███████╗"
|
||||
echo " ██╔════╝╚══██╔══╝██╔════╝ ██╔══██╗██╔══██╗██╔════╝"
|
||||
echo " █████╗ ██║ ██║ ██████╔╝██████╔╝███████╗"
|
||||
echo " ██╔══╝ ██║ ██║ ██╔═══╝ ██╔══██╗╚════██║"
|
||||
echo " ███████╗ ██║ ╚██████╗ ██║ ██║ ██║███████║"
|
||||
echo " ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝"
|
||||
echo -e "${RESET}"
|
||||
echo -e " ${BOLD}Personality Editor — Resume Deployment${RESET}"
|
||||
divider
|
||||
echo ""
|
||||
|
||||
# ── State detection ───────────────────────────────────────────────────────────
|
||||
header "Detecting current state"
|
||||
|
||||
HAS_NODE=false; command -v node &>/dev/null && HAS_NODE=true
|
||||
HAS_PM2=false; command -v pm2 &>/dev/null && HAS_PM2=true
|
||||
HAS_NGINX=false; command -v nginx &>/dev/null && HAS_NGINX=true
|
||||
HAS_CERTBOT=false; command -v certbot &>/dev/null && HAS_CERTBOT=true
|
||||
HAS_USER=false; id "$APP_USER" &>/dev/null && HAS_USER=true
|
||||
HAS_REPO=false; [[ -d "${APP_DIR}/.git" ]] && HAS_REPO=true
|
||||
HAS_ENV=false; [[ -f "${APP_DIR}/.env" ]] && HAS_ENV=true
|
||||
HAS_BUILD=false; [[ -f "${APP_DIR}/build/index.js" ]] && HAS_BUILD=true
|
||||
HAS_ECOSYSTEM=false; [[ -f "$ECOSYSTEM" ]] && HAS_ECOSYSTEM=true
|
||||
PM2_RUNNING=false; pm2 list 2>/dev/null | grep -q "etc-prs" && PM2_RUNNING=true
|
||||
NGINX_ENABLED=false; [[ -L "/etc/nginx/sites-enabled/etc-prs" ]] && NGINX_ENABLED=true
|
||||
HAS_SSL=false; [[ -d "/etc/letsencrypt/live" ]] && ls /etc/letsencrypt/live/*/fullchain.pem &>/dev/null && HAS_SSL=true
|
||||
HAS_CRON=false; crontab -l 2>/dev/null | grep -q "$BACKUP_SCRIPT" && HAS_CRON=true
|
||||
HAS_ADMIN=false; [[ -f "${DATA_DIR}/personalities.db" ]] && \
|
||||
sqlite3 "${DATA_DIR}/personalities.db" "SELECT COUNT(*) FROM admins;" &>/dev/null && \
|
||||
[[ $(sqlite3 "${DATA_DIR}/personalities.db" "SELECT COUNT(*) FROM admins;") -gt 0 ]] && \
|
||||
HAS_ADMIN=true
|
||||
|
||||
echo -e " Node.js: $( $HAS_NODE && echo -e "${GREEN}✓ $(node --version)${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " PM2: $( $HAS_PM2 && echo -e "${GREEN}✓ $(pm2 --version)${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " Nginx: $( $HAS_NGINX && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " Certbot: $( $HAS_CERTBOT && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " prs user: $( $HAS_USER && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " Git repo: $( $HAS_REPO && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " .env: $( $HAS_ENV && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " Build: $( $HAS_BUILD && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " PM2 running: $( $PM2_RUNNING && echo -e "${GREEN}✓${RESET}" || echo -e "${YELLOW}✗ not running${RESET}" )"
|
||||
echo -e " Nginx site: $( $NGINX_ENABLED && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ not enabled${RESET}" )"
|
||||
echo -e " SSL cert: $( $HAS_SSL && echo -e "${GREEN}✓${RESET}" || echo -e "${YELLOW}✗ not issued${RESET}" )"
|
||||
echo -e " Backup cron: $( $HAS_CRON && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ missing${RESET}" )"
|
||||
echo -e " Admin user: $( $HAS_ADMIN && echo -e "${GREEN}✓${RESET}" || echo -e "${RED}✗ none found${RESET}" )"
|
||||
|
||||
echo ""
|
||||
divider
|
||||
echo ""
|
||||
|
||||
# ── Prompt for any info we need ───────────────────────────────────────────────
|
||||
header "Configuration"
|
||||
|
||||
# Domain — try to read from .env first
|
||||
DOMAIN=""
|
||||
if $HAS_ENV; then
|
||||
DOMAIN=$(grep "^PUBLIC_BASE_URL=" "${APP_DIR}/.env" | sed 's|PUBLIC_BASE_URL=https\?://||')
|
||||
fi
|
||||
if [[ -z "$DOMAIN" ]]; then
|
||||
while true; do
|
||||
read -rp "$(echo -e "${BOLD}Domain name${RESET} (e.g. etcprs.app): ")" DOMAIN
|
||||
DOMAIN="${DOMAIN#www.}"; DOMAIN="${DOMAIN%/}"
|
||||
[[ -n "$DOMAIN" ]] && break
|
||||
warn "Domain cannot be empty."
|
||||
done
|
||||
else
|
||||
echo -e " Domain: ${CYAN}${DOMAIN}${RESET} (read from .env)"
|
||||
fi
|
||||
|
||||
# Repo — only needed if not already cloned
|
||||
REPO_URL=""
|
||||
GITEA_PASS=""
|
||||
if ! $HAS_REPO; then
|
||||
echo ""
|
||||
read -rp "$(echo -e "${BOLD}Gitea repo path${RESET} [default: raine/etc-prs-ui]: ")" REPO_PATH
|
||||
REPO_PATH="${REPO_PATH:-raine/etc-prs-ui}"
|
||||
REPO_URL="https://git.etcprs.app/${REPO_PATH}.git"
|
||||
echo ""
|
||||
echo -e "${YELLOW}If your Gitea repo is private, enter credentials. Leave blank if public.${RESET}"
|
||||
read -rp "$(echo -e "${BOLD}Gitea username${RESET} (blank = public): ")" GITEA_USER
|
||||
if [[ -n "${GITEA_USER:-}" ]]; then
|
||||
read -rsp "$(echo -e "${BOLD}Gitea password / token${RESET}: ")" GITEA_PASS
|
||||
echo ""
|
||||
REPO_URL="https://${GITEA_USER}:${GITEA_PASS}@git.etcprs.app/${REPO_PATH}.git"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rate limits — only needed if .env is missing
|
||||
RATE_PUBLISH="5"; RATE_READ="100"
|
||||
if ! $HAS_ENV; then
|
||||
echo ""
|
||||
echo -e "${BOLD}Rate limits${RESET} (press Enter to accept defaults):"
|
||||
read -rp " Publish rate limit per IP/hour [default: 5]: " RATE_PUBLISH
|
||||
RATE_PUBLISH="${RATE_PUBLISH:-5}"
|
||||
read -rp " Read rate limit per IP/hour [default: 100]: " RATE_READ
|
||||
RATE_READ="${RATE_READ:-100}"
|
||||
fi
|
||||
|
||||
# SSL email — only needed if no cert
|
||||
SSL_EMAIL=""
|
||||
if ! $HAS_SSL; then
|
||||
echo ""
|
||||
read -rp "$(echo -e "${BOLD}Email for SSL certificate${RESET}: ")" SSL_EMAIL
|
||||
[[ -n "$SSL_EMAIL" ]] || error "SSL email is required."
|
||||
fi
|
||||
|
||||
# Admin creds — only needed if no admin exists
|
||||
ADMIN_USER=""; ADMIN_PASS=""
|
||||
if ! $HAS_ADMIN; then
|
||||
echo ""
|
||||
echo -e "${BOLD}Create the first admin account:${RESET}"
|
||||
while true; do
|
||||
read -rp " Admin username (2–32 chars): " ADMIN_USER
|
||||
[[ ${#ADMIN_USER} -ge 2 && ${#ADMIN_USER} -le 32 ]] && break
|
||||
warn "Username must be 2–32 characters."
|
||||
done
|
||||
while true; do
|
||||
read -rsp " Admin password (min 8 chars): " ADMIN_PASS
|
||||
echo ""
|
||||
[[ ${#ADMIN_PASS} -ge 8 ]] && break
|
||||
warn "Password must be at least 8 characters."
|
||||
done
|
||||
read -rsp " Confirm password: " ADMIN_PASS_CONFIRM
|
||||
echo ""
|
||||
[[ "$ADMIN_PASS" == "$ADMIN_PASS_CONFIRM" ]] || error "Passwords do not match."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -rp "$(echo -e "${BOLD}Resume deployment now? [y/N]: ${RESET}")" CONFIRM
|
||||
[[ "${CONFIRM,,}" == "y" ]] || { echo "Aborted."; exit 0; }
|
||||
|
||||
# ── Step 1: System packages ───────────────────────────────────────────────────
|
||||
header "Step 1 / 9 — System Packages"
|
||||
|
||||
if $HAS_NODE && $HAS_PM2 && $HAS_NGINX && $HAS_CERTBOT; then
|
||||
skip "All packages already installed"
|
||||
else
|
||||
info "Installing missing packages…"
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
|
||||
build-essential python3 git nginx certbot python3-certbot-nginx sqlite3 ufw curl
|
||||
|
||||
if ! $HAS_NODE; then
|
||||
info "Installing Node.js 20 LTS…"
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - > /dev/null 2>&1
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq nodejs
|
||||
fi
|
||||
|
||||
if ! $HAS_PM2; then
|
||||
info "Installing PM2…"
|
||||
npm install -g pm2 --quiet
|
||||
fi
|
||||
|
||||
success "Packages ready — Node $(node --version) / PM2 $(pm2 --version)"
|
||||
fi
|
||||
|
||||
# ── Step 2: Users & directories ───────────────────────────────────────────────
|
||||
header "Step 2 / 9 — Users & Directories"
|
||||
|
||||
if ! $HAS_USER; then
|
||||
info "Creating system user '${APP_USER}'…"
|
||||
useradd --system --shell /bin/false --home /opt/etc-prs "$APP_USER"
|
||||
success "User '${APP_USER}' created"
|
||||
else
|
||||
skip "User '${APP_USER}'"
|
||||
fi
|
||||
|
||||
for DIR in /opt/etc-prs "$APP_DIR" "$DATA_DIR" "$LOG_DIR" "$BACKUP_DIR"; do
|
||||
mkdir -p "$DIR"
|
||||
done
|
||||
chown -R "${APP_USER}:${APP_USER}" /opt/etc-prs "$DATA_DIR" "$LOG_DIR" "$BACKUP_DIR"
|
||||
success "Directories OK"
|
||||
|
||||
# ── Step 3: Clone / pull repo ─────────────────────────────────────────────────
|
||||
header "Step 3 / 9 — Repository"
|
||||
|
||||
if $HAS_REPO; then
|
||||
info "Repo already cloned — pulling latest…"
|
||||
git -C "$APP_DIR" pull
|
||||
success "Repo up to date"
|
||||
else
|
||||
info "Cloning from ${REPO_URL//:*@/:***@}…"
|
||||
git clone "$REPO_URL" "$APP_DIR" 2>&1 | \
|
||||
sed 's/'"${GITEA_PASS:-NOPASS}"'/***REDACTED***/g' || \
|
||||
error "Git clone failed. Check your repo URL and credentials."
|
||||
success "Repository cloned to ${APP_DIR}"
|
||||
fi
|
||||
|
||||
chown -R "${APP_USER}:${APP_USER}" "$APP_DIR"
|
||||
|
||||
# ── Step 4: Environment file ──────────────────────────────────────────────────
|
||||
header "Step 4 / 9 — Environment Configuration"
|
||||
|
||||
if $HAS_ENV; then
|
||||
skip ".env (${APP_DIR}/.env)"
|
||||
else
|
||||
cat > "${APP_DIR}/.env" <<EOF
|
||||
DATABASE_URL=${DATA_DIR}/personalities.db
|
||||
RATE_LIMIT_PUBLISH=${RATE_PUBLISH}
|
||||
RATE_LIMIT_READ=${RATE_READ}
|
||||
PUBLIC_BASE_URL=https://${DOMAIN}
|
||||
EOF
|
||||
chown "${APP_USER}:${APP_USER}" "${APP_DIR}/.env"
|
||||
chmod 600 "${APP_DIR}/.env"
|
||||
success ".env written"
|
||||
fi
|
||||
|
||||
# ── Step 5: Install deps & build ──────────────────────────────────────────────
|
||||
header "Step 5 / 9 — Install & Build"
|
||||
|
||||
if $HAS_BUILD; then
|
||||
skip "Build already exists (${APP_DIR}/build/index.js)"
|
||||
else
|
||||
info "Installing npm dependencies…"
|
||||
npm --prefix "$APP_DIR" install --quiet
|
||||
info "Building SvelteKit app…"
|
||||
npm --prefix "$APP_DIR" run build
|
||||
chown -R "${APP_USER}:${APP_USER}" "$APP_DIR"
|
||||
success "Build complete"
|
||||
fi
|
||||
|
||||
# ── Step 6: PM2 ───────────────────────────────────────────────────────────────
|
||||
header "Step 6 / 9 — PM2 Process Manager"
|
||||
|
||||
if $PM2_RUNNING; then
|
||||
skip "PM2 process 'etc-prs' is already running"
|
||||
else
|
||||
# Write ecosystem if missing
|
||||
if ! $HAS_ECOSYSTEM; then
|
||||
cat > "$ECOSYSTEM" <<EOF
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'etc-prs',
|
||||
script: '${APP_DIR}/build/index.js',
|
||||
cwd: '${APP_DIR}',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: '3000',
|
||||
HOST: '127.0.0.1',
|
||||
},
|
||||
error_file: '${LOG_DIR}/error.log',
|
||||
out_file: '${LOG_DIR}/out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss',
|
||||
restart_delay: 3000,
|
||||
max_restarts: 10,
|
||||
}]
|
||||
};
|
||||
EOF
|
||||
chown "${APP_USER}:${APP_USER}" "$ECOSYSTEM"
|
||||
fi
|
||||
|
||||
info "Starting app with PM2…"
|
||||
pm2 start "$ECOSYSTEM"
|
||||
pm2 save
|
||||
pm2 startup systemd -u root --hp /root | grep -E "^sudo" | bash || true
|
||||
success "PM2 running on 127.0.0.1:3000"
|
||||
fi
|
||||
|
||||
# ── Step 7: Nginx ─────────────────────────────────────────────────────────────
|
||||
header "Step 7 / 9 — Nginx"
|
||||
|
||||
if $NGINX_ENABLED; then
|
||||
skip "Nginx site already enabled"
|
||||
else
|
||||
info "Writing Nginx config for ${DOMAIN}…"
|
||||
cat > "$NGINX_CONF" <<EOF
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${DOMAIN} www.${DOMAIN};
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_types text/plain text/css application/json application/javascript
|
||||
text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_cache_bypass \$http_upgrade;
|
||||
proxy_read_timeout 30s;
|
||||
client_max_body_size 2M;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
ln -sf "$NGINX_CONF" /etc/nginx/sites-enabled/etc-prs
|
||||
nginx -t || error "Nginx config test failed — check ${NGINX_CONF}"
|
||||
systemctl reload nginx
|
||||
success "Nginx configured for ${DOMAIN}"
|
||||
fi
|
||||
|
||||
# ── Step 8: SSL ───────────────────────────────────────────────────────────────
|
||||
header "Step 8 / 9 — SSL Certificate"
|
||||
|
||||
if $HAS_SSL; then
|
||||
skip "SSL certificate already exists"
|
||||
else
|
||||
info "Requesting certificate for ${DOMAIN} and www.${DOMAIN}…"
|
||||
if certbot --nginx \
|
||||
--non-interactive \
|
||||
--agree-tos \
|
||||
--email "$SSL_EMAIL" \
|
||||
--domains "${DOMAIN},www.${DOMAIN}" \
|
||||
--redirect; then
|
||||
success "SSL certificate issued"
|
||||
certbot renew --dry-run --quiet && success "Auto-renewal check passed"
|
||||
else
|
||||
warn "Certbot failed — HTTP is still working."
|
||||
warn "Once DNS is pointing here, run:"
|
||||
warn " sudo certbot --nginx -d ${DOMAIN} -d www.${DOMAIN} --email ${SSL_EMAIL} --agree-tos"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Step 9: Backups, firewall & admin ─────────────────────────────────────────
|
||||
header "Step 9 / 9 — Backups, Firewall & Admin Account"
|
||||
|
||||
# Backup script
|
||||
if [[ ! -f "$BACKUP_SCRIPT" ]]; then
|
||||
cat > "$BACKUP_SCRIPT" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
DATE=$(date +%Y-%m-%d_%H%M)
|
||||
BACKUP_DIR=/var/backups/etc-prs
|
||||
DB_PATH=/var/lib/etc-prs/personalities.db
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
sqlite3 "$DB_PATH" ".backup ${BACKUP_DIR}/personalities-${DATE}.db"
|
||||
gzip "${BACKUP_DIR}/personalities-${DATE}.db"
|
||||
find "$BACKUP_DIR" -name "personalities-*.db.gz" -mtime +30 -delete
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') Backup OK: personalities-${DATE}.db.gz"
|
||||
EOF
|
||||
chmod +x "$BACKUP_SCRIPT"
|
||||
success "Backup script written"
|
||||
else
|
||||
skip "Backup script"
|
||||
fi
|
||||
|
||||
if $HAS_CRON; then
|
||||
skip "Backup cron job"
|
||||
else
|
||||
CRON_LINE="0 2 * * * ${BACKUP_SCRIPT} >> ${LOG_DIR}/backup.log 2>&1"
|
||||
( crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT"; echo "$CRON_LINE" ) | crontab -
|
||||
success "Backup cron job scheduled (daily at 2am)"
|
||||
fi
|
||||
|
||||
# Firewall
|
||||
info "Ensuring firewall rules are set…"
|
||||
ufw allow OpenSSH > /dev/null
|
||||
ufw allow 'Nginx Full' > /dev/null
|
||||
ufw --force enable > /dev/null
|
||||
success "Firewall OK"
|
||||
|
||||
# Admin account
|
||||
if $HAS_ADMIN; then
|
||||
skip "Admin account already exists in DB"
|
||||
else
|
||||
info "Creating admin account '${ADMIN_USER}'…"
|
||||
cd "$APP_DIR"
|
||||
node scripts/create-admin.js "$ADMIN_USER" "$ADMIN_PASS" || \
|
||||
warn "Admin creation failed — run manually: cd ${APP_DIR} && node scripts/create-admin.js <user> <pass>"
|
||||
success "Admin account '${ADMIN_USER}' created"
|
||||
fi
|
||||
|
||||
# ── Done ──────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
divider
|
||||
echo -e "${BOLD}${GREEN} Deployment complete!${RESET}"
|
||||
divider
|
||||
echo ""
|
||||
echo -e " ${BOLD}Site:${RESET} https://${DOMAIN}"
|
||||
echo -e " ${BOLD}Admin panel:${RESET} https://${DOMAIN}/admin"
|
||||
echo -e " ${BOLD}App logs:${RESET} pm2 logs etc-prs"
|
||||
echo -e " ${BOLD}DB path:${RESET} ${DATA_DIR}/personalities.db"
|
||||
echo -e " ${BOLD}Backups:${RESET} ${BACKUP_DIR}"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Redeploy after a push:${RESET}"
|
||||
echo -e " ${CYAN} cd ${APP_DIR} && git pull && \\"
|
||||
echo -e " npm install && npm run build && \\"
|
||||
echo -e " chown -R ${APP_USER}:${APP_USER} ${APP_DIR} && \\"
|
||||
echo -e " pm2 reload etc-prs${RESET}"
|
||||
echo ""
|
||||
divider
|
||||
echo ""
|
||||
|
||||
# Verify
|
||||
info "Checking app is responding on port 3000…"
|
||||
sleep 2
|
||||
if curl -sf http://127.0.0.1:3000 > /dev/null; then
|
||||
success "App is up and responding ✓"
|
||||
else
|
||||
warn "App did not respond on port 3000. Check logs: pm2 logs etc-prs --lines 30"
|
||||
fi
|
||||
echo ""
|
||||
Reference in New Issue
Block a user