mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 02:10:05 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			ec79cb8921
			...
			4958b08ca7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4958b08ca7 | |||
| 87262f7373 | |||
| 4e04f882e5 | |||
| edf2be504c | |||
| 79d6a68dc1 | |||
| 72deb13d07 | 
| @@ -1,8 +1,16 @@ | ||||
| # General | ||||
| pause_duration:         "120"         # Database delay to wait for the central database before continue tasks | ||||
|  | ||||
| timezone:               "Etc/UTC" | ||||
| locale:                 "en"          # Some applications are case sensitive | ||||
| HOST_CURRENCY:            "EUR" | ||||
| HOST_TIMEZONE:            "UTC" | ||||
|  | ||||
| # https://en.wikipedia.org/wiki/ISO_639 | ||||
| HOST_LL:                  "en"          # Some applications are case sensitive | ||||
| HOST_LL_CC:               "{{HOST_LL}}_{{HOST_LL | upper }}" | ||||
|  | ||||
| HOST_DATE_FORMAT:         "YYYY-MM-DD" | ||||
| HOST_TIME_FORMAT:         "HH:mm" | ||||
|  | ||||
| HOST_THOUSAND_SEPARATOR:  "." | ||||
| HOST_DECIMAL_MARK:        "," | ||||
|  | ||||
| # Deployment mode | ||||
| deployment_mode:        "single"      # Use single, if you deploy on one server. Use cluster if you setup in cluster mode. | ||||
|   | ||||
| @@ -10,6 +10,7 @@ defaults_domains: | ||||
|   bluesky_web:             "bskyweb.{{primary_domain}}" | ||||
|   discourse:               "forum.{{primary_domain}}" | ||||
|   elk:                     "elk.{{primary_domain}}" | ||||
|   espocrm:                 "espocrm.{{primary_domain}}" | ||||
|   file_server:             "files.{{primary_domain}}" | ||||
|   friendica:               "friendica.{{primary_domain}}" | ||||
|   funkwhale:               "music.{{primary_domain}}" | ||||
| @@ -55,6 +56,7 @@ defaults_redirect_domain_mappings: | ||||
| - { source: "akaunting.{{primary_domain}}",   target: "{{domains.akaunting}}" } | ||||
| - { source: "bbb.{{primary_domain}}",         target: "{{domains.bigbluebutton}}" } | ||||
| - { source: "discourse.{{primary_domain}}",   target: "{{domains.discourse}}" } | ||||
| - { source: "crm.{{primary_domain}}",         target: "{{domains.espocrm}}" } | ||||
| - { source: "funkwhale.{{primary_domain}}",   target: "{{domains.funkwhale}}" } | ||||
| - { source: "gitea.{{primary_domain}}",       target: "{{domains.gitea}}" } | ||||
| - { source: "keycloak.{{primary_domain}}",    target: "{{domains.keycloak}}" } | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| ports: | ||||
|   # Ports which are exposed to localhost | ||||
|   localhost: | ||||
|     web_socket: | ||||
|     # https://developer.mozilla.org/de/docs/Web/API/WebSockets_API | ||||
|     websocket: | ||||
|       mastodon:         4001 | ||||
|       espocrm:          4002 | ||||
|     oauth2_proxy: | ||||
|       phpmyadmin:       4181 | ||||
|       lam:              4182 | ||||
| @@ -53,6 +55,7 @@ ports: | ||||
|       phpldapadmin:     8037 | ||||
|       fusiondirectory:  8038 | ||||
|       presentation:     8039 | ||||
|       espocrm:          8040 | ||||
|       bigbluebutton:    48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port | ||||
|   # Ports which are exposed to the World Wide Web | ||||
|   public: | ||||
|   | ||||
| @@ -80,6 +80,8 @@ defaults_networks: | ||||
|       subnet: 192.168.103.32/28 | ||||
|     presentation: | ||||
|       subnet: 192.168.103.48/28 | ||||
|     espocrm: | ||||
|       subnet: 192.168.103.64/28 | ||||
|        | ||||
|     # /24 Networks / 254 Usable Clients | ||||
|     bigbluebutton: | ||||
|   | ||||
| @@ -39,7 +39,7 @@ defaults_oidc: | ||||
| # Helper Variables: | ||||
| # Keep in mind to mapp this variables if there is ever the possibility for the user to define them in the inventory | ||||
| _ldap_dn_base:      "dc={{primary_domain_sld}},dc={{primary_domain_tld}}" | ||||
| _ldap_server_port:  "{% if applications.ldap.network.local | bool %}{{ ports.localhost.ldap.ldap }}{% else %}{{ ports.localhost.ldaps.ldap }}{% endif %}" | ||||
| _ldap_server_port:  "{% if applications.ldap.network.docker | bool %}{{ ports.localhost.ldap.ldap }}{% else %}{{ ports.localhost.ldaps.ldap }}{% endif %}" | ||||
|  | ||||
| ldap: | ||||
|   # Distinguished Names (DN) | ||||
| @@ -60,11 +60,11 @@ ldap: | ||||
|   # Password to access dn.bind | ||||
|   bind_credential:      "{{applications.ldap.administrator_database_password}}" | ||||
|   server: | ||||
|     domain:             "{{applications.ldap.hostname if applications.ldap.network.local | bool else domains.ldap}}" # Mapping for public or locale access | ||||
|     domain:             "{{applications.ldap.hostname if applications.ldap.network.docker | bool else domains.ldap}}" # Mapping for public or locale access | ||||
|     port:               "{{_ldap_server_port}}" | ||||
|     uri:                "{% if applications.ldap.network.local | bool %}ldap://{{ applications.ldap.hostname }}{% else %}ldaps://{{ domains.ldap }}{% endif %}:{{ _ldap_server_port }}" | ||||
|     uri:                "{% if applications.ldap.network.docker | bool %}ldap://{{ applications.ldap.hostname }}{% else %}ldaps://{{ domains.ldap }}{% endif %}:{{ _ldap_server_port }}" | ||||
|   network: | ||||
|     local:              "{{applications.ldap.network.local}}" # Uses the application configuration to define if local network should be available or not | ||||
|     local:              "{{applications.ldap.network.docker}}" # Uses the application configuration to define if local network should be available or not | ||||
|   user_objects: | ||||
|     - person          # Basic person attributes (sn, cn …) – RFC 4519 | ||||
|     - inetOrgPerson   # Extended Internet / intranet person – RFC 2798 | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| # You should change this to match your reverse proxy DNS name and protocol | ||||
| APP_URL=https://{{domains[application_id]}} | ||||
| LOCALE={{locale}} | ||||
| LOCALE={{ HOST_LL }} | ||||
|  | ||||
| # Don't change this unless you rename your database container or use rootless podman, in case of using rootless podman you should set it to 127.0.0.1 (NOT localhost) | ||||
| DB_HOST={{database_host}} | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|      | ||||
| - name: configure {{domains[application_id]}}.conf | ||||
|   template:  | ||||
|     src: roles/nginx-docker-reverse-proxy/templates/domain.conf.j2  | ||||
|     src: roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2  | ||||
|     dest: "{{nginx.directories.http.servers}}{{domains[application_id]}}.conf" | ||||
|   notify: restart nginx | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,7 @@ env: | ||||
|   LC_ALL: en_US.UTF-8 | ||||
|   LANG: en_US.UTF-8 | ||||
|   LANGUAGE: en_US.UTF-8 | ||||
|   #DISCOURSE_DEFAULT_LOCALE: {{locale}} # Deactivated because not right format was selected @todo find right format | ||||
|   #DISCOURSE_DEFAULT_LOCALE: {{ HOST_LL }} # Deactivated because not right format was selected @todo find right format | ||||
|  | ||||
|   ## How many concurrent web requests are supported? Depends on memory and CPU cores. | ||||
|   ## will be set automatically by bootstrap based on detected CPUs, or you can override | ||||
|   | ||||
							
								
								
									
										32
									
								
								roles/docker-espocrm/Administration.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								roles/docker-espocrm/Administration.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| # Administration | ||||
