Migrated to multiple nginx servers for better service isolation

This commit is contained in:
Ezri Brimhall 2025-01-21 13:41:32 -07:00
parent bc78dbe6e1
commit 258feb3c97
Signed by: ezri
GPG Key ID: 058A78E5680C6F24
9 changed files with 279 additions and 35 deletions

75
group_vars/ext_nginx.yml Normal file
View File

@ -0,0 +1,75 @@
cert_domains:
- files.ezri.dev
- git.ezri.dev
- idm.ezri.dev
- jellyfin.ezri.dev
- mail.ezri.dev
- navidrome.ezri.dev
- vtt.ezri.dev
sites_available:
- fqdn: files.ezri.dev
enabled: yes
upstream: http://10.242.202.90:9001
max_upload: 0
- fqdn: git.ezri.dev
enabled: yes
upstream: http://10.242.202.90:30008
- fqdn: jellyfin.ezri.dev
enabled: yes
upstream: http://10.242.202.90:30013
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- 10.242.4.0/24
- fqdn: navidrome.ezri.dev
enabled: yes
upstream: http://10.242.202.90:30043
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- 10.242.4.0/24
- fqdn: mail.ezri.dev
enabled: yes
upstream: http://10.242.203.13:8000
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: vtt.ezri.dev
enabled: no
upstream: http://10.242.203.13:3000
max_upload: 512M
- fqdn: idm.ezri.dev
enabled: yes
upstream: https://10.242.203.13:8443
streams_available:
- fqdn: git.ezri.dev
enabled: yes
listen_port: 22
ssl: no
upstream: 10.242.202.90:30009
- fqdn: idm.ezri.dev
enabled: yes
listen_port: 636
ssl: yes
cert_domain: idm.ezri.dev
upstream: 10.242.203.13:3636
upstream_ssl: yes
restricted: yes
allowed_ips:
- 10.242.200.0/24
- 10.242.0.1
- 10.242.203.1
- 10.242.203.13
- 10.242.3.0/24

59
group_vars/int_nginx.yml Normal file
View File

@ -0,0 +1,59 @@
cert_domains:
- vw.ezri.dev
wildcard_domains:
- internal.ezri.dev
sites_available:
- fqdn: lidarr.internal.ezri.dev
enabled: yes
cert_domain: internal.ezri.dev
upstream: http://10.242.201.3:8686
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: radarr.internal.ezri.dev
enabled: yes
cert_domain: internal.ezri.dev
upstream: http://10.242.201.3:7878
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: sonarr.internal.ezri.dev
enabled: yes
cert_domain: internal.ezri.dev
upstream: https://10.242.201.3:8989
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: prowlarr.internal.ezri.dev
enabled: yes
cert_domain: internal.ezri.dev
upstream: http://10.242.201.3:9696
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: qbittorrent.internal.ezri.dev
enabled: yes
cert_domain: internal.ezri.dev
upstream: http://10.242.201.2:8080
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24
- fqdn: vw.ezri.dev
enabled: yes
upstream: http://10.242.202.90:30032
restricted: yes
allowed_ips:
- 10.242.0.0/23
- 10.242.3.0/24

View File

@ -29,6 +29,9 @@ sites_available:
cert_domain: ezri.dev
upstream: http://10.242.2.2:30013
restricted: yes
allowed_ips:
- 10.242.0.0/16
- 68.5.180.44/32
- fqdn: lidarr.internal.ezri.dev
enabled: yes
@ -125,6 +128,7 @@ sites_available:
allowed_ips:
- 10.242.0.0/16
- 129.123.107.0/24
- 50.39.97.200/32
streams_available:
- fqdn: git.ezri.dev

View File

@ -50,4 +50,16 @@ sysadmin_exercise:
nginx:
hosts:
peoples-home.servers.ezri.dev:
ext_nginx:
hosts:
assurance-of-peace.ext.ezri.dev:
ansible_port: 2231
ansible_user: localadmin
ansible_become: yes
int_nginx:
hosts:
peoples-home.int.ezri.dev:
ansible_user: localadmin
ansible_become: yes

View File

@ -1,11 +1,13 @@
---
- name: Configure Nginx proxy
hosts: nginx
hosts:
- ext_nginx
- int_nginx
vars_prompt:
- name: admin_password
prompt: Enter the administrator password that will be used for this system
- name: cloudflare_api_token
prompt: Enter the cloudflare API token to manage DNS records for certs
roles:
- common
- nginx

View File

@ -1,21 +1,21 @@
---
- name: Create wheel group
ansible.builtin.group:
name: wheel
state: present
system: yes
# - name: Create wheel group
# ansible.builtin.group:
# name: wheel
# state: present
# system: yes
- name: Create local administrator
ansible.builtin.user:
state: present
name: localadmin
uid: 1000
groups:
- wheel
create_home: yes
# Salt the password with the inventory name, this should be static between runs
password: '{{ admin_password|password_hash("sha512", "thisisabadsalt") }}'
# - name: Create local administrator
# ansible.builtin.user:
# state: present
# name: localadmin
# uid: 1000
# groups:
# - wheel
# create_home: yes
# # Salt the password with the inventory name, this should be static between runs
# password: '{{ admin_password|password_hash("sha512", "thisisabadsalt") }}'
- name: Load Arch tasks
import_tasks: arch.yml
@ -46,12 +46,12 @@
owner: root
group: root
- name: Configure SSH server
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: "0644"
notify: Restart SSH
# - name: Configure SSH server
# ansible.builtin.template:
# src: sshd_config.j2
# dest: /etc/ssh/sshd_config
# owner: root
# group: root
# mode: "0644"
# notify: Restart SSH

