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-countsworker.
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.
- Zip.
- Network access from the server to the Git repository.
- DNS for both
APP_DOMAINandHLS_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
cd dockerized
cp .env.example .env
nano .env
chmod +x scripts/deploy.sh
chmod +x scripts/backup.sh
./scripts/deploy.sh
At minimum, change these values in .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:
- Create
.envfrom.env.exampleif needed. - Generate missing secrets.
- Clone or update the app into
runtime/source. - Validate the Compose config.
- Build Docker images.
- Start PostgreSQL and Redis.
- Run Laravel migrations.
- 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 fromAPP_DOMAIN.APP_HTTP_PORT: host port published by Apache, default80.RTMP_PUBLIC_PORT: host RTMP port, default1935.PUBLIC_SCHEME: usuallyhttpsbehind external TLS.SEED_DATABASE: defaults tofalse; set totrueonly if you intentionally want the app seeder to run.QUEUE_NAMES: queue list for the Laravel database queue worker, defaultdefault.
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.
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:
./scripts/deploy.sh
Create a restore-ready backup zip:
./scripts/backup.sh
For the most consistent app storage and recording backup, run it during a maintenance window and let the script stop writer services while it archives files:
./scripts/backup.sh --stop-writers
Backups are written to backups/ by default. Each zip contains deployment files, .env, runtime/source, PostgreSQL dump, app storage, Redis data, checksums, restore notes, and a restore.sh helper.
Restore on a fresh server after installing Docker and Compose:
unzip nyone-backup-YYYYMMDD-HHMMSS.zip
cd nyone-backup-YYYYMMDD-HHMMSS
chmod +x restore.sh
./restore.sh /opt/nyone/dockerized
Stop the stack:
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:
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.
# /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:
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.