This repository is a VS Code Dev Containers template. It provides a reproducible Ubuntu-based development environment with common system packages, a Python virtual environment, forwarded SSH-agent access, and optional setup tasks for project checkout, opencode, and Ghidra.
The container is intended to keep heavyweight or machine-specific setup out of the workspace while still making new environments quick to rebuild.
VS Code is the most integrated workflow, but it is not required. For shell-first use over SSH on a Linux host, see Using the Devcontainer Outside VS Code.
- What Is Included
- First-Time Setup
- Adding Packages
- Adding Setup Logic
- Adding VS Code Tasks
- Optional Tools
- Useful Commands
- Maintenance Notes
- Additional Docs
- Ubuntu Noble base image from the official Dev Containers images.
- Docker-in-Docker support through the Dev Containers feature.
- Apt packages listed in
.devcontainer/pkgs/apt-pkgs. - A
vscodeuser post-create setup that installsuv, creates~/.venv, installs Python packages from.devcontainer/pkgs/pip-pkgs, and configures shell history plus venv activation. - Host SSH-agent forwarding so Git and SSH inside the container can use your host keys without copying private keys into the container.
- VS Code tasks for cloning projects and installing optional tools.
-
Install the prerequisites on your host:
- VS Code
- Docker Desktop, or Docker Engine on native Linux
- The VS Code Dev Containers extension
- Git and an SSH key loaded into your host SSH agent
-
Set up SSH-agent forwarding for your host OS.
See SSH key setup for macOS, Windows, and native Linux notes. The short version is: load your key into your host agent, then let the devcontainer bind-mount that agent socket into the container at
/ssh-agent. -
Open this repository in VS Code.
-
Run Dev Containers: Reopen in Container from the command palette.
-
Not using VS Code? See Using the Devcontainer Outside VS Code for running the devcontainer from a Linux SSH session with the Dev Container CLI.
-
Verify SSH from an integrated terminal inside the container:
ssh-add -l ssh -T git@github.com
-
Run any optional setup tasks you need with Tasks: Run Task:
Clone ProjectsInstall OpencodeInstall Ghidra
Add Debian/Ubuntu packages to .devcontainer/pkgs/apt-pkgs, one package per
line. Lines can contain comments beginning with #.
After changing apt packages, rebuild the container with Dev Containers: Rebuild Container. Apt packages are installed in the Docker image, so they require a rebuild.
Add Python packages to .devcontainer/pkgs/pip-pkgs, one package per line. The
post-create script installs them into the vscode user's ~/.venv with uv.
After changing Python packages, either rebuild the container or rerun:
bash .devcontainer/post-create.shThe post-create script is written to be idempotent, so rerunning it should not duplicate shell configuration.
Use the right layer for the kind of setup you are adding:
- Use
.devcontainer/Dockerfilefor system-level image setup that should happen as root and be cached in the image. - Use
.devcontainer/post-create.shfor user-level setup that should run as thevscodeuser, especially anything that writes to$HOME,~/.bashrc,~/.local, or~/.venv. - Use
.devcontainer/tasks/*.shfor optional tools or workflows that should be run manually from VS Code tasks.
Avoid writing user shell config from the Docker build. Docker build steps run as
root, so $HOME points at /root, not /home/vscode.
Tasks are defined in .vscode/tasks.json. To add a task:
- Create a script under
.devcontainer/tasks/. - Make it idempotent when practical, so reruns are safe.
- Add a task entry in
.vscode/tasks.jsonthat invokes the script.
Example:
If a task needs a pinned version, pass it explicitly in the task command, as the
Ghidra task does with GHIDRA_VERSION=12.1.2.
The Clone Projects task runs .devcontainer/tasks/git-clone-projects.sh and
checks out the configured repositories into this workspace. Update that
script when project repository names or destinations change.
The Install Opencode task runs .devcontainer/tasks/opencode_install.sh. It
skips installation when opencode is already available on PATH.
The Install Ghidra task runs .devcontainer/tasks/ghidra_install.sh with a
pinned GHIDRA_VERSION. The script downloads the matching public release bundle
into ~/ghidra, adds ghidraRun to PATH, and applies Java rendering options
that improve Ghidra over XQuartz.
On arm64/aarch64 Linux, the script also builds and installs the native Ghidra components missing from the public release bundle.
Rerun user setup:
bash .devcontainer/post-create.shRun the pinned Ghidra installer directly:
GHIDRA_VERSION=12.1.2 bash .devcontainer/tasks/ghidra_install.shCheck which Ghidra will launch:
command -v ghidraRunCheck SSH-agent forwarding:
ssh-add -l- Keep installation scripts idempotent where possible.
- Prefer putting package names in
pkgs/files instead of hardcoding installs inside scripts. - Keep root/image work in the Dockerfile and user-home work in post-create or tasks.
- When changing task scripts, validate them with
bash -nbefore committing.
{ "label": "Install Tool", "type": "shell", "command": "bash .devcontainer/tasks/tool_install.sh", "presentation": { "reveal": "always", "panel": "dedicated" }, "problemMatcher": [] }