diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fe17131 --- /dev/null +++ b/.env.example @@ -0,0 +1,110 @@ +COMPOSE_PROJECT_NAME= +COMPOSE_SERVER_DOMAIN= +COMPOSE_FILES= + +COMPOSE_IMAGE_VERSION=latest + +### +# PHP +### +PHP_MAX_EXECUTION_TIME=30 +PHP_MEMORY_LIMIT=128M +PHP_POST_MAX_SIZE=140M +PHP_UPLOAD_MAX_FILESIZE=128M + +### +# APPLICATION +#### +APP_ENV=prod +APP_SECRET= +APP_TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR +APP_DATABASE_URL= +APP_CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' + +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_TOKEN_TTL=3600 +APP_JWT_SCREEN_TOKEN_TTL=1296000 +APP_JWT_REFRESH_TOKEN_TTL=2592000 +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 + +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_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 + + +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' + + +# 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. +MARIADB_USER=db +MARIADB_PASSWORD=db +MARIADB_ROOT_PASSWORD=dbrootpassword +MARIADB_DATABASE=db +DB_HOST=mariadb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d6cd7e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +db_backups/ +docker-compose.*override*.yml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..738a8da --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +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) 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..443c2f5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,197 @@ -# OS2Display docker server v.3 +# OS2display v3 Hosting and Deployment +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 + +Before you begin, ensure you have the following installed on your system: + +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 + +```bash +docker --version +docker compose version +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), install the application using a user with the same UID and GID. + +```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 +``` + +## 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` via the `COMPOSE_SERVER_DOMAIN` variable. + +## Configuration + +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.example .env +``` + +Edit `.env` with your local settings. The key variables are described below. + +### 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` | + +### Infrastructure Options + +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.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 | `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**: + +| Variable | Description | +|----------|-------------| +| `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 | + +**External provider**: + +| 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 chosen settings. +2. Place your SSL certificate files (`docker.crt` and `docker.key`) in the `traefik/ssl` directory. +3. Run the install task: + +```bash +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 `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` +- **Screen client:** `https:///client` + +## Available Tasks + +For a full list of tasks, run: + +```bash +task --list +``` + +| Task | Description | +|------|-------------| +| `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 | +| `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 + +```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 +``` + +### Common console commands via task + +```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 `COMPOSE_IMAGE_VERSION` in `.env`. +2. Pull and recreate containers: + +```bash +task compose -- pull +task compose -- up --detach --remove-orphans +``` + +## License + +This project is licensed under the Mozilla Public License Version 2.0. See [LICENSE](LICENSE) for details. diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..cebc5be --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,154 @@ +version: '3' +silent: true + +tasks: + default: + desc: Show available tasks + cmds: + - task --list + + compose: + 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 ' "') + 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}} + + console: + desc: Run Symfony bin/console in the os2display container. Example{{":"}} task console -- cache{{":"}}clear + cmds: + - task compose -- exec os2display bin/console {{.CLI_ARGS}} + + install: + desc: Install the project + cmds: + - 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 + - task compose -- pull + - 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:tenant:add + - task console -- app:user:add + - task console -- cache:clear + + purge: + desc: Remove all containers (use -- --volumes to also delete volumes, -- --network to remove the frontend network) + cmds: + - task compose -- down --remove-orphans {{.CLI_ARGS}} + - | + 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 + + 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) + 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 | 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 + echo "Database backup saved to $FILENAME" + fi + + open:admin: + desc: Open the admin 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/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: + - | + INPUT=".env.example" + OUTPUT=".env" + CACHE=$(mktemp) + SEDSCRIPT=$(mktemp) + trap "rm -f $CACHE $SEDSCRIPT" EXIT + + if [ ! -f "$INPUT" ]; then + echo "Error: $INPUT not found." + exit 1 + fi + + # 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" + + # 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.mariadb.yml b/docker-compose.mariadb.yml new file mode 100644 index 0000000..35376c8 --- /dev/null +++ b/docker-compose.mariadb.yml @@ -0,0 +1,27 @@ +networks: + app: + driver: bridge + internal: false + +services: + mariadb: + image: mariadb:10.11.16 + restart: unless-stopped + networks: + - app + environment: + - MARIADB_DATABASE=${MARIADB_DATABASE} + - MARIADB_USER=${MARIADB_USER} + - MARIADB_PASSWORD=${MARIADB_PASSWORD} + - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD} + healthcheck: + 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: 5 + start_period: 30s + volumes: + - mariadb:/var/lib/mysql:rw + +volumes: + mariadb: \ No newline at end of file diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml new file mode 100644 index 0000000..6ffc7ec --- /dev/null +++ b/docker-compose.traefik.yml @@ -0,0 +1,45 @@ +networks: + proxy: + driver: bridge + internal: true + +services: + traefik: + image: traefik:v3.6 + restart: unless-stopped + networks: + - frontend + - proxy + security_opt: + - no-new-privileges:true + ports: + - "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 + - $PWD/traefik/dynamic-conf.yaml:/config/dynamic-conf.yaml:ro + + 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 + timeout: 5s + retries: 3 + start_period: 10s + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + CONTAINERS: 1 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a944aac --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,152 @@ +networks: + frontend: + external: true + app: + driver: bridge + internal: false + +services: + os2display: + image: ghcr.io/os2display/display-api-service:${COMPOSE_IMAGE_VERSION} + restart: unless-stopped + networks: + - app + extra_hosts: + - "host.docker.internal:host-gateway" + 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_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:/app/config/jwt:rw + - ./media:/app/public/media:rw + + nginx: + image: ghcr.io/os2display/display-api-service-nginx:${COMPOSE_IMAGE_VERSION} + restart: unless-stopped + networks: + - app + - frontend + environment: + - NGINX_FPM_SERVICE=${NGINX_FPM_SERVICE:-os2display} + - 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:8080/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + depends_on: + - os2display + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "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.os2display.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" + - "traefik.http.routers.os2display.entrypoints=websecure" + # Redirect root / request 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.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:/app/public/media:rw + + redis: + image: 'redis:6' + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + networks: + - app diff --git a/jwt/.gitignore b/jwt/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/jwt/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/media/.gitignore b/media/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/media/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore 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..5e7d273 --- /dev/null +++ b/traefik/ssl/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore 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 + +