When several applications are hosted on the same server, two questions soon arise: how to isolate them from one another, and how to make them reachable without exposing the whole server? A common answer rests on three ideas: application building blocks in Docker containers, Docker Compose to assemble them, and a single proxy that receives requests and redirects them. Here is the principle, without needless jargon, with the example of my own organisation.
The principle of application building blocks
A modern application is almost never a single block. It is made of services: a web interface, an application programming interface (API), a database, a cache, background jobs. An application building block corresponds to one of these services, with a single responsibility. The advantage is the same as in construction: you replace or update one block without taking the rest apart, and you see straight away which one is causing trouble.
Docker: one block, one container
Docker packages a service with everything it needs to run (minimal system, libraries, configuration) in a container. That container starts the same way on my machine, in pre-production and on the server. What this brings:
- reproducibility: no more “it works on my machine”;
- isolation: each service has its own library versions, with no conflict with the others;
- resource limits: a container’s memory can be capped so that a greedy service does not bring down the others;
- simple installation and rollback: replace the image, restart.
Docker does not solve everything: a badly configured container remains vulnerable, and the data it holds must be stored in backed-up volumes, not in the container itself.
Docker Compose: describe the whole in one file
Launching a dozen containers by hand with their options is fragile. Docker Compose lets you describe the whole set in a single file: which services, which images, which networks, which volumes, which variables, in which order to start. One command starts, stops or updates the entire application.
- A readable, versioned file: an application’s infrastructure can be reviewed and compared like code.
- Internal networks: the database is reachable only by the services that need it, not from outside.
- Environment variables: secrets are supplied at startup, never written in the file or the image.
- Health checks: a service counts as started only when it responds.
The proxy: a single entry point
A server hosting several applications should not expose each one on its own port. In front of them I place a reverse proxy: a single service that receives all web traffic and redirects it to the right application according to the requested domain name.
- One place for encryption: certificates are obtained and renewed by the proxy, the applications do not have to care.
- A reduced attack surface: only the proxy is reachable from the Internet; applications, databases and caches stay on internal networks.
- Common security headers: secure-transport policy, masking of the server’s identity.
- Centralised logs: a single place to see who asked for what, with truncated addresses where possible.
- Adding or removing an application without touching the others: add or disable a configuration file, then reload.
Example: a single proxy routing by domain name
In my organisation, a dedicated repository holds this single entry point: a proxy (Caddy) that is the only container publishing the web ports and handles encryption automatically. It routes each domain name to the matching application:
- a shared Docker network is created by the proxy;
- each application declares that network as external and attaches only its entry service to it, under an alias name (for example the application name followed by “web”);
- the applications’ production files publish no port and do not handle encryption: they trust the headers forwarded by the proxy, and only those of the proxy;
- one configuration file per application lets it be enabled or disabled by renaming it, then reloading;
- access to administration interfaces can be limited to allowed addresses, and the configuration refuses to start if that list is missing (fail closed).
The entry server is itself hardened: read-only file system, system privileges removed except the one needed to listen on the web ports, no privilege escalation, resource limits.
What this also brings: capacity
Each application has several containers, and each has a memory cap. Adding these caps gives a budget for sizing the server. A single proxy also avoids repeating a proxy in each application, which frees memory and reduces the number of things to monitor. I measure real consumption before deciding on sizing, rather than relying on caps alone.
The limits to know
- A shared network links the entry services: if one is compromised, it can see the others. Mitigation: remove unneeded privileges from the containers; clean fix: one network per application.
- The proxy is a single point of failure: if it goes down, everything does. It must be simple, monitored and quick to restart.
- Docker does not replace backups: volumes must be backed up and restoration tested.
- The host firewall is still needed: Docker can bypass some rules for the ports it publishes; open only the useful ports.
Where to start
- Split the application into services and identify what must stay internal.
- Describe the whole in a Compose file, with volumes for the data.
- Take secrets out of the file and the images.
- Place a proxy in front, with automatic encryption.
- Back up the volumes and test a restoration.
Updating one application without touching the others
- I build the new version of the relevant block’s image.
- I deploy it to pre-production, where the Compose set is identical to production.
- After validation, I update only that service; the proxy keeps routing the other applications without interruption.
- If something goes wrong, I go back to the previous image: the block, not the server, is restored.
What I monitor
- Availability of each application, through an external probe.
- Memory actually used per container, compared with the set cap.
- Certificates: their automatic renewal must be checked, not assumed.
- Volume backups: presence, date, restoration test.
- Security updates of the images and the host system.
None of this is reserved for large infrastructures: it is a matter of discipline, and of knowing in advance what will be monitored before an incident reveals it.
When Docker is not necessary
A static site, made of simple files, needs neither a container nor an application proxy: ordinary web hosting is enough, and it is simpler to maintain. Containers become worthwhile when several services depend on one another, when precise versions must be pinned, or when several applications must coexist. Choosing the tool proportionate to the need is part of the job.
In short
Isolated blocks in containers, a file that assembles them and a single proxy that exposes them: this organisation makes a multi-application server more readable, safer and easier to evolve. It is not an end in itself: it serves to keep control as the number of applications grows. For how I deploy such sets, also read development best practices.
A server to organise?
Describe the applications you want to host together: I will propose a suitable organisation, on a quote basis.

