Service Overview
Macuin runs four Docker services that work together to provide a complete development environment. Each service has a specific role in the application stack.
Nginx Image : nginx:1.27-alpinePort : 8000Web server and reverse proxy
Laravel App Image : Custom (PHP 8.3-FPM)Port : 9000 (internal)PHP application container
PostgreSQL Image : postgres:16-alpinePort : 5432Database service
Node Image : node:22-alpinePort : 5173Frontend build tools
Nginx Service
Overview
Nginx serves as the web server and entry point for HTTP requests. It handles static files and proxies PHP requests to the Laravel application container.
Configuration Details
Service Config
Server Config
Specifications
nginx :
image : nginx:1.27-alpine
container_name : laravel_nginx
ports :
- "8000:80"
volumes :
- ./:/var/www/html:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on :
- app
networks :
- laravel_network
server {
listen 80 ;
server_name _;
root /var/www/html/public;
index index.php;
location / {
try_files $ uri $ uri / /index.php?$ query_string ;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $ document_root $ fastcgi_script_name ;
fastcgi_pass app:9000;
}
location ~ /\. {
deny all ;
}
}
Property Value Base Image nginx:1.27-alpine Container Name laravel_nginx Exposed Port 8000 → 80 Document Root /var/www/html/public FastCGI Backend app:9000 Volume Access Read-only
Key Features
Alpine Linux : Minimal image size (~40MB)
Laravel Routing : Configured for Laravel’s front controller pattern
Security : Blocks access to hidden files
FastCGI : Optimized communication with PHP-FPM
Common Commands
Start
Stop
Restart
Logs
Test Config
Reload Config
docker-compose up -d nginx
Troubleshooting
The Nginx container can’t reach PHP-FPM: # Check if app container is running
docker-compose ps app
# Check app container logs
docker-compose logs app
# Verify network connectivity
docker-compose exec nginx ping app
Laravel routing may not be properly configured: # Verify Nginx config syntax
docker-compose exec nginx nginx -t
# Check document root
docker-compose exec nginx ls /var/www/html/public
Laravel App Service
Overview
The core PHP application runs in a custom PHP-FPM container. This service executes all Laravel code and handles business logic.
Configuration Details
Service Config
Dockerfile
Specifications
app :
build :
context : .
dockerfile : docker/php/Dockerfile
args :
UID : "1000"
GID : "1000"
container_name : laravel_app
working_dir : /var/www/html
volumes :
- ./:/var/www/html
environment :
DB_CONNECTION : pgsql
DB_HOST : postgres
DB_PORT : 5432
DB_DATABASE : laravel
DB_USERNAME : laravel
DB_PASSWORD : secret
depends_on :
postgres :
condition : service_healthy
networks :
- laravel_network
FROM php:8.3-fpm
ARG UID=1000
ARG GID=1000
RUN apt-get update && apt-get install -y \
git curl unzip zip \
libpq-dev \
&& docker-php-ext-install pdo pdo_pgsql \
&& rm -rf /var/lib/apt/lists/*
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
RUN groupadd -g ${GID} appuser \
&& useradd -m -u ${UID} -g ${GID} appuser
WORKDIR /var/www/html
USER appuser
Property Value Base Image php:8.3-fpm Container Name laravel_app PHP Version 8.3 Composer Version 2 Extensions pdo, pdo_pgsql Working Directory /var/www/html User appuser (UID 1000)
Installed PHP Extensions
pdo : PHP Data Objects
pdo_pgsql : PostgreSQL driver for PDO
Environment Variables
Variable Value Purpose DB_CONNECTIONpgsqlDatabase driver DB_HOSTpostgresDatabase hostname DB_PORT5432Database port DB_DATABASElaravelDatabase name DB_USERNAMElaravelDatabase user DB_PASSWORDsecretDatabase password
Common Commands
Shell Access
Run Artisan
Composer Install
Run Tests
Clear Cache
View Logs
docker-compose exec app bash
Development Workflow
Code Changes
Edit files on your host machine. Changes are immediately reflected in the container via volume mount.
Database Migrations
docker-compose exec app php artisan migrate
Install Dependencies
docker-compose exec app composer require vendor/package
Clear Cache
docker-compose exec app php artisan optimize:clear
Troubleshooting
File permission issues between host and container: # Check current UID/GID
id -u
id -g
# Rebuild with correct UID/GID
docker-compose build --build-arg UID= $( id -u ) --build-arg GID= $( id -g ) app
docker-compose up -d app
Database Connection Failed
Laravel can’t connect to PostgreSQL: # Check PostgreSQL is healthy
docker-compose ps postgres
# Test connection from app container
docker-compose exec app php artisan db:show
# Check environment variables
docker-compose exec app env | grep DB_
Composer runs out of memory: docker-compose exec app php -d memory_limit= -1 /usr/bin/composer install
PostgreSQL Service
Overview
PostgreSQL 16 provides the relational database for the application. Data is persisted in a named Docker volume.
Configuration Details
Service Config
Health Check
Specifications
postgres :
image : postgres:16-alpine
container_name : laravel_postgres
environment :
POSTGRES_DB : laravel
POSTGRES_USER : laravel
POSTGRES_PASSWORD : secret
ports :
- "5432:5432"
volumes :
- postgres_data:/var/lib/postgresql/data
networks :
- laravel_network
healthcheck :
test : [ "CMD-SHELL" , "pg_isready -U laravel -d laravel" ]
interval : 5s
timeout : 3s
retries : 20
PostgreSQL includes a health check to ensure the database is ready before dependent services start. healthcheck :
test : [ "CMD-SHELL" , "pg_isready -U laravel -d laravel" ]
interval : 5s
timeout : 3s
retries : 20
Checks every 5 seconds
Times out after 3 seconds
Retries up to 20 times (100 seconds total)
Property Value Base Image postgres:16-alpine Container Name laravel_postgres PostgreSQL Version 16 Exposed Port 5432 → 5432 Database laravel Username laravel Data Volume postgres_data
Environment Variables
Variable Default Description POSTGRES_DBlaravelInitial database name POSTGRES_USERlaravelSuperuser username POSTGRES_PASSWORDsecretSuperuser password
Change POSTGRES_PASSWORD before deploying to production!
Common Commands
Connect to Database
Execute SQL Query
Database Backup
Restore Backup
View Logs
Check Health
docker-compose exec postgres psql -U laravel -d laravel
Database Management
docker-compose exec postgres psql -U laravel -d laravel
Common psql commands:
\l - List databases
\dt - List tables
\d table_name - Describe table
\q - Exit
docker-compose exec postgres createdb -U laravel new_database
docker-compose exec postgres dropdb -U laravel database_name
This permanently deletes all data in the database!
SELECT * FROM pg_stat_activity WHERE datname = 'laravel' ;
Data Persistence
The postgres_data named volume stores all database files:
Data persists across:
Container restarts
Container recreation
docker-compose down
Data is lost when:
Volume is explicitly deleted
docker-compose down -v is run
Troubleshooting
PostgreSQL may still be starting: # Check health status
docker-compose ps postgres
# Watch startup logs
docker-compose logs -f postgres
# Verify port is accessible
nc -zv localhost 5432
Password Authentication Failed
Credentials may be incorrect: # Check environment variables
docker-compose exec postgres env | grep POSTGRES
# Try connecting with psql
docker-compose exec postgres psql -U laravel -d laravel
Check volume size: docker system df -v
docker volume inspect macuin_postgres_data
Node Service
Overview
The Node.js service runs Vite for frontend asset compilation and hot module replacement during development.
Configuration Details
Service Config
Startup Sequence
Specifications
node :
image : node:22-alpine
container_name : laravel_node
working_dir : /var/www/html
user : "0:0"
volumes :
- ./:/var/www/html
- node_modules:/var/www/html/node_modules
ports :
- "5173:5173"
command : sh -lc "chown -R 1000:1000 /var/www/html/node_modules && npm ci || npm i && npm run dev -- --host 0.0.0.0 --port 5173 --strictPort"
The container executes the following on startup:
Fix Permissions
chown -R 1000:1000 /var/www/html/node_modules
Install Dependencies
Uses npm ci for reproducible builds, falls back to npm i
Start Vite Dev Server
npm run dev -- --host 0.0.0.0 --port 5173 --strictPort
Binds to all interfaces
Forces port 5173
Fails if port is unavailable
Property Value Base Image node:22-alpine Container Name laravel_node Node Version 22 Exposed Port 5173 → 5173 Working Directory /var/www/html Initial User root (0:0) Volume Separate node_modules
Volume Strategy
volumes :
- ./:/var/www/html
- node_modules:/var/www/html/node_modules
The node_modules volume overlay provides:
Performance : Faster I/O on Docker Desktop
Isolation : Prevents host/container conflicts
Consistency : Same packages across team
Common Commands
View Vite Logs
Install Package
Run Build
Run Scripts
Access Shell
Clear node_modules
docker-compose logs -f node
Vite Development Server
Access the Vite dev server at http://localhost:5173
Features:
Hot Module Replacement (HMR)
Fast rebuild times
Error overlay
Source maps
Configuration:
export default {
server: {
host: '0.0.0.0' ,
port: 5173 ,
strictPort: true
}
}
Troubleshooting
EADDRINUSE: Port Already in Use
Port 5173 is occupied: # Find process using port 5173
lsof -i :5173
# Or change port in docker-compose.yml
ports:
- "5174:5173"
Module Not Found After Install
node_modules may need refresh: # Restart node service
docker-compose restart node
# Or clear and reinstall
docker volume rm macuin_node_modules
docker-compose up -d node
Hot reload may not be connecting:
Check Vite is bound to 0.0.0.0
Verify port 5173 is accessible
Check browser console for WebSocket errors
# Verify Vite config
docker-compose exec node cat vite.config.js
File ownership issues: # Fix permissions
docker-compose exec node chown -R 1000:1000 /var/www/html/node_modules
Service Management
Starting Services
Start All Services
Start Specific Service
Start with Logs
Rebuild and Start
Stopping Services
Stop All Services
Stop Specific Service
Stop and Remove
Stop and Remove Volumes
docker-compose down -v deletes all data in volumes, including your database!
Viewing Logs
All Services
Specific Service
Last 100 Lines
Since Timestamp
Service Status
# View running containers
docker-compose ps
# View detailed status
docker-compose ps -a
# View resource usage
docker stats
Executing Commands
Interactive Shell
Single Command
As Different User
Without TTY
docker-compose exec app bash
Health Monitoring
Check Service Health
# View health status
docker-compose ps
# Inspect specific service
docker inspect laravel_postgres | grep -A 10 Health
# Watch health checks
watch -n 1 'docker-compose ps'
Service Dependencies
The startup order ensures dependencies are ready:
postgres (healthy) → app → nginx
node (independent)
Best Practices
Development
Keep containers running during development
Use exec for running commands
Monitor logs for errors
Restart services after config changes
Performance
Use named volumes for better I/O
Limit log retention
Prune unused resources regularly
Use Alpine images where possible
Security
Change default passwords
Use environment files for secrets
Run as non-root users
Keep images updated
Maintenance
Backup database regularly
Monitor disk space
Update images periodically
Review logs for warnings
Quick Reference
Port Mappings
Service Container Port Host Port URL Nginx 80 8000 http://localhost:8000 PostgreSQL 5432 5432 localhost:5432 Node (Vite) 5173 5173 http://localhost:5173 PHP-FPM 9000 - Internal only
Volume Names
macuin_postgres_data - Database files
macuin_node_modules - Node.js packages
Network Name
macuin_laravel_network - Bridge network for inter-service communication
Next Steps
Configuration Customize Docker Compose settings
Overview Review the architecture overview