diff --git a/dockerized/README.md b/dockerized/README.md new file mode 100644 index 0000000..6d8c34c --- /dev/null +++ b/dockerized/README.md @@ -0,0 +1,206 @@ +# Nyone Dockerized Deployment + +This folder is a self-contained deployment bundle. A server only needs the `dockerized/` directory; the application repository is cloned later into `runtime/source` by `scripts/deploy.sh`. + +## What It Runs + +- Laravel app served by Apache. +- PostgreSQL database. +- Redis cache for Laravel cache and streaming viewer counts. +- MediaMTX for RTMP ingest, HLS playback, hooks, recordings, and the private API. +- Laravel queue worker. +- Laravel scheduler worker. +- Long-running `streaming:sync-viewer-counts` worker. + +Default ports use the services' normal defaults: + +- HTTP app/HLS proxy: `80` +- RTMP ingest: `1935` +- MediaMTX HLS inside Docker: `8888` +- MediaMTX API inside Docker: `9997` +- PostgreSQL inside Docker: `5432` +- Redis inside Docker: `6379` + +Only HTTP and RTMP are published by default. HLS is served through Apache on `HLS_DOMAIN`, not directly from MediaMTX. + +## Server Requirements + +- Docker with Compose v2. +- Git. +- OpenSSL. +- Network access from the server to the Git repository. +- DNS for both `APP_DOMAIN` and `HLS_DOMAIN`. +- External TLS termination through a reverse proxy, load balancer, or CDN. + +If a host-level reverse proxy already uses port `80`, set `APP_HTTP_PORT` to another local port and forward both hostnames to that port. + +## First Deployment + +```bash +cd dockerized +cp .env.example .env +nano .env +chmod +x scripts/deploy.sh +./scripts/deploy.sh +``` + +At minimum, change these values in `.env`: + +```env +GIT_REPOSITORY_URL=https://github.com/your-org/nyone.git +GIT_REF=main +APP_DOMAIN=nyone.example.com +HLS_DOMAIN=nyone-hls.example.com +PUBLIC_SCHEME=https +``` + +Leave `APP_KEY`, `POSTGRES_PASSWORD`, and `MEDIAMTX_SHARED_SECRET` empty on first deploy if you want `scripts/deploy.sh` to generate them. + +The deploy script will: + +1. Create `.env` from `.env.example` if needed. +2. Generate missing secrets. +3. Clone or update the app into `runtime/source`. +4. Validate the Compose config. +5. Build Docker images. +6. Start PostgreSQL and Redis. +7. Run Laravel migrations. +8. Start Apache, MediaMTX, queue, scheduler, and viewer-sync services. + +## Runtime Configuration + +This bundle does not use the cloned repository's `.env` file for production settings. Docker Compose passes configuration from `dockerized/.env` into the containers. + +Important values: + +- `APP_DOMAIN`: Laravel app hostname. +- `HLS_DOMAIN`: HLS playback hostname. Must differ from `APP_DOMAIN`. +- `APP_HTTP_PORT`: host port published by Apache, default `80`. +- `RTMP_PUBLIC_PORT`: host RTMP port, default `1935`. +- `PUBLIC_SCHEME`: usually `https` behind external TLS. +- `SEED_DATABASE`: defaults to `false`; set to `true` only if you intentionally want the app seeder to run. +- `QUEUE_NAMES`: queue list for the Laravel database queue worker, default `default`. + +The MediaMTX config is Docker-owned at `docker/mediamtx/mediamtx.yml.template`; it does not mount or depend on `deploy/mediamtx.yml` from the cloned repository. + +## Operations + +Run commands from the `dockerized/` directory. + +```bash +docker compose --env-file .env -f docker-compose.yml ps +docker compose --env-file .env -f docker-compose.yml logs -f app +docker compose --env-file .env -f docker-compose.yml logs -f mediamtx +docker compose --env-file .env -f docker-compose.yml exec app php artisan migrate:status +docker compose --env-file .env -f docker-compose.yml exec app php artisan streaming:sync-viewer-counts --once -v +``` + +Redeploy after new Git changes: + +```bash +./scripts/deploy.sh +``` + +Stop the stack: + +```bash +docker compose --env-file .env -f docker-compose.yml down +``` + +Do not remove volumes unless you intend to delete database, Redis, and stored app media data. + +## External Proxy Notes + +Forward both `APP_DOMAIN` and `HLS_DOMAIN` to the Apache container's published HTTP port. Preserve the `Host` header and set `X-Forwarded-Proto: https` when TLS is terminated outside Docker. + +Expose TCP `1935` publicly for OBS/RTMP ingest. Do not expose MediaMTX API port `9997` publicly. + +## Nginx TLS Proxy Example + +Use this pattern when Nginx runs on the host and handles public HTTP/HTTPS. In that setup, let Nginx own ports `80` and `443`, and bind the Docker Apache service to a private local port: + +```env +APP_HTTP_PORT=127.0.0.1:8080 +PUBLIC_SCHEME=https +APP_DOMAIN=app.example.com +HLS_DOMAIN=hls.example.com +RTMP_PUBLIC_PORT=1935 +``` + +Run `./scripts/deploy.sh` after changing `.env`, then point Nginx at `http://127.0.0.1:8080`. Replace the example domains and certificate paths before enabling the config. + +```nginx +# /etc/nginx/sites-available/nyone-dockerized.conf + +server { + listen 80; + listen [::]:80; + server_name app.example.com hls.example.com; + + location /.well-known/acme-challenge/ { + root /var/www/html; + } + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name app.example.com; + + ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem; + + client_max_body_size 100M; + + location / { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port 443; + proxy_set_header X-Forwarded-Proto https; + proxy_read_timeout 120s; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name hls.example.com; + + ssl_certificate /etc/letsencrypt/live/hls.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/hls.example.com/privkey.pem; + + location / { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port 443; + proxy_set_header X-Forwarded-Proto https; + proxy_buffering off; + proxy_request_buffering off; + proxy_read_timeout 60s; + proxy_send_timeout 60s; + add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always; + } +} +``` + +Enable and validate on the server: + +```bash +sudo ln -s /etc/nginx/sites-available/nyone-dockerized.conf /etc/nginx/sites-enabled/nyone-dockerized.conf +sudo nginx -t +sudo systemctl reload nginx +``` + +Keep RTMP separate from this HTTP proxy. Open TCP `1935` to the Docker host so OBS can publish directly to MediaMTX. diff --git a/dockerized/SKILL.md b/dockerized/SKILL.md new file mode 100644 index 0000000..1c13e4d --- /dev/null +++ b/dockerized/SKILL.md @@ -0,0 +1,70 @@ +--- +name: dockerized-deployment +description: Work on the Nyone Dockerized deployment bundle under dockerized/. Use when modifying Docker Compose, Apache, MediaMTX, PostgreSQL, Redis, Laravel queue/scheduler/viewer-sync services, deploy.sh, deployment README files, or runtime environment defaults for this self-contained Docker deployment. +--- + +# Nyone Dockerized Deployment + +## Core Rules + +- Keep deployment changes inside `dockerized/` unless the user explicitly requests application code changes. +- Treat `dockerized/.env` and `dockerized/runtime/` as server-local generated state; do not commit or depend on them. +- Do not make this bundle depend on the cloned app repository's `.env` or `deploy/mediamtx.yml`. +- Keep MediaMTX config Docker-owned at `docker/mediamtx/mediamtx.yml.template`. +- Keep `APP_DOMAIN` and `HLS_DOMAIN` separate because Apache uses separate virtual hosts. +- Do not run `scripts/deploy.sh`, `docker compose up`, or image builds unless the user confirms this is a deployment server. + +## Architecture + +- `scripts/deploy.sh` is the entrypoint for server deployment. +- `docker-compose.yml` defines `app`, `db`, `redis`, `mediamtx`, `queue`, `scheduler`, `viewer-sync`, and one-shot `migrate`. +- `docker/app/Dockerfile` builds the Laravel Apache image from `runtime/source`. +- `docker/app/entrypoint.sh` selects behavior by `CONTAINER_ROLE`. +- `docker/app/apache/nyone.conf.template` serves Laravel on `APP_DOMAIN` and proxies HLS for `HLS_DOMAIN`. +- `docker/mediamtx/entrypoint.sh` renders the MediaMTX template at container start. + +## Port Defaults + +- Apache published HTTP: `80`. +- MediaMTX RTMP: `1935`. +- MediaMTX HLS internal: `8888`. +- MediaMTX API internal: `9997`. +- PostgreSQL internal: `5432`. +- Redis internal: `6379`. + +Only publish HTTP and RTMP by default. Keep MediaMTX HLS behind Apache and keep the API private on the Docker network. + +## Editing Guidance + +- When adding an environment option, update `.env.example`, `docker-compose.yml`, and any entrypoint/template that consumes it. +- When changing MediaMTX ports, update Compose environment, published ports, entrypoint defaults, and the template together. +- When changing Laravel runtime behavior, update the shared `x-app-environment` block unless the value belongs to one role only. +- When changing queue behavior, prefer env-driven options on the `queue` service and `docker/app/entrypoint.sh`. +- Keep deploy script behavior idempotent: repeat runs should update the Git checkout, rebuild, migrate, and restart services without deleting volumes. +- Keep generated secrets in `.env`; do not bake secrets into images or templates. + +## Nginx TLS Proxy Guidance + +- Document Nginx as a host-level TLS reverse proxy in `README.md`; do not add Nginx as another Compose service unless the user asks. +- Keep Docker Apache as the upstream for both app and HLS hostnames. Nginx should proxy both domains to the published Apache port and preserve the `Host` header so Apache can select the correct virtual host. +- Recommend `APP_HTTP_PORT=127.0.0.1:8080` when Nginx owns host ports `80` and `443`. +- Include `X-Forwarded-Proto https`, `X-Forwarded-Port 443`, `X-Forwarded-Host`, `X-Real-IP`, and `X-Forwarded-For` in proxy examples. +- Keep HLS proxy examples buffering off and cache headers set to no-store. +- Keep RTMP outside the HTTP proxy guidance unless explicitly using Nginx stream proxying; the default is direct TCP `1935` to MediaMTX through Docker. + +## Static Verification + +Use static checks when not on a deployment server: + +```bash +git diff --check +rg "1993[5]|1998[8]|80[8]0|25[2]5|nyone[.]net|nyone-hls[.]net|change-this-secre[t]" dockerized -n +``` + +If Docker is available and the user allows non-deploy validation, validate only the Compose config: + +```bash +docker compose --env-file dockerized/.env.example -f dockerized/docker-compose.yml config +``` + +Do not start containers during local verification unless the user explicitly asks for runtime testing.