static-site-vps-deploy
Skill1 starsChanged 37 days agoMITView on GitHub
Use when deploying a static site to a VPS nginx.
- Deletes or force-pushes
In this repository34 other files it gives its agents.
- agent-branch-integrationSkill
- agent-config-syncSkill
- blocked-page-recoverySkill
- brand-retrofitSkill
- clickable-concept-prototypeSkill
- codebase-inspectionSkill
- commit-workSkill
- contrastive-refactor-demoSkill
- custom-domain-emailSkill
- delegate-coding-taskSkill
- delegated-agent-supervisionSkill
- delivery-verificationSkill
- domain-dns-cutoverSkill
- first-run-onboardingSkill
- frontend-render-performanceSkill
- github-pages-deploySkill
- hermes-cron-jobsSkill
- hermes-messaging-channelsSkill
- hermes-on-oracle-free-tierSkill
- hermes-provider-credentialsSkill
- isolated-worktree-testingSkill
- measurement-validitySkill
- multi-layout-previewSkill
- new-project-scaffoldingSkill
- parallel-agent-fanoutSkill
- premortemSkill
- recall-and-claim-verificationSkill
- single-source-training-materialsSkill
- stakeholder-decision-elicitationSkill
- supabase-auth-debuggingSkill
- windows-background-process-hygieneSkill
- windows-desktop-automationSkill
- windows-performance-tuningSkill
- worktree-analysisSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 6 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 97
Before editing, establish WHICH file the browser actually executes.
- Distinctive: line 115
If the value lives in the entry page, that copy is authoritative and MUST be patched too.
- Distinctive: line 136
If the server's bytes are already correct (curl+grep above) but the browser disagrees, it is cache — not the deploy.
- Distinctive: line 174
Identify the artifact the browser executes: before editing anything — bundle vs.
- Distinctive: line 178
Verify locally (open in preview) before deploy.
- Distinctive: line 179
Run the mirror deploy; read its live 200/404 checks.
- Distinctive: line 190
Don't confuse the site source with a third-party clone vendored inside it.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Deploy / mirror a static site to a VPS behind nginx
For sites that are plain files (HTML/CSS/JS, bundled SPAs) served by nginx from a directory on a VPS you reach over SSH by key. Covers the deploy script, the nginx path traps, verifying the result live, and injecting cross-framework UI like a back button.
When to Use
- publishing or updating a static site/hub of pages on a VPS (
ssh root@<ip>enters by key, nginx serves a docroot) - a page's URL has a duplicated/awkward path segment and you need to fix the route
- you removed a page and it must actually stop being reachable
- you need a "back to index" control that works across different games/apps built with different frameworks
Mirror, don't append (the #1 trap)
tar -xzf - over ssh only ADDS/overwrites files. It never deletes. So a
deploy that untars into the docroot leaves every renamed/removed file behind
as live, reachable cruft (old duplicated route, a page you "took down").
Deploy must MIRROR: what you deleted locally must disappear from the
server. Use rsync -a --delete SRC/ DEST/. Then deleting a folder in the
repo and re-running the deploy is all it takes to pull a page from the air.
When the local machine has no rsync (e.g. Windows Git Bash)
Common on Windows devices: local Git Bash has NO rsync, but the
Ubuntu VPS has /usr/bin/rsync. Do the mirror on the SERVER side:
tar -czf - --exclude=node_modules --exclude=.git --exclude=<src/offline> . \
| ssh "$SERVIDOR" "
set -e
rm -rf /tmp/site-stage && mkdir -p /tmp/site-stage
tar -xzf - -C /tmp/site-stage
rsync -a --delete /tmp/site-stage/ $DESTINO/
chown -R www-data:www-data $DESTINO
rm -rf /tmp/site-stage
"tar runs on the client (always available); rsync runs on the server (where
it exists). Check both ends first: which rsync locally and
ssh $SERVIDOR 'which rsync'.
A ready-to-copy script is in templates/deploy-mirror.sh.
Verify LIVE, including negative routes
A green deploy is not "200 on the pages I kept." It is ALSO "404 on the routes I killed." Always curl both:
codigo() { curl -s -o /dev/null -w "%{http_code}" --max-time 25 "$1" || true; }
# kept pages -> expect 200
# removed page + old duplicated route -> expect 404The || true matters on Windows Git Bash: curl prints the right code but
exits 23 writing to /dev/null, and set -e would kill the check exactly
when it passed.
Status codes are NOT behavior verification
200/404 only proves a file is reachable. It says nothing about whether your CHANGE is live. A deploy can be fully green while the bug you fixed is still in the air. After any behavior/content change, assert the changed value in the served bytes:
curl -s "$SITE/<path>/<asset>" -o srv.tmp -D hdr.tmp
grep -iE 'last-modified|etag|content-length' hdr.tmp # did it even change?
grep -c '<the new value>' srv.tmp # is the fix in there?Then exercise the actual behavior in a browser and read the number/text off the screen. "Deploy said OK" is a claim about transport, not about the fix.
The published file may not be the file you edited
Before editing, establish WHICH file the browser actually executes. A repo
often keeps a tidy modular tree (components/, data/, src/) next to a
single-file bundle that is what actually ships. Editing the modular source,
deploying green, and seeing zero change is the classic symptom.
Cheap checks, in order:
# 1. Is the entry page suspiciously huge? (300KB of "HTML" = inlined bundle)
wc -c <page>/index.html <page>/main.js <page>/data/*.js
# 2. Does it import anything, or is everything inline?
grep -nE '<script|import ' <page>/index.html
# 3. Does the value you're changing appear INSIDE the entry page?
grep -c '<the value>' <page>/index.htmlIf the value lives in the entry page, that copy is authoritative and MUST be
patched too. In the browser, document.querySelectorAll('script') returning
a single entry with src:"" and a six-figure textContent.length is the
tell: everything is inlined, nothing is fetched.
Apply the fix to BOTH the bundle and the modular source, so the readable source does not silently drift from what ships. Note in the commit message which one actually executes.
Stale cache masks a correct fix
A re-test right after deploy can serve the pre-fix asset from cache and make a good fix look broken. Before concluding failure, force a clean load — and clear any client-side state the app persists:
cdp("Network.enable"); cdp("Network.setCacheDisabled", cacheDisabled=True)
js("(() => { localStorage.clear(); return 1; })()") # apps that save progress
cdp("Page.reload", ignoreCache=True)If the server's bytes are already correct (curl+grep above) but the browser disagrees, it is cache — not the deploy.
nginx path traps
- Duplicated path segment (
/jogos/jogos/<x>): caused by a docroot that itself contains a subfolder with the same name as the location. Fix by FLATTENING at the docroot (move contents up one level) — do NOT touch the nginx config.location /jogos/ { alias /var/www/jogos/; }means the URL/jogos/<x>/maps to/var/www/jogos/<x>/, so the games belong directly in the docroot, not in a nestedjogos/. - Flattening changes relative depth: fix in-page relative refs
(
../../brand/...->../brand/...) after moving a page up a level. - Never leave a backup config in
sites-enabled/— nginx loads EVERY file in the dir, so asite.bak-<ts>beside the original breaks reload withduplicate listen options for [::]:443and downs the site. Backups go outside the dir (e.g./root/nginx-backups/).
Framework-agnostic UI injection (e.g. a back button)
To add one control to several pages built differently (one vanilla HTML, one
Vite single-file bundle), inject a self-contained <a> with INLINE styles —
no dependency on the page's CSS or framework. Anchor it position:fixed with
a high z-index. Place it BOTTOM-left, not top-left, when the app has its
own top-left nav during use (it would collide). One block works everywhere:
<a href="../" style="position:fixed;bottom:16px;left:16px;z-index:9999;...">← Todos os jogos</a>Inject after the mount node (<div id="root"> / <div id="app">) so it
survives the framework rendering into that node.
Workflow
- Find the SOURCE repo (sites are edited in the repo, not on the server).
In a typical checkout, code lives under
projects/<project>with adeploy.shat the root. - Identify the artifact the browser executes before editing anything — bundle vs. modular source (see section above). Grep for the value you are about to change and confirm every copy of it.
- Make edits locally; fix relative refs if you moved files.
- Verify locally (open in preview) before deploy.
- Run the mirror deploy; read its live 200/404 checks.
- Verify the BEHAVIOR live, not just the status codes: curl the served asset and grep for the new value, then exercise the change in a browser with cache disabled.
- Optionally
sshin to confirm the docroot and that stale dirs are gone. - Commit.
Pitfalls
- Listing a
node_modules-heavy tree withfindfloods output (700k+ chars). Scope with-maxdepthand--exclude, or list only the dirs. - Don't confuse the site source with a third-party clone vendored inside it.
- Preserve, don't delete, a page pulled from the air: move it to an
_offline/dir excluded from deploy, so it can be republished later.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

