Deployment with Docker Compose

tldr;

  1. Install docker and docker compose (v2) using your distribution’s packages.

  2. Login to CheckSec container registry with docker login containers.checksec.com. Get your credentials via support@checksec.com

  3. Copy this docker-compose.yml over to host, to let’s say /srv/canopy/.

  4. Copy Canopy license file to the same directory.

  5. Run docker compose up -d.

  6. Check logs with docker compose logs -f or tail -F logs/current.

Warning

Docker will expose ports 80/443 publicly on the server and your host firewall will not block them! This is how docker works. Do your firewalling outside the host. You can change the docker-compose.yml file to bind to a specific IP in required, see https://docs.docker.com/reference/compose-file/services/#ports

Notes

  • Get your containers.checksec.com registry account via support@checksec.com

  • Only x86_64 architecture is supported at this stage.

  • podman is also supported using the docker-compose provider.

TLS Certificate

After the first startup of the containers you will have a certs directory. Place your .pem file in there. It should contain the full certificate chain as well as the private key (without a password).

The filename doesn’t matter and you can place multiple certificates, for different hostnames.

Self-signed certificates will be generated on-demand for any non-matching hostname.

Restart the canopy container after changing certificates via docker compose restart canopy

Backups

All commands below assume Canopy is installed in /srv/canopy/ and are run as root user from that directory.

Creating a backup

This approach uses pg_dump through the running PostgreSQL container, so the application can remain online.

  1. Dump the database:

    docker compose exec postgres pg_dump -U canopy -Fc canopy > canopy_db.sqlc
    
  2. Archive the application data and configuration:

    tar -zcf canopy_files.tgz config/ data/ certs/ license docker-compose.yml
    
  3. Store both canopy_db.sqlc and canopy_files.tgz in your backup location.

Restoring a backup

  1. Stop the containers:

    docker compose down
    
  2. Extract the file archive:

    tar -zxf canopy_files.tgz
    
  3. Start only the database container:

    docker compose up -d postgres
    
  4. Restore the database dump:

    docker compose exec -T postgres pg_restore -U canopy -d canopy --clean --if-exists --no-owner --no-privileges < canopy_db.sqlc
    
  5. Start the remaining containers:

    docker compose up -d
    

Migration

The instructions in Backups and recovery still hold but the exact commands will differ slightly to compensate for the use of docker.

Exporting a database dump

To create a backup of the Canopy database from the Docker PostgreSQL container:

docker compose exec -T postgres pg_dump -U canopy -F c canopy > canopy_db.sqlc

Importing a database dump

To restore a database dump into the Docker PostgreSQL container:

  1. Stop the Canopy application container first:

    docker compose stop canopy
    
  2. Restore the dump:

    docker compose exec -T postgres pg_restore -U canopy -c -C -d postgres --if-exists < canopy_db.sqlc
    

    Warning

    This will wipe the existing database before restoring the backup.

    If you need a completely clean slate (e.g., importing from a different environment), drop the database first and let pg_restore recreate it:

    docker compose exec postgres dropdb -U canopy canopy
    docker compose exec -T postgres pg_restore -U canopy -C -d postgres < canopy_db.sqlc
    

    Warning

    Check the output of pg_restore for errors. A few warnings about the public schema are normal, but other errors could indicate an incomplete import that will cause issues at runtime.

    Note

    If the restore produces errors about roles or permissions, add -O --no-privileges to the pg_restore command. This skips ownership assignments and privilege statements, which is common when importing a dump from a different environment.

  3. Start the Canopy container again:

    docker compose start canopy
    

Configuration data

Canopy’s configuration is stored in the ./config directory on the host, which is mounted into the container as /etc/canopy/.

To restore configuration data from a backup:

tar -xvf canopy_configs.tgz -C ./config --strip-components=2

Review canopy.ini after restoring to ensure any new configuration settings from the current version are preserved.

File data

Canopy stores all uploads, templates, and other files in the ./data directory on the host, which is mounted into the container as /var/opt/checksec/canopy/.

To restore file data from a backup:

tar -xvf canopy_data.tgz -C ./data --strip-components=4

Note

The --strip-components value depends on how the backup archive was created. Verify the archive structure with tar -tf before extracting.

Upgrades

  1. Run docker compose pull to pull new versions of the container images.

  2. Run docker compose up -d to recreate containers with updated images.

This will not lead to data loss as all data is stored on the host via mounts.

By default the docker-compose.yml uses the stable tag, which lags behind releases slightly but receives weekly rebuilds with updated dependencies.

Directories

  • ./config will contain the Canopy config file canopy.ini.

  • ./data contains all user data (uploaded/generated files) as well as plugins, etc.

  • ./postgresql-data contains the Postgresql RDBMS’s data.

  • ./certs for your TLS certificates.

  • ./logs file based logs for canopy container.

These directories are created automatically and prepopulated with default configurations on the first startup. This is expected behaviour even when migrating from an existing non-Docker installation — you can safely replace the generated defaults with your own data afterwards.

At each startup, permissions are corrected to match the requirements of the containers.

Data directory mapping

The ./data directory on the host is mounted to /var/opt/checksec/canopy/ inside the canopy container. This directory contains several subdirectories:

  • data/ — user uploads, generated files, report templates, etc.

  • plugins/ — installed plugins

  • backups/ — application backups

Because the host directory is called data and the container has a data subdirectory inside the mount, host paths will contain data/data/. For example, the default report template at /var/opt/checksec/canopy/data/templatedocuments/report/report_xlsx_export_template.xlsx inside the container maps to ./data/data/templatedocuments/report/report_xlsx_export_template.xlsx on the host.

Logging

By default all containers log to stdout/stderr and Docker will capture these. They are viewable via docker compose logs -f or similar command.

Additionally the Canopy container will persist logs to the ./logs directory as docker doesn’t persist logs by default.

Docker can be configured to persist logs by setting "log-driver": "journald" in /etc/docker/daemon.json. e.g. echo '{"log-driver": "journald"}' > /etc/docker/daemon.json See https://docs.docker.com/engine/logging/drivers/journald/ This requires a docker daemon restart as well as container recreation.

Troubleshooting

Start off with checking if the containers are running via docker compose ps -a. All but the init container should be running.

Next check the logs, if the issue seems application based then look at the canopy container’s logs via docker compose logs canopy.

To create a log file for uploading to our support portal, use: docker compose logs | gzip > containers.log.gz