feat(deploy): add docker app+mysql stack for coolify

This commit is contained in:
Dwindi Ramadhana
2026-02-04 21:05:59 +07:00
parent 0c45435db9
commit 0d5e1a4aa1
6 changed files with 182 additions and 0 deletions

12
app/.dockerignore Normal file
View File

@@ -0,0 +1,12 @@
.git
.gitignore
.env
.env.*
node_modules
vendor
tests
storage/logs/*
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
coverage

51
app/Dockerfile Normal file
View File

@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS frontend
WORKDIR /var/www/html
COPY package.json ./
RUN npm install
COPY resources ./resources
COPY public ./public
COPY vite.config.js ./
RUN npm run build
FROM composer:2 AS vendor
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install \
--no-dev \
--no-interaction \
--no-progress \
--prefer-dist \
--optimize-autoloader
FROM php:8.2-apache
WORKDIR /var/www/html
RUN apt-get update && apt-get install -y \
libzip-dev \
libicu-dev \
unzip \
curl \
default-mysql-client \
&& docker-php-ext-install pdo_mysql bcmath exif intl zip \
&& a2enmod rewrite headers expires \
&& rm -rf /var/lib/apt/lists/*
COPY . .
COPY --from=vendor /var/www/html/vendor ./vendor
COPY --from=frontend /var/www/html/public/build ./public/build
COPY docker/apache-vhost.conf /etc/apache2/sites-available/000-default.conf
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh \
&& chown -R www-data:www-data storage bootstrap/cache \
&& chmod -R ug+rwx storage bootstrap/cache
EXPOSE 80
ENTRYPOINT ["entrypoint.sh"]
CMD ["apache2-foreground"]

View File

@@ -0,0 +1,12 @@
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

27
app/docker/entrypoint.sh Normal file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env sh
set -eu
cd /var/www/html
php artisan config:clear >/dev/null 2>&1 || true
if [ "${DB_CONNECTION:-}" = "mysql" ] && [ "${WAIT_FOR_DB:-true}" = "true" ]; then
echo "Waiting for MySQL at ${DB_HOST:-mysql}:${DB_PORT:-3306}..."
i=0
while [ "$i" -lt 60 ]; do
if php -r 'try { new PDO("mysql:host=".getenv("DB_HOST").";port=".getenv("DB_PORT").";dbname=".getenv("DB_DATABASE"), getenv("DB_USERNAME"), getenv("DB_PASSWORD"), [PDO::ATTR_TIMEOUT => 3]); exit(0);} catch (Throwable $e) { exit(1);}'; then
echo "MySQL is reachable."
break
fi
i=$((i + 1))
sleep 2
done
fi
if [ "${RUN_MIGRATIONS:-true}" = "true" ]; then
php artisan migrate --force
fi
php artisan storage:link >/dev/null 2>&1 || true
exec "$@"

66
docker-compose.yml Normal file
View File

@@ -0,0 +1,66 @@
services:
app:
build:
context: ./app
dockerfile: Dockerfile
restart: unless-stopped
depends_on:
mysql:
condition: service_healthy
ports:
- "${APP_PORT:-8000}:80"
environment:
APP_NAME: ${APP_NAME:-Dewemoji}
APP_ENV: ${APP_ENV:-production}
APP_DEBUG: ${APP_DEBUG:-false}
APP_URL: ${APP_URL:-http://localhost:8000}
APP_KEY: ${APP_KEY:-}
DB_CONNECTION: mysql
DB_HOST: mysql
DB_PORT: 3306
DB_DATABASE: ${DB_DATABASE:-dewemoji}
DB_USERNAME: ${DB_USERNAME:-dewemoji}
DB_PASSWORD: ${DB_PASSWORD:-changeme}
SESSION_DRIVER: ${SESSION_DRIVER:-file}
CACHE_STORE: ${CACHE_STORE:-file}
QUEUE_CONNECTION: ${QUEUE_CONNECTION:-sync}
DEWEMOJI_BILLING_MODE: ${DEWEMOJI_BILLING_MODE:-sandbox}
DEWEMOJI_GUMROAD_ENABLED: ${DEWEMOJI_GUMROAD_ENABLED:-false}
DEWEMOJI_GUMROAD_PRODUCT_IDS: ${DEWEMOJI_GUMROAD_PRODUCT_IDS:-}
DEWEMOJI_GUMROAD_TEST_KEYS: ${DEWEMOJI_GUMROAD_TEST_KEYS:-}
DEWEMOJI_MAYAR_ENABLED: ${DEWEMOJI_MAYAR_ENABLED:-false}
DEWEMOJI_MAYAR_API_BASE: ${DEWEMOJI_MAYAR_API_BASE:-}
DEWEMOJI_MAYAR_ENDPOINT_VERIFY: ${DEWEMOJI_MAYAR_ENDPOINT_VERIFY:-/v1/license/verify}
DEWEMOJI_MAYAR_API_KEY: ${DEWEMOJI_MAYAR_API_KEY:-}
DEWEMOJI_MAYAR_SECRET_KEY: ${DEWEMOJI_MAYAR_SECRET_KEY:-}
WAIT_FOR_DB: ${WAIT_FOR_DB:-true}
RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true}
volumes:
- app_storage:/var/www/html/storage
mysql:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE:-dewemoji}
MYSQL_USER: ${DB_USERNAME:-dewemoji}
MYSQL_PASSWORD: ${DB_PASSWORD:-changeme}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootchangeme}
ports:
- "${MYSQL_PORT:-3306}:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u$$MYSQL_USER -p$$MYSQL_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 15
start_period: 20s
volumes:
app_storage:
mysql_data:

View File

@@ -149,6 +149,16 @@
- [ ] Run parity QA on tone handling, insert/copy behavior, and API limits. - [ ] Run parity QA on tone handling, insert/copy behavior, and API limits.
- [ ] Prepare migration + rollback checklist (DNS/host switch, redirects, monitoring). - [ ] Prepare migration + rollback checklist (DNS/host switch, redirects, monitoring).
### Phase 10 - Deployment hardening (Coolify/ops)
- [x] Define single-stack deployment template (app + mysql) in the same destination/network.
- [x] Add startup sequence for server deployment:
- wait for DB readiness
- run migrations automatically (idempotent)
- start web server
- [ ] Keep local/dev simple with SQLite profile; keep staging/prod profile on MySQL.
- [ ] Add deployment runbook with minimum required env vars and health verification steps.
- [ ] Add post-deploy smoke checks (`/`, `/v1/health`, `/v1/emojis`, `/robots.txt`, `/sitemap.xml`).
## Recent implementation update ## Recent implementation update
- Added new API endpoints in rebuild: - Added new API endpoints in rebuild:
@@ -179,6 +189,10 @@
- `/sitemap.xml` route generated from dataset - `/sitemap.xml` route generated from dataset
- meta/OG/Twitter fields in shared layout - meta/OG/Twitter fields in shared layout
- JSON-LD blocks on `/pricing`, `/support`, `/api-docs`, and emoji detail page - JSON-LD blocks on `/pricing`, `/support`, `/api-docs`, and emoji detail page
- Added Docker deployment baseline for one-pack deployment:
- `docker-compose.yml` (Laravel app + MySQL 8 with healthcheck + persistent volumes)
- `app/Dockerfile` (build Vite assets + Composer deps, serve via Apache)
- `app/docker/entrypoint.sh` (DB wait + auto-migrate + startup)
## Live audit highlights (reference) ## Live audit highlights (reference)