ci: idempotent autodeploy to netcup host - #26
Merged
Conversation
mcp.profullstack.com pointed at 104.36.23.197, the decommissioned iCastCenter
VPS, and had never been migrated anywhere. This adds the deploy path for the
netcup host (152.53.47.37) so the endpoint has a home again.
bin/provision.sh runs on the server and is safe to re-run: every step checks
its desired state first. Two things it handles that a naive deploy misses:
- Each mcp_modules/* is its own pnpm project with its own lockfile, so a root
install does not reach them. Without the per-module loop, six modules fail
metadata load at boot and degrade silently.
- mise's shims are on the login PATH but the mise binary is not, so npm's shim
dies with "mise: command not found" under ssh/CI. PATH is fixed up explicitly.
Runtime is bun: it loads 27/27 modules, where node loads 26 -- csvjson does a
bare `import { version } from './package.json'`, which bun supports natively and
node rejects without an import attribute.
The systemd unit deliberately omits ProtectHome (the app lives under
/home/anthony/www) and pins an absolute runtime path, since systemd does not run
a login shell and would not see the shims.
TLS issuance is gated on the public A record already resolving to this host, so
the run does not burn a Let's Encrypt rate limit while DNS still points at the
dead box. Re-running after the record moves picks the certificate up.
The workflow triggers only on push-to-master and manual dispatch, never on
pull_request: the repo is public and DEPLOY_SSH_KEY grants shell on the host.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| < "$PROVISION" | ||
|
|
||
| echo "==> verifying" | ||
| if curl -fsS -m 15 --resolve "$DOMAIN:80:$DEPLOY_HOST" "http://$DOMAIN/health" >/dev/null 2>&1; then |
|
|
||
| if ! command -v mise >/dev/null 2>&1; then | ||
| log "installing mise" | ||
| curl -fsSL https://mise.run | sh |
ThreatCrush Security Scan19 finding(s) HIGH/CRITICAL: 16 | MEDIUM: 2 | LOW: 1
Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
mcp.profullstack.comresolves to104.36.23.197— the decommissioned iCastCenter VPS (Host profullstackin the SSH config, port 2048). The box is gone: 100% packet loss, 22/80/443/2048 all closed. It had never been migrated: there is nomcpservice among the 60+ custom domains in the shared Railway project.The service is now live on the netcup host (
152.53.47.37,profullstack-dev-vienna) at~/www/mcp-server, running asanthonyunder systemd behind nginx.What's here
bin/provision.sh— server-side, idempotent. Ensures mise/bun/node/pnpm, pulls the branch, installs deps, writes the systemd unit and nginx vhost, requests TLS when eligible, restarts and health-checks.bin/deploy.sh— local/CI entrypoint. Streamsprovision.shover ssh so the logic that runs is always the one from the deploying commit; bootstraps a fresh host by the same path as an update..github/workflows/deploy.yml— deploys on push tomasterand on manual dispatch.Things worth knowing
mcp_modules/*is its own pnpm project with its own lockfile. A root install does not reach them, and every module with missing deps degrades silently toCould not load metadataat boot. The per-module loop is why this matters.misebinary itself is not, sonpm's shim dies withmise: command not foundunder ssh/CI.csvjsondoes a bareimport { version } from './package.json', which bun supports natively and node rejects without an import attribute.ProtectHome(the app lives under/home/anthony/www) and pins an absolute runtime path, since systemd does not run a login shell.pull_request: this repo is public andDEPLOY_SSH_KEYgrants shell on the host.Secrets
DEPLOY_SSH_KEY,DEPLOY_HOST,DEPLOY_USER,DEPLOY_KNOWN_HOSTSare set on the repo; theproductionenvironment exists. The key is a dedicated ed25519 pair, already inanthony'sauthorized_keys.Still blocking the outage
DNS.
mcp.profullstack.comA must move from104.36.23.197to152.53.47.37at Porkbun. No Porkbun credentials exist in any logicsrc vault (Cloudflare only, which does not serve this domain), so that one step needs a manual change. Re-running the deploy afterwards picks up the certificate automatically.🤖 Generated with Claude Code