What happens to your code.
Plain language. No marketing-grade vagueness. Here's the whole pipeline, from drop to running.
Upload and build pipeline
Your project is zipped and inspected in the browser before anything uploads. You see the file count and the detected framework before clicking publish. Anonymous deploys cap at 50 MB; signed-in deploys at the size your plan allows (Starter 100 MB, Live 500 MB).
The upload travels over HTTPS to api.canner.ca, where the build worker extracts it inside a per-deployment scratch directory. Builds run as the project's own Linux user (canner-<slug>) under a transient systemd unit with ProtectSystem=strict, PrivateTmp=yes, RestrictNamespaces=yes, and a cgroup memory cap matching your plan. The rebuild phase (which runs any allowlisted native-module postinstall scripts) runs with PrivateNetwork=yes — fresh netns, only the loopback interface — so build-time lifecycle scripts cannot reach the internet, Postgres, Redis, or the platform API.
When the build finishes, the source archive and scratch directory are deleted. Only the compiled runtime bundle is kept on disk.
Runtime isolation
Each project runs as its own Linux user under its own systemd unit (tenant@<slug>.service). No two tenants share a process tree, a UID, a home directory, or a writable file system path. A misbehaving tenant cannot read another tenant's files, environment, or database — host-level firewall rules block lateral movement to the platform API (4001), Postgres (5432), and Redis (6379) for every non-platform UID.
The runtime starts from an immutable bundle at /opt/canner/apps/<slug>/<deployment_id>. Updates atomic-swap a new bundle into place; rollback hard-links a previous bundle. The runtime never writes to its own bundle directory.
Database security
Every project that needs Postgres gets its own database with its own credentials. Connections route through PgBouncer; the tenant role has no access to other tenants' databases, system catalogs, or superuser functions.
Connection strings are injected at build time via the DATABASE_URL environment variable. They are never logged in build output, never echoed to clients, and never stored anywhere except inside the per-tenant runtime env file (mode 0640, owned root:canner-<slug>).
Backups are encrypted at rest, each with its own key that Canner destroys when the backup is deleted, so a deleted or expired backup, including any off-site copy in your bucket, becomes unreadable. On a dedicated instance, the point-in-time recovery archive is encrypted with AES-256 with a key unique to the instance. External access is off by default and, when on, is TLS-only and limited to the IP allowlist you set. Replication logins can read and replicate one database and nothing else; whole-server (physical) replication is closed. When a database follows an external server, changes are applied with your table owner's rights and never as a superuser, and connections to private, loopback or cloud-metadata addresses are refused.
Environment variables
Variables you set in the dashboard are encrypted at rest in the platform database using pgcrypto. They are decrypted only at build time and runtime, injected into the build sandbox / tenant runtime process, and never returned in plaintext from the API after they are written (the dashboard shows redacted previews).
Variables marked sensitive at creation are additionally scrubbed from build logs — their values are matched and replaced with [REDACTED] before any line is written to the build_log column. The log streamer the dashboard uses reads from build_log, so scrubbing is enforced on the write side, not on display.
Infrastructure
Canner runs on Canadian-owned infrastructure in Montreal, Quebec. Host-level firewall rules and fail2ban restrict inbound traffic to only ports 22 (SSH), 80, and 443. SSH is key-only — password authentication is disabled — and root login is blocked outright; privileged operations go through a restricted account with sudo access instead.
Automatic security updates run nightly via unattended-upgrades for the Debian security pocket. TLS certificates for canner.ca, *.canner.app, and customer-attached custom domains are issued and renewed automatically by Caddy via Let's Encrypt — no manual rotation, no expired-certificate window.
Daily Postgres backups run at 03:30 local and are copied off-site. Redis is authenticated; BullMQ is configured noeviction so build queue state is never lossy under memory pressure.
Responsible disclosure
If you find a security issue, email security@canner.ca with a description and reproduction steps. We will acknowledge within two business days and keep you updated until the issue is resolved.
We do not currently run a paid bug-bounty programme, but credit (with permission) is given on the changelog for any disclosure that results in a fix.
Reporting abusive content hosted on Canner — phishing, malware, a deceptive download — is a different path. Use our abuse report form; no account is needed and anonymous reports are accepted.
Read more about how Canner is structured.
Security covers the day-to-day. Sovereignty covers the legal jurisdiction your data sits under.