Skip to content

Deploy with git or CI

Arkazzae edited this page Oct 7, 2026 · 1 revision

Use this page when the site's code arrives by git, rsync, Composer or a CI pipeline instead of the WordPress updater. SafeHouse needs three adjustments there: updates must not fight your deploys, Change alerts must not report every deploy as an intrusion, and page caches must be cleared at the end.

Stop SafeHouse from updating itself

SafeHouse installs its own updates in the background, signed, from the Design House update host. On a site you deploy from git or rsync, the next deploy would put the old version back. Turn updates off there and ship new SafeHouse versions with your deploys:

define( 'SHOUSE_DISABLE_UPDATES', true );

With this constant SafeHouse never contacts the update host, and wp shouse update-check answers "Updates are disabled by SHOUSE_DISABLE_UPDATES."

DISALLOW_FILE_MODS set to true also stops updates, because WordPress then refuses every install and update. It has side effects in SafeHouse: Install lockdown becomes Unavailable, since WordPress already blocks installs, and Hardening's file editor switch shows "Handled by wp-config.php, skipped here."

SafeHouse detects a git working copy on its own and does not update it when a .git folder is in the plugin folder (wp-content/plugins/shouse/.git) or in wp-content/plugins/. A repository at the site root or in wp-content is not detected. Set SHOUSE_DISABLE_UPDATES in that case.

To keep updates but not force them in the background, use SHOUSE_AUTO_UPDATE instead. SafeHouse switches background updates on for itself unless this constant is false:

define( 'SHOUSE_AUTO_UPDATE', false );

Updates are then offered on the Plugins and Updates screens and installed when someone selects them.

Accept deploys in Change alerts

Change alerts compares the site with a baseline every hour and e-mails what changed: new plugin folders, an edited wp-config.php, new drop-ins. A deploy changes exactly these, so the next hourly check would report it. Tell SafeHouse the new state is expected:

wp shouse watch accept

The command prints Success: Baseline updated.

accept also takes in anything else that changed since the last check, without reporting it. To report those first, run wp shouse watch check before the deploy. It prints each change, sends the alert e-mail and ends with Success: No changes. or a count.

Clear page caches at the end

Page caches are cleared when content changes in WordPress. Changes made by WP-CLI need one more step:

  • LiteSpeed page cache: a change made from WP-CLI waits for the next web request before LiteSpeed clears its cache. Run wp shouse cache purge to apply it straight away.
  • Cloudflare cache: run wp shouse cloudflare purge to clear the whole Cloudflare cache.

Install plugins while Install lockdown is on

If your deploy installs plugins or themes through WordPress, for example with wp plugin install, unlock first and lock again afterwards:

wp shouse unlock --minutes=10
wp plugin install query-monitor --activate
wp shouse lock

Code copied into place by git or rsync does not go through WordPress's installer and is not blocked.

A deploy script

This example puts the steps together. Module commands exist only while their module runs, so drop the lines for modules you do not use. With a missing module, WP-CLI stops with an error saying the command is not registered.

#!/bin/sh
set -e

wp shouse watch check          # report anything that changed since the last hourly check

# Your deploy: git pull, composer install, rsync, migrations ...

wp shouse watch accept         # the deployed state is the new baseline
wp shouse cache purge          # only with LiteSpeed page cache
wp shouse cloudflare purge     # only with Cloudflare cache
wp shouse status               # optional: show which modules run

Check SafeHouse from CI

wp shouse status --format=json prints one object per module with module, enabled, running, source and overlaps. A pipeline can fail when a module that should run does not, for example:

wp shouse status --format=json | jq -e '.[] | select(.module == "login_limits") | .running == "yes"'

Related pages

Clone this wiki locally