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.
PHP files
db.php auth.php style.css favorites.js login.php register.php logout.php index.php edit.php delete.php favorites.php Dockerfile .env.example docker-compose.yml .dockerignore
Node files
package.json server.js Dockerfile .env.example docker-compose.yml .dockerignore
Manual Dockerfile uses npm install (no lock file required).
Order of Docker commands
- Create project folder + every source file (from links above)
- Write
Dockerfilepiece by piece - Create
.env,docker-compose.yml,.dockerignorebefore running anything docker pull …docker network create …+docker volume create …or let Compose create themdocker build -t … .ordocker compose up --builddocker runMySQL + app or Compose — then SQLyog SQL- 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
Folders
mkdir -p ~/docker-task-php/application
cd ~/docker-task-php
Create each file (open link → copy → paste into nano/VS Code)
| Create as | Open this file |
|---|---|
application/db.php | php-app/application/db.php |
application/auth.php | php-app/application/auth.php |
application/login.php | php-app/application/login.php |
application/register.php | php-app/application/register.php |
application/logout.php | php-app/application/logout.php |
application/index.php | php-app/application/index.php |
application/edit.php | php-app/application/edit.php |
application/delete.php | php-app/application/delete.php |
application/favorites.php | php-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
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
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
Folder + files
mkdir -p ~/assignment-docker-node
cd ~/assignment-docker-node
| Create as | Open this file |
|---|---|
package.json | nodejs-app/package.json |
server.js | nodejs-app/server.js |
nano package.json # paste from link
nano server.js # paste entire linked file
ls -la
PATH B — Node: Dockerfile + Docker CLI
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"]
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
| PHP | Node | |
|---|---|---|
| Host | 127.0.0.1 | 127.0.0.1 |
| User / pass | root / rootpass | root / rootpass |
| Port | 3306 | 3307 |
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
# 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.