Code</>sensei runs against a minimal install of any of the following Linux distributions. The platform will install the runtime dependencies your project needs at deploy time; you do not need to pre-install Python, Node, gunicorn, or any reverse proxy.

Supported distributions

  • Debian 12 (Bookworm). Tested most heavily. The default OS for the public cloud images we recommend.
  • Ubuntu 22.04 LTS and Ubuntu 24.04 LTS. Same package selection as Debian; apt-based.
  • AlmaLinux 9 and Rocky Linux 9. RHEL-derived; dnf-based. Tested but used less in production than Debian.
  • FreeBSD 14. Earlier FreeBSD versions work but are not tested per release. The platform substitutes pkg for apt/dnf and rc.d service units in place of systemd, but the deploy script shape is otherwise the same.

If your distribution is not listed above, the deploy will still run but the script may fail at the package-installation step. The captured log will tell you exactly which command failed.

Pre-install checklist

None of these are strictly required, but a clean box with these items already done deploys faster and avoids common surprises:

  • System time is synchronised (NTP / chrony / systemd-timesyncd running).
  • The login the platform will use exists with a stable shell — bash is what the deploy scripts assume.
  • The SSH daemon allows public-key authentication (PubkeyAuthentication yes in /etc/ssh/sshd_config). This is the OpenSSH default on every supported distribution.
  • Inbound TCP on port 80 and 443 is open from the public internet (or whichever IP range your end users will hit) so the edge proxy can terminate TLS for your application.
  • Inbound TCP on port 22 is open from your IP and from the platform's egress range — the latter is published as a JSON list at https://codesensei.cloud/network/egress.json.

Recommended hardening

The platform works on a stock image, but the steps below reduce your exposure if anything goes wrong:

  1. Create a dedicated deploy user. Add a user named deploy, give it passwordless sudo for the narrow set of commands the deploy script needs (systemctl restart <slug>, apt install <pkg>, …), and use that account in the Add Server form instead of root. The current platform runner expects a root-equivalent login; constraining sudo is the defence in depth.
  2. Disable root password login in sshd_config (PermitRootLogin prohibit-password or PermitRootLogin no entirely if you switched to the deploy account).
  3. Enable an unattended-upgrades equivalent for security patches: unattended-upgrades on Debian/Ubuntu, dnf-automatic on the RHEL line. The platform does not patch the kernel, OpenSSL, or the SSH daemon for you.
  4. Configure a firewall. ufw allow OpenSSH, ufw allow 80,443/tcp, ufw enable on Debian/ Ubuntu; firewall-cmd --add-service=ssh --add-service=http --add-service=https --permanent followed by firewall-cmd --reload on the RHEL line.
  5. Enable swap on small instances. The Python deploy script peaks at about 400 MB of resident memory during dependency installation. On a 1 GB server, a 1 GB swap file prevents OOM kills during the first deploy of a heavy project.

Cloud provider notes

Hetzner Cloud: The CX line and CCX line both work. The default Debian 12 image is what we test against. If you use Hetzner's cloud-init user_data to pre-create a deploy user, drop the platform's pubkey into its authorized_keys as part of that user_data so the very first deploy succeeds without the manual paste step.

DigitalOcean: Same recipe as Hetzner. The base Debian and Ubuntu droplets work out of the box.

AWS EC2: Use the Ubuntu LTS or Debian AMI. The default ubuntu user works; add the platform's pubkey to its authorized_keys instead of the root account, since the Ubuntu AMI ships with PermitRootLogin no.

Bare-metal or KVM/Proxmox: Anything that runs one of the supported distributions and lets you set authorized_keys for one login will work. The platform has no minimum-bandwidth or minimum-CPU requirement; deploys are serialised one at a time per server, so a t3.micro / CX11-class box is enough for a small site.

Network egress from the platform

The platform's worker connects out to your server from a fixed set of public IPs. If you run a strict ingress firewall and only allow port 22 from named ranges, allow-list the JSON list at https://codesensei.cloud/network/egress.json. The list is updated when worker capacity is added or moved; subscribe to its Last-Modified header or refresh nightly. We do not promise a static IP per customer — that would require dedicated worker infrastructure per tenant — but the list is stable enough for an allow-list to remain valid for weeks at a stretch.

From your server outward, the deploy script needs HTTPS egress on port 443 to reach the host of your Git repository (GitHub, GitLab, Bitbucket, or self-hosted), and HTTPS egress to pypi.org and the registry your Node project pulls from (default registry.npmjs.org). If you proxy outbound traffic through a corporate gateway, set HTTPS_PROXY on the project's environment-variable form and the deploy script honours it for both pip and npm.

Disk and memory sizing

The platform keeps the five most recent successful release directories on disk so that roll-backs are instant. Each release directory holds your repository's working tree plus its virtual environment or node_modules. For Django projects with a typical dependency tree, expect roughly 250–500 MB per release; for Node.js projects with a deep node_modules, expect 500 MB – 1.5 GB per release. A 10 GB root disk is sufficient for most projects; a 20 GB disk leaves comfortable headroom for log files, package caches, and any media uploads you keep under shared/media/.

The platform tunes the gunicorn worker count to the server's CPU count by default. Sub-1 GB instances should set GUNICORN_WORKERS=1 on the project's environment-variable form to avoid swap thrash during traffic peaks; 1–2 GB instances do well with two workers; anything above 2 GB scales linearly. Node.js processes are single-process by default and the runtime allocates according to demand — set NODE_OPTIONS=--max-old-space-size=512 or similar on very small servers to keep V8 from growing past available RAM.

What the first deploy installs

During first-deploy provisioning, the script installs a baseline of operating-system packages that essentially every Django or Node deploy needs. On Debian/Ubuntu the list is: build-essential, git, python3, python3-pip, python3-venv, libpq-dev, libffi-dev, libjpeg-dev, zlib1g-dev, nodejs, npm, and the edge proxy package. On RHEL-derived distributions the equivalent dnf packages are installed via the corresponding group names. The provisioning step is idempotent — if a package is already installed, the script no-ops on it — so repeated runs of the first-deploy flow against the same server are safe.