Network isolation

Every environment gets its own private network, so a service name means one container and nothing crosses an environment boundary.

An environment gets a private Docker network named deplo-env-<environment id>. Apps and managed databases there reach each other by name. Apps outside projects use the team's deplo-team-<team id> network instead. Pull request previews use an isolated deplo-preview-<key> network.

Folders do not create a network boundary. To separate workloads, put them in different environments. Deplo derives the network from the app's location; you never create or select it.

What sees what

FromToReachable
A service in a stackAnother service in the same stackYes
An appAnother app in the same environment, same serverYes
An appA database in the same environment, same serverYes
An appAnything in the same environment on another serverNo
An app in ProductionAn app in Staging, same projectNo
An appAn app in another projectNo
An appAnything of another teamNo
A pull request previewAnything at allNo
An appA published port on the same serverYes - see below

A preview cannot reach your database

A pull request preview uses its own network and cannot reach the managed database of the environment it came from.

Give it a database inside the Compose file, or connect it to a database with a published port. There is no way to add a preview to an environment network.

Published ports bypass the boundary. Any container on the same server can reach a published port, regardless of team or environment. A firewall does not change this because the traffic stays inside the host.

Use a published port only when that reachability is intended. For app-to-app traffic, use the service name in the same environment.

The proxy answers from every network. Traefik joins each environment network, so a container can request any hostname served by that server, including domains belonging to other teams.

Anything with a domain is reachable through the proxy. Keep private services without a domain.

A network does not span servers. Apps in the same environment but on different servers cannot reach each other by name. Put them on one server, or publish a port and use the server address.

Folders affect permissions, not isolation. Moving an app between folders does not change its network. Moving it from an environment into a folder moves it to the team's network and away from that environment's databases; Deplo redeploys it on the new network before the move completes.

A domain is separate from network isolation: the proxy serves it from every network, so it remains reachable from other environments and from the internet.

Services that stay off the network

Deplo adds the environment network to every service, alongside any networks in the Compose file. A service keeps only the environment networks it is allowed to join.

Four kinds of service stay off it:

  • One with network_mode:. It joins no network of its own by definition, so there is nothing to add it to - and a domain pointed at it will not answer.
  • One whose name, or hostname:, is one the platform answers to (postgres, traefik, deplo, and the three others). It stays on the stack's own private network, and Deplo keeps every other service on that network too, so the app still reaches it by name.
  • One whose networks you all marked internal: true. That is a deliberate seal and Deplo leaves it alone. A domain still wins: route to the service and it joins, because otherwise the proxy cannot reach it.
  • One whose name is already answered by a neighbouring stack on that network. Two containers claiming one name would round-robin, so the newcomer is left off with a warning rather than quietly taking half the traffic.
services:
  web:
    image: my/app
    networks: [backend]   # on backend AND the environment's network
  worker:
    image: my/app         # names nothing: on the environment's network
  vault:
    image: vault
    networks: [sealed]    # sealed off on purpose: stays private
networks:
  backend: {}
  sealed:
    internal: true

Database placement

A managed database has a placement like an app. Choose it under Storage -> New database.

  • In an environment - the apps in that environment reach it at db-<name>. This is what you want almost always.
  • No environment - it sits on the team's network, reachable from apps that are not in a project.

The Networking card shows its placement and offers Move to environment. Deplo restarts the database on the new network before the action completes.

A database you stopped stays stopped: it follows the move the next time you start it.

A published port is outside the boundary. Exposing a database on a host port takes it out of all of this. Docker binds the port on the machine, so it answers every container on that server, whatever network they are on - and the server's own firewall does not stop them, because Docker publishes below it. The password is the only thing in the way. Leave the port off unless something outside the server really needs it.

Name collisions

Inside one environment the names have to be unique: two apps that both have a service called web both answer to web on that network, and Docker splits the lookups between them. Half your requests reach the wrong container.

Saving a compose file that takes a name already answered there is refused, and the message names one that is free:

`web` is already answered by Shop on that network, and Docker would split the
connections between the two. Rename it on this app (the service, or its
`hostname:`) - `web-2` is free - or pick another environment.

An overlap that already exists - two stacks that landed there before the check, or arrived by different routes - is reported by the deploy instead:

`web` is also answered by a stack in Shop / Production, on the same network as
this one. Docker splits the lookups between them, so half will reach the wrong
container.

Rename the service, or give it a hostname: of its own. Every service of your stack takes a name on that network, not only the ones you route: a worker with no domain is still part of the app and still has to reach your database.

Declaring your own networks does not take a service off it - frontend and backend is organisation, not a request to be cut off, and your networks are kept alongside the environment's. Three things do stay off:

Stays offWhy
A network you marked internal: trueThat IS the request to be cut off, and adding the environment's network would hand back the egress you removed
network_mode: on a serviceIt replaces the network stack entirely, so there is nothing to join - and a domain pointing at such a service is reported in the deploy log
A service named after Deplo's own infrastructureLeft off rather than refused, so an ordinary stack still deploys. It keeps a private network with the rest of your stack, so the two still talk

Deplo also refuses a move that would create the overlap - putting an app into an environment where a database already answers to one of its names, or the reverse.

A stack Deplo wrote is renamed rather than refused: a template you deploy, or an app a migration brings over from another panel. Deploying the same template twice into one environment gives the second one myapp-db instead of db, and everything that named it moves with it - the route, the variables, the config files. The app's Activity says what was renamed; a migration puts it in the report too. A compose file you wrote yourself is yours, so it is refused with the free name instead of edited behind your back.

cannot resolve host

The one thing that breaks: an app pointing at another app by name, when the two are in different environments.

could not translate host name "gamewatcher-db" to address:
Name or service not known

Deplo says so before the container tries. The deploy log carries a line naming what you pointed at and where it lives:

DATABASE_URL points at `gamewatcher-db`, which lives in GW / Production and
is not reachable from here.

The other shape says the placement is right and the machine is not:

DB_HOST points at `orders-db`, which is in Shop / Production with this app but
runs on ANOTHER SERVER.

Three ways out, best first:

Put them in the same environment, on the same server

Move the app (or the database) so both sit in one environment and on one server. That is what the boundary is for - and the server part is not the boundary's doing, it is what a Docker network is.

Use a managed database

Create it in the environment that needs it. Deplo writes the connection string and keeps it reachable.

Publish a port

Only if the two genuinely must stay apart: expose the service on a host port and point at the server address instead of the container name. Treat that port as public - it answers every container on the server, not only the one you opened it for.

Migrate existing instances

The first time a Deplo with this feature starts, it moves every existing app and database onto its environment's network, one server at a time.

  • A stack that cannot be reached stays where it is and keeps running. It is a delay, not an outage.
  • The Overview shows how many the sweep could not reach, and Activity says which ones and why. A stack it deliberately skipped - one you had stopped, one mid-deploy - is not in that count.
  • Deploying one moves it. Try again on the notice re-runs the whole sweep, and Dismiss - the cross on it - puts the notice away for good. Neither one touches a stack that is already where it belongs.

Databases that had no placement are given the environment that actually uses them, when exactly one place does. One used from two environments - or from an environment and from apps outside every project - stays at the team level for you to decide, because moving it would take it away from half its callers.

Stopped apps and stopped databases are left alone and follow when you start them. So does anything that was mid-deploy, on its next deploy.

What does not change

Domains, HTTPS, certificates, redirects and basic auth. Published ports, for apps and for databases. Logs, console, terminal, backups, cron, metrics and migrations - all of those reach a container through the server agent, never through the Docker network.

Did this page help you?

On this page