created role to configure multiple apache sites, using ansibleguy.infra_certs role to generate certificates
This commit is contained in:
		
							parent
							
								
									4875e6ef1f
								
							
						
					
					
						commit
						b0f520c8b5
					
				
							
								
								
									
										104
									
								
								README.md
								
								
								
								
							
							
						
						
									
										104
									
								
								README.md
								
								
								
								
							|  | @ -1,4 +1,4 @@ | ||||||
| # Apache2 Ansible Role | # Apache2 Role | ||||||
| Ansible role to install apache2 sites on the target server. | Ansible role to install apache2 sites on the target server. | ||||||
| 
 | 
 | ||||||
| **Tested:** | **Tested:** | ||||||
|  | @ -6,17 +6,44 @@ Ansible role to install apache2 sites on the target server. | ||||||
| 
 | 
 | ||||||
| ## Functionality | ## Functionality | ||||||
| 
 | 
 | ||||||
| * Package installation | * **Package installation** | ||||||
|   * Ansible dependencies (_minimal_) |   * Ansible dependencies (_minimal_) | ||||||
|   * Apache2 |   * Apache2 | ||||||
| * Configuration | 
 | ||||||
|   *  | 
 | ||||||
|   * Default opt-in: | * **Configuration** | ||||||
|     *  |   * Support for multiple sites/servers | ||||||
|   * Default opt-outs: |   * Two **config-modes**: | ||||||
|     *  |     * serve (_default_) | ||||||
|   * Default config: |     * redirect | ||||||
|     *  | 
 | ||||||
|  | 
 | ||||||
