From 109ed5ccf649d2340947424bf472b79367f732a3 Mon Sep 17 00:00:00 2001 From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:11:52 +0100 Subject: [PATCH 01/22] 6600: Added code from os2display/os2display-docker-server/tree/feature/application-compose-update --- .env.docker.example | 83 +++++++++ .env.example | 88 +++++++++ .gitignore | 3 + CHANGELOG.md | 35 ++++ LICENSE | 373 +++++++++++++++++++++++++++++++++++++ README.md | 89 ++++++++- Taskfile.yml | 249 +++++++++++++++++++++++++ docker-compose.mariadb.yml | 21 +++ docker-compose.server.yml | 150 +++++++++++++++ docker-compose.traefik.yml | 35 ++++ docker-compose.yml | 230 +++++++++++++++++++++++ jwt/.gitignore | 4 + load-templates-develop.sh | 28 +++ load-templates-prod.sh | 34 ++++ media/.gitignore | 4 + restart.sh | 8 + traefik/dynamic-conf.yaml | 5 + traefik/ssl/.gitignore | 4 + traefik/traefik.yml | 27 +++ 19 files changed, 1469 insertions(+), 1 deletion(-) create mode 100644 .env.docker.example create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 Taskfile.yml create mode 100644 docker-compose.mariadb.yml create mode 100644 docker-compose.server.yml create mode 100644 docker-compose.traefik.yml create mode 100644 docker-compose.yml create mode 100644 jwt/.gitignore create mode 100755 load-templates-develop.sh create mode 100755 load-templates-prod.sh create mode 100644 media/.gitignore create mode 100755 restart.sh create mode 100644 traefik/dynamic-conf.yaml create mode 100644 traefik/ssl/.gitignore create mode 100644 traefik/traefik.yml diff --git a/.env.docker.example b/.env.docker.example new file mode 100644 index 0000000..91a72b8 --- /dev/null +++ b/.env.docker.example @@ -0,0 +1,83 @@ +# ============================================================================= +# Example .env file for os2display-docker-server +# Cantains environment variables that needs local configuration. +# Copy this file to .env.docker and adjust the values as needed for your setup. +# Lines starting with # are comments. +# ============================================================================= + + +# The domain name where the server will be accessible (e.g., demo.os2display.dk) +COMPOSE_SERVER_DOMAIN=demo.os2display.dk + +# Version of itkdev/os2display-api-service +# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-api-service/tags +# Put COMPOSE_VERSION_API=develop if you want to install the dev-branch. +COMPOSE_VERSION_API=2.6.0 + +# Version of itkdev/os2display-admin-client +# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-admin-client/tags +COMPOSE_VERSION_ADMIN=2.6.0 + +# Version of itkdev/os2display-client +# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-client/tags +COMPOSE_VERSION_CLIENT=2.3.0 + +# Version of github.com/os2display/display-templates +# Find the latest version here: https://github.com/os2display/display-templates/releases +TASK_VERSION_TEMPLATES=2.6.0 + +# List the templates you want to load. +# Find all available templates here: https://github.com/os2display/display-templates/tree/develop/src +TASK_TEMPLATES="book-review,brnd,calendar,contacts,iframe,image-text,instagram-feed,poster,rss,slideshow,table,travel,video" + +# List the screen layouts you want to load. +# Find all available templates here: https://github.com/os2display/display-templates/tree/develop/src/screen-layouts +TASK_SCREEN_LAYOUTS="full-screen,three-boxes-horizontal,three-boxes,touch-template,two-boxes,two-boxes-vertical,six-areas,four-areas" + +# Have docker compose include a MariaDB database or configure an external one? +# Set to 'true' to use the built-in MariaDB database provided by the Docker Compose setup. +# Set to 'false' to configure and use an external MariaDB database. +INTERNAL_DATABASE=true + +# Have docker compose include a Traefik proxy or configure an external one? +# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. +# Set to 'false' to configure and use an external Traefik proxy. +INTERNAL_PROXY=true + +# mysql://:@:/?serverVersion= +# APP_DATABASE_URL syntax: +# - : The username for the database connection +# - : The password for the database connection +# - : The hostname or IP address of the database server +# - : The port number on which the database server is listening (default for MySQL is 3306) +# - : The name of the database to connect to +# - : The version of the database server (used by Doctrine to generate compatible SQL queries) +APP_DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11" + +# Note: When updating the database connection details, ensure that the following MariaDB variables +# are also updated to match the connection string above. These variables are used by the Docker +# Compose setup to configure the built-in MariaDB service. These variables are only necessary if +# the local MariaDB service is used (COMPOSE_INTERNAL_DATABASE=true). +MARIADB_USER=db +MARIADB_PASSWORD=db +MARIADB_ROOT_PASSWORD=dbrootpassword +MARIADB_DATABASE=db +DB_HOST=mariadb + +# Use a built-in Traefik proxy or configure one externally? +# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. +# Set to 'false' to configure and use an external proxy. +COMPOSE_INTERNAL_PROXY=true + +APP_SECRET=pleasuchangethis +APP_JWT_PASSPHRASE=pleasechangethistoo + +###> itk-dev/openid-connect-bundle ### +# "admin" open id connect configuration variables (values provided by the OIDC IdP) +INTERNAL_OIDC_METADATA_URL= +INTERNAL_OIDC_CLIENT_ID= +INTERNAL_OIDC_CLIENT_SECRET= +INTERNAL_OIDC_REDIRECT_URI= +INTERNAL_OIDC_CLAIM_GROUPS=roles +INTERNAL_OIDC_CLAIM_NAME=name +INTERNAL_OIDC_CLAIM_EMAIL=email \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..145cadc --- /dev/null +++ b/.env.example @@ -0,0 +1,88 @@ +COMPOSE_PROJECT_NAME=os2display +COMPOSE_SERVER_DOMAIN=demo.os2display.dk + +COMPOSE_ADMIN_CLIENT_PATH=/admin +COMPOSE_SCREEN_CLIENT_PATH=/client + +COMPOSE_VERSION_API=latest +COMPOSE_VERSION_ADMIN=latest +COMPOSE_VERSION_CLIENT=latest + +##### api [itkdev/os2display-api-service] ##### + +###> php ### +PHP_MAX_EXECUTION_TIME=30 +PHP_MEMORY_LIMIT=128M +PHP_POST_MAX_SIZE=140M +PHP_UPLOAD_MAX_FILESIZE=128M +###< php ### + +###> App ### +APP_DEFAULT_DATE_FORMAT='Y-m-d\TH:i:s.v\Z' +APP_KEY_VAULT_JSON="{}" +###< App ### + +###> symfony/framework-bundle ### +APP_ENV=prod +APP_SECRET= +APP_TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR +###< symfony/framework-bundle ### + +###> doctrine/doctrine-bundle ### +# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url +# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml +# DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.5.13" +APP_DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.5.13" +###< doctrine/doctrine-bundle ### + +###> nelmio/cors-bundle ### +APP_CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' +###< nelmio/cors-bundle ### + +###> lexik/jwt-authentication-bundle ### +APP_JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem +APP_JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem +APP_JWT_PASSPHRASE= +APP_JWT_TOKEN_TTL=3600 +###< lexik/jwt-authentication-bundle ### + +###> gesdinet/jwt-refresh-token-bundle ### +APP_JWT_REFRESH_TOKEN_TTL=2592000 +###< gesdinet/jwt-refresh-token-bundle ### + +###> itk-dev/openid-connect-bundle ### +# "admin" open id connect configuration variables (values provided by the OIDC IdP) +OIDC_METADATA_URL=ADMIN_APP_METADATA_URL +OIDC_CLIENT_ID=ADMIN_APP_CLIENT_ID +OIDC_CLIENT_SECRET=ADMIN_APP_CLIENT_SECRET +OIDC_REDIRECT_URI=ADMIN_APP_REDIRECT_URI +OIDC_LEEWAY=30 + +APP_CLI_REDIRECT=ADMIN_CLI_REDIRECT_URI +###< itk-dev/openid-connect-bundle ### + +###> redis ### +APP_REDIS_CACHE_PREFIX=DisplayApiService +APP_REDIS_CACHE_DSN=redis://redis:6379/0 +###< redis ### + +##### nginx-api [itkdev/os2display-api-service-nginx] ##### + +NGINX_FPM_UPLOAD_MAX=140M + +##### admin [itkdev/os2display-admin-client] ##### + +# API_PATH=https://demo.os2display.dk/ +API_PATH="/" +APP_TOUCH_BUTTON_REGIONS=true +APP_REJSEPLANEN_API_KEY= +APP_PREVIEW_CLIENT= + +##### client [itkdev/os2display-client] ##### +APP_API_ENDPOINT="https://demo.os2display.dk" +APP_API_PATH="https://demo.os2display.dk" +APP_API_AUTHENTICATION_ENDPOINT="https://demo.os2display.dk/v1/authentication/screen" +APP_API_AUTHENTICATION_REFRESH_ENDPOINT="https://demo.os2display.dk/v1/authentication/token/refresh" +APP_DATA_PULL_INTERVAL=90000 +APP_SCHEDULING_INTERVAL=60000 +APP_DEBUG=false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26a30e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env.local +.env.docker.local +db_backups/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b143bfb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## [Unreleased] + + - Add new task backup_db to backup the default internal mariadb + +## v1.1.2 + +- Bump os2display version from 2.5.1 to 2.6.0. Client updated from 2.2.1 to 2.3.0. +- Update TASK_TEMPLATES in .env.docker.example to include 'brnd' +- Bring CHANGELOG.md up-to-date with mensions of version v1.1.0 and v1.1.1 +- Update CHANGELOG.md + +## v1.1.1 + +- Assume install by user where UID and GID is1042. The README contains further details. +- Install the vimeo-template as default +- Add the screen layout two-boxes-vertical-reversed as default +- Extend wait for db, so that install will work on slow hardware/VM +- A new env var APP_KEY_VAULT_JSON has been added + +## v1.1.0 + +- BUGFIX: Fix value of COMPOSE_SCREEN_CLIENT_PATH. Default was set to "/screen". Should be "/client". +- Bump os2display version from 2.4.0 to 2.5.1 +- Improved task menu +- Env var changes now take effect if you do "task down" and then "task up". + +## v1.0.0 - Initial Release + +- Introduced a Docker-based deployment tool for hosting the OS2display application. +- Provided pre-configured files and task automation for simplifying deployment and management. +- Added support for secure mode (HTTPS on port 443) with domain name and SSL certificate requirements. +- Included a `Taskfile.yml` with tasks for installation, tenant/user management, template loading, and maintenance. +- Documented prerequisites and setup instructions for Docker, Docker Compose, and Taskfile CLI. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index 1e87b17..3175434 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,90 @@ -# OS2Display docker server v.3 +# OS2display v2 Hosting and Deployment + +This is a deployment tool designed for hosting the OS2display v2 application using Docker. It provides a Docker-based setup, pre-configured files, and task automation to simplify the deployment and management of the application. + +## Prerequisites + +Before you begin, ensure you have the following installed on your system: +1. **Docker**: Install Docker Engine (version 20.10 or later). +2. **Docker Compose**: Use Docker Compose v2 (integrated with the `docker compose` command). +3. **Task**: Install the Taskfile CLI tool. You can find installation instructions [here](https://taskfile.dev/#/installation). + +Make sure your user has the necessary permissions to run Docker commands (e.g., being part of the `docker` group). + +### Check Prerequisites + +Run the following commands to verify that the prerequisites are installed: + +```bash +# Check Docker installation +docker --version + +# Check Docker Compose installation +docker compose version + +# Check Taskfile CLI installation +task --version +``` + +## Create the deploy-user +Files inside the `os2display-api-service` container are owned by a user with UID 1042 and GID 1042. To prevent permission issues with bind mounts (the `media` and `jwt` volumes), it’s best to install the application using a user with the same UID and GID. + +To set this up on your server, create a new user (for example, `deploy`). You can choose a different username if you prefer, but make sure to assign UID and GID 1042. + +Here’s how to create the user: + +```bash +# Create group and user with UID/GID 1042 +sudo groupadd -g 1042 deploy +sudo useradd -u 1042 -g 1042 -m -s /bin/bash deploy +sudo passwd deploy + +# Add the user to the docker group +sudo usermod -aG docker deploy +``` + +## Secure Mode Requirement + +This project can only run in secure mode using HTTPS (port 443). To ensure proper functionality, you must provide a valid domain name and an SSL certificate. + +### Steps to Configure Secure Mode: +1. **Domain Name**: Use a fully qualified domain name (FQDN) that resolves to your server's IP address. +2. **SSL Certificate**: Provide a valid SSL certificate and private key for the domain. + - Place the certificate file (`docker.crt`) and the private key file (`docker.key`) in the `traefik/ssl` directory. +3. **Update Configuration**: Ensure the domain name is correctly configured in the `.env.docker.local` file. + +Without a valid domain name and SSL certificate, the project will not function as expected. + +## Available Tasks + +The project uses a `Taskfile.yml` to simplify common operations. Below is a list of the most important tasks you can run: + +### Installation and Setup +- **`task install`**: Installs the project, pulls Docker images, sets up the database, and initializes the environment. +- **`task reinstall`**: Reinstalls the project from scratch, removing all containers, volumes, and the database. +- **`task up`**: Starts the environment without altering the existing state of the containers. +- **`task down`**: Stops and removes all containers and volumes. + +### Tenant and User Management +- **`task tenant_add`**: Adds a new tenant group. A tenant is a group of users that share the same configuration. +- **`task user_add`**: Adds a new user (editor or admin) to a tenant. + +### Templates and Screen Layouts +- **`task load_templates`**: Loads templates and screen layouts based on the configuration in `.env.docker.local`. + +### Maintenance +- **`task logs`**: Follows the logs from the Docker containers. +- **`task cc`**: Clears the cache in the application. + +### Pre-installation Notes +Before running `task install`, ensure the following: +1. Update `.env.docker.local` with your domain name (replace all 5 instances) and set secure passwords. +2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. + +For a full list of tasks, run: +```bash +task --list +``` + diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..81afc25 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,249 @@ +version: '3' +silent: true + +tasks: + default: + desc: The default task that shows help + cmds: + - echo "Available tasks (in preferred order):" + - echo " install Install the project" + - echo " reinstall Reinstall from scratch. WARNING Deletes the database!" + - echo " up Start the environment" + - echo " down Remove all containers" + - echo " purge Remove all containers and volumes. WARNING Deletes the database!" + - echo " stop Stop all containers" + - echo " logs Follow docker logs" + - echo " cc Clear the cache" + - echo " tenant_add Add a new tenant group" + - echo " user_add Add a new user" + - echo " load_templates Load templates and screen layouts" + - echo " backup_db Performs a database dump, if you use the default internal mariadb." + - echo "" + + + install: + desc: Install the project + deps: + - _dc_compile + cmds: + - task _show_preinstall_notes + - echo "Installing" + - | + # Check if the external network 'frontend' exists, create if not + if ! docker network ls --format '{{.Name}}' | grep -wq frontend; then + echo "Creating external network 'frontend'" + docker network create frontend + else + echo "External network 'frontend' already exists" + fi + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml pull + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml up --force-recreate --detach --remove-orphans + - echo "Waiting for database to be ready" + - sleep 20 + - echo "Initialize the database" + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console doctrine:schema:create + - echo "Clearing the cache" + - task cc + - echo "Create jwt key pair" + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console lexik:jwt:generate-keypair --skip-if-exists + - task tenant_add + - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." + - task user_add + - task load_templates + - task _show_notes + + reinstall: + desc: Reinstall from scratch. Removes the database, all containers, and volumes. + deps: + - purge + cmds: + - task install + + down: + desc: Remove all containers + deps: + - stop + cmds: + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml down + - rm -f docker-compose.yml .env.local + + purge: + desc: Remove all containers and volumes + deps: + - stop + cmds: + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml down --volumes --remove-orphans + - | + # Check if the external network 'frontend' exists, remove if it does + if docker network ls --format '{{.Name}}' | grep -wq frontend; then + echo "Removing external network 'frontend'" + docker network rm frontend + else + echo "External network 'frontend' does not exist" + fi + - rm -f docker-compose.yml .env.local + + up: + desc: Take the environment up without altering the existing state of the containers + cmds: + - task _dc_compile + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml up -d + + stop: + desc: Stop all containers without altering anything else + cmds: + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml stop + + tenant_add: + desc: Add a new tenant group + cmds: + - echo "" + - echo "Add a tenant" + - echo "====================================================" + - echo "A tenant is a group of users that share the same configuration. F. ex. IT, Library, Schools etc." + - echo "You have to provide tenant id, tenant title and optionally a description." + - echo "====================================================" + - echo "" + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec -T api bin/console app:tenant:add + + user_add: + desc: Add a new user (editor or admin) + cmds: + - echo "" + - echo "Add a user" + - echo "====================================================" + - echo "You have to provide email, password, full name, role (editor or admin) and the tenant id." + - echo "====================================================" + - echo "" + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec -T api bin/console app:user:add + + load_templates: + desc: Load templates and screen layouts + cmds: + - | + TEMPLATES_RELEASE=$(grep ^TASK_VERSION_TEMPLATES= .env.docker.local | cut -d '=' -f 2) + TEMPLATES=$(grep ^TASK_TEMPLATES= .env.docker.local | cut -d '=' -f 2 | tr -d ' "' | tr ',' ' ') + if [ -z "$TEMPLATES_RELEASE" ]; then + echo "Error: TASK_VERSION_TEMPLATES is not set in .env.docker.local" + exit 1 + fi + if [ -z "$TEMPLATES" ]; then + echo "Error: TASK_TEMPLATES is not set or empty in .env.docker.local" + exit 1 + fi + echo "Using TEMPLATES_RELEASE=$TEMPLATES_RELEASE" + echo "Using TEMPLATES=$TEMPLATES" + for TEMPLATE in $TEMPLATES; do + if [ "$TEMPLATES_RELEASE" = "develop" ]; then + CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/heads/$TEMPLATES_RELEASE/build/$TEMPLATE-config-main.json" + else + CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/build/$TEMPLATE-config-main.json" + fi + echo "Loading template: $TEMPLATE" + docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec --user deploy api bin/console app:template:load -p $CONFIG_URL + done + + SCREEN_LAYOUTS=$(grep ^TASK_SCREEN_LAYOUTS= .env.docker.local | cut -d '=' -f 2 | tr -d ' "' | tr ',' ' ') + if [ -z "$SCREEN_LAYOUTS" ]; then + echo "Error: TASK_SCREEN_LAYOUTS is not set or empty in .env.docker.local" + exit 1 + fi + echo "Using SCREEN_LAYOUTS=$SCREEN_LAYOUTS" + for SCREEN_LAYOUT in $SCREEN_LAYOUTS; do + if [ "$TEMPLATES_RELEASE" = "develop" ]; then + CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/heads/$TEMPLATES_RELEASE/src/screen-layouts/$SCREEN_LAYOUT.json" + else + CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/src/screen-layouts/$SCREEN_LAYOUT.json" + fi + echo "Loading screen layout: $SCREEN_LAYOUT" + docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions $CONFIG_URL + done + + logs: + desc: Follow docker logs from the containers + cmds: + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml logs -f --tail=50 + + cc: + desc: Clear the cache + cmds: + - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console cache:clear + + backup_db: + desc: Perform a database dump, if you use the default internal mariadb. The dump file will be saved in the 'db_backups' directory with a timestamp in the filename. + cmds: + - | + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + DB_BACKUP_DIR=$(pwd)/db_backups + FILENAME=$DB_BACKUP_DIR/db_backup_$TIMESTAMP.sql + echo "Performing database backup..." + mkdir -p $DB_BACKUP_DIR # Ensure the backup directory exists + DB_USER=$(grep ^MARIADB_USER= .env.docker.local | cut -d '=' -f 2) + DB_NAME=$(grep ^MARIADB_DATABASE= .env.docker.local | cut -d '=' -f 2) + DB_PASSWORD=$(grep ^MARIADB_PASSWORD= .env.docker.local | cut -d '=' -f 2) + echo "Using database user: $DB_USER and database name: $DB_NAME" + docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec mariadb mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $FILENAME + if [ $? -eq 0 ]; then + echo "Database backup saved to $FILENAME" + fi + + _show_preinstall_notes: + cmds: + - echo "" + - echo "====================================================" + - echo "Pre-installation Requirements" + - echo "====================================================" + - echo "" + - echo "To proceed with the installation, ensure the following steps are completed:" + - echo "1. Update '.env.docker.local' with local settings and set secure passwords." + - echo "2. Place your SSL certificate files ('docker.crt' and 'docker.key') in the 'traefik/ssl' directory." + - echo "" + - echo "Have you completed the above pre-installation steps? (yes/no)" + - | + read answer && case $answer in + [Yy][Ee][Ss]) ;; + *) echo "Please complete the pre-install tasks before continuing."; exit 1;; + esac + + _show_notes: + cmds: + - | + DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env.docker.local | cut -d '=' -f 2) + echo "" + echo "====================================================" + echo "OS2display now is available via the URLs below" + echo "====================================================" + echo "Admin: https://$DOMAIN/admin" + echo "Screen: https://$DOMAIN/client" + echo "====================================================" + + _env_files: + cmds: + - | + echo "Copying .env.example to .env.local..." + cp .env.example .env.local + - | + if [ ! -f .env.docker.local ]; then + echo ".env.docker.local does not exist. Copying .env.docker.example to .env.docker.local..." + cp .env.docker.example .env.docker.local + fi + + _dc_compile: + deps: + - _env_files + cmds: + - | + COMPOSE_FILES="-f docker-compose.server.yml" + if grep -q '^INTERNAL_DATABASE=true' .env.docker.local; then + COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.mariadb.yml" + fi + if grep -q '^INTERNAL_PROXY=true' .env.docker.local; then + COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.traefik.yml" + fi + docker compose --env-file .env.local --env-file .env.docker.local $COMPOSE_FILES config > docker-compose.yml + + # Replace all occurrences of demo.os2display.dk with the value of COMPOSE_SERVER_DOMAIN + DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env.docker.local | cut -d '=' -f 2) + if [ -n "$DOMAIN" ]; then + sed -i "s/demo\.os2display\.dk/$DOMAIN/g" docker-compose.yml + fi \ No newline at end of file diff --git a/docker-compose.mariadb.yml b/docker-compose.mariadb.yml new file mode 100644 index 0000000..14a40b5 --- /dev/null +++ b/docker-compose.mariadb.yml @@ -0,0 +1,21 @@ +networks: + app: + driver: bridge + internal: false + +services: + mariadb: + image: mariadb:10.11.11 + restart: unless-stopped + networks: + - app + environment: + - MARIADB_DATABASE=${MARIADB_DATABASE} + - MARIADB_USER=${MARIADB_USER} + - MARIADB_PASSWORD=${MARIADB_PASSWORD} + - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD} + volumes: + - mariadb:/var/lib/mysql:rw + +volumes: + mariadb: \ No newline at end of file diff --git a/docker-compose.server.yml b/docker-compose.server.yml new file mode 100644 index 0000000..3809584 --- /dev/null +++ b/docker-compose.server.yml @@ -0,0 +1,150 @@ +networks: + frontend: + external: true + app: + driver: bridge + internal: false + +services: + api: + image: itkdev/os2display-api-service:${COMPOSE_VERSION_API} + restart: unless-stopped + networks: + - app + environment: + # PHP config values + - PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME} + - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT} + - PHP_POST_MAX_SIZE=${PHP_POST_MAX_SIZE} + - PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE} + - PHP_TIMEZONE=UTC + - PHP_PM_MAX_CHILDREN=16 + - PHP_OPCACHE_VALIDATE_TIMESTAMPS=0 + # APP (Symfony) + - APP_SECRET=${APP_SECRET:?err} + - APP_DATABASE_URL=${APP_DATABASE_URL:?err} + - APP_JWT_PASSPHRASE=${APP_JWT_PASSPHRASE:?err} + - APP_JWT_TOKEN_TTL=${APP_JWT_TOKEN_TTL} + - APP_JWT_SCREEN_TOKEN_TTL=${APP_JWT_SCREEN_TOKEN_TTL} + - APP_JWT_REFRESH_TOKEN_TTL=${APP_JWT_REFRESH_TOKEN_TTL} + - APP_JWT_SCREEN_REFRESH_TOKEN_TTL=${APP_JWT_SCREEN_REFRESH_TOKEN_TTL} + - APP_ENV=${APP_ENV} + - APP_TRUSTED_PROXIES=${APP_TRUSTED_PROXIES} + - APP_CORS_ALLOW_ORIGIN=${APP_CORS_ALLOW_ORIGIN} + - APP_DEFAULT_DATE_FORMAT=${APP_DEFAULT_DATE_FORMAT} + - APP_INTERNAL_OIDC_METADATA_URL=${INTERNAL_OIDC_METADATA_URL} + - APP_INTERNAL_OIDC_CLIENT_ID=${INTERNAL_OIDC_CLIENT_ID} + - APP_INTERNAL_OIDC_CLIENT_SECRET=${INTERNAL_OIDC_CLIENT_SECRET} + - APP_INTERNAL_OIDC_REDIRECT_URI=${INTERNAL_OIDC_REDIRECT_URI} + - APP_INTERNAL_OIDC_LEEWAY=${INTERNAL_OIDC_LEEWAY} + - APP_EXTERNAL_OIDC_METADATA_URL=${EXTERNAL_OIDC_METADATA_URL} + - APP_EXTERNAL_OIDC_CLIENT_ID=${EXTERNAL_OIDC_CLIENT_ID} + - APP_EXTERNAL_OIDC_CLIENT_SECRET=${EXTERNAL_OIDC_CLIENT_SECRET} + - APP_EXTERNAL_OIDC_REDIRECT_URI=${EXTERNAL_OIDC_REDIRECT_URI} + - APP_EXTERNAL_OIDC_LEEWAY=${EXTERNAL_OIDC_LEEWAY} + - APP_EXTERNAL_OIDC_HASH_SALT=${EXTERNAL_OIDC_HASH_SALT} + - APP_EXTERNAL_OIDC_CLAIM_ID=${EXTERNAL_OIDC_CLAIM_ID} + - APP_REDIS_CACHE_PREFIX=${APP_REDIS_CACHE_PREFIX} + - APP_REDIS_CACHE_DSN=${APP_REDIS_CACHE_DSN} + - APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT} + - APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT} + - APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT} + - APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS=${APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS} + - APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS=${APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS} + - APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT=${APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT} + - APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE=${APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE} + - APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS=${APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS} + - APP_TRACK_SCREEN_INFO=${APP_TRACK_SCREEN_INFO} + - APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS=${APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS} + - APP_KEY_VAULT_JSON=${APP_KEY_VAULT_JSON} + volumes: + - ./jwt:/var/www/html/config/jwt:rw + - ./media:/var/www/html/public/media:rw + + nginx-api: + image: itkdev/os2display-api-service-nginx:${COMPOSE_VERSION_API} + restart: unless-stopped + networks: + - app + - frontend + environment: + - PHP_FPM_SERVER=api + - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} + depends_on: + - api + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.apios2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.apios2display-http.entrypoints=web" + - "traefik.http.routers.apios2display-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.apios2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.apios2display.entrypoints=websecure" + # Redirect root / request to /${COMPOSE_ADMIN_CLIENT_PATH} + - "traefik.http.routers.apios2display.middlewares=redirect-to-admin" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.regex=^https:\\/\\/([^\\/]+)\\/?$$" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1${COMPOSE_ADMIN_CLIENT_PATH}" + # - "traefik.http.routers.apios2display.middlewares=apios2display" + # - "traefik.http.middlewares.apios2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" + # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" + volumes: + - ./media:/var/www/html/public/media:rw + + admin: + image: itkdev/os2display-admin-client:${COMPOSE_VERSION_ADMIN} + restart: unless-stopped + networks: + - app + - frontend + environment: + - APP_ADMIN_CLIENT_PATH=${COMPOSE_ADMIN_CLIENT_PATH} + - API_PATH=${API_PATH} + - APP_TOUCH_BUTTON_REGIONS=${APP_TOUCH_BUTTON_REGIONS} + - APP_REJSEPLANEN_API_KEY=${APP_REJSEPLANEN_API_KEY} + - APP_SHOW_SCREEN_STATUS=${APP_SHOW_SCREEN_STATUS} + - APP_PREVIEW_CLIENT=${APP_PREVIEW_CLIENT} + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.adminos2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_ADMIN_CLIENT_PATH}`)" + - "traefik.http.routers.adminos2display-http.entrypoints=web" + - "traefik.http.routers.adminos2display-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.adminos2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_ADMIN_CLIENT_PATH}`)" + - "traefik.http.routers.adminos2display.entrypoints=websecure" + # - "traefik.http.routers.adminos2display.middlewares=apios2display" + # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" + + client: + image: itkdev/os2display-client:${COMPOSE_VERSION_CLIENT} + restart: unless-stopped + networks: + - app + - frontend + environment: + - APP_SCREEN_CLIENT_PATH=${COMPOSE_SCREEN_CLIENT_PATH:?err} + - APP_API_ENDPOINT=${APP_API_ENDPOINT:?err} + - APP_API_PATH=${APP_API_PATH:?err} + - APP_API_AUTHENTICATION_ENDPOINT=${APP_API_AUTHENTICATION_ENDPOINT} + - APP_API_AUTHENTICATION_REFRESH_ENDPOINT=${APP_API_AUTHENTICATION_REFRESH_ENDPOINT} + - APP_DATA_PULL_INTERVAL=${APP_DATA_PULL_INTERVAL} + - APP_SCHEDULING_INTERVAL=${APP_SCHEDULING_INTERVAL} + - APP_DEBUG=${APP_DEBUG} + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.clientos2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_SCREEN_CLIENT_PATH}`)" + - "traefik.http.routers.clientos2display-http.entrypoints=web" + - "traefik.http.routers.clientos2display-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.clientos2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_SCREEN_CLIENT_PATH}`)" + - "traefik.http.routers.clientos2display.entrypoints=websecure" + # - "traefik.http.routers.clientos2display.middlewares=apios2display" + # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" + + redis: + image: 'redis:6' + restart: unless-stopped + networks: + - app diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml new file mode 100644 index 0000000..49ebe5c --- /dev/null +++ b/docker-compose.traefik.yml @@ -0,0 +1,35 @@ +networks: + proxy: + driver: bridge + internal: true + +services: + traefik: + image: traefik:latest + container_name: traefik + restart: unless-stopped + security_opt: + - no-new-privileges:true + ports: + - "80:80" + - "443:443" + - "8080:8080" # Dashboard + volumes: + - $PWD/traefik/ssl:/certs:ro + - $PWD/traefik/traefik.yml:/traefik.yml:ro + - $PWD/traefik/dynamic-conf.yaml:/config/dynamic-conf.yaml:ro + networks: + - frontend + - proxy + + socket-proxy: + image: itkdev/docker-socket-proxy + user: root + container_name: socket-proxy + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + CONTAINERS: 1 + networks: + - proxy diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fa0ea31 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,230 @@ +name: os2display +services: + admin: + environment: + API_PATH: / + APP_ADMIN_CLIENT_PATH: /admin + APP_PREVIEW_CLIENT: "" + APP_REJSEPLANEN_API_KEY: "" + APP_SHOW_SCREEN_STATUS: "" + APP_TOUCH_BUTTON_REGIONS: "true" + image: itkdev/os2display-admin-client:2.6.0 + labels: + traefik.docker.network: frontend + traefik.enable: "true" + traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https + traefik.http.routers.adminos2display-http.entrypoints: web + traefik.http.routers.adminos2display-http.middlewares: redirect-to-https + traefik.http.routers.adminos2display-http.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/admin`) + traefik.http.routers.adminos2display.entrypoints: websecure + traefik.http.routers.adminos2display.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/admin`) + networks: + app: null + frontend: null + restart: unless-stopped + api: + environment: + APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS: "" + APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS: "" + APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT: "" + APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE: "" + APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT: "" + APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS: "" + APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT: "" + APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT: "" + APP_CORS_ALLOW_ORIGIN: ^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$$ + APP_DATABASE_URL: mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11 + APP_DEFAULT_DATE_FORMAT: Y-m-d\TH:i:s.v\Z + APP_ENV: prod + APP_EXTERNAL_OIDC_CLAIM_ID: "" + APP_EXTERNAL_OIDC_CLIENT_ID: "" + APP_EXTERNAL_OIDC_CLIENT_SECRET: "" + APP_EXTERNAL_OIDC_HASH_SALT: "" + APP_EXTERNAL_OIDC_LEEWAY: "" + APP_EXTERNAL_OIDC_METADATA_URL: "" + APP_EXTERNAL_OIDC_REDIRECT_URI: "" + APP_INTERNAL_OIDC_CLIENT_ID: Sonderborg-OS2display + APP_INTERNAL_OIDC_CLIENT_SECRET: 7bdf9007-9518-4f1b-a0b5-4a42db1f58b9 + APP_INTERNAL_OIDC_LEEWAY: "30" + APP_INTERNAL_OIDC_METADATA_URL: https://adgang-idp.sonderborg.dk/.well-known/openid-configuration + APP_INTERNAL_OIDC_REDIRECT_URI: https://os2display.sonderborg.dk/admin + APP_JWT_PASSPHRASE: pleasechangethistoo + APP_JWT_REFRESH_TOKEN_TTL: "2592000" + APP_JWT_SCREEN_REFRESH_TOKEN_TTL: "" + APP_JWT_SCREEN_TOKEN_TTL: "" + APP_JWT_TOKEN_TTL: "3600" + APP_KEY_VAULT_JSON: '{}' + APP_REDIS_CACHE_DSN: redis://redis:6379/0 + APP_REDIS_CACHE_PREFIX: DisplayApiService + APP_SECRET: pleasuchangethis + APP_TRACK_SCREEN_INFO: "" + APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS: "" + APP_TRUSTED_PROXIES: 127.0.0.1,REMOTE_ADDR + PHP_MAX_EXECUTION_TIME: "30" + PHP_MEMORY_LIMIT: 128M + PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" + PHP_PM_MAX_CHILDREN: "16" + PHP_POST_MAX_SIZE: 140M + PHP_TIMEZONE: UTC + PHP_UPLOAD_MAX_FILESIZE: 128M + image: itkdev/os2display-api-service:2.6.0 + networks: + app: null + restart: unless-stopped + volumes: + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/jwt + target: /var/www/html/config/jwt + bind: + create_host_path: true + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/media + target: /var/www/html/public/media + bind: + create_host_path: true + client: + environment: + APP_API_AUTHENTICATION_ENDPOINT: https://os2display-devs.sonderborg.dk/v1/authentication/screen + APP_API_AUTHENTICATION_REFRESH_ENDPOINT: https://os2display-devs.sonderborg.dk/v1/authentication/token/refresh + APP_API_ENDPOINT: https://os2display-devs.sonderborg.dk + APP_API_PATH: https://os2display-devs.sonderborg.dk + APP_DATA_PULL_INTERVAL: "90000" + APP_DEBUG: "false" + APP_SCHEDULING_INTERVAL: "60000" + APP_SCREEN_CLIENT_PATH: /client + image: itkdev/os2display-client:2.3.0 + labels: + traefik.docker.network: frontend + traefik.enable: "true" + traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https + traefik.http.routers.clientos2display-http.entrypoints: web + traefik.http.routers.clientos2display-http.middlewares: redirect-to-https + traefik.http.routers.clientos2display-http.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/client`) + traefik.http.routers.clientos2display.entrypoints: websecure + traefik.http.routers.clientos2display.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/client`) + networks: + app: null + frontend: null + restart: unless-stopped + mariadb: + environment: + MARIADB_DATABASE: db + MARIADB_PASSWORD: db + MARIADB_ROOT_PASSWORD: dbrootpassword + MARIADB_USER: db + image: mariadb:10.11.11 + networks: + app: null + restart: unless-stopped + volumes: + - type: volume + source: mariadb + target: /var/lib/mysql + volume: {} + nginx-api: + depends_on: + api: + condition: service_started + required: true + environment: + NGINX_FPM_UPLOAD_MAX: 140M + PHP_FPM_SERVER: api + image: itkdev/os2display-api-service-nginx:2.6.0 + labels: + traefik.docker.network: frontend + traefik.enable: "true" + traefik.http.middlewares.redirect-to-admin.redirectregex.regex: ^https:\/\/([^\/]+)\/?$$ + traefik.http.middlewares.redirect-to-admin.redirectregex.replacement: https://$$1/admin + traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https + traefik.http.routers.apios2display-http.entrypoints: web + traefik.http.routers.apios2display-http.middlewares: redirect-to-https + traefik.http.routers.apios2display-http.rule: Host(`os2display-devs.sonderborg.dk`) + traefik.http.routers.apios2display.entrypoints: websecure + traefik.http.routers.apios2display.middlewares: redirect-to-admin + traefik.http.routers.apios2display.rule: Host(`os2display-devs.sonderborg.dk`) + networks: + app: null + frontend: null + restart: unless-stopped + volumes: + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/media + target: /var/www/html/public/media + bind: + create_host_path: true + redis: + image: redis:6 + networks: + app: null + restart: unless-stopped + socket-proxy: + container_name: socket-proxy + environment: + CONTAINERS: "1" + image: itkdev/docker-socket-proxy + networks: + proxy: null + restart: unless-stopped + user: root + volumes: + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + read_only: true + bind: + create_host_path: true + traefik: + container_name: traefik + image: traefik:latest + networks: + frontend: null + proxy: null + ports: + - mode: ingress + target: 80 + published: "80" + protocol: tcp + - mode: ingress + target: 443 + published: "443" + protocol: tcp + - mode: ingress + target: 8080 + published: "8080" + protocol: tcp + restart: unless-stopped + security_opt: + - no-new-privileges:true + volumes: + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/traefik/ssl + target: /certs + read_only: true + bind: + create_host_path: true + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/traefik/traefik.yml + target: /traefik.yml + read_only: true + bind: + create_host_path: true + - type: bind + source: /home/deploy/vanilla/os2display-docker-server/traefik/dynamic-conf.yaml + target: /config/dynamic-conf.yaml + read_only: true + bind: + create_host_path: true +networks: + app: + name: os2display_app + driver: bridge + frontend: + name: frontend + external: true + proxy: + name: os2display_proxy + driver: bridge + internal: true +volumes: + mariadb: + name: os2display_mariadb diff --git a/jwt/.gitignore b/jwt/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/jwt/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/load-templates-develop.sh b/load-templates-develop.sh new file mode 100755 index 0000000..207ad65 --- /dev/null +++ b/load-templates-develop.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# app:template:load +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/book-review-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/brnd-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/contacts-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/iframe-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/image-text-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/instagram-feed-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/news-feed-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/poster-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/rss-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/slideshow-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/table-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/travel-config-develop.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/video-config-develop.json + +# app:screen-layouts:load +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/full-screen.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/three-boxes-horizontal.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/three-boxes.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/touch-template.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes-vertical.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/six-areas.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/four-areas.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes-vertical-reversed.json diff --git a/load-templates-prod.sh b/load-templates-prod.sh new file mode 100755 index 0000000..42502f3 --- /dev/null +++ b/load-templates-prod.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +if [ -z "${TEMPLATES_RELEASE}" ] +then + echo "TEMPLATES_RELEASE must be set to a valid tag." + exit 2 +fi + +echo "Loading templates with tag: ${TEMPLATES_RELEASE}." + +# app:template:load +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/book-review-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/calendar-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/contacts-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/iframe-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/image-text-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/instagram-feed-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/news-feed-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/poster-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/rss-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/slideshow-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/table-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/travel-config-main.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/video-config-main.json + +# app:screen-layouts:load +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/full-screen.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/three-boxes-horizontal.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/three-boxes.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/touch-template.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/two-boxes.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/two-boxes-vertical.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/six-areas.json +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/four-areas.json diff --git a/media/.gitignore b/media/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/media/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/restart.sh b/restart.sh new file mode 100755 index 0000000..1c6fb18 --- /dev/null +++ b/restart.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +docker compose --env-file .env.docker.local -f docker-compose.server.yml pull +docker compose --env-file .env.docker.local -f docker-compose.server.yml up --force-recreate --detach --remove-orphans + +docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console doctrine:migrations:migrate --no-interaction + +echo "NB! Remember to load templates if they have changed. See 'Deployment' in README.md for instructions." diff --git a/traefik/dynamic-conf.yaml b/traefik/dynamic-conf.yaml new file mode 100644 index 0000000..63aac3f --- /dev/null +++ b/traefik/dynamic-conf.yaml @@ -0,0 +1,5 @@ +tls: + certificates: + - certFile: /certs/docker.crt + keyFile: /certs/docker.key + diff --git a/traefik/ssl/.gitignore b/traefik/ssl/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/traefik/ssl/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/traefik/traefik.yml b/traefik/traefik.yml new file mode 100644 index 0000000..46d3370 --- /dev/null +++ b/traefik/traefik.yml @@ -0,0 +1,27 @@ + +api: + dashboard: true + insecure: true + debug: true + +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + http: + tls: + {} + +providers: + file: + directory: /config + docker: + endpoint: "tcp://socket-proxy:2375" + exposedByDefault: false + +# https://doc.traefik.io/traefik/routing/services/#insecureskipverify +serversTransport: + insecureSkipVerify: true + + From 50cdd9faf3d547dd64d89ae3db906a6baf41b80b Mon Sep 17 00:00:00 2001 From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:20:25 +0100 Subject: [PATCH 02/22] 6600: Added newlines --- jwt/.gitignore | 2 +- media/.gitignore | 2 +- traefik/ssl/.gitignore | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jwt/.gitignore b/jwt/.gitignore index 86d0cb2..5e7d273 100644 --- a/jwt/.gitignore +++ b/jwt/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except this file -!.gitignore \ No newline at end of file +!.gitignore diff --git a/media/.gitignore b/media/.gitignore index 86d0cb2..5e7d273 100644 --- a/media/.gitignore +++ b/media/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except this file -!.gitignore \ No newline at end of file +!.gitignore diff --git a/traefik/ssl/.gitignore b/traefik/ssl/.gitignore index 86d0cb2..5e7d273 100644 --- a/traefik/ssl/.gitignore +++ b/traefik/ssl/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except this file -!.gitignore \ No newline at end of file +!.gitignore From 751fc8cfdfd8e929a98511b0c578e609bde84f4b Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Fri, 20 Feb 2026 13:58:44 +0100 Subject: [PATCH 03/22] 6601: First try on clean up and simplify the setup --- .env.docker.example | 83 --------- .env.example | 163 +++++++++++------- .gitignore | 4 +- CHANGELOG.md | 3 +- README.md | 172 ++++++++++++++----- Taskfile.yml | 252 +++++++++------------------- docker-compose.server.yml | 150 ----------------- docker-compose.yml | 342 ++++++++++++++------------------------ load-templates-develop.sh | 28 ---- load-templates-prod.sh | 34 ---- restart.sh | 8 - 11 files changed, 440 insertions(+), 799 deletions(-) delete mode 100644 .env.docker.example delete mode 100644 docker-compose.server.yml delete mode 100755 load-templates-develop.sh delete mode 100755 load-templates-prod.sh delete mode 100755 restart.sh diff --git a/.env.docker.example b/.env.docker.example deleted file mode 100644 index 91a72b8..0000000 --- a/.env.docker.example +++ /dev/null @@ -1,83 +0,0 @@ -# ============================================================================= -# Example .env file for os2display-docker-server -# Cantains environment variables that needs local configuration. -# Copy this file to .env.docker and adjust the values as needed for your setup. -# Lines starting with # are comments. -# ============================================================================= - - -# The domain name where the server will be accessible (e.g., demo.os2display.dk) -COMPOSE_SERVER_DOMAIN=demo.os2display.dk - -# Version of itkdev/os2display-api-service -# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-api-service/tags -# Put COMPOSE_VERSION_API=develop if you want to install the dev-branch. -COMPOSE_VERSION_API=2.6.0 - -# Version of itkdev/os2display-admin-client -# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-admin-client/tags -COMPOSE_VERSION_ADMIN=2.6.0 - -# Version of itkdev/os2display-client -# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-client/tags -COMPOSE_VERSION_CLIENT=2.3.0 - -# Version of github.com/os2display/display-templates -# Find the latest version here: https://github.com/os2display/display-templates/releases -TASK_VERSION_TEMPLATES=2.6.0 - -# List the templates you want to load. -# Find all available templates here: https://github.com/os2display/display-templates/tree/develop/src -TASK_TEMPLATES="book-review,brnd,calendar,contacts,iframe,image-text,instagram-feed,poster,rss,slideshow,table,travel,video" - -# List the screen layouts you want to load. -# Find all available templates here: https://github.com/os2display/display-templates/tree/develop/src/screen-layouts -TASK_SCREEN_LAYOUTS="full-screen,three-boxes-horizontal,three-boxes,touch-template,two-boxes,two-boxes-vertical,six-areas,four-areas" - -# Have docker compose include a MariaDB database or configure an external one? -# Set to 'true' to use the built-in MariaDB database provided by the Docker Compose setup. -# Set to 'false' to configure and use an external MariaDB database. -INTERNAL_DATABASE=true - -# Have docker compose include a Traefik proxy or configure an external one? -# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. -# Set to 'false' to configure and use an external Traefik proxy. -INTERNAL_PROXY=true - -# mysql://:@:/?serverVersion= -# APP_DATABASE_URL syntax: -# - : The username for the database connection -# - : The password for the database connection -# - : The hostname or IP address of the database server -# - : The port number on which the database server is listening (default for MySQL is 3306) -# - : The name of the database to connect to -# - : The version of the database server (used by Doctrine to generate compatible SQL queries) -APP_DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11" - -# Note: When updating the database connection details, ensure that the following MariaDB variables -# are also updated to match the connection string above. These variables are used by the Docker -# Compose setup to configure the built-in MariaDB service. These variables are only necessary if -# the local MariaDB service is used (COMPOSE_INTERNAL_DATABASE=true). -MARIADB_USER=db -MARIADB_PASSWORD=db -MARIADB_ROOT_PASSWORD=dbrootpassword -MARIADB_DATABASE=db -DB_HOST=mariadb - -# Use a built-in Traefik proxy or configure one externally? -# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. -# Set to 'false' to configure and use an external proxy. -COMPOSE_INTERNAL_PROXY=true - -APP_SECRET=pleasuchangethis -APP_JWT_PASSPHRASE=pleasechangethistoo - -###> itk-dev/openid-connect-bundle ### -# "admin" open id connect configuration variables (values provided by the OIDC IdP) -INTERNAL_OIDC_METADATA_URL= -INTERNAL_OIDC_CLIENT_ID= -INTERNAL_OIDC_CLIENT_SECRET= -INTERNAL_OIDC_REDIRECT_URI= -INTERNAL_OIDC_CLAIM_GROUPS=roles -INTERNAL_OIDC_CLAIM_NAME=name -INTERNAL_OIDC_CLAIM_EMAIL=email \ No newline at end of file diff --git a/.env.example b/.env.example index 145cadc..09cac61 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ -COMPOSE_PROJECT_NAME=os2display -COMPOSE_SERVER_DOMAIN=demo.os2display.dk +COMPOSE_PROJECT_NAME= +COMPOSE_SERVER_DOMAIN= +COMPOSE_FILES= COMPOSE_ADMIN_CLIENT_PATH=/admin COMPOSE_SCREEN_CLIENT_PATH=/client @@ -8,81 +9,127 @@ COMPOSE_VERSION_API=latest COMPOSE_VERSION_ADMIN=latest COMPOSE_VERSION_CLIENT=latest -##### api [itkdev/os2display-api-service] ##### -###> php ### +### +# PHP +### + PHP_MAX_EXECUTION_TIME=30 PHP_MEMORY_LIMIT=128M PHP_POST_MAX_SIZE=140M PHP_UPLOAD_MAX_FILESIZE=128M -###< php ### -###> App ### -APP_DEFAULT_DATE_FORMAT='Y-m-d\TH:i:s.v\Z' -APP_KEY_VAULT_JSON="{}" -###< App ### +### +# APPLICATION +#### + -###> symfony/framework-bundle ### APP_ENV=prod -APP_SECRET= +APP_SECRET= APP_TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR -###< symfony/framework-bundle ### - -###> doctrine/doctrine-bundle ### -# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url -# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml -# DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.5.13" -APP_DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.5.13" -###< doctrine/doctrine-bundle ### - -###> nelmio/cors-bundle ### +APP_DATABASE_URL= APP_CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' -###< nelmio/cors-bundle ### -###> lexik/jwt-authentication-bundle ### +APP_DEFAULT_DATE_FORMAT='Y-m-d\TH:i:s.v\Z' +APP_KEY_VAULT_SOURCE=ENVIRONMENT +APP_KEY_VAULT_JSON="{}" +APP_ACTIVATION_CODE_EXPIRE_INTERVAL=P2D +APP_TRACK_SCREEN_INFO=false +APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS=300 + +# JWT APP_JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem APP_JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem -APP_JWT_PASSPHRASE= +APP_JWT_PASSPHRASE= APP_JWT_TOKEN_TTL=3600 -###< lexik/jwt-authentication-bundle ### - -###> gesdinet/jwt-refresh-token-bundle ### +APP_JWT_SCREEN_TOKEN_TTL=1296000 APP_JWT_REFRESH_TOKEN_TTL=2592000 -###< gesdinet/jwt-refresh-token-bundle ### +APP_JWT_SCREEN_REFRESH_TOKEN_TTL=2592000 + +# Internal OIDC provider +APP_INTERNAL_OIDC_METADATA_URL= +APP_INTERNAL_OIDC_CLIENT_ID= +APP_INTERNAL_OIDC_CLIENT_SECRET= +APP_INTERNAL_OIDC_REDIRECT_URI= +APP_INTERNAL_OIDC_LEEWAY=30 +APP_INTERNAL_OIDC_CLAIM_NAME=navn +APP_INTERNAL_OIDC_CLAIM_EMAIL=email +APP_INTERNAL_OIDC_CLAIM_GROUPS=groups + +# External OIDC provider +APP_EXTERNAL_OIDC_METADATA_URL= +APP_EXTERNAL_OIDC_CLIENT_ID= +APP_EXTERNAL_OIDC_CLIENT_SECRET= +APP_EXTERNAL_OIDC_REDIRECT_URI= +APP_EXTERNAL_OIDC_LEEWAY=30 +APP_EXTERNAL_OIDC_HASH_SALT= +APP_EXTERNAL_OIDC_CLAIM_ID=signinname + +APP_OIDC_CLI_REDIRECT= + + +APP_REDIS_CACHE_PREFIX=display +APP_REDIS_CACHE_DSN=redis://redis:6379/0 -###> itk-dev/openid-connect-bundle ### -# "admin" open id connect configuration variables (values provided by the OIDC IdP) -OIDC_METADATA_URL=ADMIN_APP_METADATA_URL -OIDC_CLIENT_ID=ADMIN_APP_CLIENT_ID -OIDC_CLIENT_SECRET=ADMIN_APP_CLIENT_SECRET -OIDC_REDIRECT_URI=ADMIN_APP_REDIRECT_URI -OIDC_LEEWAY=30 +APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT= +APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT= +APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT= +APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS='{}' +APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS='{}' +APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT= +APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE= +APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS=300 -APP_CLI_REDIRECT=ADMIN_CLI_REDIRECT_URI -###< itk-dev/openid-connect-bundle ### +APP_EVENTDATABASE_API_V2_CACHE_EXPIRE_SECONDS=300 + +### +# Admin configuration +### +APP_ADMIN_REJSEPLANEN_APIKEY= +APP_ADMIN_SHOW_SCREEN_STATUS=false +APP_ADMIN_TOUCH_BUTTON_REGIONS=false +APP_ADMIN_LOGIN_METHODS='[{"type":"username-password","enabled":true,"provider":"username-password","label":""}]' +APP_ADMIN_ENHANCED_PREVIEW=false + + +### +# Client configuration +### +APP_CLIENT_LOGIN_CHECK_TIMEOUT=20000 +APP_CLIENT_REFRESH_TOKEN_TIMEOUT=300000 +APP_CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT=600000 +APP_CLIENT_SCHEDULING_INTERVAL=60000 +APP_CLIENT_PULL_STRATEGY_INTERVAL=90000 +APP_CLIENT_COLOR_SCHEME='{"type":"library","lat":56.0,"lng":10.0}' +APP_CLIENT_DEBUG=false -###> redis ### -APP_REDIS_CACHE_PREFIX=DisplayApiService -APP_REDIS_CACHE_DSN=redis://redis:6379/0 -###< redis ### -##### nginx-api [itkdev/os2display-api-service-nginx] ##### NGINX_FPM_UPLOAD_MAX=140M -##### admin [itkdev/os2display-admin-client] ##### - -# API_PATH=https://demo.os2display.dk/ -API_PATH="/" -APP_TOUCH_BUTTON_REGIONS=true -APP_REJSEPLANEN_API_KEY= -APP_PREVIEW_CLIENT= - -##### client [itkdev/os2display-client] ##### -APP_API_ENDPOINT="https://demo.os2display.dk" -APP_API_PATH="https://demo.os2display.dk" -APP_API_AUTHENTICATION_ENDPOINT="https://demo.os2display.dk/v1/authentication/screen" -APP_API_AUTHENTICATION_REFRESH_ENDPOINT="https://demo.os2display.dk/v1/authentication/token/refresh" -APP_DATA_PULL_INTERVAL=90000 -APP_SCHEDULING_INTERVAL=60000 -APP_DEBUG=false + +# Have docker compose include a MariaDB database or configure an external one? +# Set to 'true' to use the built-in MariaDB database provided by the Docker Compose setup. +# Set to 'false' to configure and use an external MariaDB database. +INTERNAL_DATABASE=true + +# Have docker compose include a Traefik proxy or configure an external one? +# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. +# Set to 'false' to configure and use an external Traefik proxy. +INTERNAL_PROXY=true + +# Note: When updating the database connection details, ensure that the following MariaDB variables +# are also updated to match the connection string above. These variables are used by the Docker +# Compose setup to configure the built-in MariaDB service. These variables are only necessary if +# the local MariaDB service is used (COMPOSE_INTERNAL_DATABASE=true). +MARIADB_USER=db +MARIADB_PASSWORD=db +MARIADB_ROOT_PASSWORD=dbrootpassword +MARIADB_DATABASE=db +DB_HOST=mariadb + +# Use a built-in Traefik proxy or configure one externally? +# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. +# Set to 'false' to configure and use an external proxy. +COMPOSE_INTERNAL_PROXY=true + diff --git a/.gitignore b/.gitignore index 26a30e1..d6cd7e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -.env.local -.env.docker.local +.env db_backups/ +docker-compose.*override*.yml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b143bfb..c6e4c6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## [Unreleased] - - Add new task backup_db to backup the default internal mariadb + - Rename tasks to Symfony-style colon-separated naming: `cc` → `cache:clear`, `tenant_add` → `tenant:add`, `user_add` → `user:add`, `load_templates` → `template:load`, `backup_db` → `db:backup`. Old names kept as aliases for backward compatibility. + - Add new task `db:backup` to backup the default internal mariadb ## v1.1.2 diff --git a/README.md b/README.md index 3175434..f98910d 100644 --- a/README.md +++ b/README.md @@ -5,33 +5,24 @@ This is a deployment tool designed for hosting the OS2display v2 application usi ## Prerequisites Before you begin, ensure you have the following installed on your system: -1. **Docker**: Install Docker Engine (version 20.10 or later). -2. **Docker Compose**: Use Docker Compose v2 (integrated with the `docker compose` command). -3. **Task**: Install the Taskfile CLI tool. You can find installation instructions [here](https://taskfile.dev/#/installation). + +1. **Docker**: Docker Engine (version 20.10 or later). +2. **Docker Compose**: Docker Compose v2 (integrated with the `docker compose` command). +3. **Task**: The Taskfile CLI tool. Installation instructions are available at [taskfile.dev](https://taskfile.dev/#/installation). Make sure your user has the necessary permissions to run Docker commands (e.g., being part of the `docker` group). ### Check Prerequisites -Run the following commands to verify that the prerequisites are installed: - ```bash -# Check Docker installation docker --version - -# Check Docker Compose installation docker compose version - -# Check Taskfile CLI installation task --version ``` -## Create the deploy-user -Files inside the `os2display-api-service` container are owned by a user with UID 1042 and GID 1042. To prevent permission issues with bind mounts (the `media` and `jwt` volumes), it’s best to install the application using a user with the same UID and GID. - -To set this up on your server, create a new user (for example, `deploy`). You can choose a different username if you prefer, but make sure to assign UID and GID 1042. +## Create the Deploy User -Here’s how to create the user: +Files inside the `os2display-api-service` container are owned by a user with UID 1042 and GID 1042. To prevent permission issues with bind mounts (the `media` and `jwt` volumes), install the application using a user with the same UID and GID. ```bash # Create group and user with UID/GID 1042 @@ -43,48 +34,151 @@ sudo passwd deploy sudo usermod -aG docker deploy ``` -## Secure Mode Requirement +## HTTPS Requirement + +This project can only run in secure mode using HTTPS (port 443). You must provide a valid domain name and an SSL certificate. + +1. Use a fully qualified domain name (FQDN) that resolves to your server's IP address. +2. Place the certificate file (`docker.crt`) and private key file (`docker.key`) in the `traefik/ssl` directory. +3. Set the domain name in `.env.docker.local` via the `COMPOSE_SERVER_DOMAIN` variable. + +## Configuration + +Before running `task install`, copy and edit the configuration file: + +```bash +cp .env.docker.example .env.docker.local +``` + +Edit `.env.docker.local` with your local settings. The key variables are described below. + +### Domain and Versions + +| Variable | Description | Default | +|----------|-------------|---------| +| `COMPOSE_SERVER_DOMAIN` | Domain name where the server will be accessible | `demo.os2display.dk` | +| `COMPOSE_VERSION_API` | Version of `itkdev/os2display-api-service` | `2.6.0` | +| `COMPOSE_VERSION_ADMIN` | Version of `itkdev/os2display-admin-client` | `2.6.0` | +| `COMPOSE_VERSION_CLIENT` | Version of `itkdev/os2display-client` | `2.3.0` | + +### Infrastructure Options + +| Variable | Description | Default | +|----------|-------------|---------| +| `INTERNAL_DATABASE` | Set to `true` to use the built-in MariaDB, `false` for an external database | `true` | +| `INTERNAL_PROXY` | Set to `true` to use the built-in Traefik proxy, `false` for an external proxy | `true` | + +### Database + +| Variable | Description | Default | +|----------|-------------|---------| +| `APP_DATABASE_URL` | Doctrine database connection URL | `mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11` | +| `MARIADB_USER` | MariaDB user (only when `INTERNAL_DATABASE=true`) | `db` | +| `MARIADB_PASSWORD` | MariaDB password (only when `INTERNAL_DATABASE=true`) | `db` | +| `MARIADB_ROOT_PASSWORD` | MariaDB root password (only when `INTERNAL_DATABASE=true`) | `dbrootpassword` | +| `MARIADB_DATABASE` | MariaDB database name (only when `INTERNAL_DATABASE=true`) | `db` | + +### Secrets + +| Variable | Description | Default | +|----------|-------------|---------| +| `APP_SECRET` | Symfony application secret | `pleasuchangethis` | +| `APP_JWT_PASSPHRASE` | JWT key pair passphrase | `pleasechangethistoo` | + +**NOTE:** Change both `APP_SECRET` and `APP_JWT_PASSPHRASE` to secure values before running in production. + +### Templates and Screen Layouts + +| Variable | Description | Default | +|----------|-------------|---------| +| `TASK_VERSION_TEMPLATES` | Version/branch of [os2display/display-templates](https://github.com/os2display/display-templates/releases) | `2.6.0` | +| `TASK_TEMPLATES` | Comma-separated list of templates to load | See `.env.docker.example` | +| `TASK_SCREEN_LAYOUTS` | Comma-separated list of screen layouts to load | See `.env.docker.example` | + +### OIDC (OpenID Connect) + +| Variable | Description | +|----------|-------------| +| `INTERNAL_OIDC_METADATA_URL` | OIDC metadata URL provided by the IdP | +| `INTERNAL_OIDC_CLIENT_ID` | OIDC client ID | +| `INTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | +| `INTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | + +## Installation + +1. Edit `.env.docker.local` with your domain name, secure passwords, and other settings. +2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. +3. Run the install task: -This project can only run in secure mode using HTTPS (port 443). To ensure proper functionality, you must provide a valid domain name and an SSL certificate. +```bash +task install +``` -### Steps to Configure Secure Mode: -1. **Domain Name**: Use a fully qualified domain name (FQDN) that resolves to your server's IP address. -2. **SSL Certificate**: Provide a valid SSL certificate and private key for the domain. - - Place the certificate file (`docker.crt`) and the private key file (`docker.key`) in the `traefik/ssl` directory. -3. **Update Configuration**: Ensure the domain name is correctly configured in the `.env.docker.local` file. +The install process will: +- Pull Docker images +- Start all containers +- Create the database schema +- Generate JWT key pair +- Prompt you to create a tenant and an admin user +- Load templates and screen layouts -Without a valid domain name and SSL certificate, the project will not function as expected. +After installation, the application is available at: +- **Admin:** `https:///admin` +- **Screen client:** `https:///client` ## Available Tasks -The project uses a `Taskfile.yml` to simplify common operations. Below is a list of the most important tasks you can run: +For a full list of tasks, run: + +```bash +task --list +``` ### Installation and Setup -- **`task install`**: Installs the project, pulls Docker images, sets up the database, and initializes the environment. -- **`task reinstall`**: Reinstalls the project from scratch, removing all containers, volumes, and the database. -- **`task up`**: Starts the environment without altering the existing state of the containers. -- **`task down`**: Stops and removes all containers and volumes. + +| Task | Description | +|------|-------------| +| `task install` | Install the project (pull images, create DB, generate JWT keys, add tenant/user, load templates) | +| `task reinstall` | Reinstall from scratch. **WARNING:** Deletes the database | +| `task up` | Start the environment (recompiles configuration) | +| `task down` | Stop and remove all containers | +| `task stop` | Stop all containers without removing them | +| `task purge` | Remove all containers and volumes. **WARNING:** Deletes the database | ### Tenant and User Management -- **`task tenant_add`**: Adds a new tenant group. A tenant is a group of users that share the same configuration. -- **`task user_add`**: Adds a new user (editor or admin) to a tenant. + +| Task | Description | +|------|-------------| +| `task tenant:add` | Add a new tenant group | +| `task user:add` | Add a new user (editor or admin) to a tenant | ### Templates and Screen Layouts -- **`task load_templates`**: Loads templates and screen layouts based on the configuration in `.env.docker.local`. + +| Task | Description | +|------|-------------| +| `task template:load` | Load templates and screen layouts based on configuration in `.env.docker.local` | ### Maintenance -- **`task logs`**: Follows the logs from the Docker containers. -- **`task cc`**: Clears the cache in the application. -### Pre-installation Notes -Before running `task install`, ensure the following: -1. Update `.env.docker.local` with your domain name (replace all 5 instances) and set secure passwords. -2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. +| Task | Description | +|------|-------------| +| `task logs` | Follow logs from the Docker containers | +| `task cache:clear` | Clear the application cache | +| `task db:backup` | Perform a database dump (only when using the built-in MariaDB). Saves to the `db_backups/` directory | + +## Updating an Existing Installation + +To update to newer image versions: + +1. Update the version variables (`COMPOSE_VERSION_API`, `COMPOSE_VERSION_ADMIN`, `COMPOSE_VERSION_CLIENT`) in `.env.docker.local`. +2. Run the restart script: -For a full list of tasks, run: ```bash -task --list +./restart.sh ``` +This pulls new images, recreates containers, and runs database migrations. If templates have changed, run `task template:load` afterwards. +## License +This project is licensed under the European Union Public License 1.2. See [LICENSE](LICENSE) for details. diff --git a/Taskfile.yml b/Taskfile.yml index 81afc25..b921ef0 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -3,30 +3,13 @@ silent: true tasks: default: - desc: The default task that shows help + desc: Show available tasks cmds: - - echo "Available tasks (in preferred order):" - - echo " install Install the project" - - echo " reinstall Reinstall from scratch. WARNING Deletes the database!" - - echo " up Start the environment" - - echo " down Remove all containers" - - echo " purge Remove all containers and volumes. WARNING Deletes the database!" - - echo " stop Stop all containers" - - echo " logs Follow docker logs" - - echo " cc Clear the cache" - - echo " tenant_add Add a new tenant group" - - echo " user_add Add a new user" - - echo " load_templates Load templates and screen layouts" - - echo " backup_db Performs a database dump, if you use the default internal mariadb." - - echo "" - + - task --list install: desc: Install the project - deps: - - _dc_compile cmds: - - task _show_preinstall_notes - echo "Installing" - | # Check if the external network 'frontend' exists, create if not @@ -36,43 +19,24 @@ tasks: else echo "External network 'frontend' already exists" fi - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml pull - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml up --force-recreate --detach --remove-orphans - - echo "Waiting for database to be ready" - - sleep 20 + - docker compose pull + - docker compose up --force-recreate --detach --remove-orphans +# - echo "Waiting for database to be ready" +# - sleep 20 - echo "Initialize the database" - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console doctrine:schema:create - - echo "Clearing the cache" - - task cc + - docker compose exec api bin/console doctrine:schema:create - echo "Create jwt key pair" - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console lexik:jwt:generate-keypair --skip-if-exists - - task tenant_add - - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." - - task user_add - - task load_templates - - task _show_notes - - reinstall: - desc: Reinstall from scratch. Removes the database, all containers, and volumes. - deps: - - purge - cmds: - - task install - - down: - desc: Remove all containers - deps: - - stop - cmds: - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml down - - rm -f docker-compose.yml .env.local + - docker compose exec api bin/console lexik:jwt:generate-keypair --skip-if-exists +# - task tenant:add +# - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." +# - task user:add +# - task template:load + - task _install:show-urls purge: desc: Remove all containers and volumes - deps: - - stop cmds: - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml down --volumes --remove-orphans + - docker compose down --volumes --remove-orphans - | # Check if the external network 'frontend' exists, remove if it does if docker network ls --format '{{.Name}}' | grep -wq frontend; then @@ -83,94 +47,10 @@ tasks: fi - rm -f docker-compose.yml .env.local - up: - desc: Take the environment up without altering the existing state of the containers - cmds: - - task _dc_compile - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml up -d - - stop: - desc: Stop all containers without altering anything else - cmds: - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml stop - - tenant_add: - desc: Add a new tenant group - cmds: - - echo "" - - echo "Add a tenant" - - echo "====================================================" - - echo "A tenant is a group of users that share the same configuration. F. ex. IT, Library, Schools etc." - - echo "You have to provide tenant id, tenant title and optionally a description." - - echo "====================================================" - - echo "" - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec -T api bin/console app:tenant:add - - user_add: - desc: Add a new user (editor or admin) - cmds: - - echo "" - - echo "Add a user" - - echo "====================================================" - - echo "You have to provide email, password, full name, role (editor or admin) and the tenant id." - - echo "====================================================" - - echo "" - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec -T api bin/console app:user:add - - load_templates: - desc: Load templates and screen layouts - cmds: - - | - TEMPLATES_RELEASE=$(grep ^TASK_VERSION_TEMPLATES= .env.docker.local | cut -d '=' -f 2) - TEMPLATES=$(grep ^TASK_TEMPLATES= .env.docker.local | cut -d '=' -f 2 | tr -d ' "' | tr ',' ' ') - if [ -z "$TEMPLATES_RELEASE" ]; then - echo "Error: TASK_VERSION_TEMPLATES is not set in .env.docker.local" - exit 1 - fi - if [ -z "$TEMPLATES" ]; then - echo "Error: TASK_TEMPLATES is not set or empty in .env.docker.local" - exit 1 - fi - echo "Using TEMPLATES_RELEASE=$TEMPLATES_RELEASE" - echo "Using TEMPLATES=$TEMPLATES" - for TEMPLATE in $TEMPLATES; do - if [ "$TEMPLATES_RELEASE" = "develop" ]; then - CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/heads/$TEMPLATES_RELEASE/build/$TEMPLATE-config-main.json" - else - CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/build/$TEMPLATE-config-main.json" - fi - echo "Loading template: $TEMPLATE" - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec --user deploy api bin/console app:template:load -p $CONFIG_URL - done - - SCREEN_LAYOUTS=$(grep ^TASK_SCREEN_LAYOUTS= .env.docker.local | cut -d '=' -f 2 | tr -d ' "' | tr ',' ' ') - if [ -z "$SCREEN_LAYOUTS" ]; then - echo "Error: TASK_SCREEN_LAYOUTS is not set or empty in .env.docker.local" - exit 1 - fi - echo "Using SCREEN_LAYOUTS=$SCREEN_LAYOUTS" - for SCREEN_LAYOUT in $SCREEN_LAYOUTS; do - if [ "$TEMPLATES_RELEASE" = "develop" ]; then - CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/heads/$TEMPLATES_RELEASE/src/screen-layouts/$SCREEN_LAYOUT.json" - else - CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/src/screen-layouts/$SCREEN_LAYOUT.json" - fi - echo "Loading screen layout: $SCREEN_LAYOUT" - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions $CONFIG_URL - done - - logs: - desc: Follow docker logs from the containers - cmds: - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml logs -f --tail=50 - - cc: - desc: Clear the cache - cmds: - - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec api bin/console cache:clear - - backup_db: + db:backup: desc: Perform a database dump, if you use the default internal mariadb. The dump file will be saved in the 'db_backups' directory with a timestamp in the filename. + aliases: + - backup_db cmds: - | TIMESTAMP=$(date +%Y%m%d_%H%M%S) @@ -187,25 +67,7 @@ tasks: echo "Database backup saved to $FILENAME" fi - _show_preinstall_notes: - cmds: - - echo "" - - echo "====================================================" - - echo "Pre-installation Requirements" - - echo "====================================================" - - echo "" - - echo "To proceed with the installation, ensure the following steps are completed:" - - echo "1. Update '.env.docker.local' with local settings and set secure passwords." - - echo "2. Place your SSL certificate files ('docker.crt' and 'docker.key') in the 'traefik/ssl' directory." - - echo "" - - echo "Have you completed the above pre-installation steps? (yes/no)" - - | - read answer && case $answer in - [Yy][Ee][Ss]) ;; - *) echo "Please complete the pre-install tasks before continuing."; exit 1;; - esac - - _show_notes: + _install:show-urls: cmds: - | DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env.docker.local | cut -d '=' -f 2) @@ -217,33 +79,67 @@ tasks: echo "Screen: https://$DOMAIN/client" echo "====================================================" - _env_files: + _env:build: + desc: Build .env from .env.example by prompting for placeholder values cmds: - | - echo "Copying .env.example to .env.local..." - cp .env.example .env.local - - | - if [ ! -f .env.docker.local ]; then - echo ".env.docker.local does not exist. Copying .env.docker.example to .env.docker.local..." - cp .env.docker.example .env.docker.local + INPUT=".env.example" + OUTPUT=".env" + CACHE=$(mktemp) + trap "rm -f $CACHE" EXIT + + if [ ! -f "$INPUT" ]; then + echo "Error: $INPUT not found." + exit 1 fi - _dc_compile: - deps: - - _env_files + # First pass: collect unique placeholder values + while IFS= read -r line || [ -n "$line" ]; do + for PLACEHOLDER in $(echo "$line" | grep -oE '<[^:]+:-[^>]*>'); do + VAR_NAME=$(echo "$PLACEHOLDER" | sed 's/^<\([^:]*\):-.*>/\1/') + FOUND=0 + grep -q "^${VAR_NAME}=" "$CACHE" 2>/dev/null && FOUND=1 + if [ "$FOUND" = "0" ]; then + DEFAULT=$(echo "$PLACEHOLDER" | sed 's/^<[^:]*:-\(.*\)>/\1/') + printf "%s [%s]: " "$VAR_NAME" "$DEFAULT" > /dev/tty + read ANSWER < /dev/tty + echo "${VAR_NAME}=${ANSWER:-$DEFAULT}" >> "$CACHE" + fi + done + done < "$INPUT" + + # Second pass: replace placeholders with values + rm -f "$OUTPUT" + while IFS= read -r line || [ -n "$line" ]; do + RESULT="$line" + while echo "$RESULT" | grep -qE '<[^:]+:-[^>]*>'; do + MATCH=$(echo "$RESULT" | grep -oE '<[^:]+:-[^>]*>' | head -1) + VAR_NAME=$(echo "$MATCH" | sed 's/^<\([^:]*\):-.*>/\1/') + VALUE=$(grep "^${VAR_NAME}=" "$CACHE" | cut -d '=' -f 2-) + ESCAPED_MATCH=$(printf '%s\n' "$MATCH" | sed 's/[[\.*^$()+?{|\/]/\\&/g') + ESCAPED_VALUE=$(printf '%s\n' "$VALUE" | sed 's/[&\/]/\\&/g') + RESULT=$(printf '%s\n' "$RESULT" | sed "s|${ESCAPED_MATCH}|${ESCAPED_VALUE}|") + done + printf '%s\n' "$RESULT" >> "$OUTPUT" + done < "$INPUT" + + echo "" + echo "$OUTPUT has been created." + + _env:check: + desc: Check that the .env files exist cmds: - | - COMPOSE_FILES="-f docker-compose.server.yml" - if grep -q '^INTERNAL_DATABASE=true' .env.docker.local; then - COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.mariadb.yml" + if [ ! -f .env.example ]; then + echo "Error: .env.example not found. The repository may be incomplete." + exit 1 fi - if grep -q '^INTERNAL_PROXY=true' .env.docker.local; then - COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.traefik.yml" + echo "Copying .env.example to .env.local..." + cp .env.example .env.local + - | + if [ ! -f .env.docker.local ]; then + echo "Error: .env.docker.local not found." + echo "Create it by running: cp .env.docker.example .env.docker.local" + echo "Then edit it with your local settings before running this task again." + exit 1 fi - docker compose --env-file .env.local --env-file .env.docker.local $COMPOSE_FILES config > docker-compose.yml - - # Replace all occurrences of demo.os2display.dk with the value of COMPOSE_SERVER_DOMAIN - DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env.docker.local | cut -d '=' -f 2) - if [ -n "$DOMAIN" ]; then - sed -i "s/demo\.os2display\.dk/$DOMAIN/g" docker-compose.yml - fi \ No newline at end of file diff --git a/docker-compose.server.yml b/docker-compose.server.yml deleted file mode 100644 index 3809584..0000000 --- a/docker-compose.server.yml +++ /dev/null @@ -1,150 +0,0 @@ -networks: - frontend: - external: true - app: - driver: bridge - internal: false - -services: - api: - image: itkdev/os2display-api-service:${COMPOSE_VERSION_API} - restart: unless-stopped - networks: - - app - environment: - # PHP config values - - PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME} - - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT} - - PHP_POST_MAX_SIZE=${PHP_POST_MAX_SIZE} - - PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE} - - PHP_TIMEZONE=UTC - - PHP_PM_MAX_CHILDREN=16 - - PHP_OPCACHE_VALIDATE_TIMESTAMPS=0 - # APP (Symfony) - - APP_SECRET=${APP_SECRET:?err} - - APP_DATABASE_URL=${APP_DATABASE_URL:?err} - - APP_JWT_PASSPHRASE=${APP_JWT_PASSPHRASE:?err} - - APP_JWT_TOKEN_TTL=${APP_JWT_TOKEN_TTL} - - APP_JWT_SCREEN_TOKEN_TTL=${APP_JWT_SCREEN_TOKEN_TTL} - - APP_JWT_REFRESH_TOKEN_TTL=${APP_JWT_REFRESH_TOKEN_TTL} - - APP_JWT_SCREEN_REFRESH_TOKEN_TTL=${APP_JWT_SCREEN_REFRESH_TOKEN_TTL} - - APP_ENV=${APP_ENV} - - APP_TRUSTED_PROXIES=${APP_TRUSTED_PROXIES} - - APP_CORS_ALLOW_ORIGIN=${APP_CORS_ALLOW_ORIGIN} - - APP_DEFAULT_DATE_FORMAT=${APP_DEFAULT_DATE_FORMAT} - - APP_INTERNAL_OIDC_METADATA_URL=${INTERNAL_OIDC_METADATA_URL} - - APP_INTERNAL_OIDC_CLIENT_ID=${INTERNAL_OIDC_CLIENT_ID} - - APP_INTERNAL_OIDC_CLIENT_SECRET=${INTERNAL_OIDC_CLIENT_SECRET} - - APP_INTERNAL_OIDC_REDIRECT_URI=${INTERNAL_OIDC_REDIRECT_URI} - - APP_INTERNAL_OIDC_LEEWAY=${INTERNAL_OIDC_LEEWAY} - - APP_EXTERNAL_OIDC_METADATA_URL=${EXTERNAL_OIDC_METADATA_URL} - - APP_EXTERNAL_OIDC_CLIENT_ID=${EXTERNAL_OIDC_CLIENT_ID} - - APP_EXTERNAL_OIDC_CLIENT_SECRET=${EXTERNAL_OIDC_CLIENT_SECRET} - - APP_EXTERNAL_OIDC_REDIRECT_URI=${EXTERNAL_OIDC_REDIRECT_URI} - - APP_EXTERNAL_OIDC_LEEWAY=${EXTERNAL_OIDC_LEEWAY} - - APP_EXTERNAL_OIDC_HASH_SALT=${EXTERNAL_OIDC_HASH_SALT} - - APP_EXTERNAL_OIDC_CLAIM_ID=${EXTERNAL_OIDC_CLAIM_ID} - - APP_REDIS_CACHE_PREFIX=${APP_REDIS_CACHE_PREFIX} - - APP_REDIS_CACHE_DSN=${APP_REDIS_CACHE_DSN} - - APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT} - - APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT} - - APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT} - - APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS=${APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS} - - APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS=${APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS} - - APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT=${APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT} - - APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE=${APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE} - - APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS=${APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS} - - APP_TRACK_SCREEN_INFO=${APP_TRACK_SCREEN_INFO} - - APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS=${APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS} - - APP_KEY_VAULT_JSON=${APP_KEY_VAULT_JSON} - volumes: - - ./jwt:/var/www/html/config/jwt:rw - - ./media:/var/www/html/public/media:rw - - nginx-api: - image: itkdev/os2display-api-service-nginx:${COMPOSE_VERSION_API} - restart: unless-stopped - networks: - - app - - frontend - environment: - - PHP_FPM_SERVER=api - - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} - depends_on: - - api - labels: - - "traefik.enable=true" - - "traefik.docker.network=frontend" - - "traefik.http.routers.apios2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.apios2display-http.entrypoints=web" - - "traefik.http.routers.apios2display-http.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.apios2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.apios2display.entrypoints=websecure" - # Redirect root / request to /${COMPOSE_ADMIN_CLIENT_PATH} - - "traefik.http.routers.apios2display.middlewares=redirect-to-admin" - - "traefik.http.middlewares.redirect-to-admin.redirectregex.regex=^https:\\/\\/([^\\/]+)\\/?$$" - - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1${COMPOSE_ADMIN_CLIENT_PATH}" - # - "traefik.http.routers.apios2display.middlewares=apios2display" - # - "traefik.http.middlewares.apios2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" - # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" - volumes: - - ./media:/var/www/html/public/media:rw - - admin: - image: itkdev/os2display-admin-client:${COMPOSE_VERSION_ADMIN} - restart: unless-stopped - networks: - - app - - frontend - environment: - - APP_ADMIN_CLIENT_PATH=${COMPOSE_ADMIN_CLIENT_PATH} - - API_PATH=${API_PATH} - - APP_TOUCH_BUTTON_REGIONS=${APP_TOUCH_BUTTON_REGIONS} - - APP_REJSEPLANEN_API_KEY=${APP_REJSEPLANEN_API_KEY} - - APP_SHOW_SCREEN_STATUS=${APP_SHOW_SCREEN_STATUS} - - APP_PREVIEW_CLIENT=${APP_PREVIEW_CLIENT} - labels: - - "traefik.enable=true" - - "traefik.docker.network=frontend" - - "traefik.http.routers.adminos2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_ADMIN_CLIENT_PATH}`)" - - "traefik.http.routers.adminos2display-http.entrypoints=web" - - "traefik.http.routers.adminos2display-http.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.adminos2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_ADMIN_CLIENT_PATH}`)" - - "traefik.http.routers.adminos2display.entrypoints=websecure" - # - "traefik.http.routers.adminos2display.middlewares=apios2display" - # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" - - client: - image: itkdev/os2display-client:${COMPOSE_VERSION_CLIENT} - restart: unless-stopped - networks: - - app - - frontend - environment: - - APP_SCREEN_CLIENT_PATH=${COMPOSE_SCREEN_CLIENT_PATH:?err} - - APP_API_ENDPOINT=${APP_API_ENDPOINT:?err} - - APP_API_PATH=${APP_API_PATH:?err} - - APP_API_AUTHENTICATION_ENDPOINT=${APP_API_AUTHENTICATION_ENDPOINT} - - APP_API_AUTHENTICATION_REFRESH_ENDPOINT=${APP_API_AUTHENTICATION_REFRESH_ENDPOINT} - - APP_DATA_PULL_INTERVAL=${APP_DATA_PULL_INTERVAL} - - APP_SCHEDULING_INTERVAL=${APP_SCHEDULING_INTERVAL} - - APP_DEBUG=${APP_DEBUG} - labels: - - "traefik.enable=true" - - "traefik.docker.network=frontend" - - "traefik.http.routers.clientos2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_SCREEN_CLIENT_PATH}`)" - - "traefik.http.routers.clientos2display-http.entrypoints=web" - - "traefik.http.routers.clientos2display-http.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.clientos2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`) && PathPrefix(`${COMPOSE_SCREEN_CLIENT_PATH}`)" - - "traefik.http.routers.clientos2display.entrypoints=websecure" - # - "traefik.http.routers.clientos2display.middlewares=apios2display" - # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" - - redis: - image: 'redis:6' - restart: unless-stopped - networks: - - app diff --git a/docker-compose.yml b/docker-compose.yml index fa0ea31..b03d483 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,230 +1,136 @@ -name: os2display +networks: + frontend: + external: true + app: + driver: bridge + internal: false + services: - admin: - environment: - API_PATH: / - APP_ADMIN_CLIENT_PATH: /admin - APP_PREVIEW_CLIENT: "" - APP_REJSEPLANEN_API_KEY: "" - APP_SHOW_SCREEN_STATUS: "" - APP_TOUCH_BUTTON_REGIONS: "true" - image: itkdev/os2display-admin-client:2.6.0 - labels: - traefik.docker.network: frontend - traefik.enable: "true" - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https - traefik.http.routers.adminos2display-http.entrypoints: web - traefik.http.routers.adminos2display-http.middlewares: redirect-to-https - traefik.http.routers.adminos2display-http.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/admin`) - traefik.http.routers.adminos2display.entrypoints: websecure - traefik.http.routers.adminos2display.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/admin`) - networks: - app: null - frontend: null + os2display: + image: ghcr.io/itk-dev/os2display-api-service:${COMPOSE_IMAGE_VERSION} restart: unless-stopped - api: - environment: - APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS: "" - APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS: "" - APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT: "" - APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE: "" - APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT: "" - APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS: "" - APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT: "" - APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT: "" - APP_CORS_ALLOW_ORIGIN: ^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$$ - APP_DATABASE_URL: mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11 - APP_DEFAULT_DATE_FORMAT: Y-m-d\TH:i:s.v\Z - APP_ENV: prod - APP_EXTERNAL_OIDC_CLAIM_ID: "" - APP_EXTERNAL_OIDC_CLIENT_ID: "" - APP_EXTERNAL_OIDC_CLIENT_SECRET: "" - APP_EXTERNAL_OIDC_HASH_SALT: "" - APP_EXTERNAL_OIDC_LEEWAY: "" - APP_EXTERNAL_OIDC_METADATA_URL: "" - APP_EXTERNAL_OIDC_REDIRECT_URI: "" - APP_INTERNAL_OIDC_CLIENT_ID: Sonderborg-OS2display - APP_INTERNAL_OIDC_CLIENT_SECRET: 7bdf9007-9518-4f1b-a0b5-4a42db1f58b9 - APP_INTERNAL_OIDC_LEEWAY: "30" - APP_INTERNAL_OIDC_METADATA_URL: https://adgang-idp.sonderborg.dk/.well-known/openid-configuration - APP_INTERNAL_OIDC_REDIRECT_URI: https://os2display.sonderborg.dk/admin - APP_JWT_PASSPHRASE: pleasechangethistoo - APP_JWT_REFRESH_TOKEN_TTL: "2592000" - APP_JWT_SCREEN_REFRESH_TOKEN_TTL: "" - APP_JWT_SCREEN_TOKEN_TTL: "" - APP_JWT_TOKEN_TTL: "3600" - APP_KEY_VAULT_JSON: '{}' - APP_REDIS_CACHE_DSN: redis://redis:6379/0 - APP_REDIS_CACHE_PREFIX: DisplayApiService - APP_SECRET: pleasuchangethis - APP_TRACK_SCREEN_INFO: "" - APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS: "" - APP_TRUSTED_PROXIES: 127.0.0.1,REMOTE_ADDR - PHP_MAX_EXECUTION_TIME: "30" - PHP_MEMORY_LIMIT: 128M - PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" - PHP_PM_MAX_CHILDREN: "16" - PHP_POST_MAX_SIZE: 140M - PHP_TIMEZONE: UTC - PHP_UPLOAD_MAX_FILESIZE: 128M - image: itkdev/os2display-api-service:2.6.0 networks: - app: null - restart: unless-stopped - volumes: - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/jwt - target: /var/www/html/config/jwt - bind: - create_host_path: true - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/media - target: /var/www/html/public/media - bind: - create_host_path: true - client: + - app environment: - APP_API_AUTHENTICATION_ENDPOINT: https://os2display-devs.sonderborg.dk/v1/authentication/screen - APP_API_AUTHENTICATION_REFRESH_ENDPOINT: https://os2display-devs.sonderborg.dk/v1/authentication/token/refresh - APP_API_ENDPOINT: https://os2display-devs.sonderborg.dk - APP_API_PATH: https://os2display-devs.sonderborg.dk - APP_DATA_PULL_INTERVAL: "90000" - APP_DEBUG: "false" - APP_SCHEDULING_INTERVAL: "60000" - APP_SCREEN_CLIENT_PATH: /client - image: itkdev/os2display-client:2.3.0 - labels: - traefik.docker.network: frontend - traefik.enable: "true" - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https - traefik.http.routers.clientos2display-http.entrypoints: web - traefik.http.routers.clientos2display-http.middlewares: redirect-to-https - traefik.http.routers.clientos2display-http.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/client`) - traefik.http.routers.clientos2display.entrypoints: websecure - traefik.http.routers.clientos2display.rule: Host(`os2display-devs.sonderborg.dk`) && PathPrefix(`/client`) - networks: - app: null - frontend: null + # PHP config values + - PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME} + - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT} + - PHP_POST_MAX_SIZE=${PHP_POST_MAX_SIZE} + - PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE} + - PHP_TIMEZONE=UTC + - PHP_PM_MAX_CHILDREN=16 + - PHP_OPCACHE_VALIDATE_TIMESTAMPS=0 + + # APP (Symfony) + - APP_ENV=${APP_ENV} + - APP_SECRET=${APP_SECRET:?err} + + - DATABASE_URL=${APP_DATABASE_URL:?err} + - JWT_PASSPHRASE=${APP_JWT_PASSPHRASE:?err} + - JWT_TOKEN_TTL=${APP_JWT_TOKEN_TTL} + - JWT_SCREEN_TOKEN_TTL=${APP_JWT_SCREEN_TOKEN_TTL} + - JWT_REFRESH_TOKEN_TTL=${APP_JWT_REFRESH_TOKEN_TTL} + - JWT_SCREEN_REFRESH_TOKEN_TTL=${APP_JWT_SCREEN_REFRESH_TOKEN_TTL} + + - TRUSTED_PROXIES=${APP_TRUSTED_PROXIES} + - CORS_ALLOW_ORIGIN=${APP_CORS_ALLOW_ORIGIN} + - DEFAULT_DATE_FORMAT=${APP_DEFAULT_DATE_FORMAT} + - ACTIVATION_CODE_EXPIRE_INTERVAL=${APP_ACTIVATION_CODE_EXPIRE_INTERVAL} + + # OIDC - internal provider + - INTERNAL_OIDC_METADATA_URL=${APP_INTERNAL_OIDC_METADATA_URL} + - INTERNAL_OIDC_CLIENT_ID=${APP_INTERNAL_OIDC_CLIENT_ID} + - INTERNAL_OIDC_CLIENT_SECRET=${APP_INTERNAL_OIDC_CLIENT_SECRET} + - INTERNAL_OIDC_REDIRECT_URI=${APP_INTERNAL_OIDC_REDIRECT_URI} + - INTERNAL_OIDC_LEEWAY=${APP_INTERNAL_OIDC_LEEWAY} + - INTERNAL_OIDC_CLAIM_NAME=${APP_INTERNAL_OIDC_CLAIM_NAME} + - INTERNAL_OIDC_CLAIM_EMAIL=${APP_INTERNAL_OIDC_CLAIM_EMAIL} + - INTERNAL_OIDC_CLAIM_GROUPS=${APP_INTERNAL_OIDC_CLAIM_GROUPS} + + # OIDC - external provider + - EXTERNAL_OIDC_METADATA_URL=${APP_EXTERNAL_OIDC_METADATA_URL} + - EXTERNAL_OIDC_CLIENT_ID=${APP_EXTERNAL_OIDC_CLIENT_ID} + - EXTERNAL_OIDC_CLIENT_SECRET=${APP_EXTERNAL_OIDC_CLIENT_SECRET} + - EXTERNAL_OIDC_REDIRECT_URI=${APP_EXTERNAL_OIDC_REDIRECT_URI} + - EXTERNAL_OIDC_LEEWAY=${APP_EXTERNAL_OIDC_LEEWAY} + - EXTERNAL_OIDC_HASH_SALT=${APP_EXTERNAL_OIDC_HASH_SALT} + - EXTERNAL_OIDC_CLAIM_ID=${APP_EXTERNAL_OIDC_CLAIM_ID} + + - OIDC_CLI_REDIRECT=${APP_OIDC_CLI_REDIRECT} + + - REDIS_CACHE_PREFIX=${APP_REDIS_CACHE_PREFIX} + - REDIS_CACHE_DSN=${APP_REDIS_CACHE_DSN} + + # Calendar Api Feed Source + - CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT} + - CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT} + - CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT=${APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT} + - CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS=${APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS} + - CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS=${APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS} + - CALENDAR_API_FEED_SOURCE_DATE_FORMAT=${APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT} + - CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE=${APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE} + - CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS=${APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS} + + # Event Database Api V2 + - EVENTDATABASE_API_V2_CACHE_EXPIRE_SECONDS=${APP_EVENTDATABASE_API_V2_CACHE_EXPIRE_SECONDS} + + - TRACK_SCREEN_INFO=${APP_TRACK_SCREEN_INFO} + - TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS=${APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS} + + - KEY_VAULT_SOURCE=${APP_KEY_VAULT_SOURCE} + - KEY_VAULT_JSON=${APP_KEY_VAULT_JSON} + + # Admin + - ADMIN_REJSEPLANEN_APIKEY=${APP_ADMIN_REJSEPLANEN_APIKEY:-} + - ADMIN_SHOW_SCREEN_STATUS=${APP_ADMIN_SHOW_SCREEN_STATUS:-false} + - ADMIN_TOUCH_BUTTON_REGIONS=${APP_ADMIN_TOUCH_BUTTON_REGIONS:-false} + - ADMIN_LOGIN_METHODS=${APP_ADMIN_LOGIN_METHODS:?err} + - ADMIN_ENHANCED_PREVIEW=${APP_ADMIN_ENHANCED_PREVIEW:-false} + + # Client + - CLIENT_LOGIN_CHECK_TIMEOUT=${CLIENT_LOGIN_CHECK_TIMEOUT:-20000} + - CLIENT_REFRESH_TOKEN_TIMEOUT=${CLIENT_REFRESH_TOKEN_TIMEOUT:-300000} + - CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT=${CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT:-600000} + - CLIENT_SCHEDULING_INTERVAL=${CLIENT_SCHEDULING_INTERVAL:-60000} + - CLIENT_PULL_STRATEGY_INTERVAL=${CLIENT_PULL_STRATEGY_INTERVAL:-90000} + - CLIENT_COLOR_SCHEME=${CLIENT_COLOR_SCHEME:-{"type":"library","lat":56.0,"lng":10.0}} + - CLIENT_DEBUG=${CLIENT_DEBUG:-false} + volumes: + - ./jwt:/var/www/html/config/jwt:rw + - ./media:/var/www/html/public/media:rw + + nginx: + image: ghcr.io/itk-dev/os2display-api-service-nginx:${COMPOSE_IMAGE_VERSION} restart: unless-stopped - mariadb: - environment: - MARIADB_DATABASE: db - MARIADB_PASSWORD: db - MARIADB_ROOT_PASSWORD: dbrootpassword - MARIADB_USER: db - image: mariadb:10.11.11 networks: - app: null - restart: unless-stopped - volumes: - - type: volume - source: mariadb - target: /var/lib/mysql - volume: {} - nginx-api: - depends_on: - api: - condition: service_started - required: true + - app + - frontend environment: - NGINX_FPM_UPLOAD_MAX: 140M - PHP_FPM_SERVER: api - image: itkdev/os2display-api-service-nginx:2.6.0 + - PHP_FPM_SERVER=api + - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} + depends_on: + - api labels: - traefik.docker.network: frontend - traefik.enable: "true" - traefik.http.middlewares.redirect-to-admin.redirectregex.regex: ^https:\/\/([^\/]+)\/?$$ - traefik.http.middlewares.redirect-to-admin.redirectregex.replacement: https://$$1/admin - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https - traefik.http.routers.apios2display-http.entrypoints: web - traefik.http.routers.apios2display-http.middlewares: redirect-to-https - traefik.http.routers.apios2display-http.rule: Host(`os2display-devs.sonderborg.dk`) - traefik.http.routers.apios2display.entrypoints: websecure - traefik.http.routers.apios2display.middlewares: redirect-to-admin - traefik.http.routers.apios2display.rule: Host(`os2display-devs.sonderborg.dk`) - networks: - app: null - frontend: null - restart: unless-stopped + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.apios2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.apios2display-http.entrypoints=web" + - "traefik.http.routers.apios2display-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.apios2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.apios2display.entrypoints=websecure" + # Redirect root / request to /${COMPOSE_ADMIN_CLIENT_PATH} + - "traefik.http.routers.apios2display.middlewares=redirect-to-admin" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.regex=^https:\\/\\/([^\\/]+)\\/?$$" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1${COMPOSE_ADMIN_CLIENT_PATH}" + # - "traefik.http.routers.apios2display.middlewares=apios2display" + # - "traefik.http.middlewares.apios2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" + # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" volumes: - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/media - target: /var/www/html/public/media - bind: - create_host_path: true + - ./media:/var/www/html/public/media:rw + redis: - image: redis:6 - networks: - app: null + image: 'redis:6' restart: unless-stopped - socket-proxy: - container_name: socket-proxy - environment: - CONTAINERS: "1" - image: itkdev/docker-socket-proxy - networks: - proxy: null - restart: unless-stopped - user: root - volumes: - - type: bind - source: /var/run/docker.sock - target: /var/run/docker.sock - read_only: true - bind: - create_host_path: true - traefik: - container_name: traefik - image: traefik:latest networks: - frontend: null - proxy: null - ports: - - mode: ingress - target: 80 - published: "80" - protocol: tcp - - mode: ingress - target: 443 - published: "443" - protocol: tcp - - mode: ingress - target: 8080 - published: "8080" - protocol: tcp - restart: unless-stopped - security_opt: - - no-new-privileges:true - volumes: - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/traefik/ssl - target: /certs - read_only: true - bind: - create_host_path: true - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/traefik/traefik.yml - target: /traefik.yml - read_only: true - bind: - create_host_path: true - - type: bind - source: /home/deploy/vanilla/os2display-docker-server/traefik/dynamic-conf.yaml - target: /config/dynamic-conf.yaml - read_only: true - bind: - create_host_path: true -networks: - app: - name: os2display_app - driver: bridge - frontend: - name: frontend - external: true - proxy: - name: os2display_proxy - driver: bridge - internal: true -volumes: - mariadb: - name: os2display_mariadb + - app diff --git a/load-templates-develop.sh b/load-templates-develop.sh deleted file mode 100755 index 207ad65..0000000 --- a/load-templates-develop.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# app:template:load -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/book-review-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/brnd-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/contacts-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/iframe-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/image-text-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/instagram-feed-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/news-feed-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/poster-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/rss-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/slideshow-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/table-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/travel-config-develop.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p -t https://raw.githubusercontent.com/os2display/display-templates/develop/build/video-config-develop.json - -# app:screen-layouts:load -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/full-screen.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/three-boxes-horizontal.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/three-boxes.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/touch-template.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes-vertical.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/six-areas.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/four-areas.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/develop/src/screen-layouts/two-boxes-vertical-reversed.json diff --git a/load-templates-prod.sh b/load-templates-prod.sh deleted file mode 100755 index 42502f3..0000000 --- a/load-templates-prod.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -if [ -z "${TEMPLATES_RELEASE}" ] -then - echo "TEMPLATES_RELEASE must be set to a valid tag." - exit 2 -fi - -echo "Loading templates with tag: ${TEMPLATES_RELEASE}." - -# app:template:load -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/book-review-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/calendar-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/contacts-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/iframe-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/image-text-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/instagram-feed-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/news-feed-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/poster-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/rss-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/slideshow-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/table-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/travel-config-main.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:template:load -p https://raw.githubusercontent.com/os2display/display-templates/refs/tags/${TEMPLATES_RELEASE}/build/video-config-main.json - -# app:screen-layouts:load -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/full-screen.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/three-boxes-horizontal.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/three-boxes.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/touch-template.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/two-boxes.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/two-boxes-vertical.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/six-areas.json -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console app:screen-layouts:load --update --cleanup-regions https://raw.githubusercontent.com/os2display/display-templates/main/src/screen-layouts/four-areas.json diff --git a/restart.sh b/restart.sh deleted file mode 100755 index 1c6fb18..0000000 --- a/restart.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -docker compose --env-file .env.docker.local -f docker-compose.server.yml pull -docker compose --env-file .env.docker.local -f docker-compose.server.yml up --force-recreate --detach --remove-orphans - -docker compose --env-file .env.docker.local -f docker-compose.server.yml exec --user deploy api bin/console doctrine:migrations:migrate --no-interaction - -echo "NB! Remember to load templates if they have changed. See 'Deployment' in README.md for instructions." From 7ff09bf63a02d8bd35599ede97e3b6eb4df12039 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Fri, 20 Feb 2026 14:16:08 +0100 Subject: [PATCH 04/22] 6601: Start on task install process --- .env.example | 12 ++-------- Taskfile.yml | 56 +++++++++++++++++++++++++++++----------------- docker-compose.yml | 2 +- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/.env.example b/.env.example index 09cac61..3befd9a 100644 --- a/.env.example +++ b/.env.example @@ -1,19 +1,13 @@ COMPOSE_PROJECT_NAME= COMPOSE_SERVER_DOMAIN= -COMPOSE_FILES= +COMPOSE_FILES= -COMPOSE_ADMIN_CLIENT_PATH=/admin -COMPOSE_SCREEN_CLIENT_PATH=/client - -COMPOSE_VERSION_API=latest -COMPOSE_VERSION_ADMIN=latest -COMPOSE_VERSION_CLIENT=latest +COMPOSE_IMAGE_VERSION=latest ### # PHP ### - PHP_MAX_EXECUTION_TIME=30 PHP_MEMORY_LIMIT=128M PHP_POST_MAX_SIZE=140M @@ -22,8 +16,6 @@ PHP_UPLOAD_MAX_FILESIZE=128M ### # APPLICATION #### - - APP_ENV=prod APP_SECRET= APP_TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR diff --git a/Taskfile.yml b/Taskfile.yml index b921ef0..c13558b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,6 +7,25 @@ tasks: cmds: - task --list + + + compose: + desc: Run docker compose with -f flags from COMPOSE_FILES in .env + cmds: + - | + COMPOSE_FILES=$(grep ^COMPOSE_FILES= .env | cut -d '=' -f 2 | tr -d ' "') + if [ -z "$COMPOSE_FILES" ]; then + echo "Error: COMPOSE_FILES is not set in .env" + exit 1 + fi + FILE_ARGS="" + IFS=',' + for FILE in $COMPOSE_FILES; do + FILE_ARGS="$FILE_ARGS -f $FILE" + done + unset IFS + docker compose $FILE_ARGS {{.CLI_ARGS}} + install: desc: Install the project cmds: @@ -19,14 +38,14 @@ tasks: else echo "External network 'frontend' already exists" fi - - docker compose pull - - docker compose up --force-recreate --detach --remove-orphans + - task compose -- pull + - task compose -- up --force-recreate --detach --remove-orphans # - echo "Waiting for database to be ready" # - sleep 20 - echo "Initialize the database" - - docker compose exec api bin/console doctrine:schema:create + - task compose -- exec os2display bin/console doctrine:schema:create - echo "Create jwt key pair" - - docker compose exec api bin/console lexik:jwt:generate-keypair --skip-if-exists + - task compose -- exec os2display bin/console lexik:jwt:generate-keypair --skip-if-exists # - task tenant:add # - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." # - task user:add @@ -36,7 +55,7 @@ tasks: purge: desc: Remove all containers and volumes cmds: - - docker compose down --volumes --remove-orphans + - task compose -- down --volumes --remove-orphans - | # Check if the external network 'frontend' exists, remove if it does if docker network ls --format '{{.Name}}' | grep -wq frontend; then @@ -62,7 +81,7 @@ tasks: DB_NAME=$(grep ^MARIADB_DATABASE= .env.docker.local | cut -d '=' -f 2) DB_PASSWORD=$(grep ^MARIADB_PASSWORD= .env.docker.local | cut -d '=' -f 2) echo "Using database user: $DB_USER and database name: $DB_NAME" - docker compose --env-file .env.local --env-file .env.docker.local -f docker-compose.yml exec mariadb mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $FILENAME + task compose -- exec mariadb mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $FILENAME if [ $? -eq 0 ]; then echo "Database backup saved to $FILENAME" fi @@ -86,7 +105,8 @@ tasks: INPUT=".env.example" OUTPUT=".env" CACHE=$(mktemp) - trap "rm -f $CACHE" EXIT + SEDSCRIPT=$(mktemp) + trap "rm -f $CACHE $SEDSCRIPT" EXIT if [ ! -f "$INPUT" ]; then echo "Error: $INPUT not found." @@ -108,20 +128,14 @@ tasks: done done < "$INPUT" - # Second pass: replace placeholders with values - rm -f "$OUTPUT" - while IFS= read -r line || [ -n "$line" ]; do - RESULT="$line" - while echo "$RESULT" | grep -qE '<[^:]+:-[^>]*>'; do - MATCH=$(echo "$RESULT" | grep -oE '<[^:]+:-[^>]*>' | head -1) - VAR_NAME=$(echo "$MATCH" | sed 's/^<\([^:]*\):-.*>/\1/') - VALUE=$(grep "^${VAR_NAME}=" "$CACHE" | cut -d '=' -f 2-) - ESCAPED_MATCH=$(printf '%s\n' "$MATCH" | sed 's/[[\.*^$()+?{|\/]/\\&/g') - ESCAPED_VALUE=$(printf '%s\n' "$VALUE" | sed 's/[&\/]/\\&/g') - RESULT=$(printf '%s\n' "$RESULT" | sed "s|${ESCAPED_MATCH}|${ESCAPED_VALUE}|") - done - printf '%s\n' "$RESULT" >> "$OUTPUT" - done < "$INPUT" + # Build sed script from collected values + while IFS='=' read -r VAR_NAME VALUE; do + ESCAPED_VALUE=$(printf '%s\n' "$VALUE" | sed 's/[&\\|]/\\&/g') + printf 's|<%s:-[^>]*>|%s|g\n' "$VAR_NAME" "$ESCAPED_VALUE" >> "$SEDSCRIPT" + done < "$CACHE" + + # Single sed pass to replace all placeholders + sed -f "$SEDSCRIPT" "$INPUT" > "$OUTPUT" echo "" echo "$OUTPUT has been created." diff --git a/docker-compose.yml b/docker-compose.yml index b03d483..c10e793 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -109,7 +109,7 @@ services: - PHP_FPM_SERVER=api - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} depends_on: - - api + - os2display labels: - "traefik.enable=true" - "traefik.docker.network=frontend" From c2aac7e5d5696f8f9af8c07ec8f66c01e184dcdd Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Fri, 20 Feb 2026 15:13:46 +0100 Subject: [PATCH 05/22] 6601: Taskfile clean up --- .env.example | 1 - Taskfile.yml | 48 ++++++++++++-------------------------- docker-compose.mariadb.yml | 6 +++++ docker-compose.traefik.yml | 12 ++++++++++ docker-compose.yml | 18 +++++++++++--- 5 files changed, 48 insertions(+), 37 deletions(-) diff --git a/.env.example b/.env.example index 3befd9a..7905f0e 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,6 @@ COMPOSE_FILES= COMPOSE_IMAGE_VERSION=latest - ### # PHP ### diff --git a/Taskfile.yml b/Taskfile.yml index c13558b..776577a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,8 +7,6 @@ tasks: cmds: - task --list - - compose: desc: Run docker compose with -f flags from COMPOSE_FILES in .env cmds: @@ -26,6 +24,11 @@ tasks: unset IFS docker compose $FILE_ARGS {{.CLI_ARGS}} + console: + desc: Run the console + cmds: + - task compose -- exec os2display bin/console {{.CLI_ARGS}} + install: desc: Install the project cmds: @@ -39,18 +42,15 @@ tasks: echo "External network 'frontend' already exists" fi - task compose -- pull - - task compose -- up --force-recreate --detach --remove-orphans -# - echo "Waiting for database to be ready" -# - sleep 20 - - echo "Initialize the database" - - task compose -- exec os2display bin/console doctrine:schema:create + - task compose -- up --detach --remove-orphans + - task console -- doctrine:migrations:migrate - echo "Create jwt key pair" - - task compose -- exec os2display bin/console lexik:jwt:generate-keypair --skip-if-exists -# - task tenant:add + - task console -- lexik:jwt:generate-keypair --skip-if-exists + - task console -- app:update +# - task console tenant:add # - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." # - task user:add -# - task template:load - - task _install:show-urls +# - task _install:show-urls purge: desc: Remove all containers and volumes @@ -77,9 +77,9 @@ tasks: FILENAME=$DB_BACKUP_DIR/db_backup_$TIMESTAMP.sql echo "Performing database backup..." mkdir -p $DB_BACKUP_DIR # Ensure the backup directory exists - DB_USER=$(grep ^MARIADB_USER= .env.docker.local | cut -d '=' -f 2) - DB_NAME=$(grep ^MARIADB_DATABASE= .env.docker.local | cut -d '=' -f 2) - DB_PASSWORD=$(grep ^MARIADB_PASSWORD= .env.docker.local | cut -d '=' -f 2) + DB_USER=$(grep ^MARIADB_USER= .env | cut -d '=' -f 2) + DB_NAME=$(grep ^MARIADB_DATABASE= .env | cut -d '=' -f 2) + DB_PASSWORD=$(grep ^MARIADB_PASSWORD= .env | cut -d '=' -f 2) echo "Using database user: $DB_USER and database name: $DB_NAME" task compose -- exec mariadb mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $FILENAME if [ $? -eq 0 ]; then @@ -89,7 +89,7 @@ tasks: _install:show-urls: cmds: - | - DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env.docker.local | cut -d '=' -f 2) + DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env | cut -d '=' -f 2) echo "" echo "====================================================" echo "OS2display now is available via the URLs below" @@ -139,21 +139,3 @@ tasks: echo "" echo "$OUTPUT has been created." - - _env:check: - desc: Check that the .env files exist - cmds: - - | - if [ ! -f .env.example ]; then - echo "Error: .env.example not found. The repository may be incomplete." - exit 1 - fi - echo "Copying .env.example to .env.local..." - cp .env.example .env.local - - | - if [ ! -f .env.docker.local ]; then - echo "Error: .env.docker.local not found." - echo "Create it by running: cp .env.docker.example .env.docker.local" - echo "Then edit it with your local settings before running this task again." - exit 1 - fi diff --git a/docker-compose.mariadb.yml b/docker-compose.mariadb.yml index 14a40b5..90d42f3 100644 --- a/docker-compose.mariadb.yml +++ b/docker-compose.mariadb.yml @@ -14,6 +14,12 @@ services: - MARIADB_USER=${MARIADB_USER} - MARIADB_PASSWORD=${MARIADB_PASSWORD} - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD} + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s volumes: - mariadb:/var/lib/mysql:rw diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml index 49ebe5c..27746cb 100644 --- a/docker-compose.traefik.yml +++ b/docker-compose.traefik.yml @@ -14,6 +14,12 @@ services: - "80:80" - "443:443" - "8080:8080" # Dashboard + healthcheck: + test: ["CMD", "traefik", "healthcheck"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s volumes: - $PWD/traefik/ssl:/certs:ro - $PWD/traefik/traefik.yml:/traefik.yml:ro @@ -27,6 +33,12 @@ services: user: root container_name: socket-proxy restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "wget -q --spider http://localhost:2375/version || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: diff --git a/docker-compose.yml b/docker-compose.yml index c10e793..8e2e303 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -106,8 +106,14 @@ services: - app - frontend environment: - - PHP_FPM_SERVER=api + - NGINX_FPM_SERVICE=${NGINX_FPM_SERVICE:-os2display} - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s depends_on: - os2display labels: @@ -119,10 +125,10 @@ services: - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.routers.apios2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - "traefik.http.routers.apios2display.entrypoints=websecure" - # Redirect root / request to /${COMPOSE_ADMIN_CLIENT_PATH} + # Redirect root / request to /admin - "traefik.http.routers.apios2display.middlewares=redirect-to-admin" - "traefik.http.middlewares.redirect-to-admin.redirectregex.regex=^https:\\/\\/([^\\/]+)\\/?$$" - - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1${COMPOSE_ADMIN_CLIENT_PATH}" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1$/admin" # - "traefik.http.routers.apios2display.middlewares=apios2display" # - "traefik.http.middlewares.apios2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" @@ -132,5 +138,11 @@ services: redis: image: 'redis:6' restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s networks: - app From 61bc91333b87870f85191b0bbac433183bf8539a Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 16:14:41 +0100 Subject: [PATCH 06/22] 6601: Docker compose setup clean up --- docker-compose.yml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8e2e303..3ad919a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -105,11 +105,15 @@ services: networks: - app - frontend + ports: + - 8080 environment: - NGINX_FPM_SERVICE=${NGINX_FPM_SERVICE:-os2display} - - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX} + - NGINX_FPM_PORT=${NGINX_FPM_PORT:-9000} + - NGINX_FPM_UPLOAD_MAX=${NGINX_FPM_UPLOAD_MAX:?} + - NGINX_SET_REAL_IP_FROM=${NGINX_SET_REAL_IP_FROM:-172.16.0.0/16} healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"] + test: ["CMD-SHELL", "curl -f http://localhost:8080/ || exit 1"] interval: 30s timeout: 5s retries: 3 @@ -119,18 +123,18 @@ services: labels: - "traefik.enable=true" - "traefik.docker.network=frontend" - - "traefik.http.routers.apios2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.apios2display-http.entrypoints=web" - - "traefik.http.routers.apios2display-http.middlewares=redirect-to-https" + - "traefik.http.routers.os2display-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.os2display-http.entrypoints=web" + - "traefik.http.routers.os2display-http.middlewares=redirect-to-https" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.apios2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.apios2display.entrypoints=websecure" + - "traefik.http.routers.os2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.os2display.entrypoints=websecure" # Redirect root / request to /admin - - "traefik.http.routers.apios2display.middlewares=redirect-to-admin" + - "traefik.http.routers.os2display.middlewares=redirect-to-admin" - "traefik.http.middlewares.redirect-to-admin.redirectregex.regex=^https:\\/\\/([^\\/]+)\\/?$$" - - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1$/admin" - # - "traefik.http.routers.apios2display.middlewares=apios2display" - # - "traefik.http.middlewares.apios2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" + - "traefik.http.middlewares.redirect-to-admin.redirectregex.replacement=https://$$1/admin" + # - "traefik.http.routers.os2display.middlewares=os2display" + # - "traefik.http.middlewares.os2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" volumes: - ./media:/var/www/html/public/media:rw From 4e2ab428f50e06d03c6f6e0c27e198e6c43f408c Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 16:47:34 +0100 Subject: [PATCH 07/22] 6601: Fixed media folder --- Taskfile.yml | 9 +++++---- docker-compose.yml | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 776577a..7aa01e7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -43,13 +43,14 @@ tasks: fi - task compose -- pull - task compose -- up --detach --remove-orphans - - task console -- doctrine:migrations:migrate +# - task console -- doctrine:migrations:migrate - echo "Create jwt key pair" - task console -- lexik:jwt:generate-keypair --skip-if-exists - task console -- app:update -# - task console tenant:add -# - echo "CREATE AN ADMIN USER. CHOOSE THE TENANT YOU JUST CREATED." -# - task user:add +# - task console -- app:update + - task console -- app:tenant:add + - task console -- app:user:add + - task console -- cache:clear # - task _install:show-urls purge: diff --git a/docker-compose.yml b/docker-compose.yml index 3ad919a..2c48d30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -97,7 +97,7 @@ services: - CLIENT_DEBUG=${CLIENT_DEBUG:-false} volumes: - ./jwt:/var/www/html/config/jwt:rw - - ./media:/var/www/html/public/media:rw + - ./media:/app/public/media:rw nginx: image: ghcr.io/itk-dev/os2display-api-service-nginx:${COMPOSE_IMAGE_VERSION} @@ -137,7 +137,7 @@ services: # - "traefik.http.middlewares.os2display.ipwhitelist.sourcerange=212.10.60.163, 10.225.0.0/16" # - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" volumes: - - ./media:/var/www/html/public/media:rw + - ./media:/app/public/media:rw redis: image: 'redis:6' From 20bc6c5c8a466a10449ad138504da2caa25f6a1d Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 16:51:12 +0100 Subject: [PATCH 08/22] 6601: Locked traefik version in docker compose --- docker-compose.traefik.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml index 27746cb..4b08c34 100644 --- a/docker-compose.traefik.yml +++ b/docker-compose.traefik.yml @@ -5,8 +5,7 @@ networks: services: traefik: - image: traefik:latest - container_name: traefik + image: traefik:v3.6 restart: unless-stopped security_opt: - no-new-privileges:true @@ -31,7 +30,6 @@ services: socket-proxy: image: itkdev/docker-socket-proxy user: root - container_name: socket-proxy restart: unless-stopped healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:2375/version || exit 1"] From 3e9fa63bc7f4c3827c731cdbd4f6f51f428f7406 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 17:04:20 +0100 Subject: [PATCH 09/22] 6601: Added missing env to example --- .env.example | 3 ++- docker-compose.yml | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 7905f0e..eef83b5 100644 --- a/.env.example +++ b/.env.example @@ -95,8 +95,9 @@ APP_CLIENT_COLOR_SCHEME='{"type":"library","lat":56.0,"lng":10.0}' APP_CLIENT_DEBUG=false - NGINX_FPM_UPLOAD_MAX=140M +# Ensure corret IP's gets send to logs, should be the docker network (e.g. 172.16.0.0/16) +NGINX_SET_REAL_IP_FROM='0.0.0.0' # Have docker compose include a MariaDB database or configure an external one? diff --git a/docker-compose.yml b/docker-compose.yml index 2c48d30..2322a27 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -105,8 +105,6 @@ services: networks: - app - frontend - ports: - - 8080 environment: - NGINX_FPM_SERVICE=${NGINX_FPM_SERVICE:-os2display} - NGINX_FPM_PORT=${NGINX_FPM_PORT:-9000} From f4f252c8feedd79100972f40fc07c5945773a0ad Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 22:35:24 +0100 Subject: [PATCH 10/22] 6601: Minor clean up and readme updates --- .env.example | 19 +----- README.md | 130 ++++++++++++++++++------------------- Taskfile.yml | 55 ++++++++++------ docker-compose.mariadb.yml | 2 +- 4 files changed, 99 insertions(+), 107 deletions(-) diff --git a/.env.example b/.env.example index eef83b5..fe17131 100644 --- a/.env.example +++ b/.env.example @@ -100,28 +100,11 @@ NGINX_FPM_UPLOAD_MAX=140M NGINX_SET_REAL_IP_FROM='0.0.0.0' -# Have docker compose include a MariaDB database or configure an external one? -# Set to 'true' to use the built-in MariaDB database provided by the Docker Compose setup. -# Set to 'false' to configure and use an external MariaDB database. -INTERNAL_DATABASE=true - -# Have docker compose include a Traefik proxy or configure an external one? -# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. -# Set to 'false' to configure and use an external Traefik proxy. -INTERNAL_PROXY=true - # Note: When updating the database connection details, ensure that the following MariaDB variables # are also updated to match the connection string above. These variables are used by the Docker -# Compose setup to configure the built-in MariaDB service. These variables are only necessary if -# the local MariaDB service is used (COMPOSE_INTERNAL_DATABASE=true). +# Compose setup to configure the built-in MariaDB service. MARIADB_USER=db MARIADB_PASSWORD=db MARIADB_ROOT_PASSWORD=dbrootpassword MARIADB_DATABASE=db DB_HOST=mariadb - -# Use a built-in Traefik proxy or configure one externally? -# Set to 'true' to use the built-in Traefik proxy provided by the Docker Compose setup. -# Set to 'false' to configure and use an external proxy. -COMPOSE_INTERNAL_PROXY=true - diff --git a/README.md b/README.md index f98910d..9f443d7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# OS2display v2 Hosting and Deployment +# OS2display v3 Hosting and Deployment -This is a deployment tool designed for hosting the OS2display v2 application using Docker. It provides a Docker-based setup, pre-configured files, and task automation to simplify the deployment and management of the application. +This is a deployment tool designed for hosting the OS2display v3 application using Docker. It provides a Docker-based setup, pre-configured files, and task automation to simplify the deployment and management of the application. ## Prerequisites @@ -40,73 +40,78 @@ This project can only run in secure mode using HTTPS (port 443). You must provid 1. Use a fully qualified domain name (FQDN) that resolves to your server's IP address. 2. Place the certificate file (`docker.crt`) and private key file (`docker.key`) in the `traefik/ssl` directory. -3. Set the domain name in `.env.docker.local` via the `COMPOSE_SERVER_DOMAIN` variable. +3. Set the domain name in `.env` via the `COMPOSE_SERVER_DOMAIN` variable. ## Configuration -Before running `task install`, copy and edit the configuration file: +Before running `task install`, generate the configuration file using one of these methods: + +**Option A** — Interactive prompt (recommended): + +```bash +task _env:build +``` + +This reads `.env.example`, prompts for each placeholder value, and writes `.env`. + +**Option B** — Manual copy and edit: ```bash -cp .env.docker.example .env.docker.local +cp .env.example .env ``` -Edit `.env.docker.local` with your local settings. The key variables are described below. +Edit `.env` with your local settings. The key variables are described below. -### Domain and Versions +### Domain and Version | Variable | Description | Default | |----------|-------------|---------| -| `COMPOSE_SERVER_DOMAIN` | Domain name where the server will be accessible | `demo.os2display.dk` | -| `COMPOSE_VERSION_API` | Version of `itkdev/os2display-api-service` | `2.6.0` | -| `COMPOSE_VERSION_ADMIN` | Version of `itkdev/os2display-admin-client` | `2.6.0` | -| `COMPOSE_VERSION_CLIENT` | Version of `itkdev/os2display-client` | `2.3.0` | +| `COMPOSE_SERVER_DOMAIN` | Domain name where the server will be accessible | `os2display.local.itkdev.dk` | +| `COMPOSE_IMAGE_VERSION` | Version of the os2display Docker images (applies to all services) | `latest` | ### Infrastructure Options -| Variable | Description | Default | -|----------|-------------|---------| -| `INTERNAL_DATABASE` | Set to `true` to use the built-in MariaDB, `false` for an external database | `true` | -| `INTERNAL_PROXY` | Set to `true` to use the built-in Traefik proxy, `false` for an external proxy | `true` | +Which infrastructure services to include is controlled by the `COMPOSE_FILES` variable in `.env`. It is a comma-separated list of Docker Compose files to load. + +| Value | Purpose | +|-------|---------| +| `docker-compose.yml` | **Required.** Core services (os2display API, nginx, redis) | +| `docker-compose.mariadb.yml` | Built-in MariaDB database. Omit if using an external database | +| `docker-compose.traefik.yml` | Built-in Traefik reverse proxy. Omit if using an external proxy | + +Default: `docker-compose.yml,docker-compose.mariadb.yml` ### Database | Variable | Description | Default | |----------|-------------|---------| -| `APP_DATABASE_URL` | Doctrine database connection URL | `mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.11.11` | -| `MARIADB_USER` | MariaDB user (only when `INTERNAL_DATABASE=true`) | `db` | -| `MARIADB_PASSWORD` | MariaDB password (only when `INTERNAL_DATABASE=true`) | `db` | -| `MARIADB_ROOT_PASSWORD` | MariaDB root password (only when `INTERNAL_DATABASE=true`) | `dbrootpassword` | -| `MARIADB_DATABASE` | MariaDB database name (only when `INTERNAL_DATABASE=true`) | `db` | +| `APP_DATABASE_URL` | Doctrine database connection URL | `mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.5.13` | +| `MARIADB_USER` | MariaDB user (only when using built-in MariaDB) | `db` | +| `MARIADB_PASSWORD` | MariaDB password (only when using built-in MariaDB) | `db` | +| `MARIADB_ROOT_PASSWORD` | MariaDB root password (only when using built-in MariaDB) | `dbrootpassword` | +| `MARIADB_DATABASE` | MariaDB database name (only when using built-in MariaDB) | `db` | ### Secrets | Variable | Description | Default | |----------|-------------|---------| -| `APP_SECRET` | Symfony application secret | `pleasuchangethis` | -| `APP_JWT_PASSPHRASE` | JWT key pair passphrase | `pleasechangethistoo` | +| `APP_SECRET` | Symfony application secret | `CHANGE_ME` | +| `APP_JWT_PASSPHRASE` | JWT key pair passphrase | `CHANGE_ME` | **NOTE:** Change both `APP_SECRET` and `APP_JWT_PASSPHRASE` to secure values before running in production. -### Templates and Screen Layouts - -| Variable | Description | Default | -|----------|-------------|---------| -| `TASK_VERSION_TEMPLATES` | Version/branch of [os2display/display-templates](https://github.com/os2display/display-templates/releases) | `2.6.0` | -| `TASK_TEMPLATES` | Comma-separated list of templates to load | See `.env.docker.example` | -| `TASK_SCREEN_LAYOUTS` | Comma-separated list of screen layouts to load | See `.env.docker.example` | - ### OIDC (OpenID Connect) | Variable | Description | |----------|-------------| -| `INTERNAL_OIDC_METADATA_URL` | OIDC metadata URL provided by the IdP | -| `INTERNAL_OIDC_CLIENT_ID` | OIDC client ID | -| `INTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | -| `INTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | +| `APP_INTERNAL_OIDC_METADATA_URL` | OIDC metadata URL provided by the IdP | +| `APP_INTERNAL_OIDC_CLIENT_ID` | OIDC client ID | +| `APP_INTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | +| `APP_INTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | ## Installation -1. Edit `.env.docker.local` with your domain name, secure passwords, and other settings. +1. Generate or edit `.env` with your domain name, secure passwords, and other settings. 2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. 3. Run the install task: @@ -117,10 +122,9 @@ task install The install process will: - Pull Docker images - Start all containers -- Create the database schema - Generate JWT key pair +- Run database migrations - Prompt you to create a tenant and an admin user -- Load templates and screen layouts After installation, the application is available at: - **Admin:** `https:///admin` @@ -134,51 +138,43 @@ For a full list of tasks, run: task --list ``` -### Installation and Setup - | Task | Description | |------|-------------| -| `task install` | Install the project (pull images, create DB, generate JWT keys, add tenant/user, load templates) | -| `task reinstall` | Reinstall from scratch. **WARNING:** Deletes the database | -| `task up` | Start the environment (recompiles configuration) | -| `task down` | Stop and remove all containers | -| `task stop` | Stop all containers without removing them | -| `task purge` | Remove all containers and volumes. **WARNING:** Deletes the database | - -### Tenant and User Management - -| Task | Description | -|------|-------------| -| `task tenant:add` | Add a new tenant group | -| `task user:add` | Add a new user (editor or admin) to a tenant | +| `task install` | Install the project (pull images, start containers, generate JWT keys, add tenant/user) | +| `task purge` | Remove all containers. Use `-- --volumes` to also delete volumes, `-- --network` to remove the frontend network | +| `task db:backup` | Perform a database dump (only when using the built-in MariaDB). Saves to the `db_backups/` directory | +| `task compose -- ` | Run `docker compose` with the correct `-f` flags derived from `COMPOSE_FILES` in `.env` | +| `task console -- ` | Run a Symfony console command inside the os2display container | -### Templates and Screen Layouts +### Common compose commands via task -| Task | Description | -|------|-------------| -| `task template:load` | Load templates and screen layouts based on configuration in `.env.docker.local` | +```bash +task compose -- up --detach # Start all containers +task compose -- down # Stop and remove containers +task compose -- logs -f # Follow container logs +task compose -- ps # List running containers +``` -### Maintenance +### Common console commands via task -| Task | Description | -|------|-------------| -| `task logs` | Follow logs from the Docker containers | -| `task cache:clear` | Clear the application cache | -| `task db:backup` | Perform a database dump (only when using the built-in MariaDB). Saves to the `db_backups/` directory | +```bash +task console -- cache:clear # Clear Symfony cache +task console -- app:tenant:add # Add a new tenant +task console -- app:user:add # Add a new user +``` ## Updating an Existing Installation To update to newer image versions: -1. Update the version variables (`COMPOSE_VERSION_API`, `COMPOSE_VERSION_ADMIN`, `COMPOSE_VERSION_CLIENT`) in `.env.docker.local`. -2. Run the restart script: +1. Update `COMPOSE_IMAGE_VERSION` in `.env`. +2. Pull and recreate containers: ```bash -./restart.sh +task compose -- pull +task compose -- up --detach --remove-orphans ``` -This pulls new images, recreates containers, and runs database migrations. If templates have changed, run `task template:load` afterwards. - ## License This project is licensed under the European Union Public License 1.2. See [LICENSE](LICENSE) for details. diff --git a/Taskfile.yml b/Taskfile.yml index 7aa01e7..93ca940 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,7 +8,7 @@ tasks: - task --list compose: - desc: Run docker compose with -f flags from COMPOSE_FILES in .env + desc: Run docker compose with -f flags from COMPOSE_FILES in .env. Example{{":"}} task compose -- up --detach cmds: - | COMPOSE_FILES=$(grep ^COMPOSE_FILES= .env | cut -d '=' -f 2 | tr -d ' "') @@ -25,7 +25,7 @@ tasks: docker compose $FILE_ARGS {{.CLI_ARGS}} console: - desc: Run the console + desc: Run Symfony bin/console in the os2display container. Example{{":"}} task console -- cache{{":"}}clear cmds: - task compose -- exec os2display bin/console {{.CLI_ARGS}} @@ -43,7 +43,6 @@ tasks: fi - task compose -- pull - task compose -- up --detach --remove-orphans -# - task console -- doctrine:migrations:migrate - echo "Create jwt key pair" - task console -- lexik:jwt:generate-keypair --skip-if-exists - task console -- app:update @@ -51,21 +50,20 @@ tasks: - task console -- app:tenant:add - task console -- app:user:add - task console -- cache:clear -# - task _install:show-urls purge: - desc: Remove all containers and volumes + desc: Remove all containers (use -- --volumes to also delete volumes, -- --network to remove the frontend network) cmds: - - task compose -- down --volumes --remove-orphans + - task compose -- down --remove-orphans {{.CLI_ARGS}} - | - # Check if the external network 'frontend' exists, remove if it does - if docker network ls --format '{{.Name}}' | grep -wq frontend; then - echo "Removing external network 'frontend'" - docker network rm frontend - else - echo "External network 'frontend' does not exist" + if echo "{{.CLI_ARGS}}" | grep -q -- '--network'; then + if docker network ls --format '{{.Name}}' | grep -wq frontend; then + echo "Removing external network 'frontend'" + docker network rm frontend + else + echo "External network 'frontend' does not exist" + fi fi - - rm -f docker-compose.yml .env.local db:backup: desc: Perform a database dump, if you use the default internal mariadb. The dump file will be saved in the 'db_backups' directory with a timestamp in the filename. @@ -87,19 +85,34 @@ tasks: echo "Database backup saved to $FILENAME" fi - _install:show-urls: + open:admin: + desc: Open the admin interface in the default browser cmds: - | DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env | cut -d '=' -f 2) - echo "" - echo "====================================================" - echo "OS2display now is available via the URLs below" - echo "====================================================" - echo "Admin: https://$DOMAIN/admin" - echo "Screen: https://$DOMAIN/client" - echo "====================================================" + if [ -z "$DOMAIN" ]; then + echo "Error: COMPOSE_SERVER_DOMAIN is not set in .env" + exit 1 + fi + URL="https://$DOMAIN/admin" + echo "Opening $URL" + xdg-open "$URL" 2>/dev/null || open "$URL" 2>/dev/null || echo "Could not open browser. Visit: $URL" + + open:client: + desc: Open the client interface in the default browser + cmds: + - | + DOMAIN=$(grep ^COMPOSE_SERVER_DOMAIN= .env | cut -d '=' -f 2) + if [ -z "$DOMAIN" ]; then + echo "Error: COMPOSE_SERVER_DOMAIN is not set in .env" + exit 1 + fi + URL="https://$DOMAIN/client" + echo "Opening $URL" + xdg-open "$URL" 2>/dev/null || open "$URL" 2>/dev/null || echo "Could not open browser. Visit: $URL" _env:build: + internal: true desc: Build .env from .env.example by prompting for placeholder values cmds: - | diff --git a/docker-compose.mariadb.yml b/docker-compose.mariadb.yml index 90d42f3..48a1a5e 100644 --- a/docker-compose.mariadb.yml +++ b/docker-compose.mariadb.yml @@ -5,7 +5,7 @@ networks: services: mariadb: - image: mariadb:10.11.11 + image: mariadb:10.11.16 restart: unless-stopped networks: - app From 59340bf6e10a26651bc03400c9fc0726de1565ea Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Mon, 23 Feb 2026 23:03:05 +0100 Subject: [PATCH 11/22] 6601: Updated readme to match task file --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f443d7..ca4d0ac 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,11 @@ cp .env.example .env Edit `.env` with your local settings. The key variables are described below. -### Domain and Version +### Domain, Name and Version | Variable | Description | Default | |----------|-------------|---------| +| `COMPOSE_PROJECT_NAME` | Docker Compose project name (used for container prefixes) | `os2display` | | `COMPOSE_SERVER_DOMAIN` | Domain name where the server will be accessible | `os2display.local.itkdev.dk` | | `COMPOSE_IMAGE_VERSION` | Version of the os2display Docker images (applies to all services) | `latest` | @@ -97,11 +98,14 @@ Default: `docker-compose.yml,docker-compose.mariadb.yml` |----------|-------------|---------| | `APP_SECRET` | Symfony application secret | `CHANGE_ME` | | `APP_JWT_PASSPHRASE` | JWT key pair passphrase | `CHANGE_ME` | +| `APP_ADMIN_LOGIN_METHODS` | JSON array configuring admin login methods (required) | `[{"type":"username-password","enabled":true,...}]` | **NOTE:** Change both `APP_SECRET` and `APP_JWT_PASSPHRASE` to secure values before running in production. ### OIDC (OpenID Connect) +**Internal provider** (admin login): + | Variable | Description | |----------|-------------| | `APP_INTERNAL_OIDC_METADATA_URL` | OIDC metadata URL provided by the IdP | @@ -109,6 +113,15 @@ Default: `docker-compose.yml,docker-compose.mariadb.yml` | `APP_INTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | | `APP_INTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | +**External provider** (screen/device login): + +| Variable | Description | +|----------|-------------| +| `APP_EXTERNAL_OIDC_METADATA_URL` | OIDC metadata URL provided by the IdP | +| `APP_EXTERNAL_OIDC_CLIENT_ID` | OIDC client ID | +| `APP_EXTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | +| `APP_EXTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | + ## Installation 1. Generate or edit `.env` with your domain name, secure passwords, and other settings. @@ -120,11 +133,13 @@ task install ``` The install process will: +- Create the external `frontend` Docker network (if it doesn't exist) - Pull Docker images - Start all containers - Generate JWT key pair -- Run database migrations +- Run `app:update` (database migrations and other setup tasks) - Prompt you to create a tenant and an admin user +- Clear the Symfony cache After installation, the application is available at: - **Admin:** `https:///admin` @@ -145,6 +160,8 @@ task --list | `task db:backup` | Perform a database dump (only when using the built-in MariaDB). Saves to the `db_backups/` directory | | `task compose -- ` | Run `docker compose` with the correct `-f` flags derived from `COMPOSE_FILES` in `.env` | | `task console -- ` | Run a Symfony console command inside the os2display container | +| `task open:admin` | Open the admin interface in the default browser | +| `task open:client` | Open the client interface in the default browser | ### Common compose commands via task From 172c2b0f94c6f2621f745fcd83d0f2905cf76471 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 11:49:20 +0100 Subject: [PATCH 12/22] Update README.md Co-authored-by: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca4d0ac..ac1554e 100644 --- a/README.md +++ b/README.md @@ -194,4 +194,4 @@ task compose -- up --detach --remove-orphans ## License -This project is licensed under the European Union Public License 1.2. See [LICENSE](LICENSE) for details. +This project is licensed under the Mozilla Public License Version 2.0. See [LICENSE](LICENSE) for details. From e2c452edf94361afda6b3b2df70e86dbc2282ec0 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 11:49:28 +0100 Subject: [PATCH 13/22] Update README.md Co-authored-by: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac1554e..d02a97e 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Default: `docker-compose.yml,docker-compose.mariadb.yml` ### OIDC (OpenID Connect) -**Internal provider** (admin login): +**Internal provider**: | Variable | Description | |----------|-------------| From 42ba44bf177103a806bc0dd91fe13c9d8f221010 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 11:49:34 +0100 Subject: [PATCH 14/22] Update README.md Co-authored-by: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d02a97e..32e2f0d 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Default: `docker-compose.yml,docker-compose.mariadb.yml` ## Installation -1. Generate or edit `.env` with your domain name, secure passwords, and other settings. +1. Generate or edit `.env` with your chosen settings. 2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. 3. Run the install task: From 64ac83dfd4ea3bb86198e26dc4f36b02a5fe8652 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 11:49:43 +0100 Subject: [PATCH 15/22] Update README.md Co-authored-by: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32e2f0d..443c2f5 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Default: `docker-compose.yml,docker-compose.mariadb.yml` | `APP_INTERNAL_OIDC_CLIENT_SECRET` | OIDC client secret | | `APP_INTERNAL_OIDC_REDIRECT_URI` | OIDC redirect URI | -**External provider** (screen/device login): +**External provider**: | Variable | Description | |----------|-------------| From f0bdb78a4e6797e26e2522dd13707ec67db4aa9a Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 14:22:10 +0100 Subject: [PATCH 16/22] 6601: Ensure all container are healthy before installation starts --- Taskfile.yml | 3 +-- docker-compose.mariadb.yml | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 93ca940..cebc5be 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -42,11 +42,10 @@ tasks: echo "External network 'frontend' already exists" fi - task compose -- pull - - task compose -- up --detach --remove-orphans + - task compose -- up --detach --remove-orphans --wait - echo "Create jwt key pair" - task console -- lexik:jwt:generate-keypair --skip-if-exists - task console -- app:update -# - task console -- app:update - task console -- app:tenant:add - task console -- app:user:add - task console -- cache:clear diff --git a/docker-compose.mariadb.yml b/docker-compose.mariadb.yml index 48a1a5e..35376c8 100644 --- a/docker-compose.mariadb.yml +++ b/docker-compose.mariadb.yml @@ -15,10 +15,10 @@ services: - MARIADB_PASSWORD=${MARIADB_PASSWORD} - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD} healthcheck: - test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] - interval: 30s + test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized && mariadb -u\"$MARIADB_USER\" -p\"$MARIADB_PASSWORD\" \"$MARIADB_DATABASE\" -e 'SELECT 1'"] + interval: 10s timeout: 5s - retries: 3 + retries: 5 start_period: 30s volumes: - mariadb:/var/lib/mysql:rw From 4cdbe777f128c018f053183dd4ce72ad54913229 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 14:32:36 +0100 Subject: [PATCH 17/22] 6601: Added missing extra host to connect to local db --- docker-compose.traefik.yml | 10 +++++----- docker-compose.yml | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml index 4b08c34..6ffc7ec 100644 --- a/docker-compose.traefik.yml +++ b/docker-compose.traefik.yml @@ -7,6 +7,9 @@ services: traefik: image: traefik:v3.6 restart: unless-stopped + networks: + - frontend + - proxy security_opt: - no-new-privileges:true ports: @@ -23,14 +26,13 @@ services: - $PWD/traefik/ssl:/certs:ro - $PWD/traefik/traefik.yml:/traefik.yml:ro - $PWD/traefik/dynamic-conf.yaml:/config/dynamic-conf.yaml:ro - networks: - - frontend - - proxy socket-proxy: image: itkdev/docker-socket-proxy user: root restart: unless-stopped + networks: + - proxy healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:2375/version || exit 1"] interval: 30s @@ -41,5 +43,3 @@ services: - /var/run/docker.sock:/var/run/docker.sock:ro environment: CONTAINERS: 1 - networks: - - proxy diff --git a/docker-compose.yml b/docker-compose.yml index 2322a27..8a4bb0b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,8 @@ services: restart: unless-stopped networks: - app + extra_hosts: + - "host.docker.internal:host-gateway" environment: # PHP config values - PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME} From 6a09d66af58a4cb6eca32698fa4e3b2a12b9e4ac Mon Sep 17 00:00:00 2001 From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:33:12 +0100 Subject: [PATCH 18/22] 6600: Cleaned up changelog --- CHANGELOG.md | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6e4c6c..9261ed3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,35 +2,4 @@ ## [Unreleased] - - Rename tasks to Symfony-style colon-separated naming: `cc` → `cache:clear`, `tenant_add` → `tenant:add`, `user_add` → `user:add`, `load_templates` → `template:load`, `backup_db` → `db:backup`. Old names kept as aliases for backward compatibility. - - Add new task `db:backup` to backup the default internal mariadb - -## v1.1.2 - -- Bump os2display version from 2.5.1 to 2.6.0. Client updated from 2.2.1 to 2.3.0. -- Update TASK_TEMPLATES in .env.docker.example to include 'brnd' -- Bring CHANGELOG.md up-to-date with mensions of version v1.1.0 and v1.1.1 -- Update CHANGELOG.md - -## v1.1.1 - -- Assume install by user where UID and GID is1042. The README contains further details. -- Install the vimeo-template as default -- Add the screen layout two-boxes-vertical-reversed as default -- Extend wait for db, so that install will work on slow hardware/VM -- A new env var APP_KEY_VAULT_JSON has been added - -## v1.1.0 - -- BUGFIX: Fix value of COMPOSE_SCREEN_CLIENT_PATH. Default was set to "/screen". Should be "/client". -- Bump os2display version from 2.4.0 to 2.5.1 -- Improved task menu -- Env var changes now take effect if you do "task down" and then "task up". - -## v1.0.0 - Initial Release - -- Introduced a Docker-based deployment tool for hosting the OS2display application. -- Provided pre-configured files and task automation for simplifying deployment and management. -- Added support for secure mode (HTTPS on port 443) with domain name and SSL certificate requirements. -- Included a `Taskfile.yml` with tasks for installation, tenant/user management, template loading, and maintenance. -- Documented prerequisites and setup instructions for Docker, Docker Compose, and Taskfile CLI. \ No newline at end of file +- Added docker setup for OS2Display version 3.x. From 60941a7fa60a64a5570c997eaa07eb827075ac1b Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Tue, 24 Feb 2026 14:41:10 +0100 Subject: [PATCH 19/22] 6601: Added missing links to change log --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9261ed3..738a8da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +![keep a changelog](https://img.shields.io/badge/Keep%20a%20Changelog-v1.1.0-brightgreen.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmMTVkMzAiIHZpZXdCb3g9IjAgMCAxODcgMTg1Ij48cGF0aCBkPSJNNjIgN2MtMTUgMy0yOCAxMC0zNyAyMmExMjIgMTIyIDAgMDAtMTggOTEgNzQgNzQgMCAwMDE2IDM4YzYgOSAxNCAxNSAyNCAxOGE4OSA4OSAwIDAwMjQgNCA0NSA0NSAwIDAwNiAwbDMtMSAxMy0xYTE1OCAxNTggMCAwMDU1LTE3IDYzIDYzIDAgMDAzNS01MiAzNCAzNCAwIDAwLTEtNWMtMy0xOC05LTMzLTE5LTQ3LTEyLTE3LTI0LTI4LTM4LTM3QTg1IDg1IDAgMDA2MiA3em0zMCA4YzIwIDQgMzggMTQgNTMgMzEgMTcgMTggMjYgMzcgMjkgNTh2MTJjLTMgMTctMTMgMzAtMjggMzhhMTU1IDE1NSAwIDAxLTUzIDE2bC0xMyAyaC0xYTUxIDUxIDAgMDEtMTItMWwtMTctMmMtMTMtNC0yMy0xMi0yOS0yNy01LTEyLTgtMjQtOC0zOWExMzMgMTMzIDAgMDE4LTUwYzUtMTMgMTEtMjYgMjYtMzMgMTQtNyAyOS05IDQ1LTV6TTQwIDQ1YTk0IDk0IDAgMDAtMTcgNTQgNzUgNzUgMCAwMDYgMzJjOCAxOSAyMiAzMSA0MiAzMiAyMSAyIDQxLTIgNjAtMTRhNjAgNjAgMCAwMDIxLTE5IDUzIDUzIDAgMDA5LTI5YzAtMTYtOC0zMy0yMy01MWE0NyA0NyAwIDAwLTUtNWMtMjMtMjAtNDUtMjYtNjctMTgtMTIgNC0yMCA5LTI2IDE4em0xMDggNzZhNTAgNTAgMCAwMS0yMSAyMmMtMTcgOS0zMiAxMy00OCAxMy0xMSAwLTIxLTMtMzAtOS01LTMtOS05LTEzLTE2YTgxIDgxIDAgMDEtNi0zMiA5NCA5NCAwIDAxOC0zNSA5MCA5MCAwIDAxNi0xMmwxLTJjNS05IDEzLTEzIDIzLTE2IDE2LTUgMzItMyA1MCA5IDEzIDggMjMgMjAgMzAgMzYgNyAxNSA3IDI5IDAgNDJ6bS00My03M2MtMTctOC0zMy02LTQ2IDUtMTAgOC0xNiAyMC0xOSAzN2E1NCA1NCAwIDAwNSAzNGM3IDE1IDIwIDIzIDM3IDIyIDIyLTEgMzgtOSA0OC0yNGE0MSA0MSAwIDAwOC0yNCA0MyA0MyAwIDAwLTEtMTJjLTYtMTgtMTYtMzEtMzItMzh6bS0yMyA5MWgtMWMtNyAwLTE0LTItMjEtN2EyNyAyNyAwIDAxLTEwLTEzIDU3IDU3IDAgMDEtNC0yMCA2MyA2MyAwIDAxNi0yNWM1LTEyIDEyLTE5IDI0LTIxIDktMyAxOC0yIDI3IDIgMTQgNiAyMyAxOCAyNyAzM3MtMiAzMS0xNiA0MGMtMTEgOC0yMSAxMS0zMiAxMXptMS0zNHYxNGgtOFY2OGg4djI4bDEwLTEwaDExbC0xNCAxNSAxNyAxOEg5NnoiLz48L3N2Zz4K) + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [Unreleased] - Added docker setup for OS2Display version 3.x. + +[Unreleased]: https://github.com/itk-dev/os2display-docker-server-v3/compare/0.1.0...HEAD + +[//]: # ([0.1.0]: https://github.com/itk-dev/os2display-docker-server-v3/releases/tag/0.1.0) From 859fd470b6887b0e5a22853b4b4dbc0d8eebb5d7 Mon Sep 17 00:00:00 2001 From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> Date: Wed, 18 Mar 2026 12:24:54 +0100 Subject: [PATCH 20/22] 6998: Fixed volumes mapping for jwt --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8a4bb0b..e8f99f4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -98,7 +98,7 @@ services: - CLIENT_COLOR_SCHEME=${CLIENT_COLOR_SCHEME:-{"type":"library","lat":56.0,"lng":10.0}} - CLIENT_DEBUG=${CLIENT_DEBUG:-false} volumes: - - ./jwt:/var/www/html/config/jwt:rw + - ./jwt:/app/config/jwt:rw - ./media:/app/public/media:rw nginx: From dd41e817059f35b0b786b96fa8a050836056d82a Mon Sep 17 00:00:00 2001 From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com> Date: Mon, 4 May 2026 15:28:12 +0200 Subject: [PATCH 21/22] Changed to use os2display images instead of itk-dev images --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index e8f99f4..d183629 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ networks: services: os2display: - image: ghcr.io/itk-dev/os2display-api-service:${COMPOSE_IMAGE_VERSION} + image: ghcr.io/os2display/os2display-api-service:${COMPOSE_IMAGE_VERSION} restart: unless-stopped networks: - app @@ -102,7 +102,7 @@ services: - ./media:/app/public/media:rw nginx: - image: ghcr.io/itk-dev/os2display-api-service-nginx:${COMPOSE_IMAGE_VERSION} + image: ghcr.io/os2display/os2display-api-service-nginx:${COMPOSE_IMAGE_VERSION} restart: unless-stopped networks: - app From bcf1443f8d38fbd4621f2b47dd722b4126ed9630 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 5 May 2026 09:58:22 +0200 Subject: [PATCH 22/22] Fix image names --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d183629..a944aac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ networks: services: os2display: - image: ghcr.io/os2display/os2display-api-service:${COMPOSE_IMAGE_VERSION} + image: ghcr.io/os2display/display-api-service:${COMPOSE_IMAGE_VERSION} restart: unless-stopped networks: - app @@ -102,7 +102,7 @@ services: - ./media:/app/public/media:rw nginx: - image: ghcr.io/os2display/os2display-api-service-nginx:${COMPOSE_IMAGE_VERSION} + image: ghcr.io/os2display/display-api-service-nginx:${COMPOSE_IMAGE_VERSION} restart: unless-stopped networks: - app