diff --git a/docs/compose/compose.custom-domain-ssl.yaml b/docs/compose/compose.custom-domain-ssl.yaml new file mode 100644 index 00000000..5aa1d0ea --- /dev/null +++ b/docs/compose/compose.custom-domain-ssl.yaml @@ -0,0 +1,5 @@ +services: + custom-domain: + labels: + - traefik.http.routers.${ROUTER}.entrypoints=http,https + - traefik.http.routers.${ROUTER}.tls.certresolver=le diff --git a/docs/compose/compose.custom-domain.yaml b/docs/compose/compose.custom-domain.yaml new file mode 100644 index 00000000..5746a325 --- /dev/null +++ b/docs/compose/compose.custom-domain.yaml @@ -0,0 +1,31 @@ +version: "3.3" + +services: + custom-domain: + image: caddy:2 + command: + - caddy + - reverse-proxy + - --to + - frontend:8080 + - --from + - :2016 + labels: + - traefik.enable=true + - traefik.docker.network=traefik-public + - traefik.http.services.${ROUTER?ROUTER not set}.loadbalancer.server.port=2016 + - traefik.http.routers.${ROUTER}.service=${ROUTER} + - traefik.http.routers.${ROUTER}.entrypoints=http + - traefik.http.routers.${ROUTER}.rule=Host(${SITES?SITES not set}) + - traefik.http.middlewares.${ROUTER}.headers.customrequestheaders.Host=${BASE_SITE?BASE_SITE not set} + - traefik.http.routers.${ROUTER}.middlewares=${ROUTER} + networks: + - traefik-public + - bench-network + +networks: + traefik-public: + external: true + bench-network: + name: ${BENCH_NETWORK?BENCH_NETWORK not set} + external: true diff --git a/overrides/compose.mariadb-shared.yaml b/docs/compose/compose.mariadb-shared.yaml similarity index 95% rename from overrides/compose.mariadb-shared.yaml rename to docs/compose/compose.mariadb-shared.yaml index 25e2e508..132593b9 100644 --- a/overrides/compose.mariadb-shared.yaml +++ b/docs/compose/compose.mariadb-shared.yaml @@ -4,6 +4,7 @@ services: database: container_name: mariadb-database image: mariadb:10.6 + restart: unless-stopped healthcheck: test: mysqladmin ping -h localhost --password=${DB_PASSWORD:-changeit} interval: 1s diff --git a/docs/compose/compose.multi-bench-ssl.yaml b/docs/compose/compose.multi-bench-ssl.yaml new file mode 100644 index 00000000..73e6becd --- /dev/null +++ b/docs/compose/compose.multi-bench-ssl.yaml @@ -0,0 +1,5 @@ +services: + frontend: + labels: + - traefik.http.routers.${ROUTER}.entrypoints=http,https + - traefik.http.routers.${ROUTER}.tls.certresolver=le diff --git a/overrides/compose.multi-bench.yaml b/docs/compose/compose.multi-bench.yaml similarity index 61% rename from overrides/compose.multi-bench.yaml rename to docs/compose/compose.multi-bench.yaml index d6b2c5f2..ee2e17ee 100644 --- a/overrides/compose.multi-bench.yaml +++ b/docs/compose/compose.multi-bench.yaml @@ -3,12 +3,14 @@ services: networks: - traefik-public - mariadb-network + - bench-network labels: - traefik.enable=true - - traefik.http.routers.${ROUTER?ROUTER not set}.rule=Host(${SITES?SITES not set}) - - traefik.http.routers.${ROUTER}.entrypoints=http,https - - traefik.http.routers.${ROUTER}.tls.certresolver=le - - traefik.http.services.${ROUTER}.loadbalancer.server.port=8080 + - traefik.docker.network=traefik-public + - traefik.http.services.${ROUTER?ROUTER not set}.loadbalancer.server.port=8080 + - traefik.http.routers.${ROUTER}.service=${ROUTER} + - traefik.http.routers.${ROUTER}.entrypoints=http + - traefik.http.routers.${ROUTER}.rule=Host(${SITES?SITES not set}) configurator: networks: - mariadb-network @@ -39,3 +41,6 @@ networks: external: true mariadb-network: external: true + bench-network: + name: ${ROUTER} + external: false diff --git a/overrides/compose.traefik-docker.yaml b/docs/compose/compose.traefik-ssl.yaml similarity index 51% rename from overrides/compose.traefik-docker.yaml rename to docs/compose/compose.traefik-ssl.yaml index 0d569ec9..115b91ac 100644 --- a/overrides/compose.traefik-docker.yaml +++ b/docs/compose/compose.traefik-ssl.yaml @@ -1,24 +1,11 @@ -version: "3.3" - services: traefik: - image: "traefik:v2.6" labels: - # Enable Traefik for this service, to make it available in the public network - - traefik.enable=true - # Use the traefik-public network (declared below) - - traefik.docker.network=traefik-public - # admin-auth middleware with HTTP Basic auth - # Using the environment variables USERNAME and HASHED_PASSWORD - - traefik.http.middlewares.admin-auth.basicauth.users=admin:${HASHED_PASSWORD:?No HASHED_PASSWORD set} # https-redirect middleware to redirect HTTP to HTTPS # It can be re-used by other stacks in other Docker Compose files - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true - # traefik-http set up only to use the middleware to redirect to https - # Uses the environment variable DOMAIN - - traefik.http.routers.traefik-public-http.rule=Host(`${TRAEFIK_DOMAIN:?No TRAEFIK_DOMAIN set}`) - - traefik.http.routers.traefik-public-http.entrypoints=http + # traefik-http to use the middleware to redirect to https - traefik.http.routers.traefik-public-http.middlewares=https-redirect # traefik-https the actual router using HTTPS # Uses the environment variable DOMAIN @@ -31,15 +18,7 @@ services: - traefik.http.routers.traefik-public-https.tls.certresolver=le # Enable HTTP Basic auth, using the middleware created above - traefik.http.routers.traefik-public-https.middlewares=admin-auth - # Define the port inside of the Docker service to use - - traefik.http.services.traefik-public.loadbalancer.server.port=8080 command: - # Enable Docker in Traefik, so that it reads labels from Docker services - - --providers.docker=true - # Do not expose all Docker services, only the ones explicitly exposed - - --providers.docker.exposedbydefault=false - # Create an entrypoint http listening on port 80 - - --entrypoints.http.address=:80 # Create an entrypoint https listening on port 443 - --entrypoints.https.address=:443 # Create the certificate resolver le for Let's Encrypt, uses the environment variable EMAIL @@ -48,22 +27,7 @@ services: - --certificatesresolvers.le.acme.storage=/certificates/acme.json # Use the TLS Challenge for Let's Encrypt - --certificatesresolvers.le.acme.tlschallenge=true - # Enable the access log, with HTTP requests - - --accesslog - # Enable the Traefik log, for configurations and errors - - --log - # Enable the Dashboard and API - - --api ports: - - 80:80 - 443:443 volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - /data/traefik/certificates:/certificates - networks: - - traefik-public - -networks: - traefik-public: - name: traefik-public - external: false diff --git a/docs/compose/compose.traefik-swarm.yaml b/docs/compose/compose.traefik-swarm.yaml new file mode 100644 index 00000000..cf310165 --- /dev/null +++ b/docs/compose/compose.traefik-swarm.yaml @@ -0,0 +1,7 @@ +version: "3.3" + +services: + traefik: + command: + # Enable Docker Swarm mode + - --providers.docker.swarmmode diff --git a/docs/compose/compose.traefik.yaml b/docs/compose/compose.traefik.yaml new file mode 100644 index 00000000..1aff7ed4 --- /dev/null +++ b/docs/compose/compose.traefik.yaml @@ -0,0 +1,46 @@ +version: "3.3" + +services: + traefik: + image: "traefik:v2.6" + labels: + # Enable Traefik for this service, to make it available in the public network + - traefik.enable=true + # Use the traefik-public network (declared below) + - traefik.docker.network=traefik-public + # admin-auth middleware with HTTP Basic auth + # Using the environment variables USERNAME and HASHED_PASSWORD + - traefik.http.middlewares.admin-auth.basicauth.users=admin:${HASHED_PASSWORD:?No HASHED_PASSWORD set} + # Uses the environment variable TRAEFIK_DOMAIN + - traefik.http.routers.traefik-public-http.rule=Host(`${TRAEFIK_DOMAIN:?No TRAEFIK_DOMAIN set}`) + - traefik.http.routers.traefik-public-http.entrypoints=http + # Use the special Traefik service api@internal with the web UI/Dashboard + - traefik.http.routers.traefik-public-http.service=api@internal + # Enable HTTP Basic auth, using the middleware created above + - traefik.http.routers.traefik-public-http.middlewares=admin-auth + # Define the port inside of the Docker service to use + - traefik.http.services.traefik-public.loadbalancer.server.port=8080 + command: + # Enable Docker in Traefik, so that it reads labels from Docker services + - --providers.docker=true + # Do not expose all Docker services, only the ones explicitly exposed + - --providers.docker.exposedbydefault=false + # Create an entrypoint http listening on port 80 + - --entrypoints.http.address=:80 + # Enable the access log, with HTTP requests + - --accesslog + # Enable the Traefik log, for configurations and errors + - --log + # Enable the Dashboard and API + - --api + ports: + - 80:80 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - traefik-public + +networks: + traefik-public: + name: traefik-public + external: false diff --git a/docs/single-server-example.md b/docs/single-server-example.md index 1242a749..58034756 100644 --- a/docs/single-server-example.md +++ b/docs/single-server-example.md @@ -39,13 +39,22 @@ curl -SL https://github.com/docker/compose/releases/download/v2.2.3/docker-compo chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose ``` -### Create directory to store your configuration files. +### Prepare + +Clone `frappe_docker` repo for the needed YAMLs and change the current working director of you shell to the cloned repo. ```shell -mkdir -p ~/gitops/overrides +git clone https://github.com/frappe/frappe_docker +cd frappe_docker ``` -This directory will store all the resources that we use for setup. We will also keep the environment files in this directory as there will be multiple projects with different environment variables. You can create a private repo for this directory and track the changes there. +Create configuration and resources directory + +```shell +mkdir ~/gitops +``` + +The `~/gitops` directory will store all the resources that we use for setup. We will also keep the environment files in this directory as there will be multiple projects with different environment variables. You can create a private repo for this directory and track the changes there. ### Install Traefik @@ -54,9 +63,9 @@ Basic Traefik setup using docker compose. Create a file called `traefik.env` in `~/gitops` ```shell -echo "TRAEFIK_DOMAIN=traefik.example.com" > ~/gitops/traefik.env -echo "EMAIL=admin@example.com" >> ~/gitops/traefik.env -echo "HASHED_PASSWORD=`openssl passwd -apr1 changeit`" >> ~/gitops/traefik.env +echo 'TRAEFIK_DOMAIN=traefik.example.com' > ~/gitops/traefik.env +echo 'EMAIL=admin@example.com' >> ~/gitops/traefik.env +echo 'HASHED_PASSWORD='$(openssl passwd -apr1 $PASSWORD | sed 's/\$/\\\$/g') >> ~/gitops/traefik.env ``` Note: @@ -73,20 +82,19 @@ EMAIL=admin@example.com HASHED_PASSWORD=$apr1$K.4gp7RT$tj9R2jHh0D4Gb5o5fIAzm/ ``` -Create a yaml file called `traefik.yaml` in `~/gitops` directory by downloading the traefik compose file. +Deploy the traefik container with letsencrypt SSL ```shell -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/overrides/compose.traefik-docker.yaml -o ~/gitops/traefik.yaml -``` - -Deploy the traefik container - -```shell -docker compose --project-name traefik --env-file ~/gitops/traefik.env -f ~/gitops/traefik.yaml up -d +docker compose --project-name traefik \ + --env-file ~/gitops/traefik.env \ + -f docs/compose/compose.traefik.yaml \ + -f docs/compose/compose.traefik-ssl.yaml up -d ``` This will make the traefik dashboard available on `traefik.example.com` and all certificates will reside in `/data/traefik/certificates` on host filesystem. +For LAN setup deploy the traefik container without overriding `docs/compose/compose.traefik-ssl.yaml`. + ### Install MariaDB Basic MariaDB setup using docker compose. @@ -109,31 +117,16 @@ DB_PASSWORD=changeit Note: Change the password from `changeit` to more secure one. -Create a yaml file called `mariadb.yaml` in `~/gitops` directory by downloading the mariadb compose file. - -```shell -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/overrides/compose.mariadb-shared.yaml -o ~/gitops/mariadb.yaml -``` - Deploy the mariadb container ```shell -docker compose --project-name mariadb --env-file ~/gitops/mariadb.env -f ~/gitops/mariadb.yaml up -d +docker compose --project-name mariadb --env-file ~/gitops/mariadb.env -f docs/compose/compose.mariadb-shared.yaml up -d ``` This will make `mariadb-database` service available under `mariadb-network`. Data will reside in `/data/mariadb`. ### Install ERPNext -Download the common files to generate templates into `~/gitops/overrides`: - -```shell -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/compose.yaml -o ~/gitops/overrides/compose.yaml -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/overrides/compose.erpnext.yaml -o ~/gitops/overrides/compose.erpnext.yaml -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/overrides/compose.redis.yaml -o ~/gitops/overrides/compose.redis.yaml -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/overrides/compose.multi-bench.yaml -o ~/gitops/overrides/compose.multi-bench.yaml -``` - #### Create first bench Create second bench called `erpnext-one` with `one.example.com` and `two.example.com` @@ -141,12 +134,13 @@ Create second bench called `erpnext-one` with `one.example.com` and `two.example Create a file called `erpnext-one.env` in `~/gitops` ```shell -curl -sL https://raw.githubusercontent.com/frappe/frappe_docker/main/example.env -o ~/gitops/erpnext-one.env +cp example.env ~/gitops/erpnext-one.env sed -i 's/DB_PASSWORD=123/DB_PASSWORD=changeit/g' ~/gitops/erpnext-one.env sed -i 's/DB_HOST=/DB_HOST=mariadb-database/g' ~/gitops/erpnext-one.env sed -i 's/DB_PORT=/DB_PORT=3306/g' ~/gitops/erpnext-one.env -echo "ROUTER=erpnext-one" >> ~/gitops/erpnext-one.env +echo 'ROUTER=erpnext-one' >> ~/gitops/erpnext-one.env echo "SITES=\`one.example.com\`,\`two.example.com\`" >> ~/gitops/erpnext-one.env +echo "BENCH_NETWORK=erpnext-one" >> ~/gitops/erpnext-one.env ``` Note: @@ -160,12 +154,15 @@ Create a yaml file called `erpnext-one.yaml` in `~/gitops` directory: ```shell docker compose --project-name erpnext-one \ --env-file ~/gitops/erpnext-one.env \ - -f ~/gitops/overrides/compose.yaml \ - -f ~/gitops/overrides/compose.erpnext.yaml \ - -f ~/gitops/overrides/compose.redis.yaml \ - -f ~/gitops/overrides/compose.multi-bench.yaml config > ~/gitops/erpnext-one.yaml + -f compose.yaml \ + -f overrides/compose.erpnext.yaml \ + -f overrides/compose.redis.yaml \ + -f docs/compose/compose.multi-bench.yaml \ + -f docs/compose/compose.multi-bench-ssl.yaml config > ~/gitops/erpnext-one.yaml ``` +For LAN setup do not override `compose.multi-bench-ssl.yaml`. + Use the above command after any changes are made to `erpnext-one.env` file to regenerate `~/gitops/erpnext-one.yaml`. e.g. after changing version to migrate the bench. Deploy `erpnext-one` containers: @@ -205,6 +202,7 @@ sed -i 's/DB_HOST=/DB_HOST=mariadb-database/g' ~/gitops/erpnext-two.env sed -i 's/DB_PORT=/DB_PORT=3306/g' ~/gitops/erpnext-two.env echo "ROUTER=erpnext-two" >> ~/gitops/erpnext-two.env echo "SITES=\`three.example.com\`,\`four.example.com\`" >> ~/gitops/erpnext-two.env +echo "BENCH_NETWORK=erpnext-two" >> ~/gitops/erpnext-two.env ``` Note: @@ -218,10 +216,11 @@ Create a yaml file called `erpnext-two.yaml` in `~/gitops` directory: ```shell docker compose --project-name erpnext-two \ --env-file ~/gitops/erpnext-two.env \ - -f ~/gitops/overrides/compose.yaml \ - -f ~/gitops/overrides/compose.erpnext.yaml \ - -f ~/gitops/overrides/compose.redis.yaml \ - -f ~/gitops/overrides/compose.multi-bench.yaml config > ~/gitops/erpnext-two.yaml + -f compose.yaml \ + -f overrides/compose.erpnext.yaml \ + -f overrides/compose.redis.yaml \ + -f docs/compose/compose.multi-bench.yaml \ + -f docs/compose/compose.multi-bench-ssl.yaml config > ~/gitops/erpnext-two.yaml ``` Use the above command after any changes are made to `erpnext-two.env` file to regenerate `~/gitops/erpnext-two.yaml`. e.g. after changing version to migrate the bench. @@ -243,6 +242,47 @@ docker compose --project-name erpnext-two --env-file ~/gitops/erpnext-two.env ex bench new-site four.example.com --mariadb-root-password changeit --install-app erpnext --admin-password changeit ``` +#### Create custom domain to existing site + +In case you need to point custom domain to existing site follow these steps. +Also useful if custom domain is required for LAN based access. + +Create environment file + +```shell +echo "ROUTER=custom-one-example" > ~/gitops/custom-one-example.env +echo "SITES=\`custom-one.example.com\`" >> ~/gitops/custom-one-example.env +echo "BASE_SITE=one.example.com" >> ~/gitops/custom-one-example.env +echo "BENCH_NETWORK=erpnext-one" >> ~/gitops/custom-one-example.env +``` + +Note: + +- Change the file name from `custom-one-example.env` to a logical one. +- Change `ROUTER` variable from `custom-one.example.com` to the one being added. +- Change `SITES` variable from `custom-one.example.com` to the one being added. You can add multiple sites quoted in backtick (`) and separated by commas. +- Change `BASE_SITE` variable from `one.example.com` to the one which is being pointed to. +- Change `BENCH_NETWORK` variable from `erpnext-one` to the one which was created with the bench. + +env file is generated at location mentioned in command. + +Generate yaml to reverse proxy: + +```shell +docker compose --project-name custom-one-example \ + --env-file ~/gitops/custom-one-example.env \ + -f docs/compose/compose.custom-domain.yaml \ + -f docs/compose/compose.custom-domain-ssl.yaml config > ~/gitops/custom-one-example.yaml +``` + +For LAN setup do not override `compose.custom-domain-ssl.yaml`. + +Deploy `erpnext-two` containers: + +```shell +docker compose --project-name custom-one-example -f ~/gitops/custom-one-example.yaml up -d +``` + ### Site operations Refer: [site operations](./site-operations.md)