|  |   * **Default config**: | ||||||
|  |     * Disabled: <TLS1.2, unsecure ciphers, autoindex, servertokens/-signature, ServerSideIncludes, CGI | ||||||
|  |     * Security headers: HSTS, X-Frame, Referrer-Policy, Content-Type nosniff, X-Domain-Policy, XXS-Protection | ||||||
|  |     * Limits to prevent DDoS | ||||||
|  |     * Logging to syslog | ||||||
|  |     * Using a Self-Signed certificate | ||||||
|  |     * Modules: +ssl, headers, rewrite; -autoindex | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   * **SSL modes** (_for more info see: [CERT ROLE](https://github.com/ansibleguy/infra_certs)_) | ||||||
|  |     * **selfsigned** => Generate self-signed ones | ||||||
|  |     * **ca** => Generate a minimal Certificate Authority and certificate signed by it | ||||||
|  |     * **letsencrypt** => Uses the LetsEncrypt certbot | ||||||
|  |     * **existing** => Copy certificate files or use existing ones | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   * **Default opt-ins**: | ||||||
|  |     * restricting methods to POST/GET/HEAD | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   * **Default opt-outs**: | ||||||
|  |     * Include the config file 'site_{{ site_name }}_app.conf' for advanced usage | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Options to provide module config will be added in the future!<br> | ||||||
|  | Also some basic mods will get a pre-config added. (_prefork, evasive_) | ||||||
| 
 | 
 | ||||||
| ## Info | ## Info | ||||||
| 
 | 
 | ||||||
|  | @ -25,24 +52,65 @@ Ansible role to install apache2 sites on the target server. | ||||||
| 
 | 
 | ||||||
| * **Note:** this role currently only supports debian-based systems | * **Note:** this role currently only supports debian-based systems | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | * **Note:** This role expects that the site's unencrypted 'server' will only redirect to its encrypted connection. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | * **Note:** If you want all domain-names to get 'caught' by a site/server you need to add an underline '*' as alias or domain!<br> | ||||||
|  | This will also be done automatically if no domain is supplied. | ||||||
|  | 
 | ||||||
| ## Requirements | ## Requirements | ||||||
| 
 | 
 | ||||||
| * Community collection: ```ansible-galaxy install -r requirements.yml``` | * Community collection and certificate role: ```ansible-galaxy install -r requirements.yml``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## Usage | ## Usage | ||||||
|  | 
 | ||||||
|  | ### Config | ||||||
|  | 
 | ||||||
|  | Define the apache dictionary as needed! | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  | apache: | ||||||
|  |   headers: | ||||||
|  |     mySuperCustom: 'headerContent' | ||||||
|  | 
 | ||||||
|  |   modules: | ||||||
|  |     present: ['evasive'] | ||||||
|  | 
 | ||||||
|  |   guys_statics: | ||||||
|  |     mode: 'serve' | ||||||
|  |     domain: 'static.guy.net' | ||||||
|  |     serve: | ||||||
|  |       path: '/var/www/static' | ||||||
|  | 
 | ||||||
|  |     ssl: | ||||||
|  |       mode: 'ca'  # create minimal ca with signed server-certificate | ||||||
|  | 
 | ||||||
|  |     config: | ||||||
|  |       KeepAliveTimeout: 10 | ||||||
|  | 
 | ||||||
|  |   git_stuff: | ||||||
|  |     mode: 'redirect' | ||||||
|  |     domain: 'ansibleguy.net' | ||||||
|  |     aliases: ['www.ansibleguy.net'] | ||||||
|  |     redirect: | ||||||
|  |       target: 'https://github.com/ansibleguy' | ||||||
|  | 
 | ||||||
|  |     ssl: | ||||||
|  |       mode: 'letsencrypt' | ||||||
|  | 
 | ||||||
|  |     letsencrypt: | ||||||
|  |       email: 'apache@template.ansibleguy.net' | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Execution | ||||||
|  | 
 | ||||||
| Run the playbook: | Run the playbook: | ||||||
| ```bash | ```bash | ||||||
| ansible-playbook -K -D -i inventory/hosts.yml playbook.yml | ansible-playbook -K -D -i inventory/hosts.yml playbook.yml | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| You need to define your instances by configuring the 'mariadb' dictionary! |  | ||||||
| 
 |  | ||||||
| ```yaml |  | ||||||
| apache |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| There are also some useful **tags** available: | There are also some useful **tags** available: | ||||||
| * base => only configure basics; sites will not be touched | * base => only configure basics; sites will not be touched | ||||||
| * sites | * sites | ||||||
|  |  | ||||||
|  | @ -21,10 +21,13 @@ default_apache: | ||||||
|   user: 'www-data' |   user: 'www-data' | ||||||
|   group: 'www-data' |   group: 'www-data' | ||||||
| 
 | 
 | ||||||
|   # additions to the main apache config |   settings: | ||||||
|   config:  # see: https://httpd.apache.org/docs/2.4/mod/core.html |     # setting to be set in apache2.conf | ||||||
|     ServerTokens: 'Prod' |     ServerTokens: 'Prod' | ||||||
|     ServerSignature: 'Off' |     ServerSignature: 'Off' | ||||||
|  | 
 | ||||||
|  |   # additions to the main apache config | ||||||
|  |   config:  # see: https://httpd.apache.org/docs/2.4/mod/core.html | ||||||
|     FileETag: 'None' |     FileETag: 'None' | ||||||
|     KeepAlive: 'On' |     KeepAlive: 'On' | ||||||
|     KeepAliveTimeout: 5 |     KeepAliveTimeout: 5 | ||||||
|  | @ -45,6 +48,7 @@ default_apache: | ||||||
|     SSLCompression: 'off' |     SSLCompression: 'off' | ||||||
| 
 | 
 | ||||||
|   headers:  # https://htaccessbook.com/important-security-headers/ | https://geekflare.com/http-header-implementation/ |   headers:  # https://htaccessbook.com/important-security-headers/ | https://geekflare.com/http-header-implementation/ | ||||||
|  |     # if first key does not include 'Header' => prepend 'Header set' | ||||||
|     'Header always set Strict-Transport-Security': '"max-age=31536000; includeSubDomains; preload"' |     'Header always set Strict-Transport-Security': '"max-age=31536000; includeSubDomains; preload"' | ||||||
|     'Referrer-Policy': '"same-origin"' |     'Referrer-Policy': '"same-origin"' | ||||||
|     'Content-Security-Policy': "\"default-src 'self';\"" |     'Content-Security-Policy': "\"default-src 'self';\"" | ||||||
|  | @ -56,6 +60,18 @@ default_apache: | ||||||
|     # 'Header set Permissions-Policy': '"none"' |     # 'Header set Permissions-Policy': '"none"' | ||||||
|     # 'Header set Content-Security-Policy': '"default-src https:; font-src https:; img-src https:; script-src https:; style-src https:;"' |     # 'Header set Content-Security-Policy': '"default-src https:; font-src https:; img-src https:; script-src https:; style-src https:;"' | ||||||
| 
 | 
 | ||||||
|  |   ssl: | ||||||
|  |     path: '/etc/apache2/ssl' | ||||||
|  |     ca: | ||||||
|  |       file:  # can be used if you want to use an existing ca | ||||||
|  |       cn: 'Apache CA Certificate' | ||||||
|  |       org: 'AnsibleGuy' | ||||||
|  |       ou: | ||||||
|  |       country: | ||||||
|  |       state: | ||||||
|  |       locality: | ||||||
|  |       email: | ||||||
|  |       pwd:  # it's highly recommended setting a passphrase! | ||||||
| 
 | 
 | ||||||
|   modules: |   modules: | ||||||
|     present: ['ssl', 'headers', 'rewrite'] |     present: ['ssl', 'headers', 'rewrite'] | ||||||
|  | @ -64,28 +80,32 @@ default_apache: | ||||||
|   letsencrypt: |   letsencrypt: | ||||||
|     key_size: 4096 |     key_size: 4096 | ||||||
|     path: '/etc/letsencrypt' |     path: '/etc/letsencrypt' | ||||||
|     path_key: '/etc/ssl/private' |     renew_timer: 'Mon *-*-* 03:00:00' | ||||||
|     path_cert: '/etc/ssl/certs' |  | ||||||
|     renew_timer: 'Mon *-*-* 00:00:00' |  | ||||||
|     verbosity: 'v' |     verbosity: 'v' | ||||||
|  |     email: | ||||||
|  |     renew: false  # if a renewal should be started by the role; the renewal service will auto-renew the certificates otherwise | ||||||
| 
 | 
 | ||||||
| APACHE_CONFIG: "{{ default_apache | combine(apache, recursive=true) }}" | APACHE_CONFIG: "{{ default_apache | combine(apache, recursive=true) }}" | ||||||
| 
 | 
 | ||||||
| # site-specific config | # site-specific config | ||||||
| default_site_config: | default_site_config: | ||||||
|   mode: 'serve' |   mode: 'serve' | ||||||
|  |   state: 'present' | ||||||
|   admin: 'apache@template.ansibleguy.net' |   admin: 'apache@template.ansibleguy.net' | ||||||
|   port_plain: 80 |   port_plain: 80 | ||||||
|   port_ssl: 443 |   port_ssl: 443 | ||||||
|  |   aliases: [] | ||||||
|  |   ip: | ||||||
| 
 | 
 | ||||||
|   config: {}  # site-specific setting-value pairs |   config: {}  # site-specific setting-value pairs | ||||||
|   config_additions: []  # lines that will 1-to-1 be appended to the site-config |   config_additions: []  # lines that will 1-to-1 be appended to the site-config | ||||||
|  |   app_include: false | ||||||
|  |   headers: {} | ||||||
| 
 | 
 | ||||||
|   security:  # https://www.nixpal.com/apache-httpd-hardening/ |   security:  # https://www.nixpal.com/apache-httpd-hardening/ | ||||||
|     disable_root_index: true |     disable_root_index: true | ||||||
|     disable_directory_access: true |  | ||||||
|     disable_ssi_cgi: true |     disable_ssi_cgi: true | ||||||
|     limit_directory_access: true |     restrict_methods: true | ||||||
| 
 | 
 | ||||||
|   redirect: |   redirect: | ||||||
|     target: 'https://github.com/ansibleguy' |     target: 'https://github.com/ansibleguy' | ||||||
|  | @ -95,16 +115,37 @@ default_site_config: | ||||||
|     path: '/var/www/html' |     path: '/var/www/html' | ||||||
| 
 | 
 | ||||||
|   ssl: |   ssl: | ||||||
|     mode: 'letsencrypt'  # local/selfsigned/letsencrypt |     mode: 'selfsigned'  # existing/selfsigned/ca/letsencrypt | ||||||
|     file_pub: '/etc/apache2/ssl/DOMAIN.crt'  # should use the certificate chain => top is server cert; bottom root cert |     # existing: | ||||||
|     file_key: '/etc/apache2/ssl/DOMAIN.key' |     #   We expect the certs to be placed in the role's 'files' directory named like the site | ||||||
|     file_csr: '/etc/apache2/ssl/DOMAIN.csr' |     #   Example: files/certs/ansibleguy.key and files/certs/ansibleguy.crt | ||||||
|     file_ca: |     # letsencrypt: | ||||||
|     csr_data: |     #   Host needs to have a valid public dns record pointed at it | ||||||
|       country: 'AT' |     #   Needs to be publicly reachable over port 80/tcp | ||||||
|       org: 'AnsibleGuy' |     cert: | ||||||
|       email: 'apache@template.ansibleguy.net' |       name: | ||||||
|       cn: 'Apache Certificate' |       cn: 'Apache Certificate' | ||||||
|  |       org: 'AnsibleGuy' | ||||||
|  |       ou: | ||||||
|  |       country: | ||||||
|  |       state: | ||||||
|  |       locality: | ||||||
|  |       email: | ||||||
|  |       crl_distribution: [] | ||||||
|  |     ca: | ||||||
|  |       file:  # can be used if you want to use an existing ca | ||||||
|  |       cn: | ||||||
|  |       org: | ||||||
|  |       ou: | ||||||
|  |       country: | ||||||
|  |       state: | ||||||
|  |       locality: | ||||||
|  |       email: | ||||||
|  |       pwd:  # it's highly recommended setting a passphrase! | ||||||
|  | 
 | ||||||
|  |   letsencrypt: | ||||||
|  |     key_size: | ||||||
|  |     email: | ||||||
| 
 | 
 | ||||||
| default_modules: | default_modules: | ||||||
|   # <IfModule ${MOD}> |   # <IfModule ${MOD}> | ||||||
|  | @ -137,10 +178,6 @@ default_modules: | ||||||
| 
 | 
 | ||||||
| APACHE_MODULES: "{{ default_modules | combine(modules, recursive=true) }}" | APACHE_MODULES: "{{ default_modules | combine(modules, recursive=true) }}" | ||||||
| 
 | 
 | ||||||
| packages: |  | ||||||
|   apache: ['apache2'] |  | ||||||
|   letsencrypt: ['python3-certbot-apache'] |  | ||||||
| 
 |  | ||||||
| apache_config_graylist: [ | apache_config_graylist: [ | ||||||
|     'SSLEngine', 'SSLCertificateKeyFile', 'SSLCertificateFile', 'SSLCertificateChainFile', 'ErrorLog', 'CustomLog', 'ServerAdmin', |     'SSLEngine', 'SSLCertificateKeyFile', 'SSLCertificateFile', 'SSLCertificateChainFile', 'ErrorLog', 'CustomLog', 'ServerAdmin', | ||||||
|     'ServerAlias', 'ServerName', 'Redirect' |     'ServerAlias', 'ServerName', 'Redirect' | ||||||
|  |  | ||||||
|  | @ -7,12 +7,26 @@ class FilterModule(object): | ||||||
|         return { |         return { | ||||||
|             "safe_key": self.safe_key, |             "safe_key": self.safe_key, | ||||||
|             "all_true": self.all_true, |             "all_true": self.all_true, | ||||||
|  |             "prepare_letsencrypt": self.prepare_letsencrypt, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def safe_key(key: str) -> str: |     def safe_key(key: str) -> str: | ||||||
|         return regex_replace('[^0-9a-zA-Z]+', '', key.replace(' ', '_')) |         return regex_replace(r'[^0-9a-zA-Z\.]+', '', key.replace(' ', '_')) | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def all_true(data: list) -> bool: |     def all_true(data: list) -> bool: | ||||||
|         return all(data) |         return all(data) | ||||||
|  | 
 | ||||||
|  |     @staticmethod | ||||||
|  |     def prepare_letsencrypt(site: dict, name: str) -> dict: | ||||||
|  |         domains = [site['domain']] | ||||||
|  |         domains.extend(site['aliases']) | ||||||
|  |         return { | ||||||
|  |             name: { | ||||||
|  |                 'domains': domains, | ||||||
|  |                 'key_size': site['letsencrypt']['key_size'], | ||||||
|  |                 'email': site['letsencrypt']['email'], | ||||||
|  |                 'state': site['state'], | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | @ -7,3 +7,8 @@ collections: | ||||||
| 
 | 
 | ||||||
|   - name: 'community.general' |   - name: 'community.general' | ||||||
|     source: 'https://galaxy.ansible.com' |     source: 'https://galaxy.ansible.com' | ||||||
|  | 
 | ||||||
|  | roles: | ||||||
|  |   - src: 'https://github.com/ansibleguy/infra_certs.git' | ||||||
|  |     version: 'stable' | ||||||
|  |     name: 'ansibleguy.infra_certs' | ||||||
|  |  | ||||||
|  | @ -0,0 +1,67 @@ | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Certs | Creating public directory" | ||||||
|  |   ansible.builtin.file: | ||||||
|  |     path: "{{ APACHE_CONFIG.ssl.path }}" | ||||||
|  |     state: directory | ||||||
|  |     mode: 0755 | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Certs | Creating certificates" | ||||||
|  |   ansible.builtin.import_role: | ||||||
|  |     name: ansibleguy.infra_certs | ||||||
|  |   vars: | ||||||
|  |     certs: | ||||||
|  |       mode: "{{ site.ssl.mode }}" | ||||||
|  |       path: "{{ APACHE_CONFIG.ssl.path }}" | ||||||
|  |       owner_key: "{{ APACHE_CONFIG.user }}" | ||||||
|  |       group_key: "{{ APACHE_CONFIG.group }}" | ||||||
|  |       owner_cert: "{{ APACHE_CONFIG.user }}" | ||||||
|  |       group_cert: "{{ APACHE_CONFIG.group }}" | ||||||
|  |       cert: | ||||||
|  |         name: "{{ name }}" | ||||||
|  |         cn: "{{ site.ssl.cert.cn }}" | ||||||
|  |         org: "{{ site.ssl.cert.org }}" | ||||||
|  |         ou: "{{ site.ssl.cert.ou }}" | ||||||
|  |         country: "{{ site.ssl.cert.country }}" | ||||||
|  |         state: "{{ site.ssl.cert.state }}" | ||||||
|  |         locality: "{{ site.ssl.cert.locality }}" | ||||||
|  |         email: "{{ site.ssl.cert.email }}" | ||||||
|  |         crl_distribution: "{{ site.ssl.cert.crl_distribution }}" | ||||||
|  |         domains: "{{ site.aliases + [site.domain] }}" | ||||||
|  |         ips: ["{{ site.ip }}"] | ||||||
|  |       ca: | ||||||
|  |         path: "{{ APACHE_CONFIG.ssl.path }}" | ||||||
|  |         cn: "{{ site.ssl.ca.cn | default(APACHE_CONFIG.ssl.ca.cn, true) }}" | ||||||
|  |         org: "{{ site.ssl.ca.org | default(APACHE_CONFIG.ssl.ca.org, true) }}" | ||||||
|  |         ou: "{{ site.ssl.ca.ou | default(APACHE_CONFIG.ssl.ca.ou, true) }}" | ||||||
|  |         country: "{{ site.ssl.ca.country | default(APACHE_CONFIG.ssl.ca.country, true) }}" | ||||||
|  |         state: "{{ site.ssl.ca.state | default(APACHE_CONFIG.ssl.ca.state, true) }}" | ||||||
|  |         locality: "{{ site.ssl.ca.locality | default(APACHE_CONFIG.ssl.ca.locality, true) }}" | ||||||
|  |         email: "{{ site.ssl.ca.email | default(APACHE_CONFIG.ssl.ca.email, true) }}" | ||||||
|  |         pwd: "{{ site.ssl.ca.pwd | default(APACHE_CONFIG.ssl.ca.pwd, true) }}" | ||||||
|  |   when: "site.ssl.mode in ['ca', 'selfsigned']" | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Certs | Trying to copy cert pub" | ||||||
|  |   ansible.builtin.copy: | ||||||
|  |     dest: "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.crt" | ||||||
|  |     src: "files/certs/{{ name }}.crt" | ||||||
|  |     mode: 0644 | ||||||
|  |     owner: "{{ APACHE_CONFIG.user }}" | ||||||
|  |     group: "{{ APACHE_CONFIG.group }}" | ||||||
|  |   ignore_errors: true | ||||||
|  |   register: copy_cert_pub | ||||||
|  |   when: site.ssl.mode == 'existing' | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Certs | Trying to copy cert pk" | ||||||
|  |   ansible.builtin.copy: | ||||||
|  |     dest: "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.key" | ||||||
|  |     src: "files/certs/{{ name }}.key" | ||||||
|  |     mode: 0640 | ||||||
|  |     owner: "{{ APACHE_CONFIG.user }}" | ||||||
|  |     group: "{{ APACHE_CONFIG.group }}" | ||||||
|  |   no_log: true | ||||||
|  |   register: copy_cert_key | ||||||
|  |   ignore_errors: true | ||||||
|  |   when: | ||||||
|  |     - site.ssl.mode == 'existing' | ||||||
|  |     - copy_cert_pub.failed is undefined or not copy_cert_pub.failed | ||||||
|  | @ -1,6 +1,18 @@ | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Configuring listen-ports" | - name: "Apache | Debian | Site '{{ name }}' | Checking config" | ||||||
|  |   ansible.builtin.fail: | ||||||
|  |     msg: "The required site-configuration was not provided! | ||||||
|  |     Needed: 'domain'" | ||||||
|  |   when: site.domain is undefined | ||||||
|  |   tags: [config, sites, certs] | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Configuring certificates" | ||||||
|  |   ansible.builtin.import_tasks: add_certs.yml | ||||||
|  |   when: "site.ssl.mode in ['selfsigned', 'existing', 'ca']" | ||||||
|  |   tags: [sites, certs] | ||||||
|  | 
 | ||||||
|  | - name: "Apache | Debian | Site '{{ name }}' | Configuring listen-ports" | ||||||
|   ansible.builtin.blockinfile: |   ansible.builtin.blockinfile: | ||||||
|     path: '/etc/apache2/ports.conf' |     path: '/etc/apache2/ports.conf' | ||||||
|     block: | |     block: | | ||||||
|  | @ -18,8 +30,9 @@ | ||||||
|   with_items: |   with_items: | ||||||
|     - "{{ site.port_plain }}" |     - "{{ site.port_plain }}" | ||||||
|     - "{{ site.port_ssl }}" |     - "{{ site.port_ssl }}" | ||||||
|  |   tags: [config, sites] | ||||||
| 
 | 
 | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Create root directory" | - name: "Apache | Debian | Site '{{ name }}' | Create root directory" | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "{{ site.serve.path }}" |     path: "{{ site.serve.path }}" | ||||||
|     state: directory |     state: directory | ||||||
|  | @ -27,38 +40,18 @@ | ||||||
|     group: "{{ APACHE_CONFIG.group }}" |     group: "{{ APACHE_CONFIG.group }}" | ||||||
|     mode: 0755 |     mode: 0755 | ||||||
|   when: site.mode == 'serve' |   when: site.mode == 'serve' | ||||||
|  |   tags: [sites] | ||||||
| 
 | 
 | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Configuring site" | - name: "Apache | Debian | Site '{{ name }}' | Configuring site" | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: 'templates/etc/apache2/sites-available/site.conf.j2' |     src: 'templates/etc/apache2/sites-available/site.conf.j2' | ||||||
|     dest: "/etc/apache2/sites-available/site_{{ name }}.conf" |     dest: "/etc/apache2/sites-available/site_{{ name }}.conf" | ||||||
|     owner: 'root' |     owner: 'root' | ||||||
|     group: 'root' |     group: 'root' | ||||||
|     mode: 0644 |     mode: 0644 | ||||||
|     validate: 'apachectl -t -f %s' |   tags: [config, sites] | ||||||
|   register: apache_config_deployment |  | ||||||
|   ignore_errors: yes |  | ||||||
| 
 | 
 | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Ask user" | - name: "Apache | Debian | Site '{{ name }}' | Enabling site" | ||||||
|   ansible.builtin.pause: |  | ||||||
|     prompt: "The apache config validation failed! Sometimes this is a false-negative. |  | ||||||
|     Do you want to force the deployment? (yes/no)" |  | ||||||
|   register: force_deploy |  | ||||||
|   when: apache_config_deployment.failed |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Configuring site (forced)" |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: 'templates/etc/apache2/sites-available/site.conf.j2' |  | ||||||
|     dest: "/etc/apache2/sites-available/site_{{ name }}.conf" |  | ||||||
|     owner: 'root' |  | ||||||
|     group: 'root' |  | ||||||
|     mode: 0644 |  | ||||||
|     backup: true |  | ||||||
|   when: |  | ||||||
|     - apache_config_deployment.failed |  | ||||||
|     - force_deploy.user_input == 'yes' |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Enabling site" |  | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     state: link |     state: link | ||||||
|     src: "/etc/apache2/sites-available/site_{{ name }}.conf" |     src: "/etc/apache2/sites-available/site_{{ name }}.conf" | ||||||
|  | @ -66,3 +59,4 @@ | ||||||
|     owner: 'root' |     owner: 'root' | ||||||
|     group: 'root' |     group: 'root' | ||||||
|     mode: 0644 |     mode: 0644 | ||||||
|  |   tags: [sites] | ||||||
|  |  | ||||||
|  | @ -1,13 +0,0 @@ | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Cleanup | Disable temporary apache site |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     state: absent |  | ||||||
|     dest: '/etc/apache2/sites-enabled/tmp_le_dummy.conf' |  | ||||||
|   register: tmp_site_config |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Cleanup | Reload apache |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     name: 'apache2.service' |  | ||||||
|     state: reloaded |  | ||||||
|   when: tmp_site_config.changed |  | ||||||
|  | @ -1,23 +0,0 @@ | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Dependencies | Deploying temporary apache site |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: 'templates/etc/apache2/sites-available/le_dummy.conf.j2' |  | ||||||
|     dest: '/etc/apache2/sites-available/tmp_le_dummy.conf' |  | ||||||
|     owner: 'root' |  | ||||||
|     group: 'root' |  | ||||||
|     mode: 0644 |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Dependencies | Enable apache site |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     state: link |  | ||||||
|     src: '/etc/apache2/sites-available/tmp_le_dummy.conf' |  | ||||||
|     dest: '/etc/apache2/sites-enabled/tmp_le_dummy.conf' |  | ||||||
|     owner: 'root' |  | ||||||
|     group: 'root' |  | ||||||
|     mode: 0644 |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Dependencies | Reload apache |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     name: 'apache2.service' |  | ||||||
|     state: reloaded |  | ||||||
|  | @ -1,45 +0,0 @@ | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Checking if cert for domain '{{ site.domain }}' exists" |  | ||||||
|   ansible.builtin.shell: 'certbot certificates' |  | ||||||
|   register: domain_cert |  | ||||||
|   changed_when: false |  | ||||||
| 
 |  | ||||||
| # todo: check domains registered in current certificate (certbot certificates) and remove it if there are more than configured before re-configuring it |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Set key/cert paths for domain '{{ site.domain }}'" |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     _path_key: "{{ APACHE_CONFIG.letsencrypt.path_key }}/{{ name }}" |  | ||||||
|     _path_cert: "{{ APACHE_CONFIG.letsencrypt.path_cert }}/{{ name }}" |  | ||||||
|     _path_live: "{{ APACHE_CONFIG.letsencrypt.path }}/live/{{ name }}" |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Creating key/cert directories for domain '{{ site.domain }}'" |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item }}" |  | ||||||
|     state: directory |  | ||||||
|     owner: 'root' |  | ||||||
|     group: 'root' |  | ||||||
|     mode: 0755 |  | ||||||
|   with_items: |  | ||||||
|   - "{{ _path_key }}" |  | ||||||
|   - "{{ _path_cert }}" |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Getting cert |  | ||||||
|   ansible.builtin.include_tasks: domain_new.yml |  | ||||||
|   when: domain_cert.stdout.find(site.domain) == -1 |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Linking certificates for domain '{{ site.domain }}'" |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     state: link |  | ||||||
|     src: "{{ item.value.src }}" |  | ||||||
|     dest: "{{ item.value.dst }}" |  | ||||||
|     owner: "{{ APACHE_CONFIG.user }}" |  | ||||||
|     group: "{{ APACHE_CONFIG.group }}" |  | ||||||
|     mode: 0400 |  | ||||||
|     follow: yes |  | ||||||
|   with_dict: |  | ||||||
|     - {'config': {'dst': "{{ _path_key }}/privkey.pem", 'src': "{{ _path_live }}/privkey.pem"}} |  | ||||||
|     - {'config': {'dst': "{{ _path_cert }}/cert.pem", 'src': "{{ _path_live }}/cert.pem"}} |  | ||||||
|     - {'config': {'dst': "{{ _path_cert }}/chain.pem", 'src': "{{ _path_live }}/chain.pem"}} |  | ||||||
|     - {'config': {'dst': "{{ _path_cert }}/fullchain.pem", 'src': "{{ _path_live }}/fullchain.pem"}} |  | ||||||
|   ignore_errors: yes |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Creating alternative name string (1/3)" |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     _aliases: "{{ site.aliases | join(' --domain ') }}" |  | ||||||
|   when: apache_aliases | length > 0 |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Creating alternative name string (2/3)" |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     _apache_aliases: "{{ '--domain ' + _aliases }}" |  | ||||||
|   when: apache_aliases | length > 0 |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Creating alternative name string (3/3)" |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     _apache_aliases: '' |  | ||||||
|   when: apache_aliases | length == 0 |  | ||||||
| 
 |  | ||||||
| - name: debug |  | ||||||
|   ansible.builtin.debug: |  | ||||||
|     msg: "certbot certonly --apache -{{ APACHE_CONFIG.letsencrypt.verbosity }} --non-interactive --agree-tos --email {{ site.admin }} --cert-name {{ name }} |  | ||||||
|     --rsa-key-size {{ APACHE_CONFIG.letsencrypt.key_size }} --no-redirect --domain {{ site.domain }} {{ _apache_aliases }}" |  | ||||||
| 
 |  | ||||||
| - name: "Apache | Debian | LetsEncrypt Certbot | Starting certbot for domain '{{ site.domain }}'" |  | ||||||
|   ansible.builtin.shell: "certbot certonly --apache -{{ APACHE_CONFIG.letsencrypt.verbosity }} --non-interactive --agree-tos --email {{ site.admin }} --cert-name {{ name }} |  | ||||||
|   --rsa-key-size {{ APACHE_CONFIG.letsencrypt.key_size }} --no-redirect --domain {{ site.domain }} {{ _apache_aliases }}" |  | ||||||
|   ignore_errors: yes |  | ||||||
|  | @ -1,41 +0,0 @@ | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Install package |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: "{{ packages.letsencrypt }}" |  | ||||||
|     state: present |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Check if a apache virtualhost is available |  | ||||||
|   ansible.builtin.shell: 'ls /etc/apache2/sites-enabled/' |  | ||||||
|   register: enabled_apache_sites |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Checking dependencies |  | ||||||
|   ansible.builtin.include_tasks: dependencies.yml |  | ||||||
|   when: enabled_apache_sites.stdout == '' |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Processing apache sites |  | ||||||
|   ansible.builtin.include_tasks: domain.yml |  | ||||||
|   vars: |  | ||||||
|     site: "{{ default_site_config | combine(site_item, recursive=true) }}" |  | ||||||
|     name: "{{ site_item.key | safe_key }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: site_item |  | ||||||
|   with_dict: "{{ APACHE_CONFIG.sites }}" |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Cleanup dependencies |  | ||||||
|   ansible.builtin.include_tasks: cleanup.yml |  | ||||||
| 
 |  | ||||||
| - name: Apache | Debian | LetsEncrypt Certbot | Adding systemd files for certbot renewal |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: "templates/etc/systemd/system/{{ item }}.j2" |  | ||||||
|     dest: "/etc/systemd/system/{{ item }}" |  | ||||||
|   with_items: |  | ||||||
|     - 'ansibleguy.infra_apache.LetsEncryptCertbot.service' |  | ||||||
|     - 'ansibleguy.infra_apache.LetsEncryptCertbot.timer' |  | ||||||
| 
 |  | ||||||
| - name:  Apache | Debian | LetsEncrypt Certbot | Enabling cert-renewal systemd timer |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     daemon_reload: yes |  | ||||||
|     name: 'LetsEncryptCertbot.timer' |  | ||||||
|     enabled: yes |  | ||||||
|     state: started |  | ||||||
|  | @ -2,54 +2,101 @@ | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Install apache | - name: Apache | Debian | Install apache | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
|     name: "{{ packages.apache }}" |     name: ['apache2'] | ||||||
|     state: present |     state: present | ||||||
|  |     update_cache: true | ||||||
|  |   tags: [base] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Checking if all sites exist (1/2) | - name: Apache | Debian | Creating service user | ||||||
|   ansible.builtin.stat: |   ansible.builtin.user: | ||||||
|     path: "/etc/apache2/sites-available/site_{{ item.key | safe_key }}.conf" |     name: "{{ APACHE_CONFIG.user }}" | ||||||
|   register: sites_exist_raw |     shell: '/usr/sbin/nologin' | ||||||
|   with_dict: "{{ APACHE_CONFIG.sites }}" |     comment: 'Apache Service User' | ||||||
|  |   tags: [base] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Checking if all sites exist (2/2) | - name: Apache | Debian | Setting service user | ||||||
|   ansible.builtin.set_fact: |   ansible.builtin.lineinfile: | ||||||
|     sites_exist: "{{ sites_exist_raw | json_query('[*].results.stat.exists') | all_true }}" |     state: present | ||||||
| 
 |     path: '/etc/apache2/envvars' | ||||||
| - name: Apache | Debian | Getting certificate via LetsEncrypt |     regexp: "{{ item.reg }}" | ||||||
|   ansible.builtin.import_tasks: letsencrypt/main.yml |     line: "{{ item.line }}" | ||||||
|   when: > |   register: apache_user_update_raw | ||||||
|     (APACHE_CONFIG.ssl.renew or |   loop: | ||||||
|     not sites_exist) and |     - {reg: '^export APACHE_RUN_USER=', line: "export APACHE_RUN_USER={{ APACHE_CONFIG.user }}"} | ||||||
|     APACHE_CONFIG.ssl.mode == 'letsencrypt' |     - {reg: '^export APACHE_RUN_GROUP=', line: "export APACHE_RUN_GROUP={{ APACHE_CONFIG.group }}"} | ||||||
|  |   tags: [base, config] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Enabling apache modules | - name: Apache | Debian | Enabling apache modules | ||||||
|   community.general.apache2_module: |   community.general.apache2_module: | ||||||
|     state: present |     state: present | ||||||
|     name: "{{ item }}" |     name: "{{ item }}" | ||||||
|   when: item not in APACHE_CONFIG.modules.absent |   when: item not in APACHE_CONFIG.modules.absent | ||||||
|  |   register: apache_mods_enable_raw | ||||||
|   loop: "{{ APACHE_CONFIG.modules.present }}" |   loop: "{{ APACHE_CONFIG.modules.present }}" | ||||||
|  |   tags: [base] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Disabling apache modules | - name: Apache | Debian | Disabling apache modules | ||||||
|   community.general.apache2_module: |   community.general.apache2_module: | ||||||
|     state: absent |     state: absent | ||||||
|     name: "{{ item }}" |     name: "{{ item }}" | ||||||
|  |     force: True | ||||||
|  |     ignore_configcheck: True | ||||||
|  |   register: apache_mods_disable_raw | ||||||
|   loop: "{{ APACHE_CONFIG.modules.absent }}" |   loop: "{{ APACHE_CONFIG.modules.absent }}" | ||||||
|  |   tags: [base] | ||||||
| 
 | 
 | ||||||
| # todo: configure module settings | # todo: configure module settings | ||||||
| 
 | 
 | ||||||
| # todo: check if apache2.conf editing is still needed | - name: Apache | Debian | Adding main settings | ||||||
| #- name: Apache | Debian | Adding global config |   ansible.builtin.lineinfile: | ||||||
| #  ansible.builtin.blockinfile: |     state: present | ||||||
| #    path: '/etc/apache2/apache2.conf' |     path: '/etc/apache2/apache2.conf' | ||||||
| #    block: | |     regexp: "{{ item.key }}\\s" | ||||||
| #      {% for setting, value in apache_config_additions_default.items() %} |     line: "{{ item.key }} {{ item.value }}" | ||||||
| #        {{ setting }} {{ value }} |     validate: "apachectl -t -f %s" | ||||||
| #      {% endfor %} |   register: apache_settings_raw | ||||||
| #      {% for setting, value in apache_config_additions.items() %} |   with_dict: "{{ APACHE_CONFIG.settings }}" | ||||||
| #        {{ setting }} {{ value }} |   tags: [config, base] | ||||||
| #      {% endfor %} | 
 | ||||||
| #    marker: "# {mark} ANSIBLE MANAGED BLOCK - global config" | - name: Apache | Debian | Restarting apache | ||||||
| #    validate: 'apachectl -t -f %s' |   ansible.builtin.systemd: | ||||||
|  |     name: 'apache2.service' | ||||||
|  |     state: restarted | ||||||
|  |   when: > | ||||||
|  |     apache_user_update_raw.changed or | ||||||
|  |     apache_mods_enable_raw.changed or | ||||||
|  |     apache_mods_disable_raw.changed or | ||||||
|  |     apache_settings_raw.changed | ||||||
|  |   tags: [base, config] | ||||||
|  | 
 | ||||||
|  | # is an additional site-loop since certificates can be pre-/absent | ||||||
|  | - name: Apache | Debian |  Getting certificates using LetsEncrypt | ||||||
|  |   ansible.builtin.include_role: | ||||||
|  |     name: ansibleguy.infra_certs | ||||||
|  |   when: site.ssl.mode == 'letsencrypt' | ||||||
|  |   vars: | ||||||
|  |     site: "{{ default_site_config | combine(site_item.value, recursive=true) }}" | ||||||
|  |     name: "{{ site_item.key | safe_key }}" | ||||||
|  |     certs: | ||||||
|  |       mode: 'le_certbot' | ||||||
|  |       path: "{{ APACHE_CONFIG.ssl.path }}" | ||||||
|  |       owner_key: "{{ APACHE_CONFIG.user }}" | ||||||
|  |       group_key: "{{ APACHE_CONFIG.group }}" | ||||||
|  |       owner_cert: "{{ APACHE_CONFIG.user }}" | ||||||
|  |       group_cert: "{{ APACHE_CONFIG.group }}" | ||||||
|  |       letsencrypt: | ||||||
|  |         certs: "{{ site | prepare_letsencrypt(name) }}" | ||||||
|  |         path: "{{ APACHE_CONFIG.letsencrypt.path }}" | ||||||
|  |         email: "{{ APACHE_CONFIG.letsencrypt.email }}" | ||||||
|  |         renew_timer: "{{ APACHE_CONFIG.letsencrypt.renew_timer }}" | ||||||
|  |         verbosity: "{{ APACHE_CONFIG.letsencrypt.verbosity }}" | ||||||
|  |         service: 'apache' | ||||||
|  |         renew: "{{ APACHE_CONFIG.letsencrypt.renew }}" | ||||||
|  |   loop_control: | ||||||
|  |     loop_var: site_item | ||||||
|  |   with_dict: "{{ APACHE_CONFIG.sites }}" | ||||||
|  |   no_log: true | ||||||
|  |   tags: [certs, sites] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Disabling default apache sites | - name: Apache | Debian | Disabling default apache sites | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|  | @ -58,16 +105,19 @@ | ||||||
|   with_items: |   with_items: | ||||||
|     - '000-default.conf' |     - '000-default.conf' | ||||||
|     - 'default-ssl.conf' |     - 'default-ssl.conf' | ||||||
|  |   tags: [config, base] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Removing apache site | - name: Apache | Debian | Removing site | ||||||
|   ansible.builtin.include_tasks: rm_site.yml |   ansible.builtin.include_tasks: rm_site.yml | ||||||
|  |   when: site.state != 'present' | ||||||
|   vars: |   vars: | ||||||
|     site: "{{ default_site_config | combine(site_item, recursive=true) }}" |     site: "{{ default_site_config | combine(site_item.value, recursive=true) }}" | ||||||
|     name: "{{ site_item.key | safe_key }}" |     name: "{{ site_item.key | safe_key }}" | ||||||
|   when: site_item.state | default('present') != 'present' |  | ||||||
|   loop_control: |   loop_control: | ||||||
|     loop_var: site_item |     loop_var: site_item | ||||||
|   with_dict: "{{ APACHE_CONFIG.sites }}" |   with_dict: "{{ APACHE_CONFIG.sites }}" | ||||||
|  |   no_log: true | ||||||
|  |   tags: [config, sites, certs] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Reloading apache | - name: Apache | Debian | Reloading apache | ||||||
|   ansible.builtin.systemd: |   ansible.builtin.systemd: | ||||||
|  | @ -75,15 +125,16 @@ | ||||||
|     state: reloaded |     state: reloaded | ||||||
|   tags: [base, config, sites, certs] |   tags: [base, config, sites, certs] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Adding apache site | - name: Apache | Debian | Adding site | ||||||
|   ansible.builtin.include_tasks: add_site.yml |   ansible.builtin.include_tasks: add_site.yml | ||||||
|  |   when: site.state == 'present' | ||||||
|   vars: |   vars: | ||||||
|     site: "{{ default_site_config | combine(site_item, recursive=true) }}" |     site: "{{ default_site_config | combine(site_item.value, recursive=true) }}" | ||||||
|     name: "{{ site_item.key | safe_key }}" |     name: "{{ site_item.key | safe_key }}" | ||||||
|   when: site_item.state | default('present') == 'present' |  | ||||||
|   loop_control: |   loop_control: | ||||||
|     loop_var: site_item |     loop_var: site_item | ||||||
|   with_dict: "{{ APACHE_CONFIG.sites }}" |   with_dict: "{{ APACHE_CONFIG.sites }}" | ||||||
|  |   tags: [config, sites, certs] | ||||||
| 
 | 
 | ||||||
| - name: Apache | Debian | Starting/Enabling apache | - name: Apache | Debian | Starting/Enabling apache | ||||||
|   ansible.builtin.systemd: |   ansible.builtin.systemd: | ||||||
|  |  | ||||||
|  | @ -1,24 +1,16 @@ | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # ports will be left configured since I found no clean way to manage them statefully | # ports will be left configured since I found no clean way to manage them statefully | ||||||
| 
 | # also: the web-root will be left as-is | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Removing web-root" |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ site.serve.path }}" |  | ||||||
|     state: absent |  | ||||||
|     force: yes |  | ||||||
|   when: site.mode == 'serve' |  | ||||||
| 
 | 
 | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Removing/Disabling site" | - name: "Apache | Debian | Config | Site '{{ name }}' | Removing/Disabling site" | ||||||
|   ansible.builtin.template: |   ansible.builtin.file: | ||||||
|     path: "{{ item }}" |     path: "{{ item }}" | ||||||
|     state: absent |     state: absent | ||||||
|   loop: |   loop: | ||||||
|     - "/etc/apache2/sites-available/site_{{ name }}.conf" |  | ||||||
|     - "/etc/apache2/sites-enabled/site_{{ name }}.conf" |     - "/etc/apache2/sites-enabled/site_{{ name }}.conf" | ||||||
| 
 |     - "/etc/apache2/sites-available/site_{{ name }}.conf" | ||||||
| - name: "Apache | Debian | Config | Site '{{ name }}' | Removing certificate from certbot" |     - "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.key" | ||||||
|   ansible.builtin.shell: "certbot certonly --apache -{{ APACHE_LE_CONFIG.verbosity }} --non-interactive --agree-tos --email {{ site.admin }} --cert-name {{ name }} |     - "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.crt" | ||||||
|   --rsa-key-size {{ APACHE_LE_CONFIG.key_size }} --no-redirect --domain {{ site.domain }} {{ _apache_aliases }}" |     - "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.chain.crt" | ||||||
|   ignore_errors: yes |     - "{{ APACHE_CONFIG.ssl.path }}/{{ name }}.fullchain.crt" | ||||||
|   when: site.ssl.mode == 'letsencrypt' |  | ||||||
|  |  | ||||||
|  | @ -1,5 +1,14 @@ | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
|  | - name: Apache | Checking config | ||||||
|  |   ansible.builtin.fail: | ||||||
|  |     msg: "The required configuration was not provided! | ||||||
|  |     Needed: 'apache', 'apache.sites'" | ||||||
|  |   when: > | ||||||
|  |     apache is undefined or | ||||||
|  |     apache.sites is undefined or | ||||||
|  |     apache.sites | length == 0 | ||||||
|  | 
 | ||||||
| - name: Apache | Processing debian config | - name: Apache | Processing debian config | ||||||
|   ansible.builtin.import_tasks: debian/main.yml |   ansible.builtin.import_tasks: debian/main.yml | ||||||
|   when: "ansible_distribution|lower in ['debian', 'ubuntu']" |   when: "ansible_distribution|lower in ['debian', 'ubuntu']" | ||||||
|  |  | ||||||
|  | @ -1,6 +0,0 @@ | ||||||
| <VirtualHost *:80> |  | ||||||
|     ServerName dummy.letsencrypt.localhost |  | ||||||
|     ServerAdmin webmaster@localhost |  | ||||||
|     ErrorLog {{ APACHE_CONFIG.log.path }}/error.log |  | ||||||
|     CustomLog {{ APACHE_CONFIG.log.path }}/access.log combined |  | ||||||
| </VirtualHost> |  | ||||||
|  | @ -1,8 +1,11 @@ | ||||||
|  | # {{ ansible_managed }} | ||||||
|  | # ansibleguy.infra_apache | ||||||
|  | 
 | ||||||
| <VirtualHost *:{{ site.port_plain }}> | <VirtualHost *:{{ site.port_plain }}> | ||||||
|   ServerName {{ site.domain }} |   ServerName {{ site.domain }} | ||||||
| 
 | 
 | ||||||
| {% if site.aliases | length > 0 %} | {% if site.aliases | length > 0 %} | ||||||
|   ServerAlias {% for name in site.aliases %} {{ name }} {% endfor %} |   ServerAlias {% for name in site.aliases %} {{ name }} {% endfor %}{% if site.ip is not none %} {{ site.ip }}{% endif %} | ||||||
| {% endif %} | {% endif %} | ||||||
|   ServerAdmin {{ site.admin }} |   ServerAdmin {{ site.admin }} | ||||||
| 
 | 
 | ||||||
|  | @ -30,18 +33,18 @@ | ||||||
|   ServerName {{ site.domain }} |   ServerName {{ site.domain }} | ||||||
| 
 | 
 | ||||||
| {% if site.aliases | length > 0 %} | {% if site.aliases | length > 0 %} | ||||||
|   ServerAlias {% for name in site.aliases %} {{ name }} {% endfor %} |   ServerAlias {% for alias in site.aliases %} {{ alias }} {% endfor %}{% if site.ip is not none %} {{ site.ip }}{% endif %} | ||||||
| {% endif %} | {% endif %} | ||||||
| 
 | 
 | ||||||
|   ServerAdmin {{ site.admin }} |   ServerAdmin {{ site.admin }} | ||||||
| 
 | 
 | ||||||
|   # log config |   # log config | ||||||
| {% if APACHE_CONFIG.log.syslog and APACHE_CONFIG.log.syslog_host is not none %} | {% if APACHE_CONFIG.log.syslog and APACHE_CONFIG.log.syslog_host is not none %} | ||||||
|   ErrorLog "| /usr/bin/logger -n {{ APACHE_CONFIG.log.syslog_host }} -P {{ APACHE_CONFIG.log.syslog_port }} -p local1.error -t {{ APACHE_CONFIG.log.prefix_ue }}{{ name }}" |   ErrorLog "| /usr/bin/logger -n {{ APACHE_CONFIG.log.syslog_host }} -P {{ APACHE_CONFIG.log.syslog_port }} -p local1.error -t {{ APACHE_CONFIG.log.prefix_ssl }}{{ name }}" | ||||||
|   CustomLog "| /usr/bin/logger -n {{ APACHE_CONFIG.log.syslog_host }} -P {{ APACHE_CONFIG.log.syslog_port }} -p local1.info -t {{ APACHE_CONFIG.log.prefix_ue }}{{ name }}" combined |   CustomLog "| /usr/bin/logger -n {{ APACHE_CONFIG.log.syslog_host }} -P {{ APACHE_CONFIG.log.syslog_port }} -p local1.info -t {{ APACHE_CONFIG.log.prefix_ssl }}{{ name }}" combined | ||||||
| {% elif APACHE_CONFIG.log.syslog %} | {% elif APACHE_CONFIG.log.syslog %} | ||||||
|   ErrorLog "| /usr/bin/logger -p local1.error -t {{ APACHE_CONFIG.log.prefix_ue }}{{ name }}" |   ErrorLog "| /usr/bin/logger -p local1.error -t {{ APACHE_CONFIG.log.prefix_ssl }}{{ name }}" | ||||||
|   CustomLog "| /usr/bin/logger -p local1.info -t {{ APACHE_CONFIG.log.prefix_ue }}{{ name }}" combined |   CustomLog "| /usr/bin/logger -p local1.info -t {{ APACHE_CONFIG.log.prefix_ssl }}{{ name }}" combined | ||||||
| {% elif APACHE_CONFIG.log.per_site %} | {% elif APACHE_CONFIG.log.per_site %} | ||||||
|   ErrorLog {{ APACHE_CONFIG.log.path }}/{{ name }}_error.log |   ErrorLog {{ APACHE_CONFIG.log.path }}/{{ name }}_error.log | ||||||
|   CustomLog {{ APACHE_CONFIG.log.path }}/{{ name }}_access.log combined |   CustomLog {{ APACHE_CONFIG.log.path }}/{{ name }}_access.log combined | ||||||
|  | @ -53,9 +56,11 @@ | ||||||
|   # ssl config |   # ssl config | ||||||
|   <IfModule mod_ssl.c> |   <IfModule mod_ssl.c> | ||||||
|     SSLEngine on |     SSLEngine on | ||||||
|     SSLCertificateKeyFile /etc/ssl/private/{{ apache_site }}/privkey.pem |     SSLCertificateKeyFile {{ APACHE_CONFIG.ssl.path }}/{{ name }}.key | ||||||
|     SSLCertificateFile /etc/ssl/certs/{{ apache_site }}/cert.pem |     SSLCertificateFile {{ APACHE_CONFIG.ssl.path }}/{{ name }}.crt | ||||||
|     SSLCertificateChainFile /etc/ssl/certs/{{ apache_site }}/fullchain.pem | {% if site.ssl.mode != 'selfsigned' %} | ||||||
|  |     SSLCertificateChainFile {{ APACHE_CONFIG.ssl.path }}/{{ name }}{% if site.ssl.mode == 'letsencrypt' %}.fullchain{% else %}.chain{% endif %}.crt | ||||||
|  | {% endif %} | ||||||
|   </IfModule> |   </IfModule> | ||||||
| 
 | 
 | ||||||
| {% if APACHE_CONFIG.config | length > 0 %} | {% if APACHE_CONFIG.config | length > 0 %} | ||||||
|  | @ -106,20 +111,15 @@ | ||||||
| 
 | 
 | ||||||
|   # security config |   # security config | ||||||
| {% if site.security.restrict_methods %} | {% if site.security.restrict_methods %} | ||||||
|   <LimitExcept {% for method in apache_restricted_methods %}{{ method }} {% endfor %}> |   <IfModule mod_rewrite.c> | ||||||
|     deny from all |     RewriteEngine On | ||||||
|   </LimitExcept> |     RewriteCond %{REQUEST_METHOD} ^(?!{% for method in apache_restricted_methods %}{{ method }}{% if not loop.last %}|{% endif %}{% endfor %}) | ||||||
| {% endif %} |     RewriteRule .* - [F] | ||||||
| {% if site.security.limit_directory_access %} |   </IfModule> | ||||||
|   <Directory /> |   <Directory /> | ||||||
|     Options None |     <LimitExcept {% for method in apache_restricted_methods %}{{ method }} {% endfor %}> | ||||||
|     Order deny,allow |       deny from all | ||||||
|     Deny from all |     </LimitExcept> | ||||||
|   </Directory> |  | ||||||
| {% endif %} |  | ||||||
| {% if site.security.disable_directory_access %} |  | ||||||
|   <Directory "="> |  | ||||||
|     Require all denied |  | ||||||
|   </Directory> |   </Directory> | ||||||
| {% endif %} | {% endif %} | ||||||
| 
 | 
 | ||||||
|  | @ -158,6 +158,11 @@ | ||||||
|   {{ line }} |   {{ line }} | ||||||
| {% endfor %} | {% endfor %} | ||||||
| 
 | 
 | ||||||
|  | {% if site.app_include %} | ||||||
|  |   # additional application config include | ||||||
|  |   IncludeOptional site_{{ name }}_app.conf | ||||||
|  | {% endif %} | ||||||
|  | 
 | ||||||
| </VirtualHost> | </VirtualHost> | ||||||
| 
 | 
 | ||||||
| ServerName {{ site.domain }} | ServerName {{ site.domain }} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue