If you’ve used Upsun, you’ve likely noticed something unusual when SSH’ing into your container: the filesystem is read-only. You deploy an application, log in to investigate, attempt to create a directory, and encounter this error:Documentation Index
Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
Use this file to discover all available pages before exploring further.
Security: eliminating entire attack vectors
Read-only filesystems eliminate entire classes of security vulnerabilities. Common attack patterns become impossible: Consider CMS vulnerabilities where attackers upload malicious executables and compromise websites. With read-only filesystems, these attacks fail at the most fundamental level. Container escape vulnerabilities that rely on writing to host filesystems—such as CVE-2019-5736, which allowed attackers to overwrite the host container runtime binary—cannot succeed when the filesystem rejects all write operations. Without write access, attackers cannot:- Upload backdoors or web shells
- Modify application code to inject malicious functionality
- Install persistence mechanisms
- Alter system binaries for privilege escalation
The trade-off: managing multiple filesystem layers
This architecture does introduce complexity. We maintain separate filesystems for/app (your application code) and / (the base operating system). We don’t rebuild your application every time we patch a Debian package on the root filesystem. This requires managing different SquashFS images for each layer.
This approach demands strict ABI (Application Binary Interface) stability. Breaking the ABI would cause applications to fail. That’s why specific versions of container images remain on the same Debian version permanently. Once you’re running type: python:3.11 with Debian 11, that combination stays locked to Debian 11 throughout its lifecycle. This constraint ensures compatibility but reduces flexibility in base system updates.
Reproducibility: what you deploy is what you get
Upsun environments map directly to git branches. What you deploy is precisely what runs on the server. Files cannot be modified because they’re read-only. This guarantees reproducibility and integrity. When you merge code from staging to production, you’re deploying the identical filesystem image. There’s no configuration drift, no manual modifications, no “works on my machine” discrepancies. The code that passed testing is byte-for-byte identical to what runs in production.Explicit state management: declaring what changes
Read-only infrastructure requires explicit declaration of writable directories. Rather than allowing arbitrary filesystem writes, you specify which directories need write access for uploads, cache, or temporary data. This intentionality makes application behavior predictable and state management explicit. Configure writable mounts in your.upsun/config.yaml:
Infrastructure benefits: platform-wide read-only design
The entire Upsun infrastructure operates on read-only filesystems. This eliminates an entire category of operational problems: in-place system upgrades. Distribution upgrades and live system patching are notoriously difficult. Package conflicts, dependency resolution failures, configuration file drift, and partial upgrade states create unpredictable system behavior. When managing infrastructure at scale, these issues multiply—each host becomes a unique snowflake with its own upgrade history and potential failure modes. Read-only infrastructure sidesteps this complexity entirely. We don’t runapt-get upgrade on live systems. We build new VM images with updated packages, test them thoroughly, and replace running VMs wholesale. This approach requires solving different technical challenges (particularly safe VM replacement under load), but once implemented, it eliminates the fragility and unpredictability inherent in in-place upgrades.
The operational benefits scale significantly. When managing thousands of VMs across multiple cloud providers, knowing that every VM is identical eliminates entire classes of debugging sessions. Configuration drift between hosts becomes impossible. When functionality is verified on one VM, it functions identically on all VMs running that image.