Skip to content

Commit

Permalink
Require explicit redirects and drop www_redirect
Browse files Browse the repository at this point in the history
Discontinues the `reverse_www` filter, overcoming
its challenges in handling subdomains.
  • Loading branch information
fullyint committed Jul 27, 2016
1 parent 41c782a commit db89d49
Show file tree
Hide file tree
Showing 13 changed files with 58 additions and 51 deletions.
12 changes: 9 additions & 3 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,20 @@ Vagrant.configure('2') do |config|
# Required for NFS to work
config.vm.network :private_network, ip: ip, hostsupdater: 'skip'

hostname, *aliases = wordpress_sites.flat_map { |(_name, site)| site['site_hosts'] }
wordpress_sites.flat_map { |(_name, site)| site['site_hosts'] }.each do |host|
if !host.is_a?(Hash) or !host.has_key?('canonical')
fail_with_message File.read(File.join(ANSIBLE_PATH, 'roles/common/templates/site_hosts.j2')).sub!('{{ env }}', 'development').gsub!(/com$/, 'dev')
end
end

hostname, *aliases = wordpress_sites.flat_map { |(_name, site)| site['site_hosts'].map { |host| host['canonical'] } }
config.vm.hostname = hostname
www_aliases = ["www.#{hostname}"] + aliases.map { |host| "www.#{host}" }
redirects = wordpress_sites.flat_map { |(_name, site)| site['site_hosts'].select { |host| host.has_key?('redirects') }.flat_map { |host| host['redirects'] } }

if Vagrant.has_plugin? 'vagrant-hostmanager'
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.hostmanager.aliases = aliases + www_aliases
config.hostmanager.aliases = aliases + redirects
else
fail_with_message "vagrant-hostmanager missing, please install the plugin with this command:\nvagrant plugin install vagrant-hostmanager"
end
Expand Down
3 changes: 3 additions & 0 deletions group_vars/all/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ wordpress_env_defaults:
wp_siteurl: "${WP_HOME}/wp"

site_env: "{{ wordpress_env_defaults | combine(item.value.env | default({}), vault_wordpress_sites[item.key].env) }}"
site_hosts_canonical: "{{ item.value.site_hosts | map(attribute='canonical') | list }}"
site_hosts_redirects: "{{ item.value.site_hosts | selectattr('redirects', 'defined') | sum(attribute='redirects', start=[]) | list }}"
site_hosts: "{{ site_hosts_canonical | union(site_hosts_redirects) }}"

# Values of raw_vars will be wrapped in `{% raw %}` to avoid templating problems if values include `{%` and `{{`.
# Will recurse dicts/lists. `*` is wildcard for one or more dict keys, list indices, or strings. Example:
Expand Down
4 changes: 3 additions & 1 deletion group_vars/development/wordpress_sites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
wordpress_sites:
example.com:
site_hosts:
- example.dev
- canonical: example.dev
redirects:
- www.example.dev
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
admin_email: admin@example.dev
multisite:
Expand Down
4 changes: 3 additions & 1 deletion group_vars/production/wordpress_sites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
wordpress_sites:
example.com:
site_hosts:
- example.com
- canonical: example.com
redirects:
- www.example.com
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
repo: git@github.com:example/example.com.git # replace with your Git repo URL
repo_subtree_path: site # relative path to your Bedrock/WP directory in your repo
Expand Down
4 changes: 3 additions & 1 deletion group_vars/staging/wordpress_sites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
wordpress_sites:
example.com:
site_hosts:
- staging.example.com
- canonical: staging.example.com
# redirects:
# - otherdomain.com
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
repo: git@github.com:example/example.com.git # replace with your Git repo URL
repo_subtree_path: site # relative path to your Bedrock/WP directory in your repo
Expand Down
32 changes: 0 additions & 32 deletions lib/trellis/plugins/filter/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,6 @@
from ansible import errors
from ansible.compat.six import string_types

def reverse_www(hosts, enabled=True, append=True):
''' Add or remove www subdomain '''

if not enabled:
return hosts

# Check if hosts is a list and parse each host
if isinstance(hosts, (list, tuple, types.GeneratorType)):
reversed_hosts = [reverse_www(host) for host in hosts]

if append:
return list(set(hosts + reversed_hosts))
else:
return reversed_hosts

# Add or remove www
elif isinstance(hosts, string_types):
host = hosts

if host.startswith('www.'):
return host[4:]
else:
if len(host.split('.')) > 2:
return host
else:
return 'www.{0}'.format(host)

# Handle invalid input type
else:
raise errors.AnsibleFilterError('The reverse_www filter expects a string or list of strings, got ' + repr(hosts))

def to_env(dict_value):
envs = ["{0}='{1}'".format(key.upper(), value) for key, value in sorted(dict_value.items())]
return "\n".join(envs)
Expand All @@ -51,7 +20,6 @@ class FilterModule(object):

def filters(self):
return {
'reverse_www': reverse_www,
'to_env': to_env,
'underscore': underscore,
}
7 changes: 7 additions & 0 deletions roles/common/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
when: ansible_version is not defined or false in [{% for item in ansible_requirements %}{{ ansible_version.full | version_compare(item.version, item.operator) }},{% endfor %}]
run_once: true

- name: Validate format of site_hosts
fail:
msg: "{{ lookup('template', 'site_hosts.j2') }}"
with_dict: "{{ wordpress_sites }}"
when: item.value.site_hosts | rejectattr('canonical', 'defined') | list | count
tags: [letsencrypt, wordpress]

- name: Update Apt
apt:
update_cache: yes
Expand Down
17 changes: 17 additions & 0 deletions roles/common/templates/site_hosts.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Required format for `site_hosts` (group_vars/{{ env }}/wordpress_sites.yml):

