diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..05f3f9d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +.git +.github +vendor/ +.env +.env.* +logs/*.log +logs/*.txt +cache/* +!cache/.gitkeep +domain-monitor-docker/ +*.bak +*.backup +*.old +*.tmp +.DS_Store +Thumbs.db +node_modules/ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b4e680f --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +# Copy to .env and fill in real values before running docker compose up + +DB_DATABASE=domain_monitor +DB_USERNAME=domain_monitor +DB_PASSWORD=changeme +DB_ROOT_PASSWORD=rootchangeme + +# Timezone (e.g. Europe/Bucharest) +TZ=UTC + +# Set to 'development' to show detailed error pages +APP_ENV=production diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6fd68b0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +FROM php:apache + +# Build-time deps for PHP extensions +RUN apt-get update && apt-get install -y --no-install-recommends \ + libicu-dev libzip-dev libpng-dev libjpeg62-turbo-dev libfreetype6-dev \ + libxml2-dev libcurl4-openssl-dev libonig-dev pkg-config unzip git tzdata \ + && docker-php-ext-configure gd --with-jpeg --with-freetype \ + && docker-php-ext-install -j"$(nproc)" \ + pdo pdo_mysql mysqli intl zip gd bcmath mbstring curl xml \ + && a2enmod rewrite headers \ + && rm -rf /var/lib/apt/lists/* + +# Composer from official image +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +# Configure Apache to listen on port 7876 +RUN sed -i 's/Listen 80/Listen 7876/' /etc/apache2/ports.conf \ + && sed -i 's///' /etc/apache2/sites-available/000-default.conf + +# Set Apache DocumentRoot to /var/www/html/public +RUN sed -ri -e 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/000-default.conf + +# Apache request timeout +RUN echo "Timeout 300" > /etc/apache2/conf-available/timeouts.conf && a2enconf timeouts + +# PHP config +COPY docker/php.ini /usr/local/etc/php/conf.d/custom.ini + +WORKDIR /var/www/html + +# Copy application source +COPY . . + +# Install Composer dependencies +RUN composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader + +# Base permissions: code owned root:www-data, writable dirs owned www-data +RUN chown -R root:www-data /var/www/html \ + && find /var/www/html -type d -exec chmod 755 {} \; \ + && find /var/www/html -type f -exec chmod 644 {} \; \ + && mkdir -p logs cache public/assets/uploads/avatars \ + && chown -R www-data:www-data logs cache public/assets/uploads \ + && chmod -R 775 logs cache public/assets/uploads \ + && chmod 775 /var/www/html + +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +EXPOSE 7876 + +ENTRYPOINT ["/entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..af6f80d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +services: + web: + build: . + container_name: domnitor-web + restart: unless-stopped + ports: + - "7876:7876" + environment: + DB_HOST: db + DB_PORT: "3306" + DB_DATABASE: ${DB_DATABASE:-domain_monitor} + DB_USERNAME: ${DB_USERNAME:-domain_monitor} + DB_PASSWORD: ${DB_PASSWORD:-changeme} + APP_ENV: ${APP_ENV:-production} + TZ: ${TZ:-UTC} + depends_on: + db: + condition: service_healthy + + db: + image: mariadb:lts + container_name: domnitor-db + restart: unless-stopped + environment: + MARIADB_DATABASE: ${DB_DATABASE:-domain_monitor} + MARIADB_USER: ${DB_USERNAME:-domain_monitor} + MARIADB_PASSWORD: ${DB_PASSWORD:-changeme} + MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootchangeme} + TZ: ${TZ:-UTC} + command: + - "--character-set-server=utf8mb4" + - "--collation-server=utf8mb4_unicode_ci" + volumes: + - dbdata:/var/lib/mysql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + start_period: 15s + interval: 10s + timeout: 5s + retries: 5 + +volumes: + dbdata: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..74f16b6 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +ENV_FILE="/var/www/html/.env" + +upsert_kv() { + local key="$1" val="$2" + if grep -qE "^${key}=" "$ENV_FILE" 2>/dev/null; then + sed -i "s#^${key}=.*#${key}=${val}#" "$ENV_FILE" + else + printf "%s=%s\n" "$key" "$val" >> "$ENV_FILE" + fi +} + +# Bootstrap .env from template if not present +if [ ! -f "$ENV_FILE" ]; then + if [ -f /var/www/html/env.example.txt ]; then + cp /var/www/html/env.example.txt "$ENV_FILE" + else + touch "$ENV_FILE" + fi +fi + +# Inject database and app config from environment variables +upsert_kv "DB_HOST" "${DB_HOST:-db}" +upsert_kv "DB_PORT" "${DB_PORT:-3306}" +upsert_kv "DB_DATABASE" "${DB_DATABASE:-domain_monitor}" +upsert_kv "DB_USERNAME" "${DB_USERNAME:-domain_monitor}" +upsert_kv "DB_PASSWORD" "${DB_PASSWORD:-}" +upsert_kv "APP_ENV" "${APP_ENV:-production}" + +[ -n "${APP_ENCRYPTION_KEY:-}" ] && upsert_kv "APP_ENCRYPTION_KEY" "$APP_ENCRYPTION_KEY" +[ -n "${SESSION_LIFETIME:-}" ] && upsert_kv "SESSION_LIFETIME" "$SESSION_LIFETIME" + +# Ownership & permissions on runtime-writable paths +chown www-data:www-data "$ENV_FILE" +chmod 660 "$ENV_FILE" + +for d in logs cache public/assets/uploads; do + dir="/var/www/html/$d" + [ -d "$dir" ] && chown -R www-data:www-data "$dir" && chmod -R 775 "$dir" +done + +exec "$@" diff --git a/docker/php.ini b/docker/php.ini new file mode 100644 index 0000000..b7fae8c --- /dev/null +++ b/docker/php.ini @@ -0,0 +1,19 @@ +; ---- PHP limits ---- +max_execution_time = 0 +max_input_time = -1 +max_input_vars = 3000 +memory_limit = 512M +post_max_size = 32M +upload_max_filesize = 16M +default_socket_timeout = 120 + +; Recommended defaults +date.timezone = UTC +display_errors = Off +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; Opcache +opcache.enable=1 +opcache.enable_cli=1 +opcache.validate_timestamps=1 +opcache.revalidate_freq=2