# Strike Arena Next.js 15 standalone application for Strike Arena. The app runs on Node.js 22, stores data in SQLite through `better-sqlite3`, and is served by Nginx in Docker Compose. ## Runtime Paths - SQLite database: `/app/data/strike-arena.db` - Uploaded files: `/app/uploads` - Game images in the repository: `uploads/games` SQLite WAL and foreign keys are enabled on startup in `src/lib/bd.ts`. ## Environment Create `.env` from the example: ```bash cp .env.local.example .env ``` Required variables: ```env ADMIN_HASHED_PASSWORD= JWT_SECRET= TELEGRAM_BOT_TOKEN= TELEGRAM_CHAT_ID= ``` Generate a production `JWT_SECRET`: ```bash JWT_SECRET_NEW="$(openssl rand -base64 48 | tr -d '\n')" sed -i "s#^JWT_SECRET=.*#JWT_SECRET=${JWT_SECRET_NEW}#" .env grep '^JWT_SECRET=' .env ``` Do not deploy with `JWT_SECRET=replace-with-generated-secret`. ## Local Development ```bash npm ci npm run dev ``` Open `http://localhost:3000`. ## Production Docker The production Compose file binds Nginx to `10.20.0.25:18083`. `uploads` is mounted as `./uploads:/app/uploads` so repository images remain available and new admin uploads are persisted on the host. SQLite data is stored in the Docker volume `sqlite_data`. Deploy on `docker-runtime-2`: ```bash ssh -i /root/.ssh/docker2_vm_ed25519 crimson@10.20.0.25 sudo su mkdir -p /opt/docker-apps/strike_arena chown -R crimson:crimson /opt/docker-apps/strike_arena cd /opt/docker-apps/strike_arena git clone https://git.flamy.studio/sbb45/StikeArena_chrt.git . cp .env.local.example .env ``` Set a real `JWT_SECRET`, fill Telegram variables if notifications are needed, then prepare uploads permissions: ```bash mkdir -p uploads/games chown -R 1001:1001 uploads ``` Check the port: ```bash ss -lntup | grep ':18083' || true ``` Build and run: ```bash docker compose config docker compose build --no-cache docker compose up -d docker compose ps docker compose logs -f --tail=120 app nginx ``` Runtime checks: ```bash curl -I http://10.20.0.25:18083 curl -I http://10.20.0.25:18083/health curl -I http://10.20.0.25:18083/api/faq curl -I http://10.20.0.25:18083/api/games ``` SQLite checks: ```bash docker compose exec app node - <<'NODE' const Database = require('better-sqlite3'); const db = new Database('/app/data/strike-arena.db'); console.log(db.pragma('journal_mode', { simple: true })); console.log(db.pragma('foreign_keys', { simple: true })); db.close(); NODE ``` Expected output: ```text wal 1 ``` Check persisted paths: ```bash docker compose exec app ls -lah /app/data docker compose exec app ls -lah /app/uploads/games | head ``` ## Caddy Add this on `edge-proxy` after the app responds on `10.20.0.25:18083`: ```bash ssh -i /root/.ssh/edge_vm_ed25519 crimson@192.168.0.80 curl -I --connect-timeout 5 http://10.20.0.25:18083 curl -I --connect-timeout 5 http://10.20.0.25:18083/health sudo grep -R "belixa.ru\|10.20.0.25:18083" -n /etc/caddy || true sudo cp -a /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak.$(date +%F-%H%M%S) ``` Append the Caddy block: ```caddyfile # Strike Arena http://www.belixa.ru, https://www.belixa.ru { redir https://belixa.ru{uri} 308 } belixa.ru { encode zstd gzip reverse_proxy 10.20.0.25:18083 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto https header_up X-Forwarded-Port 443 } } ``` Reload Caddy: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl reload caddy sudo systemctl status caddy --no-pager ``` Public checks: ```bash curl -I https://belixa.ru curl -I https://www.belixa.ru curl -I http://belixa.ru curl -I http://www.belixa.ru ```