# Download page `index.php` scans `bin/gui`, `bin/client` and `bin/server` on every request and renders whatever builds it finds, with version, size and SHA-256. No database, no JavaScript, no CSS, no dependencies. The page is plain browser defaults: black text, blue links, monospace checksums. PHP 8.0+. ## Layout ``` web/ index.php the download page latest.php newest-version feed for the installers releases.php shared scanner and hash cache install.sh stable Linux installer install.ps1 stable Windows installer bin/gui/ apps, served at /bin/gui/... bin/client/ terminal clients bin/server/ servers ``` Serve `web/` as the document root. Binaries in `bin/` are gitignored. ## Naming The page only lists files that match the release pattern; anything else in those directories is ignored. ``` bin/gui/zagan-bet-gui---[.exe] bin/client/zagan-bet-client---[.exe] bin/server/zagan-bet-server---[.exe] ``` `` is `MAJOR.MINOR.PATCH`, `` is `linux`, `windows` or `macos`, `` is `x86_64`, `i686` or `aarch64`. The installers are not versioned. They read `latest.php`, pick the newest build for the machine, verify its SHA-256 and install it for the current user: Linux writes `~/.local/bin/zagan-bet-gui` plus a `.desktop` launcher, Windows writes `%LOCALAPPDATA%\Programs\Zagan-Bet` plus a Start-menu shortcut. Updating the site only needs `publish.sh`; the installer links never change. Set `ZAGAN_SITE` (Linux) or `-Site` (Windows) to test against a staging site. The Windows installer waits for Enter before closing (`-NoPause` for automation). The page links the public git repository for the GPL corresponding source. ## Publishing a build From the repository root: ```sh ./scripts/publish.sh ``` It reads the version from `Cargo.toml`, builds every artifact and installs them under `web/bin` with the names above. The GUI is built with the workspace's `gui-release` profile (LTO, stripped). Run it from a clean tree so the release commit is the source the page links to. Override the destination with `DEST=/srv/www/bin ./scripts/publish.sh`; `ALLOW_DIRTY=1` skips the clean-tree check for a preview. The installers are static and need no regeneration. Builds are per target triple, so these must be installed: `x86_64-unknown-linux-gnu`, `i686-unknown-linux-gnu` and `x86_64-pc-windows-gnu`, plus the mingw linker for the Windows build. Client builds always pass `--no-default-features`, which drops the server's OpenSSL dependency; the client is rustls-only. Cargo itself cannot produce these names: it always writes `target//release/`. The script renames after each build. ## nginx `web/nginx.conf.example` is a working server block for a subdomain with an existing certificate. On Arch-based systems: ```sh sudo pacman -S nginx php-fpm sudo install -d -o "$USER" -g http -m 0755 /srv/zagan.bet sudo cp web/nginx.conf.example /etc/nginx/conf.d/zagan.bet.conf # edit server_name, root and the certificate paths, then: sudo nginx -t && sudo systemctl enable --now nginx php-fpm ``` The pool socket and user are Arch defaults (`http`, `/run/php-fpm/php-fpm.sock`). Check them and adjust `fastcgi_pass` if your distribution differs: ```sh grep -E '^(user|group|listen)' /etc/php/php-fpm.d/www.conf ``` `rsync` publishes files as `0755`/`0644`, so the `http` worker and the php-fpm pool can read them without extra group juggling. `index.php` is the only script; any other `.php` request 404s instead of executing. PHP's opcache is enabled by default and revalidates timestamps every two seconds, so a deployed `index.php` takes effect without reloading php-fpm. If you ever set `opcache.validate_timestamps=0`, reload php-fpm after a deploy. The php-fpm unit on Arch uses `PrivateTmp=`, so the hash cache in `/tmp` lives in the service's private tmp. It still works; point `ZAGAN_HASH_CACHE` at a writable path such as `/var/cache/zagan-bet-hashes.json` if you want it to survive a service restart. ## Preview locally ```sh php -S 127.0.0.1:8899 -t web ``` Then open . ## Deploying ```sh ./scripts/publish.sh ./scripts/deploy.sh user@host:/srv/zagan.bet https://zagan.bet/ ``` `deploy.sh` rsyncs `web/` with `--delay-updates`, so a visitor never sees a half-written binary, then fetches the live page and every artifact it lists — GUI apps, installers, terminal clients and servers — and compares the downloaded bytes with the local SHA-256. `--verify-only` skips the upload and only checks the live site. Old versions are left on the server; prune them by hand. A local directory works as a target, which is how the verification itself is tested: ```sh php -S 127.0.0.1:8899 -t /srv/staging ./scripts/deploy.sh /srv/staging http://127.0.0.1:8899/ ``` ## Notes - Hashes are cached in a JSON file keyed on size and mtime, so a file is only read once until it changes. The cache lives in the system temp directory by default because the web root is often not writable by the PHP user; set `ZAGAN_HASH_CACHE` to put it elsewhere. If the cache cannot be written, the page simply hashes every request. - The page lists every build it finds, newest version first, so old releases stay downloadable until you remove them from `bin/`. - The checksum block is in `sha256sum` format, so visitors can save it as `SHA256SUMS` and run `sha256sum -c SHA256SUMS`. - The page links for the GPL corresponding source; publish only from a committed release so that link contains the exact source.