Deployment guide

Docker Dev Stack on a VPS: an environment ready for coding

Deploy on a VPS Cloud →

Tutorial

Development

Docker Dev Stack on a VPS: an environment ready for coding

A remote development stack keeps your local machine from getting saturated and gives you a stable IP for webhooks, demos and integration tests. On a ServOrbit VPS, Docker Compose becomes a complete workshop: Nginx, PHP-FPM or Node, PostgreSQL, Redis, Mailpit and Adminer run together in isolated, persistent containers accessible via SSH from any workstation. This guide details the stack composition, service configuration and best practices for collaborative development without conflicts.

10 min read6 steps
Contents· Why host a Docker Dev Stack on a VPS?1/12
  1. 01Why host a Docker Dev Stack on a VPS?
  2. 02What you can do with a Docker Dev Stack
  3. 03Prerequisites: recommended minimum configuration
  4. 04Stack components: each service's role
  5. 05Install a Docker Dev Stack on your ServOrbit VPS
  6. 06Service configuration: volumes, networks and environment variables
  7. 07Access from your laptop: SSH tunneling and reverse proxy
  8. 08Best practices: dev vs production
  9. 09Hot reload with docker compose watch
  10. 10Stack variants by project type
  11. 11Troubleshooting: 4 common errors
  12. 12The official documentation

Why host a Docker Dev Stack on a VPS?

A local development environment works, but it remains tied to a single machine: switching workstations, onboarding a new collaborator or accessing it from another country all become points of friction. By centralizing your Docker stack on a VPS, you have a shared development server, always on, accessible via SSH or browser from anywhere. You also gain in reproducibility: each service is defined in a docker-compose.yml file, which eliminates the notorious "it works on my machine" problem.

What you can do with a Docker Dev Stack

  • Run several services simultaneously (Nginx, MySQL, Redis, PHP-FPM, Node.js) in isolated containers without port or version conflicts
  • Share an identical development environment among all members of a team thanks to the docker-compose.yml file versioned in Git
  • Test database migrations or dependency updates in an ephemeral container without risking the main environment
  • Host a lightweight CI/CD server (Gitea, Drone CI) directly on the same VPS to automate your internal deployments
  • Access your development services via subdomains or Traefik/Nginx reverse proxies without opening unnecessary ports
  • Back up and restore your entire stack in a few commands thanks to Docker volumes and VPS snapshots

Prerequisites: recommended minimum configuration

A full stack with PostgreSQL, Redis, Nginx and an application uses 4 GB of RAM at minimum in practice — below that, the Docker OOM killer interrupts PostgreSQL or Redis during a migration with no application-level error message. The VPS must run Ubuntu 22.04 LTS or Debian 12, with Docker Engine 26+ and Docker Compose v2.22+ installed (the command is written docker compose, without a hyphen). Check the version with docker compose version: the watch feature used later requires v2.22 at minimum, released in September 2023.

Stack components: each service's role

The ServOrbit reference stack assembles six complementary services.

Nginx acts as the front reverse proxy: it receives HTTP requests on port 80 and routes them to PHP-FPM (via FastCGI) or to a Node.js server. The nginx/default.conf configuration is mounted as a volume to remain editable without rebuilding the image.

PHP-FPM 8.3 (or Node.js 22 depending on the stack profile) runs the application code. Both variants are available in the ServOrbit Marketplace; the docker-compose.yml includes both services — disable the one you don't need with profiles.

PostgreSQL 16 stores persistent data. Port 5432 is not exposed on the host by default — only the internal Docker network dev_net has access, which prevents any accidental exposure on the VPS's public IP.

Redis 7 serves as cache and message broker. Like PostgreSQL, it stays on the internal network (port 6379) and is accessible from application code via the service name redis.

Mailpit 1.x replaces a real SMTP server in development: it captures all outgoing emails and exposes them in a web interface on port 8025. No special SMTP configuration on the application side — simply point to mailpit:1025.

Adminer (port 8080) provides a lightweight web interface to manage PostgreSQL or MySQL without a heavy client. It is accessible only from the machine itself or via SSH tunnel.

Install a Docker Dev Stack on your ServOrbit VPS

  1. Order a ServOrbit Cloud VPS

    Go to the /vps-cloud page and choose a plan suited to your usage. For a standard development stack (a few containers, database, reverse proxy), a VPS with 2 vCPU and 4 GB of RAM is a good starting point. Finalize the order: your VPS is provisioned in under 60 seconds on Ubuntu 22.04 LTS.

  2. Access the Marketplace in your client area

    Log in to your ServOrbit client area, then open the "Marketplace" section from your VPS dashboard. The Marketplace lists all the applications available for 1-click installation, organized by category. Select the "Development" category to filter dev-oriented stacks.

  3. Start the Docker Dev Stack installation

    Click the "Docker Dev Stack" card, then the "Install" button. The automation deploys Docker Engine, Docker Compose and a preconfigured docker-compose.yml file with the essential services (Nginx, PHP-FPM, PostgreSQL 16, Redis, Mailpit for email testing, Adminer). The full installation usually takes between 2 and 4 minutes depending on the VPS size.

  4. Retrieve your credentials and access the interface

    Once the installation is complete, the client area displays the automatically generated connection details: VPS IP address, PostgreSQL password, and the access URL for Mailpit (by default on port 8025). Connect via SSH with ssh root@<IP_VPS> to check the container status via docker compose ps in the /opt/docker-dev-stack directory.

  5. Configure your first project and customize the stack

    Copy your source code into /opt/docker-dev-stack/app/ or edit the /opt/docker-dev-stack/docker-compose.yml file to add or remove services according to your needs. Restart the stack with docker compose up -d to apply the changes. To expose your services on a domain name, configure a DNS record pointing to your VPS IP and adapt the Nginx configuration included in the /opt/docker-dev-stack/nginx/ directory.

  6. Logging in for the first time

    There is no account to create: the URL opens the Mailpit test mailbox directly, with no password. PostgreSQL (5432) and Redis (6379) are reachable only from the machine itself; the Postgres credentials are in /opt/docker-dev-stack/.env.

