app/.docker/production
2025-11-15 10:19:53 +01:00
..
.dockerignore 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
docker-compose.test.yml 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
Dockerfile 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
entrypoint.sh 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
nginx.conf 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
README.md 2 - add production build and compose files 2025-11-15 10:19:53 +01:00
supervisord.conf 2 - add production build and compose files 2025-11-15 10:19:53 +01:00

Dish Planner - Self-Hosted Deployment Guide

This directory contains everything you need to deploy Dish Planner as a self-hosted all-in-one container.

Note

: This guide uses an embedded docker-compose configuration (no separate file to download). Simply copy the YAML configuration shown below and save it as docker-compose.yml.

Quick Start

For End Users (Using Pre-Built Image)

Image Versioning: This guide uses the :latest tag for simplicity. For production deployments, consider using a specific version tag (e.g., :v0.3) for stability and predictable updates.

  1. Create a docker-compose.yml file:

    Copy the following configuration and save it as docker-compose.yml:

    # ============================================
    # Dish Planner - Self-Hosted Deployment
    # ============================================
    #
    # QUICK START:
    # 1. Save this file as docker-compose.yml
    # 2. (Optional) Edit the environment variables below
    # 3. Run: docker compose up -d
    # 4. Access your app at http://localhost:3000
    #
    # IMPORTANT SECURITY NOTES:
    # - Database credentials are auto-generated on first run
    # - Check the container logs to see generated credentials:
    #   docker logs dishplanner
    # - For production, set a custom APP_URL environment variable
    #
    # CUSTOMIZATION:
    # You can override any environment variable by uncommenting
    # and editing the values below, or by creating a .env file.
    #
    # ============================================
    
    services:
      dishplanner:
        # Pre-built all-in-one image from Codeberg Container Registry
        image: codeberg.org/lvl0/dish-planner:latest
    
        container_name: dishplanner
        restart: unless-stopped
    
        # ----------------------------------------
        # Port Configuration
        # ----------------------------------------
        # The application will be accessible on port 3000
        # Change the left number to use a different host port
        # Example: "8080:80" to access on port 8080
        ports:
          - "3000:80"
    
        # ----------------------------------------
        # Environment Variables
        # ----------------------------------------
        # Uncomment and customize as needed
        environment:
          # Application URL (set this to your domain)
          - APP_URL=http://localhost:3000
    
          # Application environment (production recommended)
          - APP_ENV=production
    
          # Debug mode (set to false in production for security)
          - APP_DEBUG=false
    
          # Database configuration
          # Note: Credentials are auto-generated on first run if not set
          # Check logs for generated credentials: docker logs dishplanner
          # - DB_DATABASE=dishplanner
          # - DB_USERNAME=dishuser
          # - DB_PASSWORD=change-this-secure-password
    
          # Timezone (optional)
          # - APP_TIMEZONE=UTC
    
        # ----------------------------------------
        # Persistent Data Volumes
        # ----------------------------------------
        # These volumes ensure data persists across container restarts
        volumes:
          # MySQL database data
          - dishplanner_mysql_data:/var/lib/mysql
    
          # Laravel storage (uploaded files, logs, cache)
          - dishplanner_storage:/var/www/backend/storage
    
          # Supervisor logs
          - dishplanner_logs:/var/log/supervisor
    
        # ----------------------------------------
        # Health Check (optional)
        # ----------------------------------------
        # Uncomment to enable container health monitoring
        # healthcheck:
        #   test: ["CMD", "curl", "-f", "http://localhost/api/health"]
        #   interval: 30s
        #   timeout: 10s
        #   retries: 3
        #   start_period: 60s
    
    # ----------------------------------------
    # Named Volumes
    # ----------------------------------------
    # Docker manages these volumes - data persists even if container is removed
    volumes:
      dishplanner_mysql_data:
        driver: local
      dishplanner_storage:
        driver: local
      dishplanner_logs:
        driver: local
    
    # ----------------------------------------
    # Network Configuration
    # ----------------------------------------
    # Uses default bridge network (suitable for single-host deployment)
    # For advanced setups, you can define custom networks here
    
  2. Start the application:

    docker compose up -d
    
  3. View the initialization logs to get your database credentials:

    docker logs dishplanner
    

    Save the auto-generated database credentials shown in the logs!

  4. Access the application: Open your browser to http://localhost:3000

