websites-role umgebaut

This commit is contained in:
DigitalInfinity committed 2026-10-14 19:42:06 +02:00
1 parent 522cfca114
commit da1b2cfe82
8 files changed
+319 -148

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
---
# included per website with state: absent, certificates and docroot are kept
- name: "{{ site.domain }}: deactivate and remove vhosts"
file:
path: "{{ item }}"
state: absent
loop:
- /etc/apache2/sites-enabled/{{ site.domain }}.conf
- /etc/apache2/sites-enabled/{{ site.domain }}-ssl.conf
- /etc/apache2/sites-available/{{ site.domain }}.conf
- /etc/apache2/sites-available/{{ site.domain }}-ssl.conf
- /etc/apache2/conf-available/{{ site.domain }}-ssl-optionalDirectives.conf
notify:
- reload apache2
- name: "{{ site.domain }}: stop certificate renewal"
shell: |
if /root/.acme.sh/acme.sh --list | awk 'NR>1 {print $1}' | grep -qxF '{{ site.domain }}'; then
/root/.acme.sh/acme.sh --remove -d '{{ site.domain }}' --ecc || /root/.acme.sh/acme.sh --remove -d '{{ site.domain }}'
echo removed
fi
register: _website_acme_remove
changed_when: "'removed' in _website_acme_remove.stdout"
+68 -109
View File
@@ -9,75 +9,23 @@
include_role:
name: acmesh
- name: create wwwroot
file:
path: "{{ docroot }}"
owner: root
group: root
mode: '0755'
state: directory
- name: enable apache module proxy
command: a2enmod proxy
- name: enable apache modules
command: a2enmod {{ item }}
args:
creates: /etc/apache2/mods-enabled/proxy.load
creates: /etc/apache2/mods-enabled/{{ item }}.load
loop:
- proxy
- proxy_html
- proxy_http
- proxy_http2
- proxy_wstunnel
- ssl
- headers
- rewrite
notify:
reload apache2
- name: enable apache module proxy_html
command: a2enmod proxy_html
args:
creates: /etc/apache2/mods-enabled/proxy_html.load
notify:
reload apache2
- name: enable apache module proxy_http
command: a2enmod proxy_http
args:
creates: /etc/apache2/mods-enabled/proxy_http.load
notify:
reload apache2
- name: enable apache module proxy_http2
command: a2enmod proxy_http2
args:
creates: /etc/apache2/mods-enabled/proxy_http2.load
notify:
reload apache2
- name: enable apache module ssl
command: a2enmod ssl
args:
creates: /etc/apache2/mods-enabled/ssl.load
notify:
reload apache2
- name: enable apache module headers
command: a2enmod headers
args:
creates: /etc/apache2/mods-enabled/headers.load
notify:
reload apache2
- name: enable apache module rewrite
command: a2enmod rewrite
args:
creates: /etc/apache2/mods-enabled/rewrite.load
notify:
reload apache2
- name: enable apache module proxy_wstunnel
command: a2enmod proxy_wstunnel
args:
creates: /etc/apache2/mods-enabled/proxy_wstunnel.load
notify:
reload apache2
- name: install acme.sh
include_role:
name: acmesh
- name: create directory for website
- name: create directory for own root ca cert
file:
path: "/usr/local/share/ca-certificates/step-ca/"
owner: root
@@ -96,68 +44,79 @@
command: /usr/sbin/update-ca-certificates
args:
creates: /etc/ssl/certs/step-ca.pem
when: acme_sh_server is defined
- name: set amce server url
- name: normalize website definitions
set_fact:
acmeshserver: "--server {{ acme_sh_server }} --insecure --force --days 10"
when: acme_sh_server is defined and use_local_ca != false
_websites: >-
{%- set out = [] -%}
{%- for name, cfg in (websites | default({}, true)).items() -%}
{%- set c = website_site_defaults | combine(cfg | default({}, true), {'domain': name}) -%}
{%- set a = c.aliases | default([], true) -%}
{%- set c = c | combine({'aliases': [a] if a is string else a | list}) -%}
{%- set _ = out.append(c) -%}
{%- endfor -%}
{{ out }}
_website_without_cert: []
- name: set amce server url
set_fact:
acmeshserver: " --server letsencrypt "
when: acme_sh_server is undefined or use_local_ca == false
- name: generate /etc/apache2/sites-available/{{ domainname }}.conf
- name: create docroot
file:
path: "{{ site.docroot }}"
owner: root
group: root
mode: '0755'
state: directory
loop: "{{ _websites | selectattr('state', 'eq', 'present') | list }}"
loop_control:
loop_var: site
label: "{{ site.domain }}"
- name: generate http vhost
template:
src: apache.conf.j2
dest: /etc/apache2/sites-available/{{ domainname }}.conf
dest: /etc/apache2/sites-available/{{ site.domain }}.conf
owner: root
group: root
mode: "0644"
loop: "{{ _websites | selectattr('state', 'eq', 'present') | list }}"
loop_control:
loop_var: site
label: "{{ site.domain }}"
notify:
- reload apache2
- name: activate /etc/apache2/sites-available/{{ domainname }}.conf
- name: activate http vhost
file:
state: link
src: /etc/apache2/sites-available/{{ domainname }}.conf
dest: /etc/apache2/sites-enabled/{{ domainname }}.conf
src: /etc/apache2/sites-available/{{ site.domain }}.conf
dest: /etc/apache2/sites-enabled/{{ site.domain }}.conf
loop: "{{ _websites | selectattr('state', 'eq', 'present') | list }}"
loop_control:
loop_var: site
label: "{{ site.domain }}"
notify:
- reload apache2
# http vhosts must be live before acme.sh uses the webroot
- name: Flush handlers
meta: flush_handlers
- name: get certificates
command: /root/.acme.sh/acme.sh --issue --webroot {{ docroot }} {{ acmeshserver }} -d {{ domainname }} --email {{ acme_sh_email }} --key-file /etc/ssl/private/{{ domainname }}.key --fullchain-file /etc/ssl/certs/{{ domainname }}.pem --reloadcmd "service apache2 reload"
args:
creates: /etc/ssl/private/{{ domainname }}.key
- name: certificate and ssl vhost
include_tasks: ssl.yml
loop: "{{ _websites | selectattr('state', 'eq', 'present') | list }}"
loop_control:
loop_var: site
label: "{{ site.domain }}"
- name: generate /etc/apache2/conf-available/{{ domainname }}-ssl-optionalDirectives.conf
template:
src: includeOptional.conf.j2
dest: /etc/apache2/conf-available/{{ domainname }}-ssl-optionalDirectives.conf
owner: root
group: root
mode: "0644"
notify:
- reload apache2
- name: generate /etc/apache2/sites-available/{{ domainname }}-ssl.conf
template:
src: apache-ssl.conf.j2
dest: /etc/apache2/sites-available/{{ domainname }}-ssl.conf
owner: root
group: root
mode: "0644"
notify:
- reload apache2
- name: activate /etc/apache2/sites-available/{{ domainname }}-ssl.conf
file:
state: link
src: /etc/apache2/sites-available/{{ domainname }}-ssl.conf
dest: /etc/apache2/sites-enabled/{{ domainname }}-ssl.conf
notify:
- reload apache2
- name: remove websites
include_tasks: absent.yml
loop: "{{ _websites | selectattr('state', 'eq', 'absent') | list }}"
loop_control:
loop_var: site
label: "{{ site.domain }}"
- name: websites without certificate (domain does not reach this host)
debug:
msg: "WARNING: no certificate and no ssl vhost for {{ _website_without_cert | join(', ') }} - check DNS and port 80, then rerun"
when: _website_without_cert | length > 0
failed_when: website_fail_without_cert | bool
+94
View File
@@ -0,0 +1,94 @@
---
# included per website, expects `site` (normalized entry of _websites)
- name: "{{ site.domain }}: check for existing certificate"
stat:
path: /etc/ssl/private/{{ site.domain }}.key
register: _website_key
- name: "{{ site.domain }}: request certificate"
when: not _website_key.stat.exists
block:
- name: "{{ site.domain }}: generate reachability token"
set_fact:
_website_token: "ansible-check-{{ lookup('password', '/dev/null chars=ascii_letters,digits length=32') }}"
- name: "{{ site.domain }}: create acme-challenge directory"
file:
path: "{{ site.docroot }}/.well-known/acme-challenge"
owner: root
group: root
mode: '0755'
state: directory
- name: "{{ site.domain }}: place reachability token"
copy:
dest: "{{ site.docroot }}/.well-known/acme-challenge/{{ _website_token }}"
content: "{{ _website_token }}"
mode: '0644'
when: site.check_dns | bool
- name: "{{ site.domain }}: check that the domain points to this host"
uri:
url: "http://{{ site.domain }}/.well-known/acme-challenge/{{ _website_token }}"
return_content: true
follow_redirects: none
timeout: "{{ website_check_timeout }}"
register: _website_check
failed_when: false
delegate_to: "{{ website_check_host }}"
when: site.check_dns | bool
- name: "{{ site.domain }}: remove reachability token"
file:
path: "{{ site.docroot }}/.well-known/acme-challenge/{{ _website_token }}"
state: absent
- name: "{{ site.domain }}: evaluate reachability"
set_fact:
_website_reachable: >-
{{ not site.check_dns | bool
or (_website_check.status | default(-1) == 200
and (_website_check.content | default('') | trim) == _website_token) }}
- name: "{{ site.domain }}: domain does not reach this host, skipping certificate"
set_fact:
_website_without_cert: "{{ _website_without_cert + [site.domain] }}"
when: not _website_reachable | bool
- name: "{{ site.domain }}: get certificate"
command: >-
/root/.acme.sh/acme.sh --issue --webroot {{ site.docroot }}
{% if site.use_local_ca | bool and acme_sh_server is defined %}--server {{ acme_sh_server }} --insecure --force --days 10{% else %}--server letsencrypt{% endif %}
-d {{ site.domain }} --email {{ acme_sh_email }}
--key-file /etc/ssl/private/{{ site.domain }}.key
--fullchain-file /etc/ssl/certs/{{ site.domain }}.pem
--reloadcmd "service apache2 reload"
args:
creates: /etc/ssl/private/{{ site.domain }}.key
when: _website_reachable | bool
- name: "{{ site.domain }}: generate ssl vhost"
template:
src: apache-ssl.conf.j2
dest: /etc/apache2/sites-available/{{ site.domain }}-ssl.conf
owner: root
group: root
mode: "0644"
when: site.domain not in _website_without_cert
notify:
- reload apache2
- name: "{{ site.domain }}: activate ssl vhost"
file:
state: link
src: /etc/apache2/sites-available/{{ site.domain }}-ssl.conf
dest: /etc/apache2/sites-enabled/{{ site.domain }}-ssl.conf
when: site.domain not in _website_without_cert
notify:
- reload apache2
# directives now live in the ssl vhost itself
- name: "{{ site.domain }}: remove legacy optionalDirectives include"
file:
path: /etc/apache2/conf-available/{{ site.domain }}-ssl-optionalDirectives.conf
state: absent