Skip to content
English
  • There are no suggestions because the search field is empty.

02.02 Upgrading via Docker

Pull the new image tag, stop the old container, start the new container with the same volume mounts. The application code comes from the new image; the database and configuration persist via the volumes; the schema migrations run on the next page load.

Why this matters

The Docker upgrade workflow is materially different from the bare-metal workflow even though the underlying SimpleRisk upgrade architecture is identical. On bare metal you replace files on disk and run the database upgrade as separate steps; on Docker you swap containers and the new container's startup runs the schema upgrade automatically. The difference is in the deployment shape, not in what's happening to SimpleRisk's data.

The honest scope to know: this article assumes you're running SimpleRisk via the official Docker images from the simplerisk/docker repository (per Installing via Docker), with persistent volume mounts for config.php, the uploads directory, and (if using embedded MySQL) the database. The upgrade workflow described here assumes that volume-mount setup; deployments with non-standard mount patterns may need adjustment.

The other thing worth knowing: the persistence pattern matters more than the upgrade procedure. If config.php isn't mounted to a persistent volume, replacing the container loses the install's database credentials and the upgrade has nothing to authenticate against. If the database is in a volume that the new container can't read, the new application code can't reach the data. Verify the volume-mount setup before the upgrade — this is one of those cases where a problem surfaced during the upgrade is much harder to fix than the same problem caught beforehand.

Before you start

Have these in hand:

  • The current SimpleRisk version — check with docker exec php -r 'require "/var/www/simplerisk/includes/version.php"; echo APP_VERSION;' or via the GET /api/upgrade/version/app endpoint.
  • The target SimpleRisk version — typically the latest release tag from the simplerisk/docker image registry. Pin to a specific version tag, not latest.
  • The release notes for every version between current and target. Each release's notes (under release_notes/ in the SimpleRisk repository) document changes including upgrade-specific notes. For multi-version upgrades, read the notes for each version in the chain.
  • A current database backup. See Database Backup and Restore. Skipping this is the single most common upgrade regret.
  • A maintenance window scheduled if your install has active users. The upgrade typically completes in minutes for routine upgrades and minutes-to-hours for upgrades that span many releases.
  • Confirmation that your volumes persist config.php, uploads, and the database. Run docker volume ls (or docker inspect ) to verify the mount points.

Step-by-step

1. Take a database backup

This is the rollback path; without it, a failed upgrade is recoverable only by running the upgrade forward through whatever issue blocked it.

For deployments using a separate MySQL container with the standard pattern:

docker exec 
  
    mysqldump -u root -p
   
     simplerisk > simplerisk-backup-$(date +%Y%m%d-%H%M%S).sql 
   
  

For deployments using embedded MySQL inside the SimpleRisk container, exec into the container first.

Verify the backup is non-empty and looks reasonable (tail simplerisk-backup-*.sql should show table-definition or insert statements, not error messages or zero bytes).

For deployments using a managed cloud database, use the cloud provider's backup mechanism (RDS automated snapshot, Azure DB on-demand backup, Cloud SQL backup) and verify the backup completed before proceeding.

2. Take a config.php backup

The config.php file holds database credentials and install-specific values. Lose it during the upgrade and you're rebuilding from scratch.

docker cp 
  
   :/var/www/simplerisk/includes/config.php ./config.php.backup 
  

If config.php is on a host bind mount, also copy it from the host filesystem; if it's on a Docker named volume, the docker cp is the easiest path.

3. Pull the new image

docker pull simplerisk/simplerisk:
   
  

Verify the image pulled successfully:

docker images simplerisk/simplerisk

For air-gapped deployments where the SimpleRisk host can't reach Docker Hub, use the standard Docker image-transfer pattern: docker save simplerisk/simplerisk: > simplerisk-image.tar on a connected machine, transfer the tarball to the SimpleRisk host, docker load < simplerisk-image.tar on the host.

4. Update the Compose file (if applicable)

If you're running with Docker Compose, edit the Compose file to reference the new image tag:

services:
  simplerisk:
    image: simplerisk/simplerisk:
  
    # changed from old version 
  

Save the file. Don't run docker compose up yet — the next step does the orchestrated upgrade.

5. Stop the current container and start the new one

For Docker Compose deployments:

docker compose down
docker compose up -d

docker compose down stops and removes the existing SimpleRisk container (and the MySQL container if it's in the same Compose file — that's fine, it'll come back with the same data via the volume mounts). docker compose up -d starts the new SimpleRisk container from the updated image, with the same volume mounts.

For non-Compose deployments, the equivalent commands are:

docker stop 
  
    docker rm 
   
     docker run -d \ --name 
    
      \ -v 
     
      :/var/www/simplerisk/includes/config.php \ -v 
      
       :/var/www/simplerisk/uploads \ -v 
       
        :/var/www/simplerisk/logs \ --link 
        
         :mysql \ -p 80:80 \ simplerisk/simplerisk:
          
         
        
       
      
     
    
   
  

The new container starts with the new application code; the persistent volumes carry forward the data and configuration.

6. Wait for the container to be healthy

docker compose ps
# OR:
docker ps

The container should show as Up and (if a healthcheck is defined) (healthy). If it shows as restarting or unhealthy, check the logs:

docker compose logs simplerisk
# OR:
docker logs 
   
  

Common startup failures: the container can't reach MySQL (network issue, MySQL container not yet ready), the volume mount for config.php is missing or empty (the new container doesn't know how to connect to the database), the new image's PHP version isn't compatible with the existing data (rare; only happens on substantial PHP-version jumps).

