# Private Services

> Run an internal service that is reachable by services in the same workspace network.

Source: https://nexthomelabs.com/docs/services/private-services
Markdown: https://nexthomelabs.com/docs-md/services/private-services
Slug: services/private-services
Section: Create
Last updated: 2026-08-30
Reading time: 5 min read

---

# Private Services

A **Private Service** is a persistent application that does **not receive a public URL**. Use it for internal APIs, internal webhooks, service-to-service RPC endpoints, and application components that should only be called by services in the same workspace network. It is the counterpart to a Web Service when the intended callers are inside the workspace rather than on the internet.

Choosing "private" is a network decision, not an authentication decision: an internal service protected only by a shared bearer token but still reachable from the public internet does not offer the same tenancy isolation as a service that has no public ingress at all.

## When to use — and when not to

**Use Private Service when:**

- The consumer is another NexHost service in the **same workspace** — for example an API called only by your Frontend App, a webhook processor other workers invoke, or a BFF (backend-for-frontend) that your worker pool internalizes.
- The API manages workspace-internal concerns (job orchestration, service-mesh control, internal event ingestion) that external users must not invoke directly.
- You want the workspace boundary to be the network boundary — code in a different workspace must not reach the internals.

**Do not use Private Service when:**

- The caller is a browser, mobile app, or third-party webhook on the public internet — ship a [Web Service](/docs/services/web-services) and enforce application-level authentication there.
- The work is a long-lived queue consumer (use [Background Worker](/docs/services/background-workers)) or a scheduler-controlled on-demand run (use [Cron Job](/docs/services/cron-jobs) / [Workflow](/docs/services/workflows)).

If the service serves both callers (an API that external apps call, plus one endpoint that only workspace services call), decompose: keep the external surface on a public service and the internal surface on a private one, each with the minimal needed environment variables.

## Configure it like a runtime service

From a configuration standpoint, a Private Service is a sibling of a Web Service: it needs a **source**, **build** and **start commands** when they apply, and any **required environment variables**. NexHost discovers a reachable TCP listener during startup even though the result is not a public hostname.

1. **Choose a source.** Select a supported repository, archive, folder, or an existing image when the dashboard offers it. Confirm the branch and root directory for that source.
2. **Set build and start commands.** The build produces the artifact the platform will attempt to start; the start command keeps the process alive. A continuous `npm start`, `gunicorn …`, or binary invocation are common.
3. **Configure environment variables.** Wire database URLs, inter-service credentials, and queue endpoints as scoped secrets. Keep them out of source — the same scoping rules that apply to public runtimes apply here.
4. **Bind the process to `0.0.0.0`.** NexHost discovers the private listener automatically; no health path or port setting is required.

Keep credentials and service connection details in the **workspace configuration** rather than committing them to source. A service definition committed to a repository that contains connection parameters is still history that must be rotated.

> [!TIP]
> Validate readiness locally before you deploy. Run the same start command with the same environment values and confirm that it opens a TCP listener on `0.0.0.0`.

## Connect from other services

The dashboard provides the private service’s **connection details in its service configuration** — the internal host, port, connection string, or workspace-scoped URL as appropriate for the runtime type. Use **those displayed details** from the other services in the **same workspace**.

Reading the correct value matters:

- A workspace-private address is not a hostname you memorize; it is the address the deployment currently advertises. A redeployment or infrastructure operation can change it, so prefer reading it at configuration time rather than caching it in application documentation.
- Cross-workspace access is not expected to succeed even when the workspace names feel similar. Treat the workspace as the addressing boundary.

Do not expect a private service to be reachable directly from the public internet. Probing it from an external browser, `curl` outside the workspace, or a third-party webhook will fail by design — use an external-service measurement (the calling workspace service’s logs, not a public-network `curl` from your laptop) to verify connectivity.

## Troubleshooting

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Calling service reports `ECONNREFUSED` to the private address | The private service never entered `ready` — check its deployment detail (build or startup/launch failure) before blaming the network | Open the private service’s last deployment; read the stage output from the first error upward |
| `401/403` on a private API call | The application route is protected; the caller did not send the application credential | Pass the application authentication header between services; this is separate from NexHost TCP readiness. |
| Intermittent failure only on first call after deploy | Transition/cold-start window on first readiness | Keep startup cheap; avoid synchronous external calls in the startup path |

## Related documentation

- [Web Services](/docs/services/web-services) — the public counterpart when external callers must reach the API.
- [Background Workers](/docs/services/background-workers) — long-lived consumers with a similar "stay alive" contract but no HTTP ingress.
- [Environment Variables](/docs/configuration/environment-variables) — scope credentials so build and runtime see the right values.
- [Domains and Networking](/docs/configuration/networking) — the public vs private split and how listener discovery fits.
- [Deployments](/docs/deployments) / [Logs](/docs/operations/logs) — diagnose why a private service never reported ready.