|  | ||||
| ## 🗑️ Cleanup (Remove instance & volumes) | ||||
| ```bash | ||||
| cd {{path_docker_compose_instances}}espocrm/ | ||||
| docker compose down | ||||
| # EspoCRM keeps all uploaded files in the *data* volume | ||||
| docker volume rm espocrm_data espocrm_database | ||||
| cd {{path_docker_compose_instances}} && rm -vR {{path_docker_compose_instances}}espocrm | ||||
| ``` | ||||
|  | ||||
| ## 🔍 Access EspoCRM container shell | ||||
| ```bash | ||||
| docker compose exec -it web /bin/bash | ||||
| ``` | ||||
|  | ||||
| ## 🛠️ Database migrations (after image upgrade) | ||||
| EspoCRM applies migrations automatically on start‑up. To run them manually: | ||||
| ```bash | ||||
| docker compose exec -it web php command.php upgrade | ||||
| ``` | ||||
|  | ||||
| ## 🗄️ Backup database | ||||
| ```bash | ||||
| # Dump the MySQL/MariaDB database | ||||
| docker exec espocrm_database /usr/bin/mysqldump -u root -p$MYSQL_ROOT_PASSWORD espocrm > backup_$(date +%F).sql | ||||
| ``` | ||||
|  | ||||
| ## 🧹 Clear cache | ||||
| ```bash | ||||
| docker compose exec web php command.php clear cache | ||||
| ``` | ||||
							
								
								
									
										25
									
								
								roles/docker-espocrm/Installation.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								roles/docker-espocrm/Installation.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| # ⚙️ Configuration & Setup | ||||
|  | ||||
| ## 🔧 Create credentials & pull image | ||||
| ```bash | ||||
| # Pull the latest EspoCRM image | ||||
| docker pull espocrm/espocrm:latest | ||||
|  | ||||
| # If you need to pre‑create a config file, copy the default | ||||
| # (the container will generate one automatically on first start) | ||||
| ``` | ||||
|  | ||||
| ## 🏗️ Initial deployment with Docker Compose | ||||
| ```bash | ||||
| # Change into the instance directory created by the role | ||||
| cd {{path_docker_compose_instances}}espocrm/ | ||||
|  | ||||
| # Launch the stack | ||||
| docker compose up -d | ||||
| ``` | ||||
| The first start can take a minute while EspoCRM initialises the database schema. | ||||
|  | ||||
| ## 🔐 LDAP & OIDC authentication | ||||
| Both mechanisms are supported out of the box: | ||||
| - **LDAP:** Configure under *Administration → Authentication → LDAP* after the first login. | ||||
| - **OIDC:** Configure under *Administration → Authentication → OpenID Connect* and paste the Issuer URL, Client ID and Client Secret from your IdP (Keycloak, Authentik, Entra ID, …). | ||||
							
								
								
									
										16
									
								
								roles/docker-espocrm/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								roles/docker-espocrm/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # EspoCRM | ||||
|  | ||||
| ## Description | ||||
|  | ||||
| EspoCRM is a lightweight, open‑source Customer Relationship Management platform that helps you manage leads, accounts, opportunities and post‑sale support in a single, web‑based interface.   | ||||
| This Ansible role deploys EspoCRM with Docker, mirroring the structure of the Mastodon role for a consistent operations workflow. | ||||
|  | ||||
| ## Overview | ||||
| - **Sales Pipeline & Activities Stream** – track every interaction and schedule follow‑ups. | ||||
| - **Workflow & BPM** – automate routine tasks and notifications. | ||||
| - **Extensible Authentication** – native LDAP and OpenID Connect (OIDC) login support. | ||||
| - **Containerised Architecture** – separate services for the web application, cron jobs and an upstream MySQL/MariaDB database. | ||||
|  | ||||
| For detailed instructions see: | ||||
| - [Installation.md](./Installation.md)   | ||||
| - [Administration.md](./Administration.md) | ||||
							
								
								
									
										2
									
								
								roles/docker-espocrm/Todo.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								roles/docker-espocrm/Todo.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # Todos | ||||
| - Finish draft implementation | ||||
							
								
								
									
										22
									
								
								roles/docker-espocrm/meta/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								roles/docker-espocrm/meta/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| galaxy_info: | ||||
|   author: "Kevin Veen-Birkenbach" | ||||
|   description: "EspoCRM is an open‑source CRM with workflow automation, LDAP/OIDC SSO and a lightweight UI" | ||||
|   license: "CyMaIS NonCommercial License (CNCL)" | ||||
|   license_url: "https://s.veen.world/cncl" | ||||
|   company: | | ||||
|     Kevin Veen-Birkenbach | ||||
|     Consulting & Coaching Solutions | ||||
|     https://www.veen.world | ||||
|   galaxy_tags: | ||||
|     - espocrm | ||||
|     - crm | ||||
|     - docker | ||||
|     - sales | ||||
|     - ldap | ||||
|     - oidc | ||||
|   repository: "https://s.veen.world/cymais" | ||||
|   issue_tracker_url: "https://s.veen.world/cymaisissues" | ||||
|   documentation: "https://s.veen.world/cymais" | ||||
|   logo: | ||||
|     class: "fa-solid fa-briefcase" | ||||
| dependencies: [] | ||||
							
								
								
									
										18
									
								
								roles/docker-espocrm/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								roles/docker-espocrm/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| --- | ||||
| - name: "include docker-central-database" | ||||
|   include_role: | ||||
|     name: docker-central-database | ||||
|  | ||||
| - name: "Include setup for domain '{{ domain }}'" | ||||
|   include_role:  | ||||
|     name: nginx-domain-setup | ||||
|   vars: | ||||
|     ws_path:              "/ws" | ||||
|     ws_port:              "{{ ports.localhost.websocket[application_id] }}" | ||||
|     client_max_body_size: "100m" | ||||
|     vhost_flavour:        "ws_generic" | ||||
|     domain:               "{{ domains[application_id] }}" | ||||
|     http_port:            "{{ ports.localhost.http[application_id] }}" | ||||
|  | ||||
| - name: "copy docker-compose.yml and env file" | ||||
|   include_tasks: copy-docker-compose-and-env.yml | ||||
							
								
								
									
										49
									
								
								roles/docker-espocrm/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								roles/docker-espocrm/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| services: | ||||
|  | ||||
| {% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %} | ||||
|  | ||||
|   web: | ||||
|     image: espocrm/espocrm:{{ applications.espocrm.version }} | ||||
| {% include 'roles/docker-compose/templates/services/base.yml.j2' %} | ||||
|     command: "php-fpm" | ||||
|     healthcheck: | ||||
|       test: ["CMD", "curl", "-f", "http://localhost/"] | ||||
|     ports: | ||||
|       - "127.0.0.1:{{ ports.localhost.http[application_id] }}:80" | ||||
| {% include 'templates/docker/container/depends-on-just-database.yml.j2' %} | ||||
| {% include 'templates/docker/container/networks.yml.j2' %} | ||||
|     volumes: | ||||
|       - data:/var/www/html | ||||
|  | ||||
|   daemon: | ||||
|     image: espocrm/espocrm:{{ applications.espocrm.version }} | ||||
|     restart: {{docker_restart_policy}} | ||||
|     logging: | ||||
|       driver: journald | ||||
|     entrypoint: docker-daemon.sh | ||||
| {% include 'templates/docker/container/networks.yml.j2' %} | ||||
|     volumes: | ||||
|       - data:/var/www/html | ||||
|  | ||||
|   websocket: | ||||
|     image: espocrm/espocrm:{{ applications.espocrm.version }} | ||||
|     restart: {{docker_restart_policy}} | ||||
|     logging: | ||||
|       driver: journald | ||||
|     environment: | ||||
|       - ESPOCRM_CONFIG_USE_WEB_SOCKET=true | ||||
|       - ESPOCRM_CONFIG_WEB_SOCKET_URL=ws://{{ domains[application_id] }}/ws | ||||
|       - ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN=tcp://*:7777 | ||||
|       - ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN=tcp://websocket:7777 | ||||
|     entrypoint: docker-websocket.sh | ||||
| {% include 'templates/docker/container/depends-on-just-database.yml.j2' %} | ||||
| {% include 'templates/docker/container/networks.yml.j2' %} | ||||
|     volumes: | ||||
|       - data:/var/www/html | ||||
|     ports: | ||||
|       - "{{ ports.localhost.websocket[application_id] | default('127.0.0.1:8081') }}:8080" | ||||
|  | ||||
| {% include 'templates/docker/compose/volumes.yml.j2' %} | ||||
|   data: | ||||
|  | ||||
| {% include 'templates/docker/compose/networks.yml.j2' %} | ||||
							
								
								
									
										98
									
								
								roles/docker-espocrm/templates/env.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								roles/docker-espocrm/templates/env.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| ############################################# | ||||
