A single Dockerfile that spins up a full-featured web development workstation. Usage instructions are at the top of each Dockerfile.
alpinearchlinuxdjangodockerdocker-composedockerfilehandcodedpostgresqlrediswebdev
1# webdev
2#
3# Used for working on most of my website development projects, using a rolling
4# distro to have the latest packages to work with. Uses tmux, neovim, and
5# claude code for a full TUI workflow.
6#
7# Build image:
8# docker build --tag overshard/webdev:latest .
9#
10# Create volumes:
11# docker volume create --name bythewood-code
12#
13# Start container:
14# docker run --detach --restart unless-stopped --name bythewood-webdev \
15# --volume bythewood-code:/home/dev/code \
16# --volume ~/.ssh:/home/dev/.ssh:ro \
17# --volume /var/run/docker.sock:/var/run/docker.sock \
18# -p 8000:8000 \
19# overshard/webdev:latest
20#
21# Connect:
22# docker exec -it bythewood-webdev tmux
23#
24# I use a code volume to make rebuilds of the container easy. The host's ~/.ssh
25# is bind mounted read-only so SSH keys are available for git. I have scripts
26# setup on my hosts to rebuild images, delete old containers, and start the new
27# containers when I make updates.
28#
29# Docker is included in this build so I can test docker stuff inside my
30# containers. Note that to get docker to function in a docker container you
31# need to use the host's docker and provide the docker.sock file from the host
32# to the container. This can be done with `--volume /var/run/docker.sock:/var/run/docker.sock`.
33#
34# The naming is so that I can make a container and volumes for each of my
35# clients and keep a separation of work.
36
37
38FROM ubuntu:24.04
39
40ENV DEBIAN_FRONTEND=noninteractive \
41 TZ=UTC \
42 LANG=C.UTF-8 \
43 LC_ALL=C.UTF-8 \
44 TERM=xterm-256color
45
46RUN apt-get update && \
47 apt-get install -y --no-install-recommends \
48 # Dev tools
49 curl git rsync neovim openssh-client tmux whois nmap \
50 # System essentials
51 tzdata ca-certificates sudo \
52 # Build tools
53 build-essential \
54 # Python
55 python3 python3-pip python3-venv \
56 # Database and caching
57 postgresql redis-server \
58 # Docker
59 docker.io docker-compose-v2 \
60 # Process management
61 supervisor && \
62 curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
63 apt-get install -y nodejs && \
64 npm install -g @anthropic-ai/claude-code && \
65 curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh && \
66 mkdir -p /root/.local/share/corepack/shims && \
67 corepack enable && \
68 corepack prepare yarn@stable --activate && \
69 rm -rf /var/lib/apt/lists/*
70
71RUN printf '%s\n' \
72 'bind 127.0.0.1' \
73 'protected-mode yes' \
74 'port 6379' \
75 'supervised no' \
76 'daemonize no' \
77 'logfile ""' \
78 'dir /var/lib/redis' \
79 'save ""' \
80 > /etc/redis/redis.conf && \
81 mkdir -p /var/lib/redis && \
82 chown redis:redis /var/lib/redis
83
84RUN ln -snf /usr/share/zoneinfo/UTC /etc/localtime && echo "UTC" > /etc/timezone
85
86RUN service postgresql start && \
87 sudo -u postgres createuser -s dev && \
88 service postgresql stop
89
90RUN printf '%s\n' \
91 '[supervisord]' \
92 'pidfile=/run/supervisord.pid' \
93 'user=root' \
94 'nodaemon=true' \
95 'logfile=/dev/null' \
96 'logfile_maxbytes=0' \
97 '' \
98 '[program:postgresql]' \
99 'command=/usr/lib/postgresql/16/bin/postgres -D /var/lib/postgresql/16/main -c config_file=/etc/postgresql/16/main/postgresql.conf' \
100 'autostart=true' \
101 'user=postgres' \
102 'stdout_logfile=/dev/fd/1' \
103 'stdout_logfile_maxbytes=0' \
104 'redirect_stderr=true' \
105 '' \
106 '[program:redis]' \
107 'command=/usr/bin/redis-server /etc/redis/redis.conf' \
108 'autostart=true' \
109 'user=redis' \
110 'stdout_logfile=/dev/fd/1' \
111 'stdout_logfile_maxbytes=0' \
112 'redirect_stderr=true' \
113 > /etc/supervisord.conf
114
115RUN useradd -m -G sudo,docker,postgres,redis -s /bin/bash dev && \
116 echo "dev ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/dev
117
118WORKDIR /home/dev
119USER dev
120
121CMD ["sudo", "/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]