View File

@ -1,8 +1,13 @@
---
- name: Install Nginx
- name: Install Nginx and certbot
ansible.builtin.apt:
name: nginx
name:
- nginx
- libnginx-mod-stream
- certbot
- python3-dnspython
- python3-certbot-dns-cloudflare
state: present
- name: Allow ports 80 and 443
@ -13,6 +18,72 @@
rule: allow
to_port: '{{ item }}'
- name: Check for existence of certificates
ansible.builtin.stat:
path: /etc/letsencrypt/live/{{ item }}/fullchain.pem
loop: '{{ [cert_domains | default([]), wildcard_domains | default([]) ] | flatten }}'
register: cert_check
- name: Deploy cloudflare secret
ansible.builtin.template:
src: certbot_secrets.j2
dest: /etc/letsencrypt/secrets
owner: root
group: root
mode: "0600"
# Only run this when it is defined
when: cloudflare_api_token is defined and not cloudflare_api_token == ""
- name: Verify cloudflare secret exists
# This is so the above conditional works; we only need to specify the API token on first run or when it changes; that said, if the variable
# is undefined and we haven't deployed the secret before, that's a problem.
ansible.builtin.stat:
path: /etc/letsencrypt/secrets
register: check_secret
failed_when: not check_secret.stat.exists
- name: Request acmedns challenges for uncertified domains
ansible.builtin.command:
argv:
- certbot
- certonly
- '--dns-cloudflare'
- '--non-interactive'
- '--agree-tos'
- '-m'
- 'sysadmins@ezri.dev'
- '--dns-cloudflare-propagation-seconds'
- '30'
- '--dns-cloudflare-credentials'
- '/etc/letsencrypt/secrets'
- '-d'
- '{{ item }}'
loop: '{{ cert_domains | default([]) }}'
loop_control:
index_var: idx
when: not cert_check.results[idx].stat.exists
- name: Request acmedns challenges for uncertified wildcard domains
ansible.builtin.command:
argv:
- certbot
- certonly
- '--dns-cloudflare'
- '--non-interactive'
- '--agree-tos'
- '-m'
- 'sysadmins@ezri.dev'
- '--dns-cloudflare-propagation-seconds'
- '30'
- '--dns-cloudflare-credentials'
- '/etc/letsencrypt/secrets'
- '-d'
- '*.{{ item }}'
loop: '{{ wildcard_domains | default([]) }}'
loop_control:
index_var: idx
when: not cert_check.results[idx + ((cert_domains | default([])) | length)].stat.exists
- name: Create config directories
loop:
- /etc/nginx
@ -48,16 +119,26 @@
- name: Enable site configurations
loop: '{{ sites_available }}'
when: item.enabled
ansible.builtin.file:
src: ../sites-available/{{ item.fqdn }}.conf
dest: /etc/nginx/sites-enabled/{{ item.fqdn }}.conf
state: '{{ item.enabled|ternary("link", "absent") }}'
state: link
owner: root
group: root
notify: Reload nginx
- name: Disable site configurations
loop: '{{ sites_available }}'
when: not item.enabled
ansible.builtin.file:
dest: /etc/nginx/sites-enabled/{{ item.fqdn }}.conf
state: absent
notify: Reload nginx
- name: Deploy stream configurations
loop: '{{ streams_available }}'
when: streams_available is defined
ansible.builtin.template:
src: stream.j2
dest: /etc/nginx/streams-available/{{ item.fqdn }}.conf
@ -67,17 +148,27 @@
notify: Reload nginx
- name: Enable stream configurations
loop: '{{ streams_available }}'
loop: '{{ streams_available | default([]) }}'
when: item.enabled
ansible.builtin.file:
src: ../streams-available/{{ item.fqdn }}.conf
dest: /etc/nginx/streams-enabled/{{ item.fqdn }}.conf
state: '{{ item.enabled|ternary("link", "absent") }}'
state: link
owner: root
group: root
notify: Reload nginx
- name: Disable stream configurations
loop: '{{ streams_available | default([]) }}'
when: not item.enabled
ansible.builtin.file:
dest: /etc/nginx/streams-enabled/{{ item.fqdn }}.conf
state: absent
notify: Reload nginx
- name: Allow connections to enabled streams
loop: '{{ streams_available }}'
when: streams_available is defined
community.general.ufw:
rule: allow
to_port: '{{ item.listen_port }}'

View File

@ -0,0 +1 @@
dns_cloudflare_api_token = {{ cloudflare_api_token }}

View File

@ -10,8 +10,8 @@ server {
server_name {{ item.fqdn }};
ssl_certificate /etc/letsencrypt/live/{{ item.cert_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ item.cert_domain }}/privkey.pem;
ssl_certificate /etc/letsencrypt/live/{{ item.cert_domain|default(item.fqdn) }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ item.cert_domain|default(item.fqdn) }}/privkey.pem;
if ($scheme = "http") {
return 301 https://$host$request_uri;