7. Run the database upgrade

The application code is now the new version. The database schema is still the old version. Run the upgrade to bring the database up to match.

Browser-based:

  1. Open https:// /admin/upgrade.php in a browser. Log in with admin credentials.
  2. The upgrade page detects that db_version lags APP_VERSION and runs the chain of upgrade_from_* functions documented in The Upgrade Process.
  3. Wait for the page to report success.

API-based (for scripted upgrades):

curl -H "X-API-KEY: 
  
   " \ https://
   
    /api/upgrade/upgrade/simplerisk/db 
   
  

The endpoint returns JSON status; on success, the database is now at the new version.

8. Upgrade the activated Extras

The Core upgrade doesn't bring Extras forward. After Core is at the new version, walk the activated Extras and run each one's upgrade. The full workflow is in Upgrading Extras; briefly, the API endpoints are GET /api/ /upgrade/app for each Extra.

9. Verify the upgrade end-to-end

  • Confirm APP_VERSION and db_version match: GET /api/upgrade/version/app should equal the value of db_version in the settings table.
  • Open the dashboard and confirm it loads.
  • Submit a test risk and confirm it saves correctly.
  • Trigger a test notification and confirm it sends.
  • Spot-check the logs at simplerisk/logs/ for any new errors that didn't exist before the upgrade.

If anything looks broken, the rollback path is to swap back to the old image and restore the database from the Step 1 backup (see Database Backup and Restore for the restore mechanics).

10. Update operational runbooks

After the upgrade succeeds, update any operational runbooks that reference the SimpleRisk version. The image tag pinned in Compose files, the version mentioned in deployment documentation, the version in monitoring/alerting configurations — all of these should reflect the new version so the next operator (or your future self) doesn't get confused.

Common pitfalls

A handful of patterns recur with Docker upgrades.

  • Pulling without pinning. A docker pull simplerisk/simplerisk:latest on production picks up whatever's currently latest, which may not be the version you intended. Always pin to a specific tag for production upgrades; the pinned tag is the version you tested in staging.

  • Stopping the container before backing up the database. docker compose down stops the MySQL container too (in single-Compose-file deployments). If you stopped MySQL before running mysqldump, the dump fails. Take the backup first, then stop.

  • Forgetting the config.php volume. A common deployment mistake is not mounting config.php to a persistent volume — it lives in the container's writable layer, which is destroyed when the container is replaced. The new container has no config.php and can't reach MySQL. Verify the volume mount before the first upgrade; ideally fix this on the install rather than discovering it during an upgrade.

  • Skipping the database upgrade after the image swap. The new container starts and the application loads, but the schema is at the old version. Some pages start erroring as code paths reference schema elements that don't exist yet. Run the database upgrade promptly after the image swap.

  • Running the database upgrade against a database that's still being modified. If users are still hitting the application during the upgrade, the schema changes can conflict with concurrent transactions. Take the application offline (point the load balancer's health check to a maintenance page, scale the SimpleRisk container to 0 replicas in Kubernetes, etc.) for the duration of the upgrade, or schedule the upgrade during a maintenance window.

  • Not testing the rollback path. "We can always roll back" is true only if the rollback works. Test the rollback (restore from backup, swap to old image) in a non-production environment before running the upgrade in production. The first time you exercise the rollback path shouldn't be during a production incident.

  • Ignoring the upgrade logs. The upgrade UI and API both produce logs that show the chain of upgrade_from_* functions executing. Log review is the first diagnostic step when something goes wrong post-upgrade.

  • Accumulating image tags on the host. Each pulled image takes disk space; a host that's pulled five releases over the past year has five SimpleRisk images. Periodic docker image prune keeps disk usage in check; for safety, prune after successful upgrades so the previous image is available for rollback for at least a few days.

  • Upgrading the SimpleRisk image without updating the MySQL image. The MySQL container has its own version that should be kept current for security patches. The two images upgrade on independent cadences; make sure both are current per your patch policy.

Related

Reference

  • Permission required: check_admin for the browser-based upgrade UI; valid API key for the v2 API. Server-side: Docker access, MySQL admin (for backup).
  • API endpoint(s): GET /api/upgrade/version/app (current APP_VERSION); GET /api/upgrade/backup/db (database backup orchestration); GET /api/upgrade/upgrade/simplerisk/db (run the database upgrade).
  • Implementing files: The Docker images from the separate simplerisk/docker repository; SimpleRisk's simplerisk/admin/upgrade.php (browser UI); simplerisk/includes/upgrade.php (the upgrade chain); simplerisk/includes/version.php (the APP_VERSION constant).
  • Database tables: settings (the db_version key updated atomically by update_database_version()); the schema of every other table is what the upgrade functions modify.
  • config_settings keys: db_version (the database version stamp).
  • Volume mounts: config.php (must persist), uploads directory (data continuity), logs directory (operational continuity), MySQL data directory (data persistence for embedded-MySQL deployments).
  • External dependencies: Docker Hub (or a private mirror) for image pulls; outbound HTTPS to the new image registry.