research.hgphnm.com portal deployment — ubuntu 26.04, nginx 1.28.3, php 8.5-fpm

assumptions:
- nginx and php-fpm are installed, with socket /run/php/php8.5-fpm.sock
- research content is static (html/js/css/images/pdf); arbitrary PHP demos are deliberately NOT executed
- existing wildcard certificate /etc/letsencrypt/live/hgphnm.com/ is valid
- site files are under /var/www/research.hgphnm.com

1) upload this folder to VPS (example from YOUR computer, in the download directory):
   scp common.php auth.php portal.php research.hgphnm.com.conf ubuntu@YOUR_VPS_IP:/home/ubuntu/

2) on VPS, install scripts:
   sudo install -o root -g www-data -m 640 /home/ubuntu/common.php /opt/research-portal/common.php
   sudo install -o root -g www-data -m 640 /home/ubuntu/auth.php /opt/research-portal/auth.php
   sudo install -o root -g www-data -m 640 /home/ubuntu/portal.php /opt/research-portal/portal.php

3) choose a LONG secret PIN/passphrase, hashing it without placing plaintext in shell history:
   read -rsp 'new research PIN/passphrase: ' PORTAL_PIN; echo
   export PORTAL_PIN
   php -r 'echo password_hash(getenv("PORTAL_PIN"), PASSWORD_DEFAULT), PHP_EOL;' | sudo tee /opt/research-portal/pin.hash >/dev/null
   unset PORTAL_PIN
   sudo chown root:www-data /opt/research-portal/pin.hash
   sudo chmod 640 /opt/research-portal/pin.hash

4) create private directories (already done in this conversation):
   sudo install -d -o www-data -g www-data -m 700 /var/lib/research-portal/sessions
   sudo install -d -o www-data -g www-data -m 700 /var/lib/research-portal/attempts
   sudo install -d -o root -g www-data -m 750 /opt/research-portal

5) install dedicated nginx vhost (does not overwrite wildcard file):
   sudo install -o root -g root -m 644 /home/ubuntu/research.hgphnm.com.conf /etc/nginx/sites-available/research.hgphnm.com.conf
   sudo ln -s /etc/nginx/sites-available/research.hgphnm.com.conf /etc/nginx/sites-enabled/research.hgphnm.com.conf
   sudo nginx -t && sudo systemctl reload nginx

6) TEST BEFORE USING IT:
   - https://research.hgphnm.com/_portal shows PIN form
   - https://research.hgphnm.com/ should redirect to /_portal without a valid session
   - wrong PIN is rejected; correct one shows welcome with countdown
   - clicking enter loads original request if an index.html exists
   - an unauthenticated direct request to a known PDF/asset redirects to portal
   - logout revokes session on next request
   - if no index.html, visiting '/' after login will show 404 until you upload one

7) security:
   - the .htaccess file from Apache is ignored by nginx, but hidden-file access is denied
   - do NOT upload old gatekeeper.php to the new web root; PHP demos aren't executed in this config
   - no PHP endpoint in website root is permitted. Only /_portal and internal /_auth run PHP
   - valid access is enforced by nginx auth_request on each new protected request
   - countdown is display only; server enforces fixed 30-minute expiry
   - login requests rate limited to five incorrect PIN attempts per source IP in rolling 15m window
   - consider additional nginx/WAF request limits against distributed attempts/DoS
   - session records remain until access checks after expiry; optional private cleanup job can remove aged files
   - WATERMARK is on the portal only, not the changing projects or PDF bytes
   - session is shared by browser tabs; there is no per-tab welcome-screen detection
   - PHP-generated sites, Node servers, WebSockets and upload endpoints need tailored protected routing
   - HTTPS is required for the __Host- cookies
