chg: pkg: make compatible the whole project with bare metal AND with docker #4
This commit is contained in:
12
.dockerignore
Normal file
12
.dockerignore
Normal file
@@ -0,0 +1,12 @@
|
||||
.git
|
||||
.gitignore
|
||||
node_modules
|
||||
var/cache
|
||||
var/log
|
||||
var/sessions
|
||||
public/build
|
||||
*.md
|
||||
docker-compose*.yml
|
||||
compose.override.yaml
|
||||
.env.local
|
||||
.env.*.local
|
||||
@@ -16,7 +16,8 @@ APP_SECRET=c1c278747d952ea66326352b72bb8ec6
|
||||
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
|
||||
###< doctrine/doctrine-bundle ###
|
||||
###> symfony/mailer ###
|
||||
# MAILER_DSN=smtp://localhost
|
||||
MAILER_DSN=smtp://localhost:1025
|
||||
MAIL_DOMAIN=localhost
|
||||
###< symfony/mailer ###
|
||||
|
||||
###> symfony/mercure-bundle ###
|
||||
|
||||
25
Caddyfile
Normal file
25
Caddyfile
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
{$CADDY_GLOBAL_OPTIONS}
|
||||
|
||||
frankenphp {
|
||||
{$FRANKENPHP_CONFIG}
|
||||
}
|
||||
}
|
||||
|
||||
{$SERVER_NAME:localhost} {
|
||||
log
|
||||
|
||||
root * /app/public
|
||||
|
||||
encode zstd br gzip
|
||||
|
||||
mercure {
|
||||
transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
|
||||
publisher_jwt {$MERCURE_JWT_SECRET} HS256
|
||||
subscriber_jwt {$MERCURE_JWT_SECRET} HS256
|
||||
anonymous
|
||||
subscriptions
|
||||
}
|
||||
|
||||
php_server
|
||||
}
|
||||
52
Dockerfile
Normal file
52
Dockerfile
Normal file
@@ -0,0 +1,52 @@
|
||||
FROM node:22-alpine AS assets
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
COPY vite.config.js ./
|
||||
COPY assets/ assets/
|
||||
COPY public/ public/
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM dunglas/frankenphp:latest
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_pgsql \
|
||||
gd \
|
||||
intl \
|
||||
zip \
|
||||
opcache \
|
||||
apcu \
|
||||
sodium
|
||||
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
RUN printf '[opcache]\nopcache.enable=1\nopcache.memory_consumption=256\nopcache.max_accelerated_files=20000\nopcache.validate_timestamps=0\n' \
|
||||
> "$PHP_INI_DIR/conf.d/opcache.ini"
|
||||
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
ENV APP_ENV=prod
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN composer install \
|
||||
--no-dev \
|
||||
--no-interaction \
|
||||
--no-scripts \
|
||||
--optimize-autoloader
|
||||
|
||||
COPY --from=assets /app/public/build ./public/build
|
||||
|
||||
RUN mkdir -p var/cache var/log var/sessions && \
|
||||
chown -R www-data:www-data var/
|
||||
|
||||
COPY Caddyfile /etc/caddy/Caddyfile
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
48
Makefile
Normal file
48
Makefile
Normal file
@@ -0,0 +1,48 @@
|
||||
.PHONY: help start start-build stop build down ps logs prune-everything db-reset
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
help:
|
||||
@echo "Available commands:"
|
||||
@echo " make start - Start services without building (uses existing images)"
|
||||
@echo " make start-build - Start services and build images if needed"
|
||||
@echo " make stop - Stop running services"
|
||||
@echo " make build - Build Docker images only"
|
||||
@echo " make down - Stop and remove containers/networks"
|
||||
@echo " make prune-everything - Prune volumes, networks and images (DANGEROUS!)"
|
||||
@echo " make db-reset - Reset the database (drop, create, migrate) (DANGEROUS!)"
|
||||
|
||||
start:
|
||||
docker compose up -d
|
||||
|
||||
start-build:
|
||||
docker compose up -d --build
|
||||
|
||||
stop:
|
||||
docker compose stop
|
||||
|
||||
build:
|
||||
docker compose build
|
||||
|
||||
down:
|
||||
docker compose down
|
||||
|
||||
prune-everything:
|
||||
@echo "WARNING: This will remove ALL containers, volumes, networks and images!"
|
||||
@read -p "Type 'yes' to confirm: " confirm; \
|
||||
if [ "$$confirm" != "yes" ]; then \
|
||||
echo "Aborted."; \
|
||||
exit 1; \
|
||||
fi
|
||||
docker compose down -v --rmi all --remove-orphans
|
||||
|
||||
db-reset:
|
||||
@echo "WARNING: This will DROP and RECREATE the database!"
|
||||
@read -p "Type 'yes' to confirm: " confirm; \
|
||||
if [ "$$confirm" != "yes" ]; then \
|
||||
echo "Aborted."; \
|
||||
exit 1; \
|
||||
fi
|
||||
bin/console doctrine:database:drop --force --if-exists --no-interaction
|
||||
bin/console doctrine:database:create --if-not-exists --no-interaction
|
||||
bin/console doctrine:migrations:migrate --no-interaction
|
||||
69
compose.yaml
Normal file
69
compose.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "10080:80"
|
||||
environment:
|
||||
SERVER_NAME: ${SERVER_NAME:-:80}
|
||||
APP_ENV: prod
|
||||
APP_SECRET: ${APP_SECRET}
|
||||
DATABASE_URL: >-
|
||||
postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?serverVersion=${POSTGRES_VERSION}&charset=utf8
|
||||
POSTGRES_URL: db
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
MERCURE_URL: http://localhost/.well-known/mercure
|
||||
MERCURE_PUBLIC_URL: https://${PUBLIC_HOSTNAME:-localhost}/.well-known/mercure
|
||||
MERCURE_JWT_SECRET: ${MERCURE_JWT_SECRET}
|
||||
MERCURE_JWT_TOKEN: ${MERCURE_JWT_TOKEN}
|
||||
MERCURE_SUBSCRIBER_JWT: ${MERCURE_SUBSCRIBER_JWT}
|
||||
MAILER_DSN: smtp://mail:25?verify_peer=0
|
||||
RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY}
|
||||
RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY}
|
||||
WEBAUTHN_RP_ID: ${WEBAUTHN_RP_ID:-localhost}
|
||||
WEBAUTHN_ORIGIN: ${WEBAUTHN_ORIGIN:-https://localhost}
|
||||
volumes:
|
||||
- app_var:/app/var
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
mail:
|
||||
condition: service_started
|
||||
mail:
|
||||
image: boky/postfix:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
ALLOWED_SENDER_DOMAINS: ${MAIL_DOMAIN:-localhost}
|
||||
# Optional: set a relay host if you need to forward to an external SMTP
|
||||
# RELAYHOST: "[smtp.example.com]:587"
|
||||
volumes:
|
||||
- postfix_spool:/var/spool/postfix
|
||||
db:
|
||||
image: postgres:${POSTGRES_VERSION:-latest}-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}" ]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
ports:
|
||||
- "15432:5432"
|
||||
volumes:
|
||||
app_var:
|
||||
postgres_data:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
postfix_spool:
|
||||
@@ -7,14 +7,7 @@ parameters:
|
||||
|
||||
doctrine:
|
||||
dbal:
|
||||
# configure these for your database server
|
||||
driver: 'pdo_mysql'
|
||||
server_version: '5.7'
|
||||
charset: utf8mb4
|
||||
default_table_options:
|
||||
charset: utf8mb4
|
||||
collate: utf8mb4_unicode_ci
|
||||
|
||||
driver: 'pdo_pgsql'
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
|
||||
orm:
|
||||
|
||||
18
docker/entrypoint.sh
Normal file
18
docker/entrypoint.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "[entrypoint] Waiting for database..."
|
||||
until php -r "new PDO('pgsql:host=db;port=5432;dbname=${POSTGRES_DB}', '${POSTGRES_USER}', '${POSTGRES_PASSWORD}');" 2>/dev/null; do
|
||||
echo "[entrypoint] Database not ready, retrying in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "[entrypoint] Database is ready."
|
||||
|
||||
echo "[entrypoint] Warming up Symfony cache..."
|
||||
php bin/console cache:warmup
|
||||
|
||||
echo "[entrypoint] Running database migrations..."
|
||||
php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
|
||||
|
||||
echo "[entrypoint] Starting FrankenPHP..."
|
||||
exec frankenphp run --config /etc/caddy/Caddyfile "$@"
|
||||
@@ -42,6 +42,11 @@ class RecaptchaType extends AbstractType
|
||||
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (PreSubmitEvent $event): void {
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
$token = $request?->request->getString('g-recaptcha-response') ?? '';
|
||||
// For forms that set the token directly on the field (e.g. registration_form[recaptcha])
|
||||
// rather than via a standalone g-recaptcha-response input, fall back to the submitted value.
|
||||
if ($token === '') {
|
||||
$token = (string) ($event->getData() ?? '');
|
||||
}
|
||||
$event->setData($token);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,6 +58,14 @@ readonly class RecaptchaService
|
||||
->request('POST', self::SITEVERIFY_URL, ['body' => $body])
|
||||
->toArray();
|
||||
|
||||
$this->logger->info('reCAPTCHA verify response', [
|
||||
'success' => $data['success'] ?? null,
|
||||
'score' => $data['score'] ?? null,
|
||||
'hostname' => $data['hostname'] ?? null,
|
||||
'error-codes' => $data['error-codes'] ?? [],
|
||||
'token_length' => strlen($token),
|
||||
]);
|
||||
|
||||
return ($data['success'] ?? false) === true
|
||||
&& ($data['score'] ?? 0.0) >= self::SCORE_THRESHOLD;
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
Reference in New Issue
Block a user