roots / roots/wp-packages

Add staging environment

Open
#39 0 comments 0 reactions 1 assignee View on GitHub

@retlehs is already working on this.

Since Mar 19, 2026.

enhancement
Dominant language
Go
Stars
143
Forks
9
PR merge metrics
No merged PRs in 30d

Description

Context

We need a staging environment to safely test changes before production. Staging will be gated with Caddy basic auth and use dedicated R2 buckets.


Step 1: Caddyfile — Add Conditional Basic Auth

File: deploy/ansible/roles/caddy/templates/Caddyfile.j2

Add a conditional basicauth * block. Production never defines caddy_basic_auth_enabled, so it's unaffected.

{% if caddy_basic_auth_enabled | default(false) %}
	basicauth * {
		{{ caddy_basic_auth_user }} {{ caddy_basic_auth_hash }}
	}
{% endif %}

Caddy uses bcrypt hashes natively — generate with caddy hash-password --plaintext '<password>'.

For Composer client testing, configure auth.json:

{"http-basic": {"staging.wp-packages.org": {"username": "staging", "password": "<pass>"}}}

Step 2: Ansible Multi-Environment Setup

2a. Update ansible.cfg

File: deploy/ansible/ansible.cfg

Remove inventory = inventory/hosts/production.yml. Inventory will be passed explicitly via -i flag to prevent accidental production deploys.

2b. Create staging inventory example

New file: deploy/ansible/inventory/hosts/staging.example.yml

all:
  hosts:
    wp-packages-staging:
      ansible_host: your.staging.server.ip
      ansible_user: deploy
      ansible_python_interpreter: /usr/bin/python3
2c. Create staging group_vars

New file: deploy/ansible/group_vars/staging/main.yml

Copy from production with these overrides:

app_domain: staging.wp-packages.org
app_env: staging
app_debug: "true"
go_log_level: debug
r2_cdn_public_url: "https://cdn-staging.wp-packages.org"
caddy_basic_auth_enabled: true
caddy_basic_auth_user: "staging"
caddy_basic_auth_hash: "{{ vault_caddy_basic_auth_hash }}"

Everything else (timers, users, litestream version, etc.) stays the same as production.

New file: deploy/ansible/group_vars/staging/vault.example.yml

Same as production vault.example.yml plus vault_caddy_basic_auth_hash: "REPLACE_ME".


Step 3: GitHub Actions Workflow

File: .github/workflows/deploy.yml

Add an environment input (choice: staging/production, default: staging):

  • concurrency: ${{ inputs.environment }}-deploy — independent locks per env
  • Conditionally use PROD_* or STAGING_* secrets based on the selected environment
  • Pass -i inventory/hosts/${{ inputs.environment }}.yml explicitly to ansible-playbook

GitHub repo setup (manual, one-time):
Add repo-level secrets: STAGING_SSH_PRIVATE_KEY, STAGING_ANSIBLE_VAULT_PASSWORD, STAGING_INVENTORY_YML_B64, STAGING_VAULT_YML_B64


Step 4: R2 Buckets (Manual in Cloudflare)

Create three staging buckets (using existing R2 API token):

  1. wp-packages-staging — Composer package metadata
  2. wp-packages-staging-cdn — CDN assets, with custom domain cdn-staging.wp-packages.org
  3. wp-packages-staging-backups — Litestream SQLite replicas

Step 5: DNS & Cloudflare (Manual)

  1. staging.wp-packages.org — A record to staging server IP (proxied through Cloudflare)
  2. cdn-staging.wp-packages.org — set up via R2 custom domain settings
  3. Generate a separate Cloudflare origin certificate for staging.wp-packages.org
  4. Store staging cert + key in staging vault (vault_ssl_certificate, vault_ssl_private_key)

Step 6: Provision & Verify

  1. Spin up staging VPS
  2. Add all STAGING_* secrets to the GitHub repo
  3. Run workflow: environment: staging, action: provision, ref: main
  4. Verify:
    • curl https://staging.wp-packages.org → 401 (basic auth required)
    • curl -u staging:<pass> https://staging.wp-packages.org → 200
    • R2 uploads land in staging buckets
    • composer require wp-plugin/akismet works with auth.json configured

Files to Create/Modify

File Action
deploy/ansible/roles/caddy/templates/Caddyfile.j2 Add conditional basicauth block
deploy/ansible/ansible.cfg Remove hardcoded inventory line
deploy/ansible/group_vars/staging/main.yml Create — staging config
deploy/ansible/group_vars/staging/vault.example.yml Create — vault key reference
deploy/ansible/inventory/hosts/staging.example.yml Create — inventory example
.github/workflows/deploy.yml Add environment input, conditional secrets, per-env concurrency
docs/operations.md Update for multi-environment support (inventory -i flag, staging secrets, etc.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.