I have an Ubuntu server and want to host several websites or applications, with each one running in its own isolated Docker container. I'm considering URLs such as example.com/website1 and example.com/website2, but I'm open to using subdomains or another layout if that works better. What is the recommended way to route public requests to the appropriate containers? I'd also like advice on handling application logs: should they remain in the containers, be stored in mounted volumes, or be collected somewhere outside the containers for easier review?
4 Answers
Subdomains are usually easier than path-based URLs. For example, site1.example.com and site2.example.com avoid problems with applications that assume they are installed at the root path, which can otherwise break redirects, cookies, or static assets. Caddy is a convenient option because it can handle HTTPS certificates and reverse-proxy rules with relatively little configuration.
For a simple setup, Docker Compose with one reverse-proxy container and separate networks for the applications is enough; you probably do not need Swarm or Kubernetes for a single server. If the services are private or still being secured, a managed tunnel and access-control layer can avoid exposing the server directly, but public sites still need careful firewall rules, updates, TLS, and authentication.
Treat containers as disposable and keep persistent data outside them. Application files that must survive replacement should use bind mounts or named volumes, while databases should generally run as separate services with their own persistent storage. For logs, have applications write to standard output and error, then use Docker’s logging driver or a centralized system. If you use Docker’s default JSON logging, configure rotation with limits such as max-size and max-file so logs cannot fill the disk.
Put a reverse proxy such as Caddy, Nginx, or Traefik in front of everything. It should be the only service exposed on ports 80 and 443, then route requests to the appropriate container over an internal Docker network. The application containers themselves do not need to publish ports directly to the internet.

Path routing can work, but only when the application explicitly supports running beneath a prefix such as /website1. Otherwise, subdomains tend to require much less troubleshooting.