How I Built EphemerOS: A Tool for Instant, Disposable Dev Environments

How I Built EphemerOS: A Tool for Instant, Disposable Dev Environments
EphemerOS is powered by containerisation, not actually a full OS as the name might suggest.

When working on complex projects, I often ran into two big headaches: some packages just didn’t feel trustworthy, and often, some programs required me to tweak my system in ways that could break things down the line. I needed a better way to isolate such development in a way that was intuitive and would not cause too much friction against my current workflow.

That’s why I created EphemerOS - an internal tool that lets me spin up ephemeral development containers with just a few clicks through a clean UI. These containers are completely disposable, so I can test sketchy packages or run experiments that would normally force me to alter my system, all without fear of lasting damage. Once I’m done, I just destroy the container and everything goes away - no clutter, no risk.

In this blog, I’ll dive into how EphemerOS works, why it became essential for my workflow, and how it can help anyone who needs safe, temporary dev environments. This is an experimental internal tool that I will not be releasing without a rewrite.

Whilst the concept and core functionality works great, I do not use these for security research or testing malware, please do not use something like this to provide true secure isolation.

The backend

The backend is a FastAPI server that talks directly to a provided docker daemon (this is typically just the local daemon but it can work on remote ones as well!). It exposes a /create endpoint which triggers a run of the custom docker image using the Python docker library, it also provides a /list and /cleanup API. There is no functionality to delete specific EphemerOS instances as the whole point is they are very ephemeral and should be destroyed frequently, this means that the only way to destroy a EphemerOS container is to destroy all of them. I also have a job that runs once a day to clean them up, this ensures EphemerOS instances are truly ephemeral and never persist for too long.

I have a few custom CLI tools written in Go (another blog coming soon) that assist with my development, these are built from source using a docker multi-stage build, to keep the docker image as slim as possible. The Dockerfile is large and installs all of the tools I use during development, I have taken some small parts out to demonstrate below.

FROM alpine:3.22.0

# Install core tools
RUN apk update && apk add --no-cache \
    openssh \
    git \
    curl \
    zsh \
    shadow \
    && rm -rf /var/cache/apk/*

# Copy MOTD and authorized_keys
COPY /config/motd /etc/motd
COPY /config/authorized_keys /root/.ssh/authorized_keys

Example EphemerOS Dockerfile Snippet

This is a small snippet of that large Dockerfile that I use to configure and install some tools. My SSH public key is copied across so I can authenticate with the EphemerOS and I display a custom MOTD explaining the concept. All my tools are installed and managed by the Alpine package manager, APK, this makes adding and removing them extremely simple.

The frontend

The EphemerOS web panel hosted locally in my homelab, it's legacy name was 'Snaplet' hence the unchanged domain zones and panel title.

For simplicity, the frontend is just a single HTML page, it includes the JS to make the very simple API calls. It's extremely simple, very lightweight and easily maintainable, exactly what EphemerOS required. The frontend is hosted behind a reverse proxy that handles authentication via Authentik.

In the future, if the project gets more complex, I would like to use a more fully featured web framework like React to power EphemerOS however currently, the incredibly small HTML file (~2kb) is making the panel incredibly responsive and quick to load, with the largest contentful paint taking just 0.09s.

Example use case

A few weeks ago I was using Ansible to automate my Homelab, check out the full blog here, some services I deploy use roles from Ansible Galaxy. You can think of Ansible Galaxy as essentially a package manager, whilst these roles are open source and I reviewed the code, I wanted to run them in a EphemerOS instance to see exactly how they configure the LXC, instead of waiting for a container to start up every time, I could simply run the Ansible role against a EphemerOS instance which meant extremely rapid iteration and debugging as I could just dispose of broken or corrupted instances.

I also find the EphemerOS instances incredibly useful for making my development experience consistent across my devices, if I start working on a project up on my Mac, I can instantly resume it on my Windows or Linux PCs with zero downtime. My developer experience is always the same, with an identical operating system and installed tools every time. This massively increases my productivity and it continues to speed up as I add more tools and features to EphemerOS.

EphemerOS's Future

Using EphemerOS for development is great and it provides basic protection against malicious code, it does not provides true isolation as Docker containers should not be treated as a secure boundary without proper configuration. All of the EphemerOS instances are also placed in my central compute VLAN, compromise of this network could result in an attacker traversing my compute network and gaining full control over my homelab. To mitigate these issues I would like to investigate running the EphemerOS instances as a Firecracker MicroVM.

This would completely isolate the VMs and make escape extremely difficult, Firecracker is the technology that underpins the AWS serverless technology, and thus it has been battle tested and was designed with the sole purpose of having extremely rapid cold starts and isolation. These match up perfectly with EphemerOS's goals and integrating MicroVMs would be a great addition and challenge.

Solving the other networking issue is more complex and would require a dedicated host positioned in a dedicated, locked down network. Specific firewall rules could then be provisioned and destroyed as EphemerOS instances spin up and down to allow SSH sessions from my main network. This could also allow me to manage the internet access that one or many EphemerOS instances have via more firewall rules, giving me full control over them.

Final thoughts

EphemerOS was my first deep dive into dynamically provisioning Docker containers with my own code and not an orchestrator like Kubernetes, it has been a fun experience that has resulted in real world productivity improvements. I would eventually like to release it as a production ready tool once I complete the discussed Firecracker integration, watch this space!