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
Node files
package.json server.js Dockerfile
Manual Dockerfile uses npm install (no lock file required).
Order of Docker commands
- Create project folder + every source file (from links above)
docker pull …docker network create ba-docker-netdocker volume create …(mysql + uploads)- Write
Dockerfilepiece by piece docker build -t … .docker runMySQL → SQLyog SQLdocker runapp- CRUD in browser · prove persistence with same volumes
sudo service docker start
PATH A — PHP: create files
Folders
mkdir -p ~/ba-docker-php/application
cd ~/ba-docker-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/index.php | php-app/application/index.php |
application/create.php | php-app/application/create.php |
application/edit.php | php-app/application/edit.php |
application/delete.php | php-app/application/delete.php |
nano application/db.php
# paste from linked file, save
# repeat for index, create, edit, delete
ls -la application/
Full paste blocks also live in manual-steps.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 ba-docker-net
docker volume create ba-docker-mysql
docker volume create ba-docker-uploads
docker volume ls
docker volume inspect ba-docker-mysql
cd ~/ba-docker-php
docker build -t ba-docker-php .
docker run -d \
--name ba-docker-db \
--network ba-docker-net \
--network-alias db \
-e MYSQL_ROOT_PASSWORD=rootpass \
-v ba-docker-mysql:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0
# wait: docker logs -f ba-docker-db
# then SQLyog port 3306 → run setup SQL
docker run -d \
--name ba-docker-app \
--network ba-docker-net \
-e DB_HOST=db -e DB_NAME=userdb -e DB_USER=appuser -e DB_PASS=apppass \
-v ba-docker-uploads:/var/www/html/uploads \
-p 8080:80 \
ba-docker-php
Browser: http://localhost:8080
docker run --rm -v ba-docker-uploads:/data alpine ls -la /data
docker network inspect ba-docker-net
PATH B — Node: create files
Folder + files
mkdir -p ~/ba-docker-node
cd ~/ba-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 ba-docker-net # if not exists
docker volume create ba-docker-mysql-node
docker volume create ba-docker-uploads-node
# if PHP containers still running:
docker rm -f ba-docker-app ba-docker-db
cd ~/ba-docker-node
docker build -t ba-docker-node .
docker run -d --name ba-docker-db --network ba-docker-net --network-alias db \
-e MYSQL_ROOT_PASSWORD=rootpass \
-v ba-docker-mysql-node:/var/lib/mysql \
-p 3307:3306 mysql:8.0
# SQLyog port 3307 → same SQL
docker run -d --name ba-docker-app --network ba-docker-net \
-e DB_HOST=db -e DB_NAME=userdb -e DB_USER=appuser -e DB_PASS=apppass -e PORT=3000 \
-v ba-docker-uploads-node:/app/uploads \
-p 3000:3000 ba-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,
file_name VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Persistence proof & cleanup
# Remove containers only — named volumes stay
docker rm -f ba-docker-app ba-docker-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 ba-docker-uploads:/data alpine ls -la /data
Cleanup
docker rm -f ba-docker-app ba-docker-db
docker volume rm ba-docker-mysql ba-docker-uploads
# or node: ba-docker-mysql-node ba-docker-uploads-node
docker network rm ba-docker-net
docker rmi ba-docker-php # or ba-docker-node
After you change code
Edit the file on disk → docker build -t … . again → docker rm -f ba-docker-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-steps.html has every file’s full code, every command, and the file links again.
Use that as your main checklist while typing.