# Docker Compose Setup This folder contains the Docker Compose definitions for Pulse Signage, including the public stack and the remote player stack. ## Files - [docker-compose.yml](docker-compose.yml) - full public stack with web, player, player bridge, and MySQL. - [.env.example](.env.example) - sample environment values for the public stack. - [docker-compose.remote.yml](docker-compose.remote.yml) - remote player-only stack for machines that sit behind the player bridge. - [.env.remote.example](.env.remote.example) - sample environment values for the remote stack. ## Stack Overview ### Public stack The main compose stack is the most complete setup. It runs: - `web` - the dashboard and admin app. - `player` - the local screen player. - `player-bridge` - the bridge service that proxies dashboard commands and player communication. - `mysql` - the database used by the web, player, and bridge services. This is the stack to use when you want the full app running on one machine. ### Remote player The remote stack runs only the `player` service. Use it when the player is installed on a remote device and connects back through the player bridge instead of running the full app separately. ## Services ### `web` The dashboard and admin application. Responsibilities: - serves the web UI on port `8080` - reads and writes application data from MySQL - forwards player actions through the configured bridge base URL - renders connected clients, dashboard pages, and admin workflows Key configuration: - `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` - `PULSE_SIGNAGE_SHARED_SECRET` - `SESSION_MAX_AGE_DAYS` - `DEFAULT_ADMIN_USERNAME` - `DEFAULT_ADMIN_NAME` - `DEFAULT_ADMIN_PASSWORD` - `PASSWORD_HASH_ITERATIONS` ### `player` The screen runtime that renders playlists and receives commands. Responsibilities: - serves the player UI on port `8081` - connects to MySQL in local mode - connects to the bridge in remote mode through `BRIDGE_PUBLIC_URL` - registers live connections and accepts control commands Key configuration: - `PLAYER_PUBLIC_URL` - `PLAYER_INTERNAL_URL` - `BRIDGE_INTERNAL_URL` - `PLAYER_IDENTIFIER` - `BRIDGE_PUBLIC_URL` in remote mode - `PULSE_SIGNAGE_SHARED_SECRET` - database settings in local mode ### `player-bridge` The bridge layer that connects the dashboard to the player network. Responsibilities: - serves the bridge API on port `8090` - forwards authenticated dashboard commands to registered players - exposes screen connection snapshots and player registration data - proxies command traffic between the web app and remote players Key configuration: - `PULSE_SIGNAGE_SHARED_SECRET` - `WEB_INTERNAL_URL` for the bridge when it should call the web app directly instead of inferring from request headers - `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` ### `mysql` The MySQL 8.4 database used by the public stack. Responsibilities: - stores application data, screen state, onboarding state, and registry records - provides persistent storage through `mysql_data` Key configuration: - `MYSQL_DATABASE` - `MYSQL_USER` - `MYSQL_PASSWORD` - `MYSQL_ROOT_PASSWORD` ## Environment Files ### `.env.example` Use this file as a starting point for the public compose stack. Important values: - `PULSE_SIGNAGE_WEB_IMAGE` - image to run for the web app and bridge services, typically `.../pulse-signage-web:latest` - `PULSE_SIGNAGE_PLAYER_IMAGE` - image to run for the player services, typically `.../pulse-signage-player:latest` - `PULSE_SIGNAGE_SHARED_SECRET` - long random secret shared by the web, player, and bridge services for authenticated requests - `PLAYER_IDENTIFIER` - unique local player identifier - `DB_*` - MySQL credentials and database name for the stack - `PLAYER_PUBLIC_URL` - public URL the player advertises - `PLAYER_INTERNAL_URL` - internal URL the web app uses for local player calls - `BRIDGE_INTERNAL_URL` - bridge URL the web app uses for player snapshot and command forwarding - `WEB_INTERNAL_URL` - internal URL the bridge uses to call the web app directly - `SESSION_MAX_AGE_DAYS` - dashboard session lifetime - `DEFAULT_ADMIN_*` - bootstrap admin account values - `PASSWORD_HASH_ITERATIONS` - password hashing cost - `MYSQL_ROOT_PASSWORD` - root password for the local MySQL container ### `.env.remote.example` Use this file on a remote player device. Important values: - `PULSE_SIGNAGE_PLAYER_IMAGE` - image to run on the device, typically `.../pulse-signage-player:latest` - `PULSE_SIGNAGE_SHARED_SECRET` - must match the public stack and should be the same long random value used everywhere in the deployment - `PLAYER_IDENTIFIER` - unique remote player identifier - `PLAYER_PUBLIC_URL` - public URL for the remote player - `BRIDGE_PUBLIC_URL` - bridge URL the player connects back to - `PLAYER_AGENT_RECONNECT_DELAY_MS` - reconnect delay for the player agent ### `PULSE_SIGNAGE_SHARED_SECRET` This secret is the shared signing key for requests between the services. Use a single value for every service that needs to talk to the same stack, including the web app, player, bridge, and any remote player that connects back to that bridge. Recommended shape: - at least 32 random bytes - ideally 64 hex characters, or another equally long cryptographically random string - not a password, phrase, or anything human-readable If you want a quick local value, generate one with a password manager or a command such as `openssl rand -hex 32`. Leave it blank only if you intentionally want to run without request signing in a throwaway local setup. ## Main Configuration Variables | Variable | Used By | Purpose | | --- | --- | --- | | `PULSE_SIGNAGE_WEB_IMAGE` | web, bridge | Docker image to run for the web app and bridge services. | | `PULSE_SIGNAGE_PLAYER_IMAGE` | player, remote player | Docker image to run for the player services. | | `PULSE_SIGNAGE_SHARED_SECRET` | web, player, bridge, remote player | Shared secret for authenticated requests between services. | | `DB_HOST` | web, player, bridge | Database host name. | | `DB_PORT` | web, player, bridge | Database port. | | `DB_NAME` | web, player, bridge, mysql | Database name. | | `DB_USER` | web, player, bridge, mysql | Database user. | | `DB_PASSWORD` | web, player, bridge, mysql | Database password. | | `MYSQL_ROOT_PASSWORD` | mysql | Root password for the local MySQL container. | | `SESSION_MAX_AGE_DAYS` | web | Session cookie lifetime. | | `DEFAULT_ADMIN_USERNAME` | web | Bootstrap admin username. | | `DEFAULT_ADMIN_NAME` | web | Bootstrap admin display name. | | `DEFAULT_ADMIN_PASSWORD` | web | Bootstrap admin password. | | `PASSWORD_HASH_ITERATIONS` | web | Password hashing cost. | | `PLAYER_INTERNAL_URL` | web, player | Internal player URL used by the dashboard and player runtime. | | `BRIDGE_INTERNAL_URL` | web | Bridge URL used by the web app for player snapshot and command forwarding. | | `WEB_INTERNAL_URL` | player-bridge | Internal web URL used by the bridge to call the dashboard app directly. | | `PLAYER_PUBLIC_URL` | player, remote player | Public URL advertised by the player. | | `BRIDGE_PUBLIC_URL` | player, remote player | URL of the bridge service. | | `PLAYER_IDENTIFIER` | player | Stable player identifier. | | `PLAYER_AGENT_RECONNECT_DELAY_MS` | remote player | Delay before reconnecting to the bridge. | | `MYSQL_DATABASE` | mysql | Database name used by the local MySQL container. | | `MYSQL_USER` | mysql | Database user used by the local MySQL container. | | `MYSQL_PASSWORD` | mysql | Database password used by the local MySQL container. | ## Ports Public stack ports: - `8080` - web dashboard - `8081` - player - `8090` - player bridge - `3306` - MySQL Remote stack ports: - `8081` - player only ## Volumes ### Public stack - `mysql_data` - persistent MySQL data. - `pulse-signage` - shared media and cache volume for the app services. ### Remote stack - `pulse-signage` - shared media and cache volume for the remote player. ## Networks Each compose file creates its own named network: - `pulse-signage` for the public stack - `pulse-signage-remote` for remote player deployment. ## Notes - The public stack expects the app services and MySQL to share the same `PULSE_SIGNAGE_SHARED_SECRET`. - A remote player must use the same `PULSE_SIGNAGE_SHARED_SECRET` as the bridge it connects to. - The bridge service is the dashboard-facing command path for connected remote players. - The remote player should point `BRIDGE_PUBLIC_URL` at the bridge, not at the public web endpoint. - The `PULSE_SIGNAGE_WEB_IMAGE` and `PULSE_SIGNAGE_PLAYER_IMAGE` tags default to the published `pulse-signage-web` and `pulse-signage-player` repositories with `latest` and `v1.2.3` style tags, but they can be overridden for local builds or custom releases. ## Recommended Setup 1. Copy `.env.example` to a local `.env` file for the public stack. 2. Copy `.env.remote.example` to a device-specific `.env` file for the remote player. 3. Make sure `PULSE_SIGNAGE_SHARED_SECRET` matches everywhere. 4. Start the public stack first, then start the remote player after the bridge is reachable. 5. Verify that the player appears in Connected clients before testing screen commands.