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 —
bashis what the deploy scripts assume. - The SSH daemon allows public-key authentication
(
PubkeyAuthentication yesin/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:
- 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 ofroot. The current platform runner expects a root-equivalent login; constraining sudo is the defence in depth. - Disable root password login in
sshd_config(PermitRootLogin prohibit-passwordorPermitRootLogin noentirely if you switched to the deploy account). - Enable an unattended-upgrades equivalent for
security patches:
unattended-upgradeson Debian/Ubuntu,dnf-automaticon the RHEL line. The platform does not patch the kernel, OpenSSL, or the SSH daemon for you. - Configure a firewall.
ufw allow OpenSSH,ufw allow 80,443/tcp,ufw enableon Debian/ Ubuntu;firewall-cmd --add-service=ssh --add-service=http --add-service=https --permanentfollowed byfirewall-cmd --reloadon the RHEL line. - 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.