Service configuration: volumes, networks and environment variables

The stack's docker-compose.yml declares three named volumes — postgres_data, redis_data and app_data — mounted in /var/lib/postgresql/data, /data and /var/www/html respectively. These volumes survive a docker compose down: database data and uploaded files remain intact between restarts.

All services share the internal dev_net bridge network. Nginx is the only service exposing a port on the host (80); the others remain isolated and communicate by service name — postgres, redis, mailpit.

Sensitive variables (PostgreSQL password, application secret key) are never written directly in docker-compose.yml. They are read from /opt/docker-dev-stack/.env via the env_file directive. This file is excluded from the Git repository by .gitignore. Non-sensitive environment variables (port, PHP version, database name) can appear directly in the Compose file under the environment key, so they are visible during code review.

Access from your laptop: SSH tunneling and reverse proxy

PostgreSQL, Adminer and Redis are not exposed on the VPS's public IP. To access them from your local workstation, open an SSH tunnel: ssh -L 5432:localhost:5432 -L 8080:localhost:8080 root@<IP_VPS> creates two local forwards — your laptop's port 5432 points to PostgreSQL, and port 8080 to Adminer. Your usual SQL client then connects on localhost:5432 as if the database were running locally.

For HTTP services (Nginx, Mailpit), two approaches are available. If you have a domain name, configure an A record pointing to the VPS IP and set up Nginx to serve dev.yourdomain.com over plain HTTP (no TLS needed for a development environment). If you work without a domain, an SSH tunnel is sufficient: ssh -L 8025:localhost:8025 root@<IP_VPS> gives access to Mailpit on localhost:8025.

Best practices: dev vs production

In development, the .env file centralizes all secrets. In production, Docker secrets (docker secret) or an external secrets manager (Vault, AWS Secrets Manager) replace the flat file — an accidentally versioned .env exposes credentials in the Git history.

Resource limits (deploy.resources.limits) are worth setting in dev: PostgreSQL can consume all available RAM if a query goes wrong. Start with memory: 512m on PostgreSQL, memory: 256m on Redis and memory: 256m on PHP-FPM, then adjust based on actual usage profiles.

Never mount the Docker socket (/var/run/docker.sock) in an application container unless strictly necessary: a container with socket access can launch other containers with root privileges on the host. In development the risk is limited, but habits formed here tend to be reproduced in production.

Hot reload with docker compose watch

Docker Compose v2.22+ introduces docker compose watch, available since September 2023. Enable it by adding a develop.watch block in the app service of your docker-compose.yml: specify the paths to watch and the associated action (sync to copy files into the container without restarting it, rebuild to rebuild the image). Then run docker compose watch instead of docker compose up -d: file changes are propagated in real time into the container, with no manual restart. Check your version beforehand with docker compose version.

Stack variants by project type

Scroll the table

StackMain servicesUse caseRecommended RAM
LAMPNginx + PHP-FPM 8.3, MariaDB 10.11, RedisWordPress, OctoberCMS, Laravel4 GB
MERNNode.js 22, MongoDB 7, RedisREST API + React/Vue SPA4 GB
Django / PostgreSQLPython 3.12, PostgreSQL 16, Redis, CeleryPython apps, ML, Django REST API4 GB
PHP + PostgreSQLNginx + PHP-FPM 8.3, PostgreSQL 16, Redis, MailpitSymfony, API Platform, Drupal4 GB
Full NodeNode.js 22, PostgreSQL 16, Redis, MailpitNestJS, Express, Fastify4 GB

Troubleshooting: 4 common errors

Port already in use. The error Bind for 0.0.0.0:80 failed: port is already allocated means a host service (Apache, system nginx) is already listening on port 80. Stop the system service (systemctl stop nginx or systemctl stop apache2) or change the host port in docker-compose.yml ("8080:80") and access the stack on port 8080.

Volume permissions. The Permission denied error on a mounted volume often comes from a container uid/gid different from the host's. Add user: "1000:1000" in the affected service, or change the host directory permissions with chown -R 1000:1000 /opt/docker-dev-stack/app.

Bridge network not found. The message network dev_net declared as external, but could not be found appears if you use external: true on a network not yet created. Remove external: true: Docker Compose creates the network automatically on the first docker compose up.

Insufficient RAM. PostgreSQL displays FATAL: out of memory or keeps restarting if the VPS is undersized. Check with free -m: at least 4 GB must be available for the full stack. Reduce shared_buffers in the PostgreSQL configuration (command: postgres -c shared_buffers=128MB) or upgrade to a larger VPS plan.

Pro tip: take an on-demand snapshot of your ServOrbit VPS from the client area before making deep changes to the Docker configuration. A snapshot lets you revert to a stable state in one click if a container update or a Compose file change breaks your environment. Also remember to use a .env file to store your sensitive variables (passwords, API keys) and to exclude it from your Git repository via .gitignore — even on a development server, it is a good habit to anchor from the start.

The official documentation

For advanced configuration, tool-specific options and version changes, refer to the official Docker Compose documentation. This guide covers going live on a ServOrbit VPS; the vendor documentation remains the reference for fine-tuning.

Deploy a Docker Dev Stack in minutes on a ServOrbit Cloud VPS

Enjoy a Cloud VPS with 1-click installation of your Docker environment, support included and a no-commitment monthly option.