December 29, 2025

Install and run Docker on Ubuntu VPS

STEP 1️⃣ Prerequisites (Once per server)

You already have most of this, but for completeness:

sudo apt update
sudo apt install -y nginx mysql-client git curl

Docker (if not installed):

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

Verify:

docker --version
docker compose version

STEP 2️⃣ Create project directory

mkdir -p /var/www/php82-app
cd /var/www/php82-app

Structure:

php82-app/
├── public/
│   └── index.php
├── docker/
│   └── php/
│       ├── Dockerfile
│       └── php.ini
├── docker-compose.yml
├── .env.example
└── .gitignore


STEP 3️⃣ Create PHP app file

📄 public/index.php

<?php
echo "PHP 8.2 Docker is working!";


STEP 4️⃣ PHP 8.2 Dockerfile

📄 docker/php/Dockerfile

FROM php:8.2-fpm

# Install PHP extensions needed for MySQL
RUN docker-php-ext-install pdo pdo_mysql

WORKDIR /var/www/html

COPY php.ini /usr/local/etc/php/conf.d/custom.ini

📄 docker/php/php.ini

memory_limit=256M
display_errors=Off
log_errors=On
error_log=/proc/self/fd/2
max_execution_time=60


STEP 5️⃣ docker-compose.yml

📄 docker-compose.yml

version: "3.9"

services:
  php:
    build: ./docker/php
    container_name: php82_app
    volumes:
      - .:/var/www/html
    ports:
      - "127.0.0.1:9005:9000"
    restart: unless-stopped

⚠️ Port 9005 must be unused.
(Use a different port per project.)


STEP 6️⃣ Environment variables (MySQL on host)

📄 .env.example

DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=app_db
DB_USER=app_user
DB_PASS=secret

📄 .gitignore

.env
vendor/
node_modules/

Create real env:

cp .env.example .env


STEP 7️⃣ Build & start PHP container

docker compose build
docker compose up -d

Check:

docker ps

You should see php82_app.


STEP 8️⃣ Configure Nginx (HOST)

📄 /etc/nginx/sites-available/php82-app.conf

server {
    listen 80;
    server_name php82-app.test;

    root /var/www/php82-app/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass 127.0.0.1:9005;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    error_log /var/log/nginx/php82-app-error.log;
    access_log /var/log/nginx/php82-app-access.log;
}

Enable site:

sudo ln -s /etc/nginx/sites-available/php82-app.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx


STEP 9️⃣ Test PHP

Open:

http://php82-app.test

Expected output:

PHP 8.2 Docker is working!


STEP 🔟 Test MySQL connection (IMPORTANT)

📄 public/db-test.php

<?php
$pdo = new PDO(
    "mysql:host=127.0.0.1;dbname=app_db",
    "app_user",
    "secret",
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

echo "MySQL connection OK";

Open:

http://php82-app.test/db-test.php


⚠️ IMPORTANT: MySQL access from Docker

Because MySQL is on host:

✅ Use:

DB_HOST=host.docker.internal

OR (Linux best way):

DB_HOST=172.17.0.1

Find it:

ip route | grep docker0

👉 127.0.0.1 inside container ≠ host

Essential Commands

List of running Docker containers

docker ps

You should see:

CONTAINER ID   IMAGE          NAMES          PORTS
abcd1234       nginx:alpine   nginx_proxy    0.0.0.0:8080->80/tcp

Down a container

docker-compose down

Up a Docker container

Go the the container directory first then run

docker-compose up -d

Down & up again a container

docker-compose down
docker-compose up -d

Restart a container

docker restart container_name

Open a container

docker exec -it container_name sh
docker exec -it service_status_prismict bash

🔄 Rebuild & start

docker-compose build --no-cache
docker-compose up -d

🧠 Correct DB_HOST (Linux Docker)

Use in .env:

DB_HOST=172.17.0.1

✅ Final Result

✔ PHP 8.2 isolated
✔ MySQL shared globally
✔ Nginx stays fast on host
✔ Easy to migrate VPS
✔ Everything Git-friendly