example.com:
site_hosts:
- canonical: example.com

The above is the minimum required. Multiple hosts and redirects are possible:

example.com:
site_hosts:
- canonical: example.com
redirects:
- www.example.com
- site.com
- canonical: example.co.uk
redirects:
- www.example.co.uk
8 changes: 4 additions & 4 deletions roles/letsencrypt/tasks/certificates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@
tags: [letsencrypt_keys]

- name: Generate CSRs for single domain keys
shell: openssl req -new -sha256 -key "{{ letsencrypt_keys_dir }}/{{ item.key }}.key" -subj "/CN={{ item.value.site_hosts[0] }}" > {{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr
shell: openssl req -new -sha256 -key "{{ letsencrypt_keys_dir }}/{{ item.key }}.key" -subj "/CN={{ item.value.site_hosts[0].canonical }}" > {{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr
args:
creates: "{{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr"
when: site_uses_letsencrypt and item.value.site_hosts | length == 1 and not item.value.www_redirect | default(true)
when: site_uses_letsencrypt and site_hosts | count == 1
with_dict: "{{ wordpress_sites }}"
tags: [letsencrypt_keys]

- name: Generate CSRs for multiple domain keys
shell: "openssl req -new -sha256 -key '{{ letsencrypt_keys_dir }}/{{ item.key }}.key' -subj '/' -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:{{ item.value.site_hosts | reverse_www(enabled=item.value.www_redirect | default(true)) | join(',DNS:') }}')) > {{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr"
shell: "openssl req -new -sha256 -key '{{ letsencrypt_keys_dir }}/{{ item.key }}.key' -subj '/' -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:{{ site_hosts | join(',DNS:') }}')) > {{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr"
args:
executable: /bin/bash
creates: "{{ acme_tiny_data_directory }}/csrs/{{ item.key }}.csr"
when: site_uses_letsencrypt and item.value.www_redirect | default(true)
when: site_uses_letsencrypt and site_hosts | count > 1
with_dict: "{{ wordpress_sites }}"
tags: [letsencrypt_keys]

Expand Down
2 changes: 1 addition & 1 deletion roles/letsencrypt/tasks/nginx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

- name: Test Acme Challenges
test_challenges:
hosts: "{{ item.value.site_hosts | reverse_www(enabled=item.value.www_redirect | default(true)) }}"
hosts: "{{ site_hosts }}"
register: letsencrypt_test_challenges
ignore_errors: true
when: site_uses_letsencrypt
Expand Down
2 changes: 1 addition & 1 deletion roles/letsencrypt/templates/nginx-challenge-site.conf.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
server {
listen 80;
server_name {{ item.item.value.site_hosts | reverse_www(enabled=item.item.value.www_redirect | default(true)) | join(' ') }};
server_name{% for item in item.item.value.site_hosts %} {{ item.canonical }}{% for redirect in item.redirects | default([]) %} {{ redirect }}{% endfor %}{% endfor %};
include acme-challenge-location.conf;
}
2 changes: 1 addition & 1 deletion roles/wordpress-setup/tasks/self-signed-certificate.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
- name: Generate self-signed certificates
shell: >
openssl req -subj "/CN={{ item.value.site_hosts | first }}" -new
openssl req -subj "/CN={{ item.value.site_hosts[0].canonical }}" -new
-newkey rsa:2048 -days 3650 -nodes -x509 -sha256
-keyout {{ item.key }}.key -out {{ item.key }}.cert
args:
Expand Down
12 changes: 6 additions & 6 deletions roles/wordpress-setup/templates/wordpress-site.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ server {
listen 80;
{% endif %}

server_name {% for host in item.value.site_hosts %} {{ host }} {% if item.value.multisite.subdomains | default(false) %} *.{{ host }} {% endif %} {% endfor %};
server_name {% for host in site_hosts_canonical %}{{ host }} {% if item.value.multisite.subdomains | default(false) %}*.{{ host }} {% endif %}{% endfor %};
access_log {{ www_root }}/{{ item.key }}/logs/access.log;
error_log {{ www_root }}/{{ item.key }}/logs/error.log;

Expand Down Expand Up @@ -81,7 +81,7 @@ server {
server {
listen 80;

server_name {{ item.value.site_hosts | reverse_www(enabled=item.value.www_redirect | default(true)) | join(' ') }} {% if item.value.multisite.subdomains | default(false) %} *.{{ item.value.site_hosts | join(' *.') }} {% endif %};
server_name {{ site_hosts | join(' ') }}{% if item.value.multisite.subdomains | default(false) %} *.{{ site_hosts_canonical | join(' *.') }}{% endif %};

{% if item.value.ssl.provider | default('manual') == 'letsencrypt' -%}
include acme-challenge-location.conf;
Expand All @@ -95,7 +95,7 @@ server {
}
{% endif %}

{% for host in item.value.site_hosts if item.value.www_redirect | default(true) %}
{% for host in item.value.site_hosts if host.redirects | default([]) %}
server {
{% if item.value.ssl is defined and item.value.ssl.enabled | default(false) -%}
listen 443 ssl http2;
Expand All @@ -105,16 +105,16 @@ server {
listen 80;
{% endif -%}

server_name {{ host | reverse_www(append=false) }};
server_name {{ host.redirects | join(' ') }};

{% if item.value.ssl is not defined or not item.value.ssl.enabled | default(false) -%}
include acme-challenge-location.conf;

location / {
return 301 $scheme://{{ host }}$request_uri;
return 301 $scheme://{{ host.canonical }}$request_uri;
}
{% else %}
return 301 $scheme://{{ host }}$request_uri;
return 301 $scheme://{{ host.canonical }}$request_uri;
{% endif %}
}
{% endfor %}

0 comments on commit db89d49

Please sign in to comment.