Skip to content

Upgrading and Releases

github-actions[bot] edited this page Oct 9, 2026 · 2 revisions

Upgrading and Releases

Which version to run

Only the latest tagged release is supported. Deploy from a tagged release (vX.Y.Z), never from main. Every release publishes:

  • the container image to both registries, ghcr.io/solarssk/wp-critical-css and docker.io/solarssk/wp-critical-css, tagged latest, X.Y.Z, X.Y and a short commit hash;
  • the plugin zip, wp-critical-css-X.Y.Z.zip, signed from 0.2.7 on (Install the Plugin);
  • an SBOM for the image, and release notes taken from the changelog.

The service and the plugin version together. When you upgrade one, upgrade the other.

Upgrade

  1. Read the changelog entry for the release, in particular its Deploy section: it lists anything you have to change in your setup.

  2. Update the service. If your compose file uses :latest, pull and recreate. If you pinned a version, change the tag first. A service that is built from the repository (build:) is not pulled: change the tag in its context: (...git#vX.Y.Z) and run docker compose up -d --build critical-css-service.

    docker compose pull critical-css-service
    docker compose up -d critical-css-service

    If you use egress filtering, name both compose files in every command. Without the second file Compose does not know the guard, and up -d recreates the service from the base file alone, dropping network_mode: service:egress-guard: the service then runs with no network filtering at all, and the only hint is a warning about an orphan container.

    docker compose -f docker-compose.yml -f docker-compose.egress.example.yml pull critical-css-service
    docker compose -f docker-compose.yml -f docker-compose.egress.example.yml up -d critical-css-service

    Also compare your copy of docker-compose.egress.example.yml with the new one: the start command in it has to stay in step with the image.

  3. Update the plugin. Upload the new zip under Plugins > Add New Plugin > Upload Plugin; WordPress offers to replace the installed version.

  4. Check the health answer (docker exec critical-css-service sh -c 'wget -qO- http://localhost:${PORT:-3939}/health') and a page's source (Getting Started). With egress filtering, also run its Verify command: it must print OK. A service that was recreated without the guard still answers /health.

CSS that is already stored keeps working. New CSS is generated when a page is saved or swept, so run a sweep (Getting Started) if you want every page regenerated by the new version.

Upgrading from 0.2.8

The release after 0.2.8 loads your pages and their stylesheets with the service's own code instead of the critical package. There is nothing new to configure, and for an ordinary page the critical CSS is the same. What changes is that the service is stricter and bounded where the old one was lenient:

  • Allow the new User-Agent if a firewall or bot filter in front of your site decides by it. Every request for a page or a stylesheet now says Mozilla/5.0 (compatible; wp-critical-css/<version>; +https://github.com/solarssk/wp-critical-css).
  • Some jobs that used to "succeed" now fail, with a reason in the log. A page that answers with an error status (a maintenance or bot-challenge page used to be processed as your page), a stylesheet on your own site that cannot be loaded (it used to be dropped silently), a redirect to a host name other than ALLOWED_HOSTNAME (typically www. against no www.), and pages over the new limits (more than 100 stylesheets, a stylesheet over 2 MiB, all of them over 8 MiB). A failed job delivers nothing, so the CSS WordPress already has for that page stays.
  • Stylesheets on other hosts are optional. One that cannot be loaded (a CDN, a font service) is left out and logged as a warning, as it was left out silently before.
  • Nothing is retried inside a job. One transient error on a stylesheet of your own site fails that job; the next save or sweep queues the page again.
  • Very large pages can still run the container out of memory. The new limits fail an oversize page early, but a page inside them can still be more than the example compose file's 1 GiB can lay out (think of more than about 2 MiB of CSS in all, or about 2 MiB of HTML). The rendering stage (penthouse and Chrome) is the same code as in 0.2.8, so this is not a new limit; it was not re-measured on 0.2.8. See Out of memory for the two signatures and for mem_limit.

After upgrading, run a sweep (Getting Started) and read the log for lines that start with [critical-css] failed for or [critical-css] skipping. Troubleshooting explains every message, and the deployment guide has the complete list of differences.

Why updating matters

The service loads your pages in headless Chrome. The Chrome build is pinned in the image to a recent Stable release, and a fix for a Chrome vulnerability reaches you only inside a new release. The project checks the pin against Chrome's current Stable build every day and flags a pin that has fallen more than 7 days behind, but you still have to pull the release.

Roll back

Deactivate (or delete) the plugin in wp-admin and remove the container with docker compose down (with both -f flags if you use egress filtering; the example compose file sets restart: always, so a container that is only stopped comes back after a reboot). Nothing else depends on this pipeline: stylesheets simply go back to loading render-blocking, exactly as before the plugin existed. The stored CSS stays in your database, unused.

To go back to an earlier version instead, pin the image tag (X.Y.Z) and upload that version's plugin zip. Only the latest release is supported, so treat that as a way to get unstuck, not a place to stay.

Cutting a release (maintainers)

A release is made by merging a release: vX.Y.Z pull request to main. Nothing else is done by hand: the merge creates the tag and the GitHub Release and starts both publish workflows. The checklist, the files that must move together and the manual fallback are in the deployment guide.

Clone this wiki locally