| # EspoCRM Docker Environment (.env) – ENGLISH | ||||
| # See: https://hub.docker.com/r/espocrm/espocrm | ||||
| ############################################# | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # Database connection | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_DATABASE_PLATFORM=Mysql | ||||
| ESPOCRM_DATABASE_HOST={{ database_host }} | ||||
| ESPOCRM_DATABASE_PORT={{ database_port }} | ||||
| ESPOCRM_DATABASE_NAME={{ database_name }} | ||||
| ESPOCRM_DATABASE_USER={{ database_username }} | ||||
| ESPOCRM_DATABASE_PASSWORD={{ database_password }} | ||||
|  | ||||
| # Disable EspoCRM’s built-in cron (handled externally) | ||||
| CRON_DISABLED=true | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # Initial admin account | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_ADMIN_USERNAME={{ applications[application_id].users.administrator.username }} | ||||
| ESPOCRM_ADMIN_PASSWORD={{ applications[application_id].credentials.administrator.password }} | ||||
|  | ||||
| # Public base URL of the EspoCRM instance | ||||
| ESPOCRM_SITE_URL={{ web_protocol }}://{{ domains[application_id] }} | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # General UI & locale settings | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_CONFIG_LANGUAGE={{ HOST_LL_CC }} | ||||
| ESPOCRM_CONFIG_DATE_FORMAT={{ HOST_DATE_FORMAT }} | ||||
| ESPOCRM_CONFIG_TIME_FORMAT={{ HOST_TIME_FORMAT }} | ||||
| ESPOCRM_CONFIG_TIME_ZONE={{ HOST_TIMEZONE }} | ||||
| # ESPOCRM_CONFIG_WEEK_START: 0 = Sunday, 1 = Monday | ||||
| ESPOCRM_CONFIG_WEEK_START=1 | ||||
| ESPOCRM_CONFIG_DEFAULT_CURRENCY={{ HOST_CURRENCY }} | ||||
| ESPOCRM_CONFIG_THOUSAND_SEPARATOR={{ HOST_THOUSAND_SEPARATOR }} | ||||
| ESPOCRM_CONFIG_DECIMAL_MARK={{HOST_DECIMAL_MARK}} | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # Logger | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_CONFIG_LOGGER_LEVEL={{ 'DEBUG' if enable_debug | bool else 'INFO' }} | ||||
| ESPOCRM_CONFIG_LOGGER_PATH=php://stdout | ||||
| ESPOCRM_CONFIG_LOGGER_ROTATION=false | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # System SMTP settings | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_CONFIG_SMTP_SERVER={{ system_email.host }} | ||||
| ESPOCRM_CONFIG_SMTP_PORT={{ system_email.port }} | ||||
| ESPOCRM_CONFIG_SMTP_SECURITY=TLS | ||||
| ESPOCRM_CONFIG_SMTP_AUTH=true | ||||
| ESPOCRM_CONFIG_SMTP_USERNAME={{ users['no-reply'].email }} | ||||
| ESPOCRM_CONFIG_SMTP_PASSWORD={{ users['no-reply'].mailu_token }} | ||||
| ESPOCRM_CONFIG_OUTBOUND_EMAIL_FROM_NAME={{ service_provider.company.titel }} - CRM | ||||
| ESPOCRM_CONFIG_OUTBOUND_EMAIL_FROM_ADDRESS={{ users['no-reply'].email }} | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # LDAP settings (optional) | ||||
| # Applied only if the feature flag is true | ||||
| # ------------------------------------------------ | ||||
| {% if applications[application_id].features.ldap | bool %} | ||||
| ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Ldap | ||||
| ESPOCRM_CONFIG_LDAP_HOST={{ ldap.server.domain }} | ||||
| ESPOCRM_CONFIG_LDAP_PORT={{ ldap.server.port }} | ||||
| # ESPOCRM_CONFIG_LDAP_SECURITY: "", SSL or TLS | ||||
| ESPOCRM_CONFIG_LDAP_SECURITY=           | ||||
| ESPOCRM_CONFIG_LDAP_USERNAME={{ ldap.dn.administrator }} | ||||
| ESPOCRM_CONFIG_LDAP_PASSWORD={{ ldap.bind_credential }} | ||||
| ESPOCRM_CONFIG_LDAP_BASE_DN={{ ldap.dn.users }} | ||||
| ESPOCRM_CONFIG_LDAP_USER_LOGIN_FILTER=(sAMAccountName=%USERNAME%) | ||||
| {% endif %} | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # OpenID Connect settings (optional) | ||||
| # Applied only if the feature flag is true | ||||
| # ------------------------------------------------ | ||||
| {% if applications[application_id].features.oidc | bool %} | ||||
|  | ||||
| # ------------------------------------------------ | ||||
| # OpenID Connect settings | ||||
| # ------------------------------------------------ | ||||
| ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Oidc | ||||
| ESPOCRM_CONFIG_OIDC_FALLBACK=false                       # set true if you want LDAP as fallback | ||||
|  | ||||
| ESPOCRM_CONFIG_OIDC_CLIENT_ID={{ oidc.client.id }} | ||||
| ESPOCRM_CONFIG_OIDC_CLIENT_SECRET={{ oidc.client.secret }} | ||||
|  | ||||
| ESPOCRM_CONFIG_OIDC_AUTHORIZATION_ENDPOINT={{ oidc.client.authorize_url }} | ||||
| ESPOCRM_CONFIG_OIDC_TOKEN_ENDPOINT={{ oidc.client.token_url }} | ||||
| ESPOCRM_CONFIG_OIDC_USER_INFO_ENDPOINT={{ oidc.client.user_info_url }} | ||||
| ESPOCRM_CONFIG_OIDC_JWKS_ENDPOINT={{ oidc.client.certs }} | ||||
|  | ||||
| ESPOCRM_CONFIG_OIDC_AUTHORIZATION_REDIRECT_URI=https://{{ domains[application_id] }}/oidc/callback | ||||
| ESPOCRM_CONFIG_OIDC_SCOPES=openid,profile,email | ||||
| {% endif %} | ||||
							
								
								
									
										5
									
								
								roles/docker-espocrm/vars/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/docker-espocrm/vars/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| application_id: "espocrm" | ||||
