Docs / Getting Started / How to Set Up a Local Development Environment That Mirrors Your VPS

How to Set Up a Local Development Environment That Mirrors Your VPS

By Admin · Mar 15, 2026 · Updated Apr 24, 2026 · 253 views · 3 min read

Developing directly on a production VPS is risky and inefficient. A local development environment that mirrors your server lets you test changes safely, work offline, and iterate faster. This guide covers multiple approaches, from Docker containers to full virtual machines.

Why Mirror Your VPS Locally?

  • Safety — Test breaking changes without affecting production
  • Speed — No network latency when developing and testing
  • Cost — Don't waste server resources on development
  • Reproducibility — Consistent environments prevent "works on my machine" bugs

Option 1: Docker (Recommended)

Docker containers are the most popular way to create reproducible development environments. They're lightweight, fast, and can exactly match your production stack.

Install Docker

# macOS
brew install --cask docker

# Ubuntu/Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# Windows
# Download Docker Desktop from docker.com

Create a docker-compose.yml for a Typical LEMP Stack

version: "3.8"
services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
      - "8443:443"
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

  php:
    build:
      context: .
      dockerfile: Dockerfile.php
    volumes:
      - ./src:/var/www/html
    environment:
      - DB_HOST=db
      - DB_NAME=myapp
      - DB_USER=root
      - DB_PASS=localdev

  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: localdev
      MYSQL_DATABASE: myapp
    volumes:
      - db_data:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  db_data:

PHP Dockerfile Matching Your VPS

# Dockerfile.php
FROM php:8.3-fpm-alpine

# Install extensions matching your production server
RUN docker-php-ext-install pdo pdo_mysql mysqli opcache

# Install additional extensions
RUN apk add --no-cache libzip-dev icu-dev \
    && docker-php-ext-install zip intl

# Match your production PHP settings
COPY php/php.ini /usr/local/etc/php/conf.d/custom.ini

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

Start Your Environment

# Start all services
docker compose up -d

# View logs
docker compose logs -f

# Stop everything
docker compose down

# Stop and remove data volumes
docker compose down -v

Option 2: Vagrant (Full VM)

If you need an exact OS match (same kernel, same packages), Vagrant creates full virtual machines.

# Install Vagrant and VirtualBox
# Then create a Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/noble64"  # Ubuntu 24.04
  config.vm.network "forwarded_port", guest: 80, host: 8080
  config.vm.network "private_network", ip: "192.168.56.10"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
    vb.cpus = 2
  end

  config.vm.provision "shell", path: "provision.sh"
end

Option 3: VS Code Dev Containers

VS Code Dev Containers combine Docker with your editor for a seamless experience.

// .devcontainer/devcontainer.json
{
  "name": "My App Dev",
  "dockerComposeFile": "../docker-compose.yml",
  "service": "php",
  "workspaceFolder": "/var/www/html",
  "customizations": {
    "vscode": {
      "extensions": [
        "bmewburn.vscode-intelephense-client",
        "ms-azuretools.vscode-docker"
      ]
    }
  }
}

Keeping Environments in Sync

  1. Pin software versions — Use specific Docker image tags, not latest
  2. Version control your configs — Commit Dockerfiles, compose files, and provisioning scripts
  3. Sync database schemas — Use migration tools (Laravel Migrations, Flyway, etc.)
  4. Match PHP/Node/Python versions — Check your VPS with php -v, node -v, etc.
  5. Document differences — Some differences are expected (SSL, production secrets). Document them in a README

Database Synchronization

# Export production database (sanitized)
mysqldump -u user -p dbname --no-data > schema.sql
mysqldump -u user -p dbname --no-create-info \
  --ignore-table=dbname.sessions \
  --ignore-table=dbname.password_resets > data.sql

# Import into local Docker container
docker compose exec -T db mysql -uroot -plocaldev myapp < schema.sql
docker compose exec -T db mysql -uroot -plocaldev myapp < data.sql

A well-configured local development environment saves hours of debugging and prevents production incidents. Invest the time upfront to set it up properly — your future self will thank you.

Was this article helpful?