That's it! The application is now running with:

  • MySQL database
  • Laravel backend API
  • React Router frontend
  • Nginx reverse proxy
  • Background queue worker

For DockGE Users

  1. In the DockGE web UI, click "Add Stack"
  2. Copy the entire YAML configuration from the code block above (starting from services: and including all volumes)
  3. Paste it into the DockGE compose editor
  4. Optionally edit the environment variables
  5. Click "Start"
  6. View logs to get auto-generated database credentials

Configuration

Environment Variables

You can customize the deployment by setting these environment variables in the docker-compose file:

Variable Default Description
APP_URL http://localhost:3000 The URL where your app is accessible
APP_ENV production Environment mode (production/local)
APP_DEBUG false Enable debug mode (never use in production!)
DB_DATABASE dishplanner Database name
DB_USERNAME dishuser Database username
DB_PASSWORD Auto-generated Database password (check logs for generated value)

Changing the Port

By default, the app runs on port 3000. To use a different port, edit the ports section:

ports:
  - "8080:80"  # This makes the app available on port 8080

Persistent Data

The following data is persisted in Docker volumes:

  • MySQL database - All your dishes, schedules, and users
  • Laravel storage - Uploaded files, logs, and cache
  • Supervisor logs - Application and service logs

Even if you remove the container, this data remains intact.

Building the Image Yourself

If you prefer to build the image yourself instead of using the pre-built one:

  1. Clone the repository:

    git clone https://codeberg.org/lvl0/dish-planner.git
    cd dish-planner
    
  2. Build the image:

    docker build -f .docker/production/Dockerfile -t codeberg.org/lvl0/dish-planner:latest .
    
  3. Create a docker-compose.yml file using the configuration shown in the Quick Start section above (or save the embedded compose config to a file)

  4. Run it:

    docker compose up -d
    

Management

Viewing Logs

# All logs
docker logs dishplanner

# Follow logs in real-time
docker logs -f dishplanner

# Last 100 lines
docker logs --tail 100 dishplanner

Stopping the Application

docker compose down

Restarting the Application

docker compose restart

Updating to a New Version

  1. Pull the latest image:

    docker compose pull
    
  2. Recreate the container:

    docker compose up -d
    
  3. Your data persists in volumes automatically!

Troubleshooting

"Cannot connect to database"

Check that MySQL started successfully:

docker logs dishplanner | grep mysql

"502 Bad Gateway"

One of the services may not have started. Check supervisor logs:

docker exec dishplanner supervisorctl status

Reset Everything (CAUTION: Deletes all data!)

docker compose down -v  # The -v flag removes volumes
docker compose up -d

Access the Container Shell

docker exec -it dishplanner bash

Run Laravel Commands

# Run migrations
docker exec dishplanner php /var/www/backend/artisan migrate

# Create a new user (if needed)
docker exec -it dishplanner php /var/www/backend/artisan tinker

Architecture

This all-in-one container includes:

  • MySQL 8.0 - Database server
  • PHP 8.2-FPM - Runs the Laravel backend
  • Node.js 20 - Runs the React Router frontend
  • Nginx - Web server and reverse proxy
  • Supervisord - Process manager that keeps everything running

All services start automatically and are monitored by supervisord. If any service crashes, it will be automatically restarted.

Security Recommendations

For production deployments:

  1. Set a strong database password:

    environment:
      - DB_PASSWORD=your-very-secure-password-here
    
  2. Use HTTPS: Put the container behind a reverse proxy (Nginx, Caddy, Traefik) with SSL/TLS

  3. Set APP_DEBUG to false:

    environment:
      - APP_DEBUG=false
    
  4. Keep the image updated: Regularly pull and deploy new versions

  5. Backup your data:

    # Backup volumes
    docker run --rm -v dishplanner_mysql_data:/data -v $(pwd):/backup ubuntu tar czf /backup/mysql-backup.tar.gz /data
    

Support

For issues and questions:

What's Inside

The container runs these processes (managed by supervisord):

  1. MySQL - Database (port 3306, internal only)
  2. PHP-FPM - Laravel application (port 9000, internal only)
  3. Node.js - React frontend (port 3000, internal only)
  4. Nginx - Reverse proxy (port 80, exposed)
  5. Queue Worker - Background job processor

Only Nginx's port 80 is exposed to the host (mapped to 3000 by default).