Internal networking
How your apps and services reach each other privately by name, how each project gets its own network, and how to connect a database from one project to an app in another.
Most apps talk to something else: a backend to its database, a worker to a queue, a website to an API. On Synq that traffic stays inside the server. It never goes through the internet, never needs a public port, and never needs a domain. Each project gets a private network, every container in it gets a name, and the other containers reach it by that name.
This page explains the names, the per-project boundary, and how to cross it on purpose with an Internal connection.
What you need first
- A project deployed with Docker to one of your own servers. (Apps that run directly on the host, without Docker, share the host's network instead and have no private names.)
- For a connection between two projects: both projects on the same server.
One private network per project
When a project deploys, Synq creates a private Docker bridge network for it, named synq-<project-slug>.
Every container of the project joins it: each service of a compose or monorepo project, and the app
container of a single-app project.
- Containers on the same network reach each other directly on their container ports. A database on port
5432is reachable on5432; you don't publish anything. - Containers of other projects are not on this network, so they can't reach it, even on the same
server. Two projects can both have a service called
dbwithout any clash. - Nothing here is exposed to the internet. Public traffic only arrives through a domain or a port you publish on purpose (see Public ports).
The names other containers use
| What | Name on the network | Example |
|---|---|---|
| A service in a compose or monorepo project | The service name | db, redis, api |
| The app of a single-app project | The project slug, lowercased, with anything that isn't a letter, digit or dash turned into a dash | my-shop |
| An extra name you choose | Your Network alias (a service) or Hostname alias (a single app) | postgres, backend |
Put the name and the container port together to get the address: db:5432, http://api:3000,
redis://redis:6379.
See a service's internal address
Open the service
Open the project, go to Apps & Services and click the service.
Read the Private network card
On the service's Overview tab, the Private network card shows its Internal address (for
example db:5432) with a copy button. Under Runtime details you also see the current container IP;
don't use that, it changes on every restart.
A single app answers to its project slug on its port, for example http://my-shop:3000 for a project with
the slug my-shop listening on 3000. An app installed from the Apps catalog also shows its connection
details on the project's Overview tab.
Give a service an extra name
Sometimes the code expects a particular host name, like postgres instead of db.
- A service: open the service, go to Settings, and in the Networking section fill in Network alias. Press Save changes.
- A single app: open the project's Advanced tab, expand Internal hostname, fill in Hostname alias and press Save.
The extra name works alongside the default one; both resolve. Use letters, digits and dashes (other characters become dashes, and names are cut at 48 characters). Synq refuses a name another container of the same project already answers to. The new name applies when the container is created, so redeploy after saving.
Coming from a platform that used project_service host names?
Some platforms give every service a host name like <project>_<service> (for example shop_db). Synq does
not create that name, and an alias can't contain an underscore (it becomes a dash). Change the host in your
connection string to the service name (db), or set a Network alias such as shop-db and use that.
Connection strings for databases
Inside the same project, point your app at the database service by name. Typical values:
# PostgreSQL service named "db"
DATABASE_URL=postgresql://app:your-password@db:5432/app
# MySQL or MariaDB service named "mysql"
DATABASE_URL=mysql://app:your-password@mysql:3306/app
# MongoDB service named "mongo"
MONGODB_URI=mongodb://root:your-password@mongo:27017/?authSource=admin
# Redis service named "redis"
REDIS_URL=redis://:your-password@redis:6379The user, password and database name are whatever the database container was started with (its
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB style variables). For a database service, its
Overview tab has a Public access card whose Internal row shows the address and, when Synq can read
the credentials, a ready-made connection URL with the password hidden. Copy it and put the real password in
yourself.
Store the finished URL as a variable, marked secret, in the app's environment.
Builds can't reach the database
The private network exists for running containers. An image build does not join it, so a build step that
opens a database connection (for example a framework that queries data while it builds) fails with
getaddrinfo ENOTFOUND db. Move the query to request time, or give the build a database address it can
reach.
Connect a service from another project (Internal connections)
Projects are private to each other by default. To let an app in project B use a database that lives in
project A, create a connection. Synq then puts the value (for example a DATABASE_URL) into project
B's environment and joins B's containers to a private network with that one service, so the traffic stays on
the server.
Create the connection
You can start from either side.
- Open project A, go to Apps & Services and open the database service.
- Press Use in a project in the service header.
- Under Project, choose project B.
- Under Values to inject, tick what you want (for a database, usually its connection URL). Each value
has a box with the variable name it will get, for example
DATABASE_URL; type in it to rename the variable. Advanced hides the name boxes and shows each name as a chip you can copy. - Keep Internal (recommended) selected.
- Press Connect.
- Open project B, go to Apps & Services and press Add.
- In Add an app or service, switch to Connect existing.
- Under Source project or app, pick project A (or the service in it).
- Tick the values, check their variable names, keep Internal (recommended), and press Connect.
An app installed from the Apps catalog has Use in a project on its connection card, on the project's Overview tab. A plain single-app project can be picked as a source with Connect existing; the value it offers is its internal address.
What happens next
A toast confirms the connection and mentions a redeploy. The new variable and the network join take effect when project B's containers are created, and Synq takes care of that redeploy for you:
- If project B already has a live deployment, Synq starts a new deployment of project B straight away.
- If project B was never deployed, the connection is picked up on its first deploy.
Once project B is running with the connection:
- Project B's Overview tab lists the link under Connected services.
- In project B's Environment section, the Edit window shows the variable with a Linked badge. It can't be edited there.
- The source service in project A lists project B under Used by.
Internal or Public
| Mode | What your app gets | When it works |
|---|---|---|
| Internal (recommended) | A private address on the server. For a service it looks like postgresql://user:password@shared-svc-1a2b3c:5432/app; for a single app it is its internal address, like http://my-shop:3000. | Both projects on the same server, both deployed with Docker, and the source service deployed and running. No public port is needed. |
| Public | The published host:port or the public URL. | Anywhere, including another server. The database port has to be published (see Public access for a database). |
Values that aren't addresses (a password, an API key, a bucket name) are injected as they are in both modes.
Remove a connection
In project B, open Overview, find the link under Connected services and press Remove (or open Environment, press Edit, click the Linked variable and press Remove connection). The injected variable is deleted with the link, project B's containers leave the private network immediately, and if project B has a live deployment Synq redeploys it without the variable.
Limits
- Same server only. Internal mode needs both projects on the same server. For projects on different servers, use Public.
- Docker only. The consuming project must run in Docker containers, not directly on the host.
- Deploy and start the source first. A service that has never been deployed or isn't running can't be connected privately.
- One owner per variable name. If project B already has a variable with the same name that you set by hand, Synq refuses the connection rather than overwrite it. Remove your own variable or choose another name.
- Deleting the source. If you delete project A, the delete dialog lists the connected projects. They keep running but lose the connection; redeploy them afterwards.
Troubleshooting
getaddrinfo ENOTFOUND db (or EAI_AGAIN)
The name doesn't resolve from where the code runs. Check that the service name is spelled exactly as it appears in Apps & Services, that both containers belong to the same project (or are connected), and that this isn't an image build step. After adding an alias, redeploy. A new connection redeploys a project that is already live for you; check that this deployment finished.
Connection refused
The name resolves but nothing listens. Use the container port (for example 5432), not a published host
port, and check the service is Running on its Overview tab.
Internal mode needs both projects on the same server
The two projects deploy to different servers. Choose Public instead, and publish the database port with its Public access switch.
Related guides
Environment variables & secrets
Give your app its settings and secrets. See and edit them inline on the Environment page or with the CLI, keep the sensitive ones masked, and apply changes without a full rebuild.
Public ports & database access
Publish TCP or UDP ports on your server for traffic a domain can't carry, keep a port on localhost for SSH tunnels, and expose a database to the internet with one switch.