agentleFS
thomaslimitedthomaslimited/chrome-extension-skills/skills/chrome-extension-deploy/SKILL.md

chrome-extension-deploy

Skill2 starsChanged 51 days agoMITView on GitHub

Use to deploy a Chrome extension backend (API + Postgres + admin dashboard) to a VPS, or publish/release a new extension version. Triggers: "deploy extension backend", "VPS docker nginx", "let's encrypt cloudflare 521", "publish extension update", "chrome web store api", "release extension". Covers shared-VPS topology (named Compose project, Postgres never published, API/admin on 127.0.0.1, host nginx proxy, Let's Encrypt via certbot webroot + renewal hook, Cloudflare "Full (strict)", real client IP); prod secret checks, warn-only webhook secrets; first-time setup, upload (Windows gotchas), idempotent redeploys, health checks, rollback, backups; post-deploy webhook/OAuth wiring, CORS smoke tests; `wxt zip --mode store`, dashboard upload, staged rollout, Chrome Web Store Publish API v2 for CI. Real incidents: port 80 clashes, Cloudflare 521, nginx http2 syntax, spoofed X-Forwarded-For. Skips listing copy, OAuth/payment setup, and extension code — see sibling skills.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    If the task touches those, do the deploy/release part here and hand off the rest.

    line 21
  2. Very specific:

    Treat .env.example as the contract: Every var the app reads must have a line there.

    line 37
  3. Very specific:

    Never read, print, or commit a real .env file, server.txt, *.pem, or *.key — only .env.example is safe to view or template.

    line 101
  4. Distinctive:

    Every production secret that gates money movement or auth (session secret, admin secret, webhook signing keys) must fail closed: missing or …

    line 103
  5. Very specific:

    Run a secret scan before every push (references/env-and-secrets.md has the command).

    line 109

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Chrome Extension Deploy

Scope

This skill handles shipping the backend and releasing the extension: VPS topology, Docker Compose, host nginx, TLS, secrets, the deploy/rollback runbook, and Chrome Web Store publishing.

It does not handle:

  • Store listing copy, screenshots, privacy-policy wording → chrome-web-store-listing
  • Setting up the OAuth provider or payment processor accounts themselves → chrome-extension-auth, chrome-extension-payments (this skill only wires their redirect URIs / webhook URLs once HTTPS exists)
  • Extension code, manifest, content scripts → chrome-extension-dev

If the task touches those, do the deploy/release part here and hand off the rest.

Workflow

  1. Confirm the topology before writing any config. One VPS, possibly shared with other sites, one Docker Compose project with its own name:, Postgres never published to the host, API and admin containers bound to 127.0.0.1:<port> only, host nginx as the single thing listening on 80/443, Cloudflare in front. Read references/server-topology.md.
  2. Write the Compose file and nginx vhosts from the templates, not from scratch — assets/docker-compose.prod.template.yml and assets/nginx-site.template.conf. Read references/docker-compose-and-nginx.md for what each service/directive does and why.
  3. Get TLS right before touching Cloudflare's proxy toggle. Issue the cert with certbot webroot on port 80 first, confirm nginx serves 443 directly, then enable the Cloudflare orange cloud with SSL mode "Full (strict)". Read references/tls-cloudflare.md — it documents the exact 521 failure mode when this order is reversed, plus the nginx 1.24 listen 443 ssl http2 syntax trap and X-Forwarded-For spoofing.
  4. Treat .env.example as the contract. Every var the app reads must have a line there. Production boot must refuse to start on placeholder secrets; webhook secrets are the one deliberate exception (warn-only, because they can't exist before HTTPS does). Read references/env-and-secrets.md before editing config/secret-loading code or .env.example.
  5. Run the first-time server setup once, then use the same idempotent redeploy procedure for every update after that (git pull or tarball upload → docker compose up -d --build → migration-on-boot → health check). Read references/deploy-runbook.md, including the Windows Git Bash upload gotchas if deploying from Windows.
  6. Wire what only works after HTTPS exists: PayPal/Alchemy-style webhooks, OAuth redirect URIs, the public privacy-policy URL. Smoke-test with curl /health and a CORS preflight using Origin: chrome-extension://<id>. Covered at the end of references/deploy-runbook.md.
  7. Schedule backups before declaring the deploy done. assets/backup.template.sh on a daily cron, pushed off the VPS. Restore procedure lives in the same file's header comment.
  8. For an extension release: bump the version, pnpm zip (store mode — no manifest key), verify the zip's contents, upload via the Chrome Web Store dashboard, use staged rollout for a material change. First-ever upload issues a new item ID — feed it back into ALLOWED_ORIGINS and the OAuth client's redirect URIs. Read references/extension-release.md.
  9. Automate publishing only after a manual upload has succeeded once. The Chrome Web Store Publish API (v2) can drive CI, but verify current auth/endpoint details against developer.chrome.com/docs/webstore/using-api before relying on assets/github-actions-publish.template.yml — this API is mid-migration and some details in the reference file are marked unverified.
  10. Before calling it done, check references/troubleshooting.md — real symptom → cause → fix entries from a shipped deployment (port 80 clash, Cloudflare 521, nginx syntax errors, spoofed client IP, stuck migrations, rejected webhooks, CORS failures).

Go-live checklist

#ItemRequired for
1Compose project has its own name:, Postgres has no host port mappingprod
2API and admin containers publish only 127.0.0.1:<port>prod
3Host nginx vhosts installed, nginx -t clean, reloadedprod
4Let's Encrypt cert issued via webroot, renewal hook reloads nginxprod
5Cloudflare proxied with SSL mode Full (strict), not Full or Flexibleprod (if using Cloudflare)
6.env has real values for every required var; assertProductionSecrets-style boot check passesprod
7ALLOWED_ORIGINS lists every extension ID actually in use (dev key + store ID once assigned)prod
8curl https://<domain>/health returns healthy; CORS preflight from the extension origin succeedsprod
9Daily backup cron installed and one restore has been test-runprod
10Webhooks (payment/on-chain) registered against the live HTTPS URL, signing secrets setstore launch
11OAuth redirect URIs include both the dev and store extension IDsstore launch
12Privacy policy URL is live and matches what the store listing links tostore submission
13pnpm zip --mode store output verified to exclude the dev signing keyevery release
14.gitignore/.gitattributes cover secrets and shell-script line endings; pre-push secret scan runalways

Reference files

  • references/server-topology.md — shared VPS layout, Compose project isolation, port binding, why Postgres is never published
  • references/docker-compose-and-nginx.md — Compose service walkthrough, Dockerfile choices, nginx vhost anatomy, enabling a site
  • references/tls-cloudflare.md — certbot webroot issuance/renewal, Cloudflare SSL modes, the 521 incident, nginx http2 syntax, real client IP restoration
  • references/env-and-secrets.md — .env.example as contract, production secret assertions, warn-only webhook secrets, ALLOWED_ORIGINS, git hygiene for secrets
  • references/deploy-runbook.md — first-time setup, upload methods (incl. Windows Git Bash gotchas), redeploy, migrations, health checks, logs, rollback, backups, post-deploy wiring
  • references/extension-release.md — version bump, wxt zip --mode store, dashboard upload, staged rollout, item-ID follow-up, Chrome Web Store Publish API for CI
  • references/troubleshooting.md — symptom → cause → fix, from a shipped deployment

Assets

  • assets/docker-compose.prod.template.yml — Postgres + API + admin, no host-published database, loopback-only app ports
  • assets/nginx-site.template.conf — HTTP→HTTPS redirect + ACME challenge + TLS proxy vhost, one per subdomain
  • assets/backup.template.sh — encrypted pg_dump to off-site remote storage, with restore instructions in the header
  • assets/github-actions-publish.template.yml — CI publish to the Chrome Web Store, credentials read from repo secrets (verify endpoint/auth details before use — see references/extension-release.md)
  • assets/env.example.template — annotated env-var contract with placeholder values only; copy to .env.example and fill in real names

Security

  • Never read, print, or commit a real .env file, server.txt, *.pem, or *.key — only .env.example is safe to view or template. Never SSH anywhere as part of this skill's tasks.
  • Every production secret that gates money movement or auth (session secret, admin secret, webhook signing keys) must fail closed: missing or default value either refuses boot or rejects every request to the endpoint it guards. See references/env-and-secrets.md.
  • Nginx must overwrite (not append) X-Forwarded-For from a trusted source (Cloudflare's CF-Connecting-IP via real_ip, or $remote_addr with no CDN) — a downstream service that rate-limits or gates signups on this header must never let a client set it itself.
  • Run a secret scan before every push (references/env-and-secrets.md has the command); do not rely on .gitignore alone once a secret has already been committed once.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.