Add Docker Compose production stack (php-apache, mariadb, node/pm2)
Single-command deploy: docker compose up -d --build brings up the LEMP stack plus the Node realtime/scheduler service. app/config.php and DB secrets are generated from .env at container start, never baked into the image or committed.
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
# Copy to .env and fill in real values before running: docker compose up -d --build
|
||||||
|
|
||||||
|
# MariaDB root password (also used by the app's db_pass)
|
||||||
|
DB_ROOT_PASSWORD=
|
||||||
|
|
||||||
|
# Public IP or domain the browser uses to reach this server (Socket.IO client URL)
|
||||||
|
PUBLIC_HOST=
|
||||||
|
|
||||||
|
# Shared secret between PHP and Node (must be a long random string)
|
||||||
|
EMIT_SECRET=
|
||||||
|
|
||||||
|
# SMTP (Gmail) used for outgoing mail
|
||||||
|
SMTP_USERNAME=
|
||||||
|
SMTP_PASSWORD=
|
||||||
|
|
||||||
|
# Port to expose the web app on (default 80)
|
||||||
|
HTTP_PORT=80
|
||||||
@@ -6,6 +6,9 @@ app/uploads
|
|||||||
node_modules/
|
node_modules/
|
||||||
nodejs/.env
|
nodejs/.env
|
||||||
|
|
||||||
|
# Docker deploy secrets
|
||||||
|
/.env
|
||||||
|
|
||||||
# zxcvbn dev dependencies (not needed at runtime)
|
# zxcvbn dev dependencies (not needed at runtime)
|
||||||
lib/zxcvbn-php-master/vendor/sebastian/
|
lib/zxcvbn-php-master/vendor/sebastian/
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: mariadb:11
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
|
MYSQL_DATABASE: wms
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
- ./docker/mariadb/init-wms2.sql:/docker-entrypoint-initdb.d/init-wms2.sql:ro
|
||||||
|
networks: [wms]
|
||||||
|
|
||||||
|
php:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/php/Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on: [db]
|
||||||
|
environment:
|
||||||
|
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
|
PUBLIC_HOST: ${PUBLIC_HOST}
|
||||||
|
EMIT_SECRET: ${EMIT_SECRET}
|
||||||
|
SMTP_USERNAME: ${SMTP_USERNAME}
|
||||||
|
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- .:/var/www/html/wms-app
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT:-80}:80"
|
||||||
|
networks: [wms]
|
||||||
|
|
||||||
|
node:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/node/Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on: [php]
|
||||||
|
environment:
|
||||||
|
PORT: 3000
|
||||||
|
EMIT_SECRET: ${EMIT_SECRET}
|
||||||
|
PHP_BASE_URL: http://php
|
||||||
|
PHP_WEBROOT: /wms-app/app
|
||||||
|
ALLOWED_ORIGIN: http://${PUBLIC_HOST}
|
||||||
|
volumes:
|
||||||
|
- ./nodejs:/app
|
||||||
|
- node_modules:/app/node_modules
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
networks: [wms]
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
node_modules:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
wms:
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
CREATE DATABASE IF NOT EXISTS wms2;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
RUN npm install -g pm2
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY nodejs/package.json nodejs/package-lock.json ./
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
|
COPY nodejs/ ./
|
||||||
|
|
||||||
|
CMD ["pm2-runtime", "ecosystem.config.js"]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
FROM php:8.3-apache
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libzip-dev libicu-dev libonig-dev default-mysql-client gettext-base \
|
||||||
|
&& docker-php-ext-install pdo_mysql mysqli mbstring gd zip intl sockets exif opcache \
|
||||||
|
&& a2enmod rewrite \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY docker/php/opcache.ini /usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||||
|
COPY docker/php/entrypoint.sh /usr/local/bin/docker-entrypoint-wms.sh
|
||||||
|
COPY docker/php/config.php.template /usr/local/etc/wms/config.php.template
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint-wms.sh
|
||||||
|
|
||||||
|
WORKDIR /var/www/html/wms-app
|
||||||
|
|
||||||
|
ENTRYPOINT ["docker-entrypoint-wms.sh"]
|
||||||
|
CMD ["apache2-foreground"]
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//<><><><><><><><> MAIN CONFIG (docker-generated) <><><><><><><><>//
|
||||||
|
if(true){
|
||||||
|
$isTest = "master";
|
||||||
|
$base_url = "/wms-app/";
|
||||||
|
$server_url = $base_url."app/";
|
||||||
|
$include_url = $_SERVER['DOCUMENT_ROOT'].$server_url;
|
||||||
|
|
||||||
|
$db_server = "db";
|
||||||
|
$db_user = "root";
|
||||||
|
$db_pass = "${DB_ROOT_PASSWORD}";
|
||||||
|
$db_type = "mysql";
|
||||||
|
$db_database = "wms";
|
||||||
|
$db_database2 = "wms2";
|
||||||
|
|
||||||
|
$db_server2 = (!empty($db_server2))?$db_server2:$db_server;
|
||||||
|
$db_user2 = (!empty($db_user2))?$db_user2:$db_user;
|
||||||
|
$db_pass2 = (!empty($db_pass2))?$db_pass2:$db_pass;
|
||||||
|
$db_type2 = (!empty($db_type2))?$db_type2:$db_type;
|
||||||
|
|
||||||
|
$time_zone = "Asia/Bangkok";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Real-time Node.js server ─────────────────────────────────────────────────
|
||||||
|
if (!defined('NODE_PUBLIC_URL')) {
|
||||||
|
define('NODE_PUBLIC_URL', 'http://${PUBLIC_HOST}:3000');
|
||||||
|
}
|
||||||
|
if (!defined('NODE_EMIT_URL')) {
|
||||||
|
define('NODE_EMIT_URL', 'http://node:3000/emit');
|
||||||
|
}
|
||||||
|
if (!defined('NODE_EMIT_SECRET')) {
|
||||||
|
define('NODE_EMIT_SECRET', '${EMIT_SECRET}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Usage packages ───────────────────────────────────────────────────────────
|
||||||
|
$packages = [
|
||||||
|
'starter' => [
|
||||||
|
'daily_limit' => 30,
|
||||||
|
'weekly_limit' => 100,
|
||||||
|
'lock_on_limit' => ['dashboard'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// unique key — used for SMTP password encryption, keep consistent across deploys
|
||||||
|
$pinkey = "wms";
|
||||||
|
|
||||||
|
$SMTP = [];
|
||||||
|
$SMTP['server'] = "smtp.gmail.com";
|
||||||
|
$SMTP['username'] = "${SMTP_USERNAME}";
|
||||||
|
$SMTP['port'] = "587";
|
||||||
|
$SMTP['password'] = "${SMTP_PASSWORD}"; // Gmail app password, not your login password
|
||||||
|
$method = "AES-256-CBC";
|
||||||
|
$iv = "1234567890123456"; // Must be exactly 16 bytes
|
||||||
|
$SMTP['password'] = openssl_encrypt($SMTP['password'], $method, $pinkey, 0, $iv);
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP_DIR=/var/www/html/wms-app
|
||||||
|
CONFIG=$APP_DIR/app/config.php
|
||||||
|
|
||||||
|
# Generate app/config.php from template on first run only.
|
||||||
|
# Restrict envsubst to known placeholders so it never touches the app's own
|
||||||
|
# $variable syntax (envsubst blanks out any $NAME it doesn't recognize).
|
||||||
|
if [ ! -f "$CONFIG" ]; then
|
||||||
|
echo "[entrypoint] generating app/config.php"
|
||||||
|
envsubst '${DB_ROOT_PASSWORD} ${PUBLIC_HOST} ${EMIT_SECRET} ${SMTP_USERNAME} ${SMTP_PASSWORD}' \
|
||||||
|
< /usr/local/etc/wms/config.php.template > "$CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$APP_DIR/app/uploads"
|
||||||
|
chown -R www-data:www-data "$APP_DIR/app/uploads"
|
||||||
|
|
||||||
|
echo "[entrypoint] waiting for database at db:3306"
|
||||||
|
until mysqladmin ping -h db -u root -p"$DB_ROOT_PASSWORD" --silent 2>/dev/null; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[entrypoint] running setup.php (idempotent schema sync)"
|
||||||
|
php "$APP_DIR/setup.php" || true
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
opcache.enable=1
|
||||||
|
opcache.memory_consumption=64
|
||||||
|
opcache.max_accelerated_files=10000
|
||||||
|
opcache.validate_timestamps=1
|
||||||
|
opcache.revalidate_freq=2
|
||||||
Reference in New Issue
Block a user