Manual Docker

Only way: create code yourself, then Docker by hand

You create every PHP or JavaScript file yourself (open the linked files and copy). Then: pull → network create → volume create → write Dockerfile → build → run.

Code enters the container with Dockerfile COPY + docker build. No host bind-mount of source code. No compose up in this guide. Named volumes only for MySQL data + uploads.

Linked code files

Open each link in your editor. Create the same file in your project folder and paste the code.

Order of Docker commands

Dockerfile build flow
You write files → Dockerfile COPY → docker build → image → docker run
  1. Create project folder + every source file (from links above)
  2. Write Dockerfile piece by piece
  3. Create .env, docker-compose.yml, .dockerignore before running anything
  4. docker pull …
  5. docker network create … + docker volume create … or let Compose create them
  6. docker build -t … . or docker compose up --build
  7. docker run MySQL + app or Compose — then SQLyog SQL
  8. CRUD in browser · prove persistence with same volumes

Full paste blocks: manual-php.html (PHP) · manual-node.html (Node).

sudo service docker start

PATH A — PHP: create files

1

Folders

mkdir -p ~/docker-task-php/application
cd ~/docker-task-php
2

Create each file (open link → copy → paste into nano/VS Code)

Create asOpen this file
application/db.phpphp-app/application/db.php
application/auth.phpphp-app/application/auth.php
application/login.phpphp-app/application/login.php
application/register.phpphp-app/application/register.php
application/logout.phpphp-app/application/logout.php
application/index.phpphp-app/application/index.php
application/edit.phpphp-app/application/edit.php
application/delete.phpphp-app/application/delete.php
application/favorites.phpphp-app/application/favorites.php
nano application/db.php
# paste from linked file, save
# repeat for auth, login, register, logout, index, edit, delete, favorites
ls -la application/

Full paste blocks also live in manual-php.html.

PATH A — PHP: Dockerfile + Docker CLI

3

Dockerfile piece by piece

Reference: php-app/Dockerfile

nano Dockerfile

Piece 1

FROM php:8.2-apache

Piece 2

RUN docker-php-ext-install pdo pdo_mysql

Piece 3 — copy YOUR code into the image (not a mount)

COPY application/ /var/www/html/

Piece 4

RUN mkdir -p /var/www/html/uploads && chown -R www-data:www-data /var/www/html/uploads
4

Pull · network · volumes · build · run

docker pull mysql:8.0
docker pull php:8.2-apache
docker images

docker network create docker-task-net
docker volume create docker-task-mysql
docker volume create docker-task-uploads
docker volume ls
docker volume inspect docker-task-mysql

cd ~/docker-task-php
docker build -t docker-task-php .

docker run -d \
  --name docker-task-db \
  --network docker-task-net \
  --network-alias db \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -v docker-task-mysql:/var/lib/mysql \
  -p 3306:3306 \
  mysql:8.0

# wait: docker logs -f docker-task-db
# then SQLyog port 3306 → run setup SQL

docker run -d \
  --name docker-task-app \
  --network docker-task-net \
  -e DB_HOST=db -e DB_NAME=userdb -e DB_USER=appuser -e DB_PASS=apppass \
  -v docker-task-uploads:/var/www/html/uploads \
  -p 8080:80 \
  docker-task-php

Browser: http://localhost:8080

docker run --rm -v docker-task-uploads:/data alpine ls -la /data
docker network inspect docker-task-net

PATH B — Node: create files

1

Folder + files

mkdir -p ~/assignment-docker-node
cd ~/assignment-docker-node
Create asOpen this file
package.jsonnodejs-app/package.json
server.jsnodejs-app/server.js
nano package.json   # paste from link
nano server.js      # paste entire linked file
ls -la

PATH B — Node: Dockerfile + Docker CLI

2

Dockerfile pieces

FROM node:22-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --omit=dev
COPY server.js ./
RUN mkdir -p /app/uploads
EXPOSE 3000
CMD ["node", "server.js"]
3

Pull · volumes · build · run

docker pull mysql:8.0
docker pull node:22-alpine

docker network create assignment-docker-net   # if not exists
docker volume create assignment-docker-mysql
docker volume create assignment-docker-uploads

# if PHP containers still running:
docker rm -f assignment-docker-app assignment-docker-db

cd ~/assignment-docker-node
docker build -t assignment-docker-node .

docker run -d --name assignment-docker-db --network assignment-docker-net --network-alias db \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -v assignment-docker-mysql:/var/lib/mysql \
  -p 3307:3306 mysql:8.0

# SQLyog port 3307 → same SQL

docker run -d --name assignment-docker-app --network assignment-docker-net \
  -e DB_HOST=db -e DB_NAME=userdb -e DB_USER=appuser -e DB_PASS=apppass -e PORT=3000 \
  -v assignment-docker-uploads:/app/uploads \
  -p 3000:3000 assignment-docker-node

Browser: http://localhost:3000

Database (required after MySQL is running)

!

Apps do not create the database. You create it in SQLyog.

Full steps: setup-database.html · raw SQL: setup.sql

PHPNode
Host127.0.0.1127.0.0.1
User / passroot / rootpassroot / rootpass
Port33063307
CREATE DATABASE IF NOT EXISTS userdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'appuser'@'%' IDENTIFIED BY 'apppass';
GRANT ALL PRIVILEGES ON userdb.* TO 'appuser'@'%';
FLUSH PRIVILEGES;
USE userdb;
CREATE TABLE IF NOT EXISTS users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(100) NOT NULL UNIQUE,
  password VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS images (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id INT NOT NULL,
  file_name VARCHAR(255) NOT NULL,
  title VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_images_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Persistence proof & cleanup

Persistence
# Remove containers only — named volumes stay
docker rm -f docker-task-app docker-task-db

# Start again with the SAME -v volume names
# (re-run the docker run commands from your path)

# Prove uploads volume:
docker run --rm -v docker-task-uploads:/data alpine ls -la /data

Cleanup

docker rm -f assignment-docker-app assignment-docker-db
docker volume rm docker-task-mysql docker-task-uploads
# or node: assignment-docker-mysql assignment-docker-uploads
docker network rm assignment-docker-net
docker rmi docker-task-php   # or assignment-docker-node

After you change code

Edit the file on disk → docker build -t … . again → docker rm -f docker-task-app → docker run app again.
Code is not live-mounted; it only updates when you rebuild.

Full step-by-step with every paste block

★

manual-php.html has every PHP file’s full code and every command; manual-node.html is the Node.js equivalent.

Use those as your main checklists while typing.