Skip to content

feat(devops): deploy client and server to own VPS via Docker - #300

Open
Alequez97 wants to merge 10 commits into
masterfrom
feat/vps-docker-deploy
Open

Alequez97 wants to merge 10 commits into
masterfrom
feat/vps-docker-deploy

Conversation

@Alequez97

@Alequez97 Alequez97 commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Переносим хостинг gomoku.app / api.gomoku.app с Vercel + Docker Hub-only на собственный VPS (89.167.121.81) через Docker.

@Alequez97 Alequez97 changed the title feat: deploy client and server to own VPS via Docker feat(devops): deploy client and server to own VPS via Docker Sep 13, 2026
@Alequez97
Alequez97 force-pushed the feat/vps-docker-deploy branch 2 times, most recently from 3930276 to dcd9ac7 Compare September 13, 2026 17:41
Alequez97 and others added 5 commits September 13, 2026 20:41
Replace Vercel + bare Docker Hub push with a full deploy to the VPS
at 89.167.121.81 (gomoku.app / api.gomoku.app):

- docker-compose.prod.yml runs gomoku-server and rapfi from Docker
  Hub images, gomoku-server bound to 127.0.0.1:7001 (VPS port
  convention: prod ends in 1), rapfi reachable only over the internal
  docker network.
- deploy/vps-setup.sh is a one-time setup script: installs Docker,
  configures nginx for gomoku.app (static client) and api.gomoku.app
  (proxy to 7001), issues certs via certbot.
- deploy.yml now builds+pushes both Docker images, builds the client,
  rsyncs the static build and compose file to the VPS, and runs
  docker compose pull/up over SSH with a health check against
  api.gomoku.app/health.
- Bump deprecated actions/upload-artifact to v4 in build-test.yml
  (v3 is deprecated and GitHub now auto-fails runs using it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
The mix10 NNUE evaluation code requires at least one supported SIMD
instruction set; with all of them off the build failed with a
static_assert. SSE is supported by both the GitHub Actions runner and
the target VPS, so enable just that.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Without corepack enabled, GitHub Actions' ubuntu-latest runners fall
back to their preinstalled Yarn Classic, which cannot read the Yarn
Berry (4.5.0) lockfile and re-resolves dependencies from scratch -
pulling a newer TypeScript than the 5.7.2 pinned in yarn.lock and
tripping over removed baseUrl/moduleResolution=node10 options that
5.7.2 still supports.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
…tory

gomoku-story's build script runs bare "tsc" but never declared
typescript as its own dependency, relying on hoisting from gomoku-core.
On GitHub Actions runners this let PATH resolution fall through to the
preinstalled system tsc (a much newer TypeScript than the 5.7.2 pinned
in yarn.lock), which rejects the removed baseUrl/moduleResolution
options still used in tsconfig.json. Declaring the dependency
explicitly guarantees the correct local binary is linked and used.

Also removes the temporary debug step added to deploy.yml while
diagnosing this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
apt's default "nodejs" package on ubuntu:22.04 is v12.22.9, which
doesn't support optional chaining. wrapper.js's dependencies (via
express/body-parser) use "?." syntax and crash-loop at startup with
SyntaxError. Install Node 20 LTS via NodeSource instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Alequez97 and others added 2 commits September 13, 2026 21:34
Vite's default build mode is "production", so it only auto-loads
.env.production (plus the always-loaded .env.local). The prod config
was named .env.prod, so it was never picked up - the client silently
fell back to .env.local's VITE_API_URL=http://localhost:62411,
causing the deployed app to call localhost instead of api.gomoku.app.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Vite's default build mode is "production", so it only auto-loads
.env.production. Our prod config is named .env.prod (also consumed by
the .NET server's EnvironmentLoader, which hardcodes that filename),
so it was never loaded - the client silently fell back to the
always-loaded .env.local, whose VITE_API_URL=http://localhost:62411
ended up baked into the production bundle instead of
https://api.gomoku.app.

Pass --mode prod explicitly so Vite loads .env.prod instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Alequez97 and others added 2 commits September 13, 2026 22:22
Mirrors the SportsSpots layout: durable agent guidance at the repo root
plus scoped skills under .agents/skills/, capturing what this session
established about the project.

- AGENTS.md / CLAUDE.md: stack, production topology, branch/PR rules
  (DCO sign-off on every commit, required PR-title scopes), safety notes
  for the tracked env files and the shared VPS.
- deploy-operations: VPS layout, the prod-ends-in-1 port convention,
  compose/nginx/certbot setup, and the gotchas that cost time here -
  nginx needing traverse permission on the home directory, sudo being
  password-gated, RAM being the binding constraint.
- ci-pipeline: workflow inventory, merge requirements, and a playbook of
  the failures already diagnosed (deprecated upload-artifact, corepack,
  undeclared typescript dependency, rapfi SIMD flag, Node 12 in the rapfi
  image, the .env.prod vs --mode prod mismatch).
- client-build-conventions: workspace layout, env wiring rules, and the
  stale-symlink / tool-resolution traps.
- live-playtest-qa: how to verify a deploy by actually playing, including
  board coordinate calibration and the invisible game-over state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
The api.gomoku.app vhost proxied straight to 127.0.0.1:7001 with
Connection hardcoded to "upgrade", so every API request opened a fresh
TCP connection to Kestrel and every plain HTTP request claimed a
WebSocket upgrade. Default proxy_read_timeout (60s) also meant idle
SignalR game sockets were dropped whenever pings stalled.

- Add /etc/nginx/conf.d/gomoku-upstream.conf with a gomoku_api upstream
  (keepalive 32) and the standard $connection_upgrade map.
- Point the vhost at the upstream, send Connection $connection_upgrade,
  and raise proxy read/send timeouts to 3600s.
- Record the setup and its gotchas in the deploy-operations skill.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Aleksandrs Vaguscenko <aleksandrs.vaguscenko@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant