From 252deefdcd7a9bfa771cd0d037e49b41b171ee9e Mon Sep 17 00:00:00 2001 From: Xander Luedtke Date: Tue, 3 Jan 2023 18:22:36 -0700 Subject: [PATCH] initial docker commit --- docker/.env | 8 + docker/Dockerfile | 75 ++++++++ docker/README.md | 53 ++++++ docker/docker-compose.yml | 59 +++++++ docker/entrypoint.sh | 57 +++++++ docker/traefik-complete/.env | 18 ++ docker/traefik-complete/docker-compose.yml | 189 +++++++++++++++++++++ 7 files changed, 459 insertions(+) create mode 100644 docker/.env create mode 100644 docker/Dockerfile create mode 100644 docker/README.md create mode 100644 docker/docker-compose.yml create mode 100644 docker/entrypoint.sh create mode 100644 docker/traefik-complete/.env create mode 100644 docker/traefik-complete/docker-compose.yml diff --git a/docker/.env b/docker/.env new file mode 100644 index 00000000..517e3a7c --- /dev/null +++ b/docker/.env @@ -0,0 +1,8 @@ +# Set container timezone +TZ=America/Edmonton + +# Used within the docker-compose.yml template to provide easy configuration for your domain. +ROOT_DOMAIN=itflow.org + +# Generate a random password using `docker run php:8.0-apache openssl rand -base64 32` +ITFLOW_DB_PASS=thisisnotsecure \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..611d98e8 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,75 @@ +FROM ubuntu:22.04 + +LABEL dockerfile.version="v1.1" dockerfile.release-date="2023-01-03" + +# Set up ENVs that will be utilized in compose file. +ENV TZ Etc/UTC + +ENV ITFLOW_NAME ITFlow + +ENV ITFLOW_URL demo.itflow.org + +ENV ITFLOW_PORT 8080 + +ENV ITFLOW_REPO github.com/itflow-org/itflow + +# apache2 log levels: emerg, alert, crit, error, warn, notice, info, debug +ENV ITFLOW_LOG_LEVEL warn + +ENV ITFLOW_DB_HOST itflow-db + +ENV ITFLOW_DB_PASS null + +# Set timezone from TZ ENV +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# PREREQS: php php-intl php-mysqli php-imap php-curl libapache2-mod-php mariadb-server git -y +# Upgrade, then install prereqs. +RUN apt-get update && apt-get upgrade -y && apt-get clean + +# ITFlow Requirements +RUN apt-get install -y \ + git\ + apache2\ + php + +# Ubuntu quality of life installs +RUN apt-get install -y \ + vim\ + cron\ + dnsutils\ + iputils-ping + +# Install & enable php extensions +RUN apt-get install -y \ + php-intl\ + php-mysqli\ + php-curl\ + php-imap + +RUN apt-get install -y \ + libapache2-mod-php\ + libapache2-mod-md + +# Enable md apache mod +RUN a2enmod md + +# Set the work dir to the git repo. +WORKDIR /var/www/html + +# Entrypoint +# On every run of the docker file, perform an entrypoint that verifies the container is good to go. +COPY entrypoint.sh /usr/bin/ + +RUN chmod +x /usr/bin/entrypoint.sh + +# forward request and error logs to docker log collector +RUN ln -sf /dev/stdout /var/log/apache2/access.log && ln -sf /dev/stderr /var/log/apache2/error.log + +ENTRYPOINT [ "entrypoint.sh" ] + +# Expose the apache port +EXPOSE $ITFLOW_PORT + +# Start the httpd service and have logs appear in stdout +CMD [ "apache2ctl", "-D", "FOREGROUND" ] \ No newline at end of file diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..04244740 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,53 @@ +# About this Image +> This is an unofficial image of [ITFlow](https://github.com/itflow-org/itflow) @ https://itflow.org. + +> Maintained by [@lued](https://github.com/lued/itflow/tree/docker) + +# Usage +## ITFlow Only (no Reverse Proxy) +1. Copy [docker-compose.yml](https://raw.githubusercontent.com/lued/itflow/docker/docker/docker-compose.yml) to a directory. +2. Within docker-compose.yml, adjust the ```environment:``` variables such as ITFLOW_NAME, ITFLOW_URL and ITFLOW_REPO (to your own MSPs fork). +3. Copy the [.env](https://raw.githubusercontent.com/lued/itflow/docker/docker/.env) file to the same directory. +> Enter your timezone, root domain and database password within this file. You can avoid this step entirely by adding the information to your docker-compose.yml file directly instead. Or being safe, by using docker secrets. +4. Run ```docker compose up -d``` +5. Go to your domain. You should be redirected to setup.php. Enter server information correlated to your set up .env and docker-compose.yml files. +> Defaults: Username: itflow, Password: $ITFLOW_DB_PASS from .env, Database: itflow, Server: itflow-db + +## Complete [Traefik](https://doc.traefik.io/traefik/getting-started/quick-start/) Solution (Reverse Proxy) +1. Copy the traefik [docker-compose.yml](https://raw.githubusercontent.com/lued/itflow/docker/docker/traefik-complete/docker-compose.yml) to a directory. +2. Within docker-compose.yml, adjust the ```environment:``` variables such as ITFLOW_NAME, ITFLOW_URL and ITFLOW_REPO (to your own MSPs fork). +3. Copy the [.env](https://raw.githubusercontent.com/lued/itflow/docker/docker/traefik-complete/.env) file to the same directory. +> Enter your docker path (/srv/docker, ., etc), cloudflare info, timezone, root domain and database password within this file. +4. Create your A records for your host. +5. Run ```docker compose up -d``` +6. Verify you are getting certificates through LetsEncrypt. You will have two public URLs, traefik.$ROOT_DOMAIN and $ITFLOW_URL. +7. Go to your domain. You should be redirected to setup.php. Enter server information correlated to .env and docker-compose.yml +> Defaults: Username: itflow, Password: $ITFLOW_DB_PASS from .env, Database: itflow, Server: itflow-db + + + +## Environment Variables +``` +ENV TZ Etc/UTC + +ENV ITFLOW_NAME ITFlow + +ENV ITFLOW_REPO github.com/itflow-org/itflow + +ENV ITFLOW_URL demo.itflow.org + +ENV ITFLOW_PORT 8080 + +# apache2 log levels: emerg, alert, crit, error, warn, notice, info, debug +ENV ITFLOW_LOG_LEVEL warn + +ENV ITFLOW_DB_HOST itflow-db + +ENV ITFLOW_DB_PASS null +``` + +### In Beta +* I highly recommend putting your solution behind [Authelia](https://www.authelia.com/). If requested, I can supply more information on this topic. +* This project is still in early beta and is considered a **work in progress**. Many changes are being performed and may cause breakage upon updates. +* Currently, we strongly recommend against storing confidential information in ITFlow; ITFlow has not undergone a third-party security assessment. +* We are hoping to have a stable 1.0 release early this year. diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..2c72110c --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,59 @@ +version: "3.9" +########################### NETWORKS + +networks: + wan: + name: wan + driver: bridge + + itflow-db: + name: itflow-db + external: false + +########################### VOLUMES + +volumes: + itflow-db: + +########################### ITFLOW +services: + itflow: + hostname: itflow + container_name: itflow + # Comment out build for docker.io image + image: lued/itflow + # build: . + restart: unless-stopped + depends_on: + - itflow-db + networks: + - wan + - itflow-db + ports: + - "80:8080" + environment: + - TZ=$TZ + - ITFLOW_NAME=ITFlow + - ITFLOW_URL=it.$ROOT_DOMAIN + - ITFLOW_PORT=8080 + - ITFLOW_REPO=github.com/itflow-org/itflow + - ITFLOW_LOG_LEVEL=info + - ITFLOW_DB_HOST=itflow-db + - ITFLOW_DB_PASS=$ITFLOW_DB_PASS + volumes: + - ./itflow/:/var/www/html + + itflow-db: + hostname: itflow-db + container_name: itflow-db + image: mariadb:10.6.11 + restart: always + networks: + - itflow-db + environment: + - MARIADB_RANDOM_ROOT_PASSWORD=true + - MARIADB_DATABASE=itflow + - MARIADB_USER=itflow + - MARIADB_PASSWORD=$ITFLOW_DB_PASS + volumes: + - itflow-db:/var/lib/mysql/ \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 00000000..72098dee --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Update the apache2 sites-available +echo " + Order allow,deny + Allow from all + Require all granted + + + ServerName $ITFLOW_URL + DocumentRoot /var/www/html/ + LogLevel $ITFLOW_LOG_LEVEL + ErrorLog /var/log/apache2/error.log + CustomLog /var/log/apache2/access.log combined +" > /etc/apache2/sites-available/000-default.conf + +sed -i "s/^Listen.*/Listen $ITFLOW_PORT/g" /etc/apache2/ports.conf + +# if itflow is not downloaded, perform the download after the volume mounting process within dockerfile is complete. +if [[ -f /var/www/html/index.php ]]; then + cd /var/www/html + git fetch +else + git clone https://$ITFLOW_REPO /var/www/html +fi + +git config --global --add safe.directory /var/www/html + +# Verify permissions of itflow git repository +chown -R www-data:www-data /var/www/html + +# This updates the config.php file once initialization through setup.php has completed +if [[ -f /var/www/html/config.php ]]; then + # Company Name + sed -i "s/\$config_app_name.*';/\$config_app_name = '$ITFLOW_NAME';/g" /var/www/html/config.php + + # MariaDB Host + sed -i "s/\$dbhost.*';/\$dbhost = '$ITFLOW_DB_HOST';/g" /var/www/html/config.php + + # Database Password + sed -i "s/\$dbpassword.*';/\$dbpassword = '$ITFLOW_DB_PASS';/g" /var/www/html/config.php + + # Base URL + sed -i "s/\$config_base_url.*';/\$config_base_url = '$ITFLOW_URL';/g" /var/www/html/config.php + + find /var/www/html -type d -exec chmod 775 {} \; + find /var/www/html -type f -exec chmod 664 {} \; + chmod 640 /var/www/html/config.php +else + chmod -R 777 /var/www/html +fi + +# Enable the apache2 sites-available +service apache2 reload +service apache2 stop + +# Execute the command in the dockerfile's CMD +exec "$@" \ No newline at end of file diff --git a/docker/traefik-complete/.env b/docker/traefik-complete/.env new file mode 100644 index 00000000..42a19c2b --- /dev/null +++ b/docker/traefik-complete/.env @@ -0,0 +1,18 @@ +# Where you want your itflow git clone files to be stored on your host. For windows, let DOCKERDIR=. +DOCKERDIR=/srv/containers + +# Cloudflare API information for traefik LetsEncrypt deployment +CLOUDFLARE_API_KEY= + +CLOUDFLARE_EMAIL= + +# Set container timezone +TZ=America/Edmonton + +# Used within the docker-compose.yml template to provide easy configuration for your domain. +ROOT_DOMAIN=itflow.org + +ITFLOW_URL=demo.$ROOT_DOMAIN + +# Generate a random password using `docker run php:8.0-apache openssl rand -base64 32` +ITFLOW_DB_PASS=thisisnotsecure \ No newline at end of file diff --git a/docker/traefik-complete/docker-compose.yml b/docker/traefik-complete/docker-compose.yml new file mode 100644 index 00000000..29b95a74 --- /dev/null +++ b/docker/traefik-complete/docker-compose.yml @@ -0,0 +1,189 @@ +version: "3.9" +########################### NETWORKS + +networks: + wan: + name: wan + driver: bridge + + dockersocket: + name: dockersocket + + itflow-db: + name: itflow-db + external: false + +########################### VOLUMES + +volumes: + traefik-acme: + itflow-db: + +########################### DOCKER / TRAEFIK + +services: + traefik: # Reverse Proxy & Router + image: traefik + hostname: traefik + container_name: traefik + restart: unless-stopped + command: + - --global.sendAnonymousUsage=false + - --entryPoints.web.address=:80 + - --entryPoints.websecure.address=:443 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entrypoints.web.http.redirections.entrypoint.scheme=https + # Allow these IPs to set the X-Forwarded-* headers - Cloudflare IPs: https://www.cloudflare.com/ips/ + - --entrypoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/12,172.64.0.0/13,131.0.72.0/22 + - --api=true + - --log=true + - --log.level=DEBUG # DEBUG, INFO, WARN, ERROR, FATAL, PANIC + - --providers.docker + - --providers.docker.endpoint=tcp://docker_proxy:2375 #unix:///var/run/docker.sock + - --providers.docker.defaultrule=Host(`{{ index .Labels "com.docker.compose.service" }}`) + - --providers.docker.exposedByDefault=false + - --providers.docker.network=wan + - --providers.docker.swarmMode=false + # Test acme resolution through LetsEncrypt's acme-staging-v02 URL to avoid blacklisting your IP. + # When ready, uncomment the line below and comment out the "acme-staging-v02" URL and uncomment the "acme-v02" URL. + #- --certificatesResolvers.dns-cloudflare.acme.caServer=https://acme-v02.api.letsencrypt.org/directory + - --certificatesResolvers.dns-cloudflare.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory + - --certificatesResolvers.dns-cloudflare.acme.email=$CLOUDFLARE_EMAIL + - --certificatesResolvers.dns-cloudflare.acme.storage=/acme/acme.json + - --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.provider=cloudflare + - --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.resolvers=1.1.1.1:53,1.0.0.1:53 + - --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.delayBeforeCheck=90 + - --providers.file.directory=/dynamic-conf # Load dynamic configuration from one or more .toml or .yml files in a directory. + - --providers.file.watch=true # Only works on top level files in the rules folder + networks: + - wan + - dockersocket + security_opt: + - no-new-privileges:true + ports: + - 80:80 + - 443:443 + volumes: + - traefik-acme:/acme + - ${DOCKERDIR}/traefik:/dynamic-conf + environment: + - CF_API_EMAIL=$CLOUDFLARE_EMAIL + - CF_API_KEY=$CLOUDFLARE_API_KEY + - TZ=$TZ + labels: + - "traefik.enable=true" + # Middleware Rules + # # Basic Authentication - https://doc.traefik.io/traefik/middlewares/http/basicauth/ + # - "traefik.http.middlewares.basic-auth.basicAuth.realm=Traefik Basic Authentication" + # - "traefik.http.middlewares.basic-auth.basicAuth.users=admin:$$2y$$05$$so1Qmqxf8H6iA19nmqQX1usVZblGrKBM9w3SDEqS1WmEiYUqF3mT2" + # # Rate Limit + - "traefik.http.middlewares.rate-limit.rateLimit.average=100" + - "traefik.http.middlewares.rate-limit.rateLimit.burst=50" # # Secure Headers + - "traefik.http.middlewares.secure-headers.headers.framedeny=false" + - "traefik.http.middlewares.secure-headers.headers.stsincludesubdomains=true" + - "traefik.http.middlewares.secure-headers.headers.stspreload=true" + - "traefik.http.middlewares.secure-headers.headers.forceSTSHeader=true" + - "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true" + - "traefik.http.middlewares.secure-headers.headers.stsseconds=63072000" + - "traefik.http.middlewares.secure-headers.headers.browserXssFilter=true" + - "traefik.http.middlewares.secure-headers.headers.contenttypenosniff=true" + - "traefik.http.middlewares.secure-headers.headers.accesscontrolallowmethods=GET,POST,PUT,OPTIONS" + - "traefik.http.middlewares.secure-headers.headers.accesscontrolmaxage=100" + - "traefik.http.middlewares.secure-headers.headers.addvaryheader=true" + #- "traefik.http.middlewares.secure-headers.headers.contentsecuritypolicy=script-src 'self'" + - "traefik.http.middlewares.secure-headers.headers.referrerpolicy=origin-when-cross-origin" + #- "traefik.http.middlewares.secure-headers.headers.customResponseHeaders=none,noarchive,nosnippet,notranslate,noimageindex" + - "traefik.http.middlewares.secure-headers.headers.hostsProxyHeaders=X-Forwarded-Host" + # Middleware Chains + - "traefik.http.middlewares.chain-no-auth.chain.middlewares=rate-limit,secure-headers" + #- "traefik.http.middlewares.chain-basic-auth.chain.middlewares=rate-limit,secure-headers,basic-auth" + # Services - API + - "traefik.http.routers.traefik-rtr.service=api@internal" + # HTTP Routers + - "traefik.http.routers.traefik-rtr.entrypoints=websecure" + - "traefik.http.routers.traefik-rtr.rule=Host(`traefik.$ROOT_DOMAIN`)" + - "traefik.http.routers.traefik-rtr.tls=true" + # Setting TLS to $DOMAIN# + - "traefik.http.routers.traefik-rtr.tls.certResolver=dns-cloudflare" + - "traefik.http.routers.traefik-rtr.tls.domains[0].main=$ROOT_DOMAIN" + - "traefik.http.routers.traefik-rtr.tls.domains[0].sans=*.$ROOT_DOMAIN" + + watchtower: + image: containrrr/watchtower + hostname: watchtower + container_name: watchtower + restart: unless-stopped + networks: + - dockersocket + environment: + DOCKER_HOST: tcp://docker_proxy:2375 + + docker_proxy: + image: tecnativa/docker-socket-proxy + hostname: docker_proxy + container_name: docker_proxy + restart: unless-stopped + networks: + - dockersocket + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + CONTAINERS: 1 + NETWORKS: 1 + SERVICES: 1 + INFO: 1 + IMAGES: 1 + VOLUMES: 1 + POST: 1 + +########################### ITFLOW + + itflow: + hostname: itflow + container_name: itflow + image: lued/itflow + # build: ../. + restart: unless-stopped + depends_on: + - itflow-db + networks: + - wan + - itflow-db + environment: + - TZ=$TZ + - ITFLOW_NAME=ITFlow + - ITFLOW_URL=$ITFLOW_URL + - ITFLOW_PORT=8080 + - ITFLOW_REPO=github.com/itflow-org/itflow + - ITFLOW_LOG_LEVEL=info + - ITFLOW_DB_HOST=itflow-db + - ITFLOW_DB_PASS=$ITFLOW_DB_PASS + volumes: + - ${DOCKERDIR}/itflow/:/var/www/html + labels: + - "traefik.enable=true" + ## HTTP Routers + - "traefik.http.routers.itflow-rtr.entrypoints=websecure" + - "traefik.http.routers.itflow-rtr.tls=true" + - "traefik.http.routers.itflow-rtr.rule=Host(`$ITFLOW_URL`)" + ## Middlewares + - "traefik.http.routers.itflow-rtr.middlewares=chain-no-auth@docker" + ## HTTP Services + - "traefik.http.routers.itflow-rtr.service=itflow-svc" + - "traefik.http.services.itflow-svc.loadbalancer.server.port=8080" + + itflow-db: + hostname: itflow-db + container_name: itflow-db + image: mariadb:10.6.11 + restart: always + networks: + - itflow-db + environment: + - TZ=$TZ + - MARIADB_RANDOM_ROOT_PASSWORD=true + - MARIADB_DATABASE=itflow + - MARIADB_USER=itflow + - MARIADB_PASSWORD=$ITFLOW_DB_PASS + volumes: + - itflow-db:/var/lib/mysql/ \ No newline at end of file