diff --git a/.env.docker.example b/.env.docker.example
new file mode 100644
index 0000000..86bc2a9
--- /dev/null
+++ b/.env.docker.example
@@ -0,0 +1,73 @@
+# =============================================================================
+#  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.5.1
+
+# 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.5.1
+
+# Version of itkdev/os2display-client
+# Find the latest version here: https://hub.docker.com/r/itkdev/os2display-client/tags
+COMPOSE_VERSION_CLIENT=2.2.0
+
+# Version of github.com/os2display/display-templates
+# Find the latest version here: https://github.com/os2display/display-templates/releases
+TASK_VERSION_TEMPLATES=2.5.1
+
+# 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,calendar,contacts,iframe,image-text,instagram-feed,poster,rss,slideshow,table,travel,video,vimeo-player"
+
+# 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,two-boxes-vertical-reversed,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://<username>:<password>@<host>:<port>/<database>?serverVersion=<server_version>
+# APP_DATABASE_URL syntax:
+# - <username>: The username for the database connection
+# - <password>: The password for the database connection
+# - <host>: The hostname or IP address of the database server
+# - <port>: The port number on which the database server is listening (default for MySQL is 3306)
+# - <database>: The name of the database to connect to
+# - <server_version>: 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
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..5fff7f5
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+
+## 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/README.md b/README.md
index 6979db8..d9c8a21 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,72 @@
-# OS2display docker server hosting
+# OS2display v2 Hosting and Deployment
 
-Basic docker based hosting setup for OS2display v.2
+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.
 
-## Deployment
+## Prerequisites
 
-### Containers
+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).
 
-Change the tags in .env.docker.local to the tags of the containers you wish to deploy.
+Make sure your user has the necessary permissions to run Docker commands (e.g., being part of the `docker` group).
 
-E.g.
+### Check Prerequisites
 
-```dotenv
-COMPOSE_VERSION_API=2.0.0
-COMPOSE_VERSION_ADMIN=2.0.0
-COMPOSE_VERSION_CLIENT=2.0.0
+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
 ```
+## Secure Mode Requirement
 
-### Templates
+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.
 
-Import templates and screen layouts:
+### 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.
 
-#### Production
+Without a valid domain name and SSL certificate, the project will not function as expected.
 
-In production run the script `load-templates-prod.sh` with the TEMPLATES_RELEASE environment variable set to the tag of
-the templates to load.
+## Available Tasks
 
-E.g.
+The project uses a `Taskfile.yml` to simplify common operations. Below is a list of the most important tasks you can run:
 
-```shell
-TEMPLATES_RELEASE=2.1.0 ./load-templates-prod.sh
-```
+### 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.
 
-#### Staging
+### 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.
 
-In staging run the script `load-templates-develop.sh`. This will load the templates from the develop branch of the
-template repository.
+### 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
 ```
-./load-templates-develop.sh
-```
+
+
+
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..b093b94
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,222 @@
+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 ""
+
+
+  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
+          CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/build/$TEMPLATE-config-main.json"
+          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
+          CONFIG_URL="https://raw.githubusercontent.com/os2display/display-templates/refs/tags/$TEMPLATES_RELEASE/src/screen-layouts/$SCREEN_LAYOUT.json"
+          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
+
+  _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.traefik.yml b/docker-compose.traefik.yml
new file mode 100644
index 0000000..c39fcef
--- /dev/null
+++ b/docker-compose.traefik.yml
@@ -0,0 +1,35 @@
+networks:
+  proxy:
+    driver: bridge
+    internal: true
+
+services:
+  traefik:
+    image: traefik:v3.2
+    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/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
+
+
