fix: critical security and Docker deployment fixes

- Dockerfile: add composer/npm build, proper entrypoint, fix EXPOSE port
- docker-compose: fix postgres volume path, add healthchecks, use named volume
- Add entrypoint.sh for auto migrations and dependency install at startup
- Update .gitignore to exclude Firebase credentials, DB files, logs
- Update .env.example with all required variables for Docker deployment

Application-level fixes (applied to src/ which is gitignored):
- RainfallController: parameterized SQL queries (was SQL injection)
- WaterLevelController: parameterized queries + fix broken WHERE clause
- DatabaseSeeder: env-based admin password instead of hardcoded 'password123'
- Migration 2025_12_11: removed duplicate admin user creation
- AlertController: FCM topic routing by stationtype+level (was hardcoded)
- sidesdecode.py: env vars for credentials, fix water level stationtype bug (1→2)
This commit is contained in:
root
2026-05-21 00:36:29 +08:00
parent a71019f000
commit c57d4bac57
5 changed files with 139 additions and 62 deletions

View File

@@ -3,3 +3,18 @@ POSTGRES_USER="<your_db_user>"
POSTGRES_PASSWORD="<your_db_password>" POSTGRES_PASSWORD="<your_db_password>"
PGADMIN_EMAIL="<your_pgadmin_name>" PGADMIN_EMAIL="<your_pgadmin_name>"
PGADMIN_PASSWORD="<your_pgadmin_password>" PGADMIN_PASSWORD="<your_pgadmin_password>"
FIREBASE_PROJECT_ID="<your_firebase_project_id>"
FIREBASE_CREDENTIALS="<path_to_firebase_credentials_json>"
FCM_TOPIC_RAINFALL_WARNING="rainfall_warning"
FCM_TOPIC_RAINFALL_DANGER="rainfall_danger"
FCM_TOPIC_WATERLEVEL_ALERT="waterlevel_alert"
FCM_TOPIC_WATERLEVEL_DANGER="waterlevel_danger"
ADMIN_EMAIL="admin@example.com"
ADMIN_PASSWORD="<set_a_strong_password>"
FTP_SERVER="<your_ftp_server>"
FTP_USERNAME="<your_ftp_username>"
FTP_PASSWORD="<your_ftp_password>"

13
.gitignore vendored
View File

