Systems & Infrastructure
Before the managed services there is a socket, a process table and a packet. These are the projects where I had to build the thing the framework usually hides — and they are the reason I can reason about the layers underneath a deployment when something breaks.
The Ansible automation is joint work with Bilal Eddinaoui, in his repository. The HTTP server, container stack and C projects are mine.
- 180+
- concurrent connections, one thread, no blocking
- 9
- services in the containerised stack
- 0
- manual steps from bare cloud host to running stack
An HTTP server, single-threaded, from scratch
A full HTTP/1.1 server in C++98 — request parsing, routing, static files, error pages, CGI execution — with no framework and no library doing the protocol work. It is deliberately single-threaded: concurrency comes from an event notification mechanism rather than from threads or processes, so one thread multiplexes every connection and never blocks on any of them.
Writing it this way forces you to confront the thing frameworks paper over: a socket does not hand you a request. It hands you bytes, at times of its choosing, in pieces that do not respect message boundaries. Every read might be half a header. Every write might not complete. The state machine that handles this correctly is the actual content of the project, and it is why ApacheBench and Siege could hold over a hundred and eighty concurrent connections against it.
- Server behaviour is driven entirely by a configuration file — ports, hosts, server names, routes, error pages and CGI paths — parsed at startup rather than compiled in.
- CGI processes are spawned and their output streamed back without blocking the event loop that serves every other client.
- Built on kqueue, which is the BSD and macOS equivalent of epoll — the same design, a different interface.
A container stack that watches itself
The containerisation project is usually done with three services. This one runs nine: NGINX terminating TLS as the only public entry point, WordPress on php-fpm, MariaDB for persistence, Redis for caching, FTP and Adminer for file and database administration, and Prometheus with Node Exporter and Grafana for metrics — plus a backup manager I wrote myself, a small React and Flask application that snapshots the WordPress files and the database.
The constraint that makes it instructive is that ready-made application images are not allowed. Each image is built from a base distribution with its own entrypoint, which means you write the process supervision, the startup ordering and the health of each service yourself. Persistence lives in named volumes and the services talk over a private network, so nothing is reachable except through the proxy.
Then removing the human from the deployment
Running that stack on your own machine proves it works. Putting it on a cloud host without touching the host is a different problem, and that is what the Ansible layer does: one playbook, run against droplets defined in an inventory, that takes a bare server to a serving stack.
It provisions in the order that matters. The firewall role installs UFW, sets the default incoming policy to deny, and opens exactly three ports. The Docker role purges conflicting packages, imports the official signing key, and installs the engine and the compose plugin from the vendor repository rather than the distribution's. Then the stack is transferred, its environment file rendered from a template with restrictive permissions, and each container started and verified — the playbook asserts the container is actually running rather than assuming the start command succeeding means it did.
Secrets are the detail worth noting: the database root password lives in an encrypted vault and is injected at render time, so the repository is publishable and the credential is not in it.
The C underneath all of it
Three more projects sit below these, and they are the ones that make the rest possible. A dining-philosophers simulation in C, which is really an exercise in threads, mutexes and proving to yourself that a deadlock you cannot reproduce is still there. A Unix shell, which is fork and exec and pipes and file descriptors and signal handling, and which teaches you what your terminal has been doing for you all along. And a raycasting engine that renders a first-person view in real time from a grid, which is arithmetic and framebuffers and no engine to help.
None of these are products. They are the reason a container, a process limit or a blocked file descriptor is something I can reason about concretely rather than by analogy.
Built with
- C++98
- C
- kqueue
- Docker Compose
- NGINX
- Ansible
- Prometheus
- Grafana
Curriculum projects, public as source. The HTTP server targets BSD and macOS because it is built on kqueue.