#!/usr/bin/env bash
# =====================================================================
# Nginx Proxy Manager — native (no Docker) install on Debian 12
# ---------------------------------------------------------------------
# Built 2026-10-03 for VM 116 edge-proxy-1 (192.168.12.52). Adapted from the
# community-scripts ProxmoxVE recipe (tteck/CrazyWolf13, MIT) with two changes:
#   * OpenResty from its official apt repo (upgradable) instead of a source build
#   * certbot venv also gets certbot-dns-ionos (our DNS provider) for DNS-01 later
# Idempotent enough to re-run; `NPM_RELEASE=v2.x.y` pins a version (default: latest).
#
#   bash install-npm-baremetal.sh            # full install
#   bash install-npm-baremetal.sh --upgrade  # rebuild app from the latest release, keep /data
#
# Layout (same as the Docker image, so upstream docs apply):
#   /app                 backend + built frontend   /data        sqlite DB, generated nginx conf, custom certs
#   /etc/nginx           -> /usr/local/openresty/nginx (conf.d from the NPM repo)
#   /etc/letsencrypt     certbot state              /opt/certbot certbot venv
# Services: openresty.service, npm.service. UI: http://<ip>:81 (private networks only, nftables).
# =====================================================================
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
MODE="${1:-install}"
NPM_RELEASE="${NPM_RELEASE:-$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest | grep -oE '"tag_name": *"[^"]+"' | cut -d'"' -f4)}"
RELEASE="${NPM_RELEASE#v}"
echo "== Nginx Proxy Manager ${NPM_RELEASE} ($MODE)"

if [ "$MODE" = "install" ]; then
  echo "== OS prep"
  apt-get -qq update
  apt-get -qq -y full-upgrade
  apt-get -qq -y install curl gnupg ca-certificates lsb-release apt-transport-https \
    apache2-utils logrotate git sqlite3 nftables unattended-upgrades qemu-guest-agent \
    python3 python3-dev python3-pip python3-venv python3-cffi build-essential libffi-dev libssl-dev
  timedatectl set-timezone Europe/Berlin
  systemctl enable -q --now qemu-guest-agent unattended-upgrades

  echo "== OpenResty (official apt repo)"
  curl -fsSL https://openresty.org/package/pubkey.gpg | gpg --dearmor -o /usr/share/keyrings/openresty.gpg
  echo "deb [signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/debian $(lsb_release -sc) openresty" >/etc/apt/sources.list.d/openresty.list
  apt-get -qq update
  apt-get -qq -y install openresty
  systemctl disable -q --now openresty 2>/dev/null || true   # replaced by our unit below

  echo "== certbot venv"
  python3 -m venv /opt/certbot
  /opt/certbot/bin/pip -q install --upgrade pip setuptools wheel
  /opt/certbot/bin/pip -q install certbot certbot-dns-ionos certbot-dns-cloudflare
  ln -sf /opt/certbot/bin/certbot /usr/local/bin/certbot

  echo "== Node.js 22 + yarn"
  curl -fsSL https://deb.nodesource.com/setup_22.x | bash - >/dev/null
  apt-get -qq -y install nodejs
  npm install -g --silent yarn
fi

echo "== fetch NPM ${NPM_RELEASE}"
rm -rf /opt/nginxproxymanager && mkdir -p /opt/nginxproxymanager
curl -fsSL "https://github.com/NginxProxyManager/nginx-proxy-manager/archive/refs/tags/${NPM_RELEASE}.tar.gz" \
  | tar -xz --strip-components=1 -C /opt/nginxproxymanager

echo "== environment"
ln -sf /usr/bin/python3 /usr/bin/python
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
[ -e /etc/nginx ] && [ ! -L /etc/nginx ] && mv /etc/nginx /etc/nginx.dist-$(date +%s)
ln -sfn /usr/local/openresty/nginx/ /etc/nginx
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/backend/package.json
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/frontend/package.json
sed -i 's+^daemon+#daemon+g' /opt/nginxproxymanager/docker/rootfs/etc/nginx/nginx.conf
find /opt/nginxproxymanager -type f -name "*.conf" -exec sed -i 's+include conf.d+include /etc/nginx/conf.d+g' {} +

mkdir -p /var/www/html /etc/nginx/logs
cp -r /opt/nginxproxymanager/docker/rootfs/var/www/html/* /var/www/html/
cp -r /opt/nginxproxymanager/docker/rootfs/etc/nginx/* /etc/nginx/
cp /opt/nginxproxymanager/docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
cp /opt/nginxproxymanager/docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf
rm -f /etc/nginx/conf.d/dev.conf
[ -f /etc/nginx/conf.d/production.conf.template ] && sed 's/{{NPM_ADMIN_PORT}}/81/g' /etc/nginx/conf.d/production.conf.template >/etc/nginx/conf.d/production.conf

mkdir -p /tmp/nginx/body /run/nginx /data/nginx /data/custom_ssl /data/logs /data/access \
  /data/nginx/default_host /data/nginx/default_www /data/nginx/proxy_host /data/nginx/redirection_host \
  /data/nginx/stream /data/nginx/dead_host /data/nginx/temp /data/letsencrypt-acme-challenge \
  /var/lib/nginx/cache/public /var/lib/nginx/cache/private /var/cache/nginx/proxy_temp /etc/letsencrypt
chmod -R 777 /var/cache/nginx
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf
if [ ! -f /data/nginx/dummycert.pem ]; then
  openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" \
    -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem 2>/dev/null
fi

echo "== build frontend"
rm -rf /app && mkdir -p /app/frontend/images
cp -r /opt/nginxproxymanager/backend/* /app
export NODE_OPTIONS="--max_old_space_size=2048 --openssl-legacy-provider"
cd /opt/nginxproxymanager/frontend
sed -E -i 's/"node-sass" *: *"([^"]*)"/"sass": "\1"/g' package.json
yarn install --network-timeout 600000 --silent
yarn locale-compile >/dev/null 2>&1 || true
yarn build >/dev/null
yarn cache clean >/dev/null
cp -r dist/* /app/frontend
cp -r public/images/* /app/frontend/images

echo "== backend"
rm -f /app/config/default.json
mkdir -p /app/config
[ -f /app/config/production.json ] || cat >/app/config/production.json <<'JSON'
{
  "database": {
    "engine": "knex-native",
    "knex": {
      "client": "better-sqlite3",
      "connection": { "filename": "/data/database.sqlite" },
      "useNullAsDefault": true
    }
  }
}
JSON
cd /app && yarn install --network-timeout 600000 --silent && yarn cache clean >/dev/null

echo "== services"
cat >/lib/systemd/system/openresty.service <<'UNIT'
[Unit]
Description=OpenResty (nginx) for Nginx Proxy Manager
After=network-online.target nss-lookup.target
Wants=network-online.target

[Service]
Type=simple
ExecStartPre=-/bin/mkdir -p /tmp/nginx/body /run/nginx
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -t
ExecStart=/usr/local/openresty/nginx/sbin/nginx -g 'daemon off;'
ExecReload=/usr/local/openresty/nginx/sbin/nginx -s reload
Restart=on-failure

[Install]
WantedBy=multi-user.target
UNIT
CERTBOT_VER=$(/opt/certbot/bin/certbot --version 2>&1 | awk '{print $NF}')
cat >/lib/systemd/system/npm.service <<UNIT
[Unit]
Description=Nginx Proxy Manager
After=network.target openresty.service
Wants=openresty.service

[Service]
Type=simple
Environment=NODE_ENV=production
Environment=CERTBOT_VERSION=${CERTBOT_VER}
ExecStartPre=-mkdir -p /tmp/nginx/body /data/letsencrypt-acme-challenge
ExecStart=/usr/bin/node index.js --abort_on_uncaught_exception --max_old_space_size=250
WorkingDirectory=/app
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
UNIT
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager

if [ "$MODE" = "install" ]; then
  echo "== nftables: admin UI :81 only from private networks"
  cat >/etc/nftables.conf <<'NFT'
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy accept;
    iif lo accept
    tcp dport 81 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } accept
    tcp dport 81 drop
  }
}
NFT
  systemctl enable -q --now nftables && nft -f /etc/nftables.conf
fi

systemctl daemon-reload
systemctl enable -q openresty npm
systemctl restart openresty
systemctl restart npm
sleep 8
echo "== status"
systemctl is-active openresty npm | paste - -
curl -s -o /dev/null -w 'UI :81 -> %{http_code}\n' http://127.0.0.1:81/
curl -s -o /dev/null -w 'default :80 -> %{http_code}\n' http://127.0.0.1:80/
echo "DONE. First login: admin@example.com / changeme at http://$(hostname -I | awk '{print $1}'):81"