| # Password for the espocrm DB user (taken from inventory applications dict) | ||||
| database_password: "{{ applications[application_id].credentials.database.password }}" | ||||
| # EspoCRM uses MySQL/MariaDB | ||||
| database_type: "mariadb" | ||||
| @@ -1,6 +1,8 @@ | ||||
| # Administration | ||||
|  | ||||
| ## Show Configuration | ||||
| ## Configuration | ||||
|  | ||||
| ### Show Configuration | ||||
| ```bash | ||||
| docker exec -it ldap bash -c "ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b 'cn=config'" | ||||
| ``` | ||||
| @@ -18,7 +20,16 @@ docker exec -it ldap bash -c "ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b 'cn=co | ||||
| docker exec -it ldap ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config" "(olcDatabase=*)" | ||||
| ``` | ||||
|  | ||||
| ## Show all Entries | ||||
| ## Data | ||||
|  | ||||
| ### Set Credentials | ||||
| To execute the following commands set the credentials via: | ||||
|  | ||||
| ```bash | ||||
| export $(grep -Ev '^(#|$)' .env/env | xargs) | ||||
| ``` | ||||
|  | ||||
| ### Show all Entries | ||||
| ```bash  | ||||
| docker exec -it ldap bash -c "ldapsearch -LLL -o ldif-wrap=no -x -D \"\$LDAP_ADMIN_DN\" -w \"\$LDAP_ADMIN_PASSWORD\" -b \"\$LDAP_ROOT\""; | ||||
| ``` | ||||
|   | ||||
| @@ -1,25 +1,42 @@ | ||||
| - name: Load memberof module from file in OpenLDAP container | ||||
|   shell: > | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}01_member_of_configuration.ldif | ||||
|   listen: "Import LDIF files" | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}configuration/01_member_of_configuration.ldif | ||||
|   listen:  | ||||
|     - "Import configuration LDIF files" | ||||
|     - "Import all LDIF files" | ||||
|   # @todo Remove the following ignore errors when setting up a new server | ||||
|   # Just here because debugging would take to much time | ||||
|   ignore_errors: true | ||||
|  | ||||
| - name: Refint Module Activation for OpenLDAP | ||||
|   shell: > | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapadd -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}02_member_of_configuration.ldif | ||||
|   listen: "Import LDIF files" | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapadd -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}configuration/02_member_of_configuration.ldif | ||||
|   listen:  | ||||
|     - "Import configuration LDIF files" | ||||
|     - "Import all LDIF files" | ||||
|   register: ldapadd_result | ||||
|   failed_when: ldapadd_result.rc not in [0, 68] | ||||
|   # @todo Remove the following ignore errors when setting up a new server | ||||
|   # Just here because debugging would take to much time | ||||
|   ignore_errors: true | ||||
|  | ||||
| - name: "Import schemas" | ||||
|   shell: > | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapadd -Y EXTERNAL -H ldapi:/// -f "{{ldif_docker_path}}schema/{{ item | basename | regex_replace('\.j2$', '') }}" | ||||
|   register: ldapadd_result | ||||
|   changed_when: "'adding new entry' in ldapadd_result.stdout" | ||||
|   failed_when: ldapadd_result.rc not in [0, 80] | ||||
|   listen: | ||||
|     - "Import schema LDIF files" | ||||
|     - "Import all LDIF files" | ||||
|   loop: "{{ lookup('fileglob', role_path ~ '/templates/ldif/schema/*.j2', wantlist=True) }}" | ||||
|  | ||||
| - name: Refint Overlay Configuration for OpenLDAP | ||||
|   shell: > | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}03_member_of_configuration.ldif | ||||
|   listen: "Import LDIF files" | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ldif_docker_path}}configuration/03_member_of_configuration.ldif | ||||
|   listen: | ||||
|     - "Import configuration LDIF files" | ||||
|     - "Import all LDIF files" | ||||
|   register: ldapadd_result | ||||
|   failed_when: ldapadd_result.rc not in [0, 68] | ||||
|   # @todo Remove the following ignore errors when setting up a new server | ||||
| @@ -32,14 +49,7 @@ | ||||
|   register: ldapadd_result | ||||
|   changed_when: "'adding new entry' in ldapadd_result.stdout" | ||||
|   failed_when: ldapadd_result.rc not in [0, 20, 68] | ||||
|   listen: "Import LDIF files" | ||||
|   loop: "{{ lookup('fileglob', role_path ~ '/templates/ldif/data/*.j2', wantlist=True) }}" | ||||
|  | ||||
| - name: "Import schemas" | ||||
|   shell: > | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapadd -Y EXTERNAL -H ldapi:/// -f "{{ldif_docker_path}}schema/{{ item | basename | regex_replace('\.j2$', '') }}" | ||||
|   register: ldapadd_result | ||||
|   changed_when: "'adding new entry' in ldapadd_result.stdout" | ||||
|   failed_when: ldapadd_result.rc not in [0, 80] | ||||
|   listen: "Import LDIF files" | ||||
|   loop: "{{ lookup('fileglob', role_path ~ '/templates/ldif/schema/*.j2', wantlist=True) }}" | ||||
|   listen: | ||||
|     - "Import data LDIF files" | ||||
|     - "Import all LDIF files" | ||||
|   loop: "{{ lookup('fileglob', role_path ~ '/templates/ldif/data/*.j2', wantlist=True) }}" | ||||
| @@ -1,9 +1,9 @@ | ||||
| # In own task file for easier looping | ||||
|  | ||||
| - name: "Create LDIF files at {{ ldif_host_path }}/{{ folder }}" | ||||
| - name: "Create LDIF files at {{ ldif_host_path }}{{ folder }}" | ||||
|   template: | ||||
|     src: "{{ item }}" | ||||
|     dest: "{{ ldif_host_path }}/{{ folder }}/{{ item | basename | regex_replace('\\.j2$', '') }}" | ||||
|     dest: "{{ ldif_host_path }}{{ folder }}/{{ item | basename | regex_replace('\\.j2$', '') }}" | ||||
|     mode: '770' | ||||
|   loop: "{{ lookup('fileglob', role_path ~ '/templates/ldif/' ~ folder ~ '/*.j2', wantlist=True) }}" | ||||
|   notify: Import LDIF files | ||||
|   notify: "Import {{ folder }} LDIF files" | ||||
|   | ||||
| @@ -35,11 +35,77 @@ | ||||
|  | ||||
| - name: "Process all LDIF types" | ||||
|   include_tasks: create_ldif_files.yml | ||||
|   loop: "{{ ldif_types }}" | ||||
|   loop: | ||||
|     - configuration | ||||
|     - schema | ||||
|   loop_control: | ||||
|     loop_var: folder | ||||
|  | ||||
| - name: Force LDIF files import | ||||
|   command: /bin/true | ||||
|   notify: Import LDIF files | ||||
|   when: applications.ldap.force_import | bool | ||||
| - name: flush LDIF handlers | ||||
|   meta: flush_handlers | ||||
|  | ||||
| - name: install python-ldap | ||||
|   community.general.pacman: | ||||
|     name: | ||||
|       - python-ldap | ||||
|     state: present | ||||
|  | ||||
| ############################################################################### | ||||
| # 1) Create the LDAP entry if it does not yet exist | ||||
| ############################################################################### | ||||
| - name: Ensure LDAP users exist | ||||
|   community.general.ldap_entry: | ||||
|     dn: "{{ ldap.attributes.user_id }}={{ item.key }},{{ ldap.dn.users }}" | ||||
|     server_uri: "ldap://127.0.0.1:{{ ports.localhost.ldap.ldap }}" | ||||
|     bind_dn: "{{ ldap.dn.administrator }}" | ||||
|     bind_pw: "{{ ldap.bind_credential }}" | ||||
|     objectClass: "{{ ldap.user_objects }}" | ||||
|     attributes: | ||||
|       uid:           "{{ item.key }}" # {{ ldap.attributes.user_id }} can't be used as key here, dynamic key generation isn't possible | ||||
|       sn:            "{{ item.value.sn  | default(item.key) }}" | ||||
|       cn:            "{{ item.value.cn  | default(item.key) }}" | ||||
|       userPassword:  "{SSHA}{{ item.value.password }}" | ||||
|       loginShell:    /bin/bash | ||||
|       homeDirectory: "/home/{{ item.key }}" | ||||
|       uidNumber:     "{{ item.value.uid | int }}" | ||||
|       gidNumber:     "{{ item.value.gid | int }}" | ||||
|     state: present            # ↳ creates but never updates | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|  | ||||
| ############################################################################### | ||||
| # 2) Keep the objectClass list AND the mail attribute up-to-date | ||||
| ############################################################################### | ||||
| - name: Ensure required objectClass values and mail address are present | ||||
|   community.general.ldap_attrs: | ||||
|     dn: "{{ ldap.attributes.user_id }}={{ item.key }},{{ ldap.dn.users }}" | ||||
|     server_uri: "ldap://127.0.0.1:{{ ports.localhost.ldap.ldap }}" | ||||
|     bind_dn: "{{ ldap.dn.administrator }}" | ||||
|     bind_pw: "{{ ldap.bind_credential }}" | ||||
|     attributes: | ||||
|       objectClass: "{{ ldap.user_objects }}" | ||||
|       mail:         "{{ item.value.email }}" | ||||
|     state: exact        # ‘exact’ is safest for single-valued attributes | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|  | ||||
| - name: "Ensure container for application roles exists" | ||||
|   community.general.ldap_entry: | ||||
|     dn: "{{ ldap.dn.application_roles }}" | ||||
|     server_uri: "ldap://127.0.0.1:{{ ports.localhost.ldap.ldap }}" | ||||
|     bind_dn:  "{{ ldap.dn.administrator }}" | ||||
|     bind_pw:  "{{ ldap.bind_credential }}" | ||||
|     objectClass: organizationalUnit | ||||
|     attributes: | ||||
|       ou: roles | ||||
|       description: Container for application access profiles | ||||
|     state: present | ||||
|  | ||||
| - name: "Process all LDIF types" | ||||
|   include_tasks: create_ldif_files.yml | ||||
|   loop: | ||||
|     - data | ||||
|   loop_control: | ||||
|     loop_var: folder | ||||
| @@ -6,7 +6,7 @@ services: | ||||
|     image: bitnami/openldap:{{ applications[application_id].version }} | ||||
|     container_name: {{ applications[application_id].hostname }} | ||||
| {% include 'roles/docker-compose/templates/services/base.yml.j2' %} | ||||
| {% if applications[application_id].network.public | bool %} | ||||
| {% if applications[application_id].network.public | bool or applications[application_id].network.local | bool %} | ||||
|     ports: | ||||
|       - 127.0.0.1:{{ports.localhost.ldap.ldap}}:{{ldap_docker_port}}  # Expose just on localhost so that nginx stream proxy can use it | ||||
| {% endif %} | ||||
|   | ||||
| @@ -1,19 +1,4 @@ | ||||
|  | ||||
| ####################################################################### | ||||
| # Generic container for Application roles | ||||
| ####################################################################### | ||||
| dn: {{ldap.dn.application_roles}} | ||||
| objectClass: organizationalUnit | ||||
| ou: roles | ||||
| description: Container for application access profiles | ||||
|  | ||||
| {#  | ||||
|   This template generates two LDIF entries for each application in defaults_applications: | ||||
|   one for the administrator role and one for the standard user role. | ||||
|   Please adjust the base DN (dc=example,dc=com) and other attributes as necessary. | ||||
| #} | ||||
|  | ||||
| {% for app, config in defaults_applications.items() %} | ||||
| {% for app, config in applications.items() %} | ||||
| dn: cn={{ app }}-administrator,{{ldap.dn.application_roles}} | ||||
| objectClass: top | ||||
| objectClass: organizationalRole | ||||
| @@ -27,3 +12,31 @@ cn: {{ app }}-user | ||||
| description: Standard user role for {{ app }} (automatically generated) | ||||
|  | ||||
| {% endfor %} | ||||
|  | ||||
| {% for username, user in users.items() %} | ||||
|  | ||||
| ####################################################################### | ||||
| # Assign {{ username }} to application user roles | ||||
| ####################################################################### | ||||
| {% for app, config in applications.items() %} | ||||
|  | ||||
| # Assign {{ username }} to {{ app }}-users | ||||
|  | ||||
| dn: cn={{ app }}-user,{{ ldap.dn.application_roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ username }},{{ ldap.dn.users }} | ||||
|  | ||||
| {% if users.is_admin | default(false) | bool %} | ||||
|  | ||||
| # Assign {{ username }} to {{ app }}-administrator | ||||
| dn: cn={{ app }}-administrator,{{ ldap.dn.application_roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ users.administrator.username }},{{ ldap.dn.users }} | ||||
|  | ||||
| {% endif %} | ||||
|  | ||||
| {% endfor %} | ||||
|  | ||||
| {% endfor %} | ||||
| @@ -1,58 +0,0 @@ | ||||
| {## | ||||
| # Iterate over all users and create LDAP entries for each, then assign admin to application roles | ||||
| # This template loops through a 'users' list variable where each user is a dict with keys: | ||||
| #   username, uid, gid, password (optional), sn (optional), cn (optional) | ||||
| ##} | ||||
| ####################################################################### | ||||
| # Container for Application Roles (if not already created) | ||||
| ####################################################################### | ||||
| dn: {{ ldap.dn.application_roles }} | ||||
| objectClass: organizationalUnit | ||||
| ou: roles | ||||
| description: Container for application access profiles | ||||
|  | ||||
| {% for username, user in users.items() %} | ||||
| ####################################################################### | ||||
| # Create User {{ username }} | ||||
| ####################################################################### | ||||
| dn: {{ ldap.attributes.user_id }}={{ username }},{{ ldap.dn.users }} | ||||
| {% for cls in ldap.user_objects %} | ||||
| objectClass: {{ cls }} | ||||
| {% endfor %} | ||||
| {{ ldap.attributes.user_id }}: {{ username }} | ||||
| sn: {{ username }} | ||||
| cn: {{ username }} | ||||
| userPassword: {SSHA}{{ user.password }} | ||||
| loginShell: /bin/bash | ||||
| homeDirectory: /home/{{ username }} | ||||
| uidNumber: {{ user.uid }} | ||||
| gidNumber: {{ user.gid }} | ||||
|  | ||||
| ####################################################################### | ||||
| # Assign {{ username }} to application user roles | ||||
| ####################################################################### | ||||
| {% for app, config in defaults_applications.items() %} | ||||
| dn: cn={{ app }}-user,{{ ldap.dn.application_roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ username }},{{ ldap.dn.users }} | ||||
|  | ||||
| {% endfor %} | ||||
| {% endfor %} | ||||
|  | ||||
| ####################################################################### | ||||
| # Add Admin User to All Application Role Groups (unchanged) | ||||
| ####################################################################### | ||||
| {% for app, config in defaults_applications.items() %} | ||||
| dn: cn={{ app }}-administrator,{{ ldap.dn.application_roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ users.administrator.username }},{{ ldap.dn.users }} | ||||
|  | ||||
| dn: cn={{ app }}-user,{{ ldap.dn.application_roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ users.administrator.username }},{{ ldap.dn.users }} | ||||
|  | ||||
| {% endfor %} | ||||
|  | ||||
| @@ -1,4 +1,4 @@ | ||||
| TZ={{timezone}} | ||||
| TZ={{ HOST_TIMEZONE }} | ||||
|  | ||||
| # Administrator setup | ||||
|  | ||||
|   | ||||
| @@ -61,7 +61,7 @@ listmonk_settings: | ||||
|  | ||||
|  | ||||
|   - key: "app.lang" | ||||
|     value: '"{{ locale }}"' | ||||
|     value: '"{{ HOST_LL }}"' | ||||
|  | ||||
| #  - key: "messengers" | ||||
| #    value: '[]' | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| - name: "include role for {{application_id}} to recieve certs & do modification routines" | ||||
|   include_role: | ||||
|     name: nginx-https-get-cert-modify-all | ||||
|      | ||||
| - name: configure {{domain}}.conf | ||||
|   template:  | ||||
|     src:  "mastodon.conf.j2"  | ||||
|     dest: "{{nginx.directories.http.servers}}{{domain}}.conf" | ||||
|   notify: restart nginx | ||||
| @@ -3,13 +3,18 @@ | ||||
|   include_role:  | ||||
|     name: docker-central-database | ||||
|  | ||||
| - name: "include create-domains.yml for mastodon" | ||||
|   include_tasks: create-domains.yml | ||||
| - name: "Include setup for domain '{{ domain }}'" | ||||
|   include_role:  | ||||
|     name: nginx-domain-setup | ||||
|   loop: "{{ [domains.mastodon] + domains.mastodon_alternates }}" | ||||
|   loop_control: | ||||
|     loop_var: domain | ||||
|   vars: | ||||
|     http_port: "{{ ports.localhost.http[application_id] }}" | ||||
|     http_port:            "{{ ports.localhost.http[application_id] }}" | ||||
|     ws_path:              "/api/v1/streaming" | ||||
|     ws_port:              "{{ ports.localhost.websocket[application_id] }}" | ||||
|     client_max_body_size: "80m" | ||||
|     vhost_flavour:        "ws_generic" | ||||
|  | ||||
| - name: "copy docker-compose.yml and env file" | ||||
|   include_tasks: copy-docker-compose-and-env.yml | ||||
|   | ||||
| @@ -24,7 +24,7 @@ services: | ||||
|     healthcheck: | ||||
|       test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1'] | ||||
|     ports: | ||||
|       - "127.0.0.1:{{ports.localhost.web_socket[application_id]}}:4000" | ||||
|       - "127.0.0.1:{{ports.localhost.websocket[application_id]}}:4000" | ||||
| {% include 'templates/docker/container/depends-on-database-redis.yml.j2' %} | ||||
| {% include 'templates/docker/container/networks.yml.j2' %} | ||||
|  | ||||
|   | ||||
| @@ -12,5 +12,5 @@ server { | ||||
|     listen [::]:8448 ssl default_server; | ||||
|  | ||||
|     {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2'%} | ||||
|     {% include 'roles/nginx-docker-reverse-proxy/templates/proxy_pass.conf.j2' %} | ||||
|     {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
| } | ||||
| @@ -8,7 +8,7 @@ | ||||
|  | ||||
| - name: configure {{domains[application_id]}}.conf | ||||
|   template:  | ||||
|     src:  "roles/nginx-docker-reverse-proxy/templates/domain.conf.j2"  | ||||
|     src:  "roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2"  | ||||
|     dest: "{{nginx.directories.http.servers}}{{domains[application_id]}}.conf" | ||||
|   notify: restart nginx | ||||
|   vars:  | ||||
|   | ||||
| @@ -75,7 +75,7 @@ http { | ||||
|         add_header X-Robots-Tag                         "noindex, nofollow"     always; | ||||
|         add_header X-XSS-Protection                     "1; mode=block"         always; | ||||
|         add_header X-Frame-Options "SAMEORIGIN" always; | ||||
|         {% include 'roles/nginx-docker-reverse-proxy/templates/iframe.conf.j2' %} | ||||
|         {% include 'roles/nginx-docker-reverse-proxy/templates/headers/iframe.conf.j2' %} | ||||
|  | ||||
|         # Remove X-Powered-By, which is an information leak | ||||
|         fastcgi_hide_header X-Powered-By; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ server | ||||
|   client_body_buffer_size 400M; | ||||
|   fastcgi_buffers 64 4K; | ||||
|  | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/proxy_pass.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
|  | ||||
|   location ^~ /.well-known { | ||||
|     rewrite ^/\.well-known/host-meta\.json  /public.php?service=host-meta-json  last; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ nextcloud_system_config: | ||||
|     value: "{{ on_calendar_nextcloud }}" | ||||
|  | ||||
|   - parameter: "default_phone_region" | ||||
|     value: "{{ locale | upper }}" | ||||
|     value: "{{ HOST_LL | upper }}" | ||||
|  | ||||
|   - parameter: "trusted_domains 0" | ||||
|     value: "{{domains[application_id]}}" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ server { | ||||
|  | ||||
|   {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2'%} | ||||
|    | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/iframe.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/headers/iframe.conf.j2' %} | ||||
|    | ||||
|   ## | ||||
|   # Application | ||||
|   | ||||
| @@ -15,8 +15,8 @@ ENFORCE_EMAIL_VERIFICATION=false | ||||
| PF_MAX_USERS=1000 | ||||
| OAUTH_ENABLED=true | ||||
|  | ||||
| APP_TIMEZONE={{timezone}} | ||||
| APP_LOCALE={{locale}} | ||||
| APP_TIMEZONE={{ HOST_TIMEZONE }} | ||||
| APP_LOCALE={{ HOST_LL }} | ||||
|  | ||||
| ## Pixelfed Tweaks | ||||
| LIMIT_ACCOUNT_SIZE=true | ||||
| @@ -49,7 +49,7 @@ MAIL_DRIVER=log | ||||
| MAIL_HOST={{system_email.host}} | ||||
| MAIL_PORT={{system_email.port}} | ||||
| MAIL_FROM_ADDRESS="{{ users['no-reply'].email }}" | ||||
| MAIL_FROM_NAME="Pixelfed" | ||||
| MAIL_FROM_NAME={{ service_provider.company.titel }} - Pixelfed | ||||
| MAIL_USERNAME={{ users['no-reply'].email }} | ||||
| MAIL_PASSWORD={{ users['no-reply'].mailu_token }} | ||||
| # Not sure if the following is correct | ||||
|   | ||||
| @@ -7,8 +7,8 @@ APP_DEBUG={{enable_debug | string | lower }} | ||||
| APP_KEY={{applications.snipe_it.app_key}} | ||||
| APP_URL=https://{{domains[application_id]}} | ||||
| # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier | ||||
| APP_TIMEZONE='{{timezone}}' | ||||
| APP_LOCALE={{locale}} | ||||
| APP_TIMEZONE='{{ HOST_TIMEZONE }}' | ||||
| APP_LOCALE={{ HOST_LL }} | ||||
| MAX_RESULTS=500 | ||||
|  | ||||
| # -------------------------------------------- | ||||
| @@ -49,15 +49,15 @@ DB_SSL_VERIFY_SERVER=null | ||||
| # REQUIRED: OUTGOING MAIL SERVER SETTINGS | ||||
| # -------------------------------------------- | ||||
| MAIL_MAILER             =   smtp | ||||
| MAIL_HOST               =   {{system_email.host}}               # SMTP server address | ||||
| MAIL_PORT               =   {{system_email.port}}               # SMTP server address | ||||
| MAIL_USERNAME           =   {{ users['no-reply'].email }}           # user to connect the SMTP server | ||||
| MAIL_PASSWORD           =   {{ users['no-reply'].mailu_token }}           # SMTP user's password | ||||
| MAIL_TLS_VERIFY_PEER    =   {{ system_email.tls | capitalize }} # use TLS (secure) connection with the SMTP server | ||||
| MAIL_FROM_ADDR          =   {{ users['no-reply'].email }}               # default email address for the automated emails | ||||
| MAIL_FROM_NAME          =   'Snipe-IT' | ||||
| MAIL_REPLYTO_ADDR       =   {{ users['no-reply'].email }}               # default email address for the automated emails | ||||
| MAIL_REPLYTO_NAME       =   'Snipe-IT' | ||||
| MAIL_HOST               =   {{system_email.host}} | ||||
| MAIL_PORT               =   {{system_email.port}} | ||||
| MAIL_USERNAME           =   {{ users['no-reply'].email }} | ||||
| MAIL_PASSWORD           =   {{ users['no-reply'].mailu_token }} | ||||
| MAIL_TLS_VERIFY_PEER    =   {{ system_email.tls | capitalize }} | ||||
| MAIL_FROM_ADDR          =   {{ users['no-reply'].email }} | ||||
| MAIL_FROM_NAME          =   {{ service_provider.company.titel }} - Snipe-IT | ||||
| MAIL_REPLYTO_ADDR       =   {{ users['no-reply'].email }} | ||||
| MAIL_REPLYTO_NAME       =   {{ service_provider.company.titel }} - Snipe-IT | ||||
| MAIL_AUTO_EMBED_METHOD  =   'attachment' | ||||
|  | ||||
| # -------------------------------------------- | ||||
|   | ||||
| @@ -1,19 +1,31 @@ | ||||
| # role nginx-docker-reverse-proxy | ||||
| # Nginx Docker Reverse Proxy 🚀 | ||||
|  | ||||
| Uses nginx as an [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) for local docker applications. | ||||
| ## Description | ||||
|  | ||||
| ## debug | ||||
| ```bash | ||||
| curl -I {{address}} | ||||
| ``` | ||||
| - https://serverfault.com/questions/434915/nginx-proxy-caching-how-to-check-if-it-is-working | ||||
| This Ansible role deploys **Nginx** as a high-performance [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) in front of Docker-hosted services.   | ||||
| It provides automatic TLS integration, WebSocket support, and a flexible templating system for per-application configuration. | ||||
|  | ||||
| ## performance | ||||
| - https://stackoverflow.com/questions/33703230/caching-images-on-all-folder-levels-of-nginx-reverse-proxy | ||||
| - https://www.tweaked.io/guide/nginx-proxying/ | ||||
| - https://serverfault.com/questions/796735/nginx-reverse-proxy-is-slow/796740 | ||||
| - https://serverfault.com/questions/741610/what-is-the-difference-between-proxy-request-buffering-and-proxy-buffering-on-ng | ||||
| - https://askubuntu.com/questions/1103626/should-i-enable-client-max-body-size-proxy-request-buffering-and-proxy-bufferin | ||||
| - https://serverfault.com/questions/692577/whats-the-difference-between-proxy-buffer-and-proxy-cache-module-in-nginx-confi | ||||
| - https://github.com/sissbruecker/linkding/issues/88 | ||||
| - https://www.bogotobogo.com/DevOps/Docker/docker/compose/Nginx-Reverse-Proxy-Multiple-Containers.php | ||||
| ## Overview | ||||
|  | ||||
| Optimised for Arch Linux, the role installs Nginx, prepares opinionated configuration snippets and exposes a simple interface for other roles to drop in new virtual-hosts.   | ||||
| It plays well with **Let’s Encrypt**, **OAuth2 Proxy**, and your existing Docker stack. | ||||
|  | ||||
| ## Purpose | ||||
|  | ||||
| The goal of this role is to deliver a **hassle-free, production-ready reverse proxy** for self-hosted containers, suitable for homelabs and small-scale production workloads. | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - **Automatic TLS & HSTS** — integrates with the *nginx-https* role for certificate management.   | ||||
| - **Flexible vHost templates** — *basic* and *ws_generic* flavours cover standard HTTP and WebSocket applications.   | ||||
| - **Security headers** — sensible defaults plus optional X-Frame-Options / CSP based on application settings.   | ||||
| - **WebSocket & HTTP/2 aware** — upgrades, keep-alive tuning, and gzip already configured.   | ||||
| - **OAuth2 gating** — drop-in support when *docker-oauth2-proxy* is present.   | ||||
| - **Modular includes** — headers, locations, and global snippets are factored for easy extension. | ||||
|  | ||||
| ## Credits 📝 | ||||
|  | ||||
| Developed and maintained by **Kevin Veen-Birkenbach**.   | ||||
| More at <https://www.veen.world> | ||||
|  | ||||
| Part of the **CyMaIS Project** — licensed under the [CyMaIS NonCommercial License (CNCL)](https://s.veen.world/cncl) | ||||
|   | ||||
| @@ -1,3 +1,28 @@ | ||||
| --- | ||||
| galaxy_info: | ||||
|   author: "Kevin Veen-Birkenbach" | ||||
|   description: "Nginx reverse proxy front-end for local Docker applications." | ||||
|   license: "CyMaIS NonCommercial License (CNCL)" | ||||
|   license_url: "https://s.veen.world/cncl" | ||||
|   company: | | ||||
|     Kevin Veen-Birkenbach | ||||
|     Consulting & Coaching Solutions | ||||
|     https://www.veen.world | ||||
|   min_ansible_version: "2.9" | ||||
|   platforms: | ||||
|     - name: Archlinux | ||||
|       versions: | ||||
|         - rolling | ||||
|   galaxy_tags: | ||||
|     - nginx | ||||
|     - docker | ||||
|     - reverse_proxy | ||||
|     - web | ||||
|     - automation | ||||
|     - archlinux | ||||
|   repository: https://s.veen.world/cymais | ||||
|   issue_tracker_url: https://s.veen.world/cymaisissues | ||||
|   documentation: https://s.veen.world/cymais | ||||
| dependencies: | ||||
| - docker | ||||
| - nginx-https | ||||
|   - role: docker | ||||
|   - role: nginx-https | ||||
| @@ -14,7 +14,7 @@ location {{location | default("/")}} | ||||
|   proxy_set_header X-Forwarded-Port 443; | ||||
|   proxy_set_header Accept-Encoding ""; | ||||
| 
 | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/iframe.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/headers/iframe.conf.j2' %} | ||||
| 
 | ||||
|   # WebSocket specific header | ||||
|   proxy_http_version 1.1; | ||||
| @@ -18,18 +18,18 @@ server | ||||
|   {% if applications | get_oauth2_enabled(application_id) %} | ||||
|     {% if applications[application_id].oauth2_proxy.location is defined %} | ||||
|       {# Exposed and Unprotected Location #} | ||||
|       {% include 'proxy_pass.conf.j2' %} | ||||
|       {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
|       {% set oauth2_proxy_enabled = true %} | ||||
|       {% set location = applications[application_id].oauth2_proxy.location %} | ||||
|       {# Gated Location by OAuth2 Proxy #} | ||||
|       {% include 'proxy_pass.conf.j2' %} | ||||
|       {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
|     {% else %} | ||||
|       {% set oauth2_proxy_enabled = true %} | ||||
|       {# Protected Domain by OAuth2 Proxy #} | ||||
|       {% include 'proxy_pass.conf.j2'%} | ||||
|       {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2'%} | ||||
|     {% endif %} | ||||
|   {% else %} | ||||
|     {# Exposed Domain - Not protected by OAuth2 Proxy #} | ||||
|     {% include 'proxy_pass.conf.j2' %} | ||||
|     {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
|   {% endif %} | ||||
| } | ||||
| @@ -4,15 +4,14 @@ map $http_upgrade $connection_upgrade { | ||||
| } | ||||
| 
 | ||||
| server { | ||||
|   server_name {{domain}}; | ||||
|   server_name {{ domain }}; | ||||
| 
 | ||||
|   {% include 'roles/letsencrypt/templates/ssl_header.j2' %} | ||||
|   {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2' %} | ||||
| 
 | ||||
|   {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2'%} | ||||
| 
 | ||||
|   client_max_body_size {{ client_max_body_size | default('100m') }}; | ||||
|   keepalive_timeout    70; | ||||
|   sendfile             on; | ||||
|   client_max_body_size 80m; | ||||
| 
 | ||||
|   gzip on; | ||||
|   gzip_disable "msie6"; | ||||
| @@ -25,24 +24,23 @@ server { | ||||
| 
 | ||||
|   add_header Strict-Transport-Security "max-age=31536000"; | ||||
| 
 | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/proxy_pass.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} | ||||
| 
 | ||||
|   location /api/v1/streaming { | ||||
|     proxy_set_header Host $host; | ||||
|     proxy_set_header X-Real-IP $remote_addr; | ||||
|     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||
|   {% if ws_path is defined %} | ||||
|     location {{ ws_path }} { | ||||
|     proxy_set_header Host              $host; | ||||
|     proxy_set_header X-Real-IP         $remote_addr; | ||||
|     proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for; | ||||
|     proxy_set_header X-Forwarded-Proto https; | ||||
|     proxy_set_header Proxy ""; | ||||
| 
 | ||||
|     proxy_pass http://127.0.0.1:{{ports.localhost.web_socket[application_id]}}; | ||||
|     proxy_buffering off; | ||||
|     proxy_redirect off; | ||||
|     proxy_http_version 1.1; | ||||
|     proxy_set_header Upgrade $http_upgrade; | ||||
|     proxy_set_header Connection $connection_upgrade; | ||||
| 
 | ||||
|     tcp_nodelay on; | ||||
|     proxy_pass           http://127.0.0.1:{{ ws_port }}; | ||||
|     proxy_buffering      off; | ||||
|     proxy_http_version   1.1; | ||||
|     proxy_set_header     Upgrade        $http_upgrade; | ||||
|     proxy_set_header     Connection     $connection_upgrade; | ||||
|     tcp_nodelay          on; | ||||
|   } | ||||
|   {% endif %} | ||||
| 
 | ||||
|   error_page 500 501 502 503 504 /500.html; | ||||
| } | ||||
| @@ -1,16 +1,35 @@ | ||||
| # Nginx Domain Setup Role 🚀 | ||||
| # Nginx Domain Setup 🚀 | ||||
|  | ||||
| This role streamlines your Nginx configuration by performing several essential tasks: | ||||
| ## Description | ||||
|  | ||||
| - **Modify Nginx configuration** with the `nginx-modifier-all` role. | ||||
| - **Request and receive HTTPS certificates** using the `nginx-https-get-cert` role. | ||||
| - **Deploy a domain configuration file** from a Jinja2 template. | ||||
| - **Optionally secure your domain** with OAuth2 via the `docker-oauth2-proxy` role if enabled. | ||||
| This role bootstraps **per-domain Nginx configuration**: it requests TLS certificates, applies global modifiers, deploys a ready-made vHost file, and can optionally lock down access via OAuth2. | ||||
|  | ||||
| ## Author | ||||
| ## Overview | ||||
|  | ||||
| Developed by [Kevin Veen-Birkenbach](https://www.veen.world) 😎 | ||||
| A higher-level orchestration wrapper, *nginx-domain-setup* ties together several lower-level roles: | ||||
|  | ||||
| --- | ||||
| 1. **`nginx-modifier-all`** – applies global tweaks and includes.   | ||||
| 2. **`nginx-https-get-cert`** – obtains Let’s Encrypt certificates.   | ||||
| 3. **Domain template deployment** – copies a Jinja2 vHost from *nginx-docker-reverse-proxy*.   | ||||
| 4. **`docker-oauth2-proxy`** *(optional)* – protects the site with OAuth2. | ||||
|  | ||||
| Happy automating! 🎉 | ||||
| The result is a complete, reproducible domain rollout in a single playbook task. | ||||
|  | ||||
| ## Purpose | ||||
|  | ||||
| Provide **one-stop, idempotent domain provisioning** for Nginx-based homelabs or small production environments. | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - **End-to-end TLS** — certificate retrieval and secure headers included.   | ||||
| - **Template-driven vHosts** — choose *basic* or *ws_generic* flavours (or your own).   | ||||
| - **Conditional OAuth2** — easily toggle authentication per application.   | ||||
| - **Handler-safe** — automatically triggers an Nginx reload when templates change.   | ||||
| - **Composable** — designed to be called repeatedly for many domains. | ||||
|  | ||||
| ## Credits 📝 | ||||
|  | ||||
| Developed and maintained by **Kevin Veen-Birkenbach**.   | ||||
| Learn more at <https://www.veen.world> | ||||
|  | ||||
| Part of the **CyMaIS Project** — licensed under the [CyMaIS NonCommercial License (CNCL)](https://s.veen.world/cncl) | ||||
							
								
								
									
										5
									
								
								roles/nginx-domain-setup/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/nginx-domain-setup/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # default vhost flavour | ||||
| vhost_flavour:        "basic"               # valid: basic | ws_generic | ||||
|  | ||||
| # build the full template path from the flavour | ||||
| vhost_template_src:   "roles/nginx-docker-reverse-proxy/templates/vhost/{{ vhost_flavour }}.conf.j2" | ||||
							
								
								
									
										25
									
								
								roles/nginx-domain-setup/meta/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								roles/nginx-domain-setup/meta/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| --- | ||||
| galaxy_info: | ||||
|   author: "Kevin Veen-Birkenbach" | ||||
|   description: "Automated domain provisioning (TLS, vHost, OAuth2) for Nginx." | ||||
|   license: "CyMaIS NonCommercial License (CNCL)" | ||||
|   license_url: "https://s.veen.world/cncl" | ||||
|   company: | | ||||
|     Kevin Veen-Birkenbach | ||||
|     Consulting & Coaching Solutions | ||||
|     https://www.veen.world | ||||
|   min_ansible_version: "2.9" | ||||
|   platforms: | ||||
|     - name: Archlinux | ||||
|       versions: | ||||
|         - rolling | ||||
|   galaxy_tags: | ||||
|     - nginx | ||||
|     - tls | ||||
|     - letsencrypt | ||||
|     - oauth2 | ||||
|     - automation | ||||
|     - archlinux | ||||
|   repository: https://s.veen.world/cymais | ||||
|   issue_tracker_url: https://s.veen.world/cymaisissues | ||||
|   documentation: https://s.veen.world/cymais | ||||
| @@ -2,10 +2,10 @@ | ||||
|   include_role: | ||||
|     name: nginx-https-get-cert-modify-all | ||||
|      | ||||
| - name: "copy nginx domain configuration to {{configuration_destination}}" | ||||
|   template:  | ||||
|     src:  "roles/nginx-docker-reverse-proxy/templates/domain.conf.j2"  | ||||
|     dest: "{{configuration_destination}}" | ||||
| - name: "copy nginx domain configuration to {{ configuration_destination }}" | ||||
|   template: | ||||
|     src:  "{{ vhost_template_src }}" | ||||
|     dest: "{{ configuration_destination }}" | ||||
|   notify: restart nginx | ||||
|    | ||||
| - name: "include the docker-oauth2-proxy role {{domain}}" | ||||
|   | ||||
| @@ -1193,4 +1193,9 @@ input.ng-empty::placeholder,.ng-empty::placeholder  { | ||||
|  | ||||
| .kanban-swimlane-title { | ||||
|     border-bottom: none; | ||||
| } | ||||
|  | ||||
| .navbar-toggler { | ||||
|     background-color:   rgba(var(--color-rgb-01-75), 0.9); | ||||
|     border-color:       var(--color-01-67) | ||||
| } | ||||
| @@ -6,7 +6,7 @@ server | ||||
|  | ||||
|   {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2'%} | ||||
|  | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/iframe.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/headers/iframe.conf.j2' %} | ||||
|   charset utf-8; | ||||
|    | ||||
|   location / | ||||
|   | ||||
| @@ -6,7 +6,7 @@ server | ||||
|  | ||||
|   {% include 'roles/nginx-modifier-all/templates/global.includes.conf.j2'%} | ||||
|  | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/iframe.conf.j2' %} | ||||
|   {% include 'roles/nginx-docker-reverse-proxy/templates/headers/iframe.conf.j2' %} | ||||
|   charset utf-8; | ||||
|    | ||||
|   location / | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="{{ locale }}"> | ||||
| <html lang="{{ HOST_LL }}"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| --- | ||||
| - name: install nginx | ||||
|   pacman: | ||||
|     name:   nginx | ||||
|     name: | ||||
|       - nginx | ||||
|       - nginx-mod-stream # Enable Stream support | ||||
|     state:  present | ||||
|   notify: restart nginx | ||||
|   when: run_once_nginx is not defined | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| load_module /usr/lib/nginx/modules/ngx_stream_module.so; # Enable Stream support | ||||
| worker_processes auto; | ||||
|  | ||||
| events | ||||
|   | ||||
| @@ -216,6 +216,11 @@ | ||||
|   include_role: | ||||
|     name: docker-presentation | ||||
|  | ||||
| - name: setup espocrm hosts | ||||
|   when: ("espocrm" in group_names) | ||||
|   include_role: | ||||
|     name: docker-espocrm | ||||
|  | ||||
| # Native Webserver Roles | ||||
| - name: setup nginx-serve-htmls | ||||
|   when: ("nginx-serve-htmls" in group_names) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ networks: | ||||
|   central_{{ database_type }}: | ||||
|     external: true | ||||
| {% endif %} | ||||
| {% if applications[application_id].get('features', {}).get('ldap', false) | bool and applications.ldap.network.local | bool %} | ||||
| {% if applications[application_id].get('features', {}).get('ldap', false) | bool and applications.ldap.network.docker | bool %} | ||||
|   central_ldap: | ||||
|     external: true | ||||
| {% endif %} | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| {% if applications | get_database_central_storage(application_id) | bool and database_type is defined %} | ||||
|       central_{{ database_type }}: | ||||
| {% endif %} | ||||
| {% if applications[application_id].get('features', {}).get('ldap', false) | bool and applications.ldap.network.local|bool %} | ||||
| {% if applications[application_id].get('features', {}).get('ldap', false) | bool and applications.ldap.network.docker|bool %} | ||||
|       central_ldap: | ||||
| {% endif %} | ||||
|       default: | ||||
|   | ||||
| @@ -126,6 +126,30 @@ defaults_applications: | ||||
|   'database': true, | ||||
| }) }}{% raw %} | ||||
|  | ||||
|   ## EspoCRM | ||||
|   espocrm: | ||||
|     version:                      "fpm-alpine" | ||||
|     users: | ||||
|       administrator: | ||||
|         username:                 "{{ users.administrator.username }}" | ||||
|         email:                    "{{ users.administrator.email }}" | ||||
|  | ||||
|     credentials: | ||||
|       administrator: | ||||
|         password:                 "{{ users.administrator.password }}" | ||||
|       database: | ||||
|         # password:                # Set in your inventory file | ||||
|  | ||||
| {% endraw %}{{ features.render_features({ | ||||
|   'matomo':   true, | ||||
|   'css':      true, | ||||
|   'iframe':   false, | ||||
|   'ldap':     true, | ||||
|   'oidc':     true, | ||||
|   'database': true | ||||
| }) }}{% raw %} | ||||
|  | ||||
|  | ||||
|   ## File Server | ||||
|   file_server: | ||||
| {% endraw %}{{ features.render_features({ | ||||
| @@ -249,7 +273,8 @@ defaults_applications: | ||||
|   ldap: | ||||
|     version:                        "latest" | ||||
|     network: | ||||
|       local:                        True                                        # Activates local network to allow other docker containers to connect | ||||
|       local:                        True                                        # Activates local network. Necessary for LDIF import routines | ||||
|       docker:                       True                                        # Activates docker network to allow other docker containers to connect | ||||
|       public:                       False                                       # Set to true in inventory file if you want to expose the LDAP port to the internet | ||||
|     hostname:                       "ldap"                                      # Hostname of the LDAP Server in the central_ldap network | ||||
|     webinterface:                   "lam"                                       # The webinterface which should be used. Possible: lam and phpldapadmin | ||||
| @@ -258,7 +283,6 @@ defaults_applications: | ||||
|         username:                   "{{users.administrator.username}}"          # Administrator username | ||||
|     # administrator_password:                                                   # CHANGE for security reasons in inventory file | ||||
|     # administrator_database_password:                                          # CHANGE for security reasons in inventory file | ||||
|     force_import:                   False                                       # Forces the import of the LDIF files | ||||
| {% endraw %}{{ features.render_features({ | ||||
|   'ldap':     true, | ||||
| }) }}{% raw %} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user