# URL shortener — deploy (FE → BE) **Topology:** same as [INFRA.md](../../docs/INFRA.md) — TLS on Gentoo FE, app on Alpine BE `:80`. ## Prerequisites | Item | Status | |------|--------| | DNS `s.f0xx.org` → FE | Done | | FE TLS + BE nginx | Done | | MariaDB `url_shortener` | Done | | DB user | **`androidcast`** (same password as crashes `config.php`) | ## Sync to BE ```bash # From dev machine (example — adjust paths) rsync -av backend/url-shortener/ alpine-be:/var/www/localhost/htdocs/apps/s/ # On BE cp /var/www/localhost/htdocs/apps/s/config/config.example.php \ /var/www/localhost/htdocs/apps/s/config/config.php # set db.mysql.password = same as crash reporter apk add libqrencode-tools # QR PNG (/api/v1/qr/…) rc-service php-fpm81 restart ``` ## MariaDB (one-time) ```bash mysql -u root -p < sql/schema.mariadb.sql ./scripts/init-mariadb-grants.sh php scripts/seed_bearer.php --label=prod # save printed bearer token ``` Optional cron (purge expired links + audit >90d): ```cron 0 4 * * * php81 /var/www/localhost/htdocs/apps/s/scripts/purge_url_shortener.php ``` ## FE (Gentoo) See [deploy/nginx.fe-s.f0xx.org.snippet](deploy/nginx.fe-s.f0xx.org.snippet) — full URI → BE `:80`. ## BE nginx See [deploy/nginx.be-url-shortener.fragment](deploy/nginx.be-url-shortener.fragment). **Quoted regex required:** `location ~ "^/[a-f0-9]{6,16}$"` ## Verify ```bash curl -fsS https://s.f0xx.org/api/v1/health export BEARER='…' ./scripts/smoke_shorten.sh ./scripts/demo_curl.sh examples/crash_reporter/backend/scripts/validate_be_services.sh ``` ## Hub admin (Short links card) Operator UI lives in the **crashes console** (shared `ac_crash_sess`), not on `s.f0xx.org`: - `https://apps.f0xx.org/app/androidcast_project/crashes/?view=short_links` - Enable in crashes `config.php`: `url_shortener.enabled => true` + MariaDB `url_shortener` block (see `examples/crash_reporter/backend/config/config.example.php`) - Smoke: `examples/crash_reporter/backend/scripts/test_short_links_api.sh` ## Config [config/config.example.php](config/config.example.php) — prefer **`socket`** `/run/mysqld/mysqld.sock` on Alpine (same as crashes when TCP refused).