Custom Apps

How to Deploy a Docker Compose Stack on a VPS

Bring your own compose file, keep the database off the public network, and let Impreza put HTTPS in front of the service you choose. One naming rule makes it work.

A multi-service app can combine a web service, database, worker and cache. Impreza runs your Compose manifest on a supported VPS with the Impreza Agent online. Configure the public service name and proxy network for HTTPS routing, then review service resources, persistent data and recovery. The naming contract below is one requirement, not a complete validation of the stack.

What you get

  • Your Compose configuration: define services, volumes, networks and resource limits
  • HTTPS routing for the selected HTTP service, on your domain or an imprezaapps.com subdomain
  • Control of network exposure: keep internal services off the proxy network and do not publish their ports
  • Deployment operations: check logs and redeploy; validate each service after changes

The one rule: name the public container

The reverse proxy reaches your container by its name on a shared Docker network called impreza-proxy. Your compose must give the public service a fixed name built from the deployment id, and join that network. Everything else is normal compose.

services:
  app:
    image: ghcr.io/yourorg/yourapp:1.2.3
    container_name: ${DEPLOYMENT_ID}-app
    restart: unless-stopped
    networks:
      - default
      - impreza-proxy
    environment:
      DOMAIN_URL: ${DOMAIN_URL}
networks:
  impreza-proxy:
    external: true

The matching route in the deployment tells the proxy where to send traffic:

{ "upstream": "{deployment_id}-app:80", "match_var": "domain" }

Without the container_name line, Compose invents a name like project-app-1, the proxy cannot find the container, and every request answers 502. The platform now rejects a manifest that misses it, with a message naming the exact line to add.

Deploy it

Write the compose with the naming rule

Give the public service container_name: ${DEPLOYMENT_ID}-<suffix> and both networks. Leave internal services such as the database on the default network only, with no ports: published. They talk to the app by service name, as usual.

Pass configuration as variables

Reference secrets as ${VAR} in the Compose manifest instead of hard-coding their values. Deployment variables are written to a .env beside the manifest, alongside DOMAIN_URL, DEPLOYMENT_ID and HOST_PORT. Keep that file and any copies or backups access-controlled; variable substitution does not make the values absent from the server.

Set limits inside the compose

In manifest mode the platform does not apply its CPU and memory defaults; your compose is the source of truth. Use the service-level cpus: and mem_limit: keys so one container cannot starve the host.

Create the deployment

From My Apps in Advanced view, the CLI, or your AI agent, create a custom deployment in manifest mode with the compose content, the route for the public service, and the domain, or leave the domain empty for a free subdomain. The agent brings the stack up with docker compose.

Check it and iterate

When the status turns to running, open the app URL and check the required services, database connection and background jobs. Use app inspection and maintenance where supported; a running deployment does not prove that every service is healthy. Redeploy in place to retain the deployment identity and route, then verify the result.

Keep the database off the proxy network

Attach only the intended HTTP service to impreza-proxy. Other containers on a shared Docker network can communicate with it; joining that network does not, by itself, create a public internet route. Keep the database on the project network, avoid published database ports, and review host bindings, firewall rules and application routes together.

A worked example: WordPress plus MariaDB

Two services. wp gets container_name: ${DEPLOYMENT_ID}-wp, both networks and the route {deployment_id}-wp:80. db runs mariadb:11 on the default network with MARIADB_PASSWORD: ${WP_DB_PASS}, and the password arrives as a deploy variable, not in the file. The full example is in the manifest section of the docs.

Volumes and Tor

Declare persistent volumes in the Compose manifest; the platform does not add its own in manifest mode. For supported deployments, optional Tor access needs a separate network review: an onion address does not remove existing public routes or published ports. See Tor publishing for the relevant flow.

Recovery for the whole stack

Before an update, map each service to its stored data. Review app backups to Impreza S3: coverage includes the deployment data directory and detected named volumes, not automatically every bind mount, external database or remote storage service. A copy made while a database is running is not proof of database consistency.

Test a recovery procedure that restores compatible data across the web app, database and workers. For a host move, follow app migration between compatible servers and plan how to stop new writes and switch traffic. Keep the original deployment record required by the integrated restore flow.

Branch previews described in the Tor preview guide do not support Compose manifest mode. Do not treat that feature as a clone of this multi-service stack.

Start now

Get an offshore VPS with the agent preselected, read the manifest routing contract at docs.imprezahost.com, or start simpler with deploy a Docker app to an offshore VPS.

Ready to build privacy-first?

No KYC, no email required, crypto payment. Deploy an offshore server in minutes, or do it all by chat with the Impreza agent.