Build Replit

KINDAreplaces $25/mosaves $300/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

code-server behind authentication and TLS, one container per project so a runaway process cannot take the machine down, secrets injected at runtime rather than written into workspaces, a template system for new projects, and a deploy command that publishes a project to a real URL.

estimated effort multi-daythe files for this build are in the project pack

Editorcode-server, self-hostedIsolationOne container per project with memory and process limitsRoutingCaddy in front, one subdomain per projectSecretsInjected as environment variables at container start, never written to disk in the workspacePersistenceA volume per project, backed up

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. have ready10 to 40 USD a month depending on how many projects run at once

    Why Each project is a container with its own memory allowance, so capacity is the number of projects multiplied by their limits.

    Get it Any virtual server provider. Start with something modest and size up once you know how many projects you actually keep.

    Verify free -m shows enough memory for your intended project count and limits

  2. installfree

    Why Isolation, limits and lifecycle all come from the container runtime.

    Get it Install from Docker's own repository rather than a distribution package, which is often behind. open ↗

    Verify docker compose version reports v2 or higher

  3. have readyroughly 10 to 15 USD a year

    Why Each project gets a subdomain, and a wildcard certificate needs a DNS challenge with a provider API token.

    Get it Any registrar with DNS API access. Add a wildcard record and create a scoped token.

    Verify A wildcard hostname resolves and the token can create a TXT record

  4. decidefree

    Why A browser development environment is a remote shell. Deciding whether it is only you, a small trusted group, or anyone changes every isolation decision.

    Get it Write down who will have accounts and what happens if one is compromised. If the answer is anything beyond a small trusted group, revisit the isolation model before Phase 2.

    Verify The access decision is written down before Phase 1 is deployed

  5. a few USD a month

    Why Workspaces are people's work and the secret store exists nowhere else. Both die with the server otherwise.

    Get it Object storage with credentials scoped to one bucket.

    Verify A test file uploads and lists from your laptop

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- This is infrastructure, so the state worth writing down is operational.
- projects(id, name, subdomain, image, cpu_limit, memory_limit, created_at, last_active_at)
- volumes · one per project, holding the workspace, backed up on a schedule
- secrets · per project, stored encrypted outside any workspace, injected at container start
- templates · base images and starter files per language
- sessions · who is authenticated, and to which projects

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
BASE_DOMAINrequireddev.example.comProjects are served at subdomains of this.
DNS_API_TOKENsecretrequiredreplace-with-provider-tokenNeeded for wildcard certificate issuance through a DNS challenge.
PROJECT_MEMORY_LIMITrequired1gPer-container memory ceiling. Unset means unlimited, which is how one project takes down the host.
PROJECT_PIDS_LIMITrequired200Per-container process limit. This is what stops a fork bomb.
SECRET_STORE_KEYsecretrequiredgenerate-a-long-random-valueEncrypts the secret store at rest. Losing it loses every project's secrets, so it belongs in your password manager and in the backup.
IDLE_STOP_MINUTESrequired60How long a project may sit idle before its container is stopped.
BACKUP_DESTrequireds3://your-bucket/devWhere volumes and the secret store are copied nightly.

The build, in order

  1. One editor, behind a locked door

    code-server runs and is reachable only after authentication, over TLS.

    1. Non-root user, key-only SSH, firewall allowing SSH and the web ports. Verify with a scan from elsewhere.

      terminal
      ufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable
      nmap -Pn YOUR_SERVER_IP
    2. Publish only to 127.0.0.1 so nothing reaches it except through the proxy.

      terminal
      docker run -d -p 127.0.0.1:8080:8080 -v ~/project:/home/coder/project codercom/code-server:latest
    3. Certificate and an authentication layer. Test the unauthenticated path before celebrating the authenticated one.

      Files Caddyfile

    done when · tick each as it passes
    watch out
    • A code-server instance reachable without authentication is a remote shell on your server offered to the internet, and these get found by scanners within hours rather than days. Put authentication in front before the port is ever reachable, not after you have confirmed the editor works.
  2. One container per project

    A runaway process in one project cannot take down the server or reach another project.

    1. Memory, process count, open files and CPU shares. Defaults are unlimited, which is the problem.

      terminal
      docker run -d --memory=1g --pids-limit=200 --cpus=1 ...
    2. One volume per project, no privileged flag, no host mounts, a non-root user inside.

      Files compose/project.yml

    3. Exhaust memory, fork bomb, and attempt to read a sibling project. Each should fail in a contained way.

    done when · tick each as it passes
    watch out
    • A container without a memory limit will happily consume the host's memory until the kernel starts killing processes, and the process it kills may well be something else important. Set memory, process count and open file limits explicitly, then test each one by exceeding it on purpose.
  3. Secrets that do not end up in git

    A project can use an API key without that key being anywhere in the workspace.

    1. Encrypted at rest, per project, on the host or in a secret manager. Never inside the volume.

      Files src/secrets.ts

    2. Environment variables passed to the container. Nothing is written into the workspace at any point.

      Files compose/project.yml

    3. A recursive grep of the workspace for the secret value, run as a test. Absence is the feature.

      Files test/secrets.sh

    done when · tick each as it passes
    watch out
    • A secret written into a .env file inside the workspace is inside a git repository the moment the user runs git init, and workspaces are exactly what people push. Inject at container start so the value exists in the process environment and never in a file the user can commit.
  4. Templates and a new project in one command

    Starting a project takes seconds rather than an afternoon of setup.

    1. Runtime, package manager and common tools baked in. Rebuild on a schedule to pick up security updates.

      Files images/

    2. Volume, container, route, certificate and starter files in one action, reporting how long it took.

      Files src/create.ts

    3. Container, volume, route, certificate and secrets. A partial delete leaves a subdomain pointing at nothing and secrets nobody is using.

      Files src/delete.ts

    done when · tick each as it passes
    watch out
    • Installing a language runtime on first use inside a generic container means every new project starts with several minutes of downloading. Bake the runtime into the image so a new project is ready in seconds, and rebuild images on a schedule rather than at project creation.
  5. Deploying what you built

    A project goes from editor to a public URL with one command.

    1. From the project source, not from the development container. Different container, different limits, no editor.

      Files src/deploy.ts

    2. Separate from the development subdomain, with its own certificate.

      Files Caddyfile

    3. Retain the prior image and a rollback command. Test by deploying something broken.

      Files src/rollback.ts

    done when · tick each as it passes
    watch out
    • Serving the development container publicly means the editor, the workspace and any process the user started are all exposed on the public URL. Deploy a separate container built from the project, and keep the development environment private.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.