@@ -1,10 +1,21 @@
# Editor # Editor
.vscode .vscode
# Container file # Container data
/docker/postgres/data/* /docker/postgres/data/*
!/docker/postgres/data/.gitkeep !/docker/postgres/data/.gitkeep
# Working directory # Working directory
src/* src/*
.env .env
# Database files
*.db
*.sqlite
# Autoscript logs
autoscript/*.log
*_error.log
# Firebase credentials
src/storage/app/firebase/*.json

View File

@@ -1,20 +1,10 @@
# PHP-FPM is a FastCGI implementation for PHP.
# Read more here: https://hub.docker.com/_/php
FROM php:8.2-fpm FROM php:8.2-fpm
RUN apt-get update && apt-get -y install --fix-missing \
RUN apt-get update
# Install useful tools
RUN apt-get -y install apt-utils nano wget dialog vim
# Install system dependencies
RUN apt-get -y install --fix-missing \
apt-utils \ apt-utils \
build-essential \ build-essential \
git \ git \
curl \ curl \
libcurl4 \
libcurl4-openssl-dev \ libcurl4-openssl-dev \
zlib1g-dev \ zlib1g-dev \
libzip-dev \ libzip-dev \
@@ -24,47 +14,61 @@ RUN apt-get -y install --fix-missing \
libmcrypt-dev \ libmcrypt-dev \
libicu-dev \ libicu-dev \
libonig-dev \ libonig-dev \
libxml2-dev libxml2-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
libwebp-dev \
libxpm-dev \
libpq-dev \
nano \
wget \
vim
RUN docker-php-ext-install \ RUN docker-php-ext-configure gd \
--with-freetype \
--with-jpeg \
--with-webp \
--with-xpm \
&& docker-php-ext-install gd \
&& docker-php-ext-install \
exif \ exif \
pcntl \ pcntl \
bcmath \ bcmath \
ctype \ ctype \
curl \ curl \
pcntl \ zip \
zip
# Install Postgre PDO
RUN apt-get install -y libpq-dev \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo pdo_pgsql pgsql && docker-php-ext-install pdo pdo_pgsql pgsql
# Install NPM RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs
RUN apt-get install -y nodejs
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/* RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html WORKDIR /var/www/html
# Add user for laravel application RUN groupadd -g 1000 www \
RUN groupadd -g 1000 www && useradd -u 1000 -ms /bin/bash -g www www
RUN useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY ./src /var/www/html COPY ./src /var/www/html
# Copy existing application directory permissions
COPY --chown=www:www ./src /var/www/html COPY --chown=www:www ./src /var/www/html
# Change current user to www RUN if [ -f composer.json ]; then composer install --no-dev --optimize-autoloader --no-interaction || true; fi
RUN if [ -f package.json ]; then npm install && npm run build || true; fi
RUN chown -R www:www /var/www/html \
&& chmod -R 775 /var/www/html/storage \
&& chmod -R 775 /var/www/html/bootstrap/cache
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
USER www USER www
# Set port for application EXPOSE 9000
EXPOSE 8000
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["php-fpm"]

View File

@@ -1,28 +1,30 @@
version: "3.9"
networks: networks:
aselole: tckdev_net:
name: aselole name: tckdev_net
services: services:
app: app:
container_name: aselole-app container_name: tckdev-app
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
volumes: volumes:
- ./src:/var/www/html - ./src:/var/www/html
depends_on: depends_on:
- postgres postgres:
condition: service_healthy
networks: networks:
- aselole - tckdev_net
restart: unless-stopped
environment:
- RUN_MIGRATIONS=true
postgres: postgres:
container_name: aselole-db container_name: tckdev-db
image: postgres:15 image: postgres:16
restart: always restart: always
volumes: volumes:
- ./docker/postgres/data:/var/lib/postgres/data - pgdata:/var/lib/postgresql/data
environment: environment:
- POSTGRES_DB=${POSTGRES_DB} - POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER} - POSTGRES_USER=${POSTGRES_USER}
@@ -30,42 +32,55 @@ services:
ports: ports:
- "5432:5432" - "5432:5432"
networks: networks:
- aselole - tckdev_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-tck} -d ${POSTGRES_DB:-sides_db}"]
interval: 5s
timeout: 5s
retries: 5
web: web:
container_name: aselole-web container_name: tckdev-web
image: nginx:stable-alpine image: nginx:stable-alpine
restart: always restart: always
ports: ports:
- "85:80" - "80:80"
volumes: volumes:
- ./src:/var/www/html - ./src:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks: networks:
- aselole - tckdev_net
# Database management with pgAdmin
pgadmin: pgadmin:
image: dpage/pgadmin4 image: dpage/pgadmin4
container_name: aselole-pgAdmin container_name: tckdev-pgAdmin
environment: environment:
- PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL} - PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL}
- PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD} - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD}
volumes:
- ./backup:/var/lib/pgadmin/storage/tck68000_gmail.com/backup:z
ports: ports:
- "5050:80" - "5050:80"
depends_on: depends_on:
- postgres postgres:
condition: service_healthy
networks: networks:
- aselole - tckdev_net
restart: unless-stopped
# Database management with Adminer
adminer: adminer:
container_name: aselole-adminer container_name: tckdev-adminer
image: adminer image: adminer
restart: always restart: always
ports: ports:
- "8080:8080" - "6060:8080"
depends_on: depends_on:
- postgres postgres:
condition: service_healthy
networks: networks:
- aselole - tckdev_net
volumes:
pgdata:

32
docker/entrypoint.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
set -e
cd /var/www/html
if [ ! -f ".env" ]; then
if [ -f ".env.example" ]; then
cp .env.example .env
fi
fi
if [ ! -d "vendor" ]; then
composer install --no-dev --optimize-autoloader --no-interaction || true
fi
if [ ! -d "node_modules" ] && [ -f "package.json" ]; then
npm install || true
fi
if [ ! -d "public/build" ] && [ -f "vite.config.js" ]; then
npm run build || true
fi
php artisan config:cache 2>/dev/null || true
php artisan route:cache 2>/dev/null || true
php artisan view:cache 2>/dev/null || true
if [ "$RUN_MIGRATIONS" = "true" ]; then
php artisan migrate --force || true
fi
exec "$@"