# Fully Booked - Dockerized Deployment with DigitalOcean and Cloudflare

Company: Fully Booked
Service: DevOps Engineering
Period: 2023-04 - 2025-06
Tech: Docker, DigitalOcean, Cloudflare, DNS, SSL Certificates, Caddy
Web: https://fully-booked.uk/
Canonical: https://webanion.com/portfolio/fully-booked-dockerized-deployment-with-digital-ocean-and-cloudflare

Fully Booked shipped as five Docker services on one DigitalOcean droplet behind Cloudflare, so a very small team could run a marketplace that holds deposits. One repository built every image, a compose file and a Makefile reduced a release to pull, build and up, a Caddy proxy handled certificates and security headers, and Playwright rendered every quote and invoice PDF on the server. Because the services were independent from the start, they later moved to a self-hosted Kubernetes cluster without a rebuild.

## The Full Story

The infrastructure that let a deposit-taking marketplace run five services with a small team and no surprises.

### A marketplace that holds deposits cannot go down

<p>Fully Booked takes customers' deposits, sends operators their earnings and delivers the documents both sides rely on. An outage is not an inconvenience here: a customer who cannot pay books elsewhere, and an operator who cannot open a quote loses the job.</p><p>The platform is five services, a customer site, an operator site, an admin dashboard, a documentation site and one backend, built and maintained by a very small team. The deployment had to be simple enough to run by hand and solid enough to trust.</p>

### Five services, one repository, one command

<p>Every service ships as its own Docker image from a single repository. The four websites are built into small static servers, the NestJS backend carries the GraphQL API, and MongoDB and the uploaded files live on persistent volumes. One compose file wires them together on a private network, and a Makefile reduces a release to pull, build and up.</p>

### Cloudflare in front, with two deliberate exceptions

<p>Cloudflare holds the DNS for every subdomain and proxies the public sites for caching, certificates and protection. Two records stay direct on purpose: the operator site, so Apple can read the file that lets links open the app, and the API, so Square's payment webhooks arrive without being blocked.</p><p>Getting either wrong would break deep links from every PDF or stop payments confirming, which is why both are documented beside the DNS table.</p>

### A reverse proxy that does the security work

<p>A Caddy container at the edge issues certificates automatically, compresses responses, redirects every www address, adds strict transport, frame and content type headers to the API, and serves the app association files with the content type the stores expect.</p>

### Documents rendered in production

<p>Every quotation, cancellation letter, invoice, booking confirmation and driver sheet is rendered on the server by Playwright running inside the backend image. Getting a headless browser to install inside a production container was the hardest part of the build, and it is what lets an operator send a polished PDF from a phone in seconds.</p>

### From one droplet to a cluster

<p>The droplet carried the platform through its first phases. When the monthly bill and the limits of a single machine began to matter, the same images moved to <a href="/portfolio/fully-booked-zero-downtime-migration-to-self-hosted-kubernetes">a self-hosted Kubernetes cluster with zero downtime</a>, possible because they had been built as independent services from the start.</p><p>For the founder that meant no rebuild and no outage, and for operators and customers nothing changed except that it kept working. The services themselves are told in <a href="/portfolio/fully-booked-all-in-one-smart-booking-solution">the Fully Booked story</a>.</p>
