add nginx, sshd, ssl roles

This commit is contained in:
2026-09-20 22:14:56 +00:00
parent ba9e1a664f
commit c640406c10
131 changed files with 1535 additions and 780 deletions
-5
View File
@@ -1,5 +0,0 @@
- name: install package
ansible.builtin.apt:
name: "{{ item }}"
update_cache: true
loop: "{{ apt }}"
-3
View File
@@ -1,3 +0,0 @@
---
- name: include apt install
ansible.builtin.include_tasks: apt.yml
+20
View File
@@ -0,0 +1,20 @@
---
- name: install certbot
ansible.builtin.apt:
name: certbot
state: present
update_cache: true
- name: issue certificate if missing
ansible.builtin.command:
cmd: >
certbot certonly --standalone
--non-interactive --agree-tos
--register-unsafely-without-email
--pre-hook "{{ item.pre_hook }}"
--post-hook "{{ item.post_hook }}"
{{ item.domains | map('regex_replace', '^(.*)$', '-d \1') | join(' ') }}
creates: "/etc/letsencrypt/live/{{ item.domains[0] }}/fullchain.pem"
loop: "{{ certbot_certs }}"
loop_control:
label: "{{ item.domains | join(',') }}"
@@ -1,6 +1,6 @@
---
- name: install wireguard-tools
- name: install certbot
ansible.builtin.apt:
name: wireguard-tools
name: certbot
state: latest
update_cache: true
@@ -1,6 +1,6 @@
---
- name: include wireguard-tools install
- name: include certbot install
ansible.builtin.include_tasks: install.yml
- name: include wireguard-tools configurure
- name: include certbot configure
ansible.builtin.include_tasks: configure.yml
+1 -1
View File
@@ -1,5 +1,5 @@
interface=lo
interface=eth0
interface=br-eth0
interface=eth0.2
interface=eth0.3
interface=eth0.4
+9 -9
View File
@@ -1,13 +1,13 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in dnsmasq_managed_group | sort %}
{% set client = hostvars[item] %}
{% set ip = client.container_ip | default(client.ansible_host | default(none)) %}
{% if client['dhcp-host'] is defined and client['dhcp-host'] and ip %}
{% set entries = client['dhcp-host'] if (client['dhcp-host'] is iterable and client['dhcp-host'] is not string) else [client['dhcp-host']] %}
{% for entry in entries %}
{% if entry.mac %}
{% set client = hostvars[item] %}
{% set ip = client.container_ip | default(client.ansible_host | default(none)) %}
{% if client['dhcp-host'] is defined and client['dhcp-host'] and ip %}
{% set entries = client['dhcp-host'] if (client['dhcp-host'] is iterable and client['dhcp-host'] is not string) else [client['dhcp-host']] %}
{% for entry in entries %}
{% if entry.mac %}
dhcp-host={{ entry.mac }},{{ ip }},{{ item }}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
+5 -11
View File
@@ -1,15 +1,9 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in dnsmasq_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'dnsmasq' in client and client.dnsmasq %}
{% set default_ip = client.container_ip | default(client.ansible_host | default(none)) %}
{% set domains = client.dnsmasq if (client.dnsmasq is iterable and client.dnsmasq is not string) else [client.dnsmasq] %}
{% for d in domains %}
{% set entry = d if (d is mapping) else {'name': d} %}
{% set ip = entry.ip | default(default_ip) %}
{% if ip %}
{% for entry in hostvars[item].dnsmasq | default([]) %}
{% set ip = entry.ip | default(hostvars[entry.ip_from].container_ip if entry.ip_from is defined else none) %}
{% if ip %}
host-record={{ entry.name }},{{ ip }}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
+4 -4
View File
@@ -1,8 +1,8 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in dnsmasq_managed_group | sort %}
{% set client = hostvars[item] %}
{% set ip = client.container_ip | default(client.ansible_host | default(none)) %}
{% if ip %}
{% set client = hostvars[item] %}
{% set ip = client.container_ip | default(client.ansible_host | default(none)) %}
{% if ip %}
host-record={{ item }},{{ item }}.lan,{{ ip }}
{% endif %}
{% endif %}
{% endfor %}
+18
View File
@@ -0,0 +1,18 @@
---
- name: ensure local output directory exists
ansible.builtin.file:
path: "{{ openvpn_client_bundle_dir }}/{{ item.0.name }}"
state: directory
mode: '0700'
loop: "{{ openvpn_instances | subelements('clients') }}"
delegate_to: localhost
become: false
- name: render standalone client bundles
ansible.builtin.template:
src: "{{ role_path }}/templates/client-certs/{{ item.0.name }}.conf.j2"
dest: "{{ openvpn_client_bundle_dir }}/{{ item.0.name }}/{{ item.1.name }}.ovpn"
mode: '0600'
loop: "{{ openvpn_instances | subelements('clients') }}"
delegate_to: localhost
become: false
+82
View File
@@ -0,0 +1,82 @@
---
- name: prepare list of client certificates
ansible.builtin.set_fact:
cert_list: "{{ cert_list | default([]) + [ {'instance': item.0.name, 'pki_dir': item.0.pki_dir, 'client': item.1} ] }}"
loop: "{{ openvpn_instances | subelements('clients') }}"
- name: ensure local PKI directories exist
ansible.builtin.file:
path: "{{ item.pki_dir }}"
state: directory
mode: '0700'
loop: "{{ openvpn_instances }}"
- name: init pki if missing
ansible.builtin.command:
cmd: /opt/easy-rsa/easyrsa --batch init-pki
creates: "{{ item.pki_dir }}/private"
environment:
EASYRSA_PKI: "{{ item.pki_dir }}"
loop: "{{ openvpn_instances }}"
- name: build ca if missing
ansible.builtin.command:
cmd: /opt/easy-rsa/easyrsa --batch build-ca nopass
creates: "{{ item.pki_dir }}/ca.crt"
environment:
EASYRSA_PKI: "{{ item.pki_dir }}"
EASYRSA_REQ_CN: "CA-{{ item.name }}"
loop: "{{ openvpn_instances }}"
- name: build server cert if missing
ansible.builtin.command:
cmd: /opt/easy-rsa/easyrsa --batch build-server-full server nopass
creates: "{{ item.pki_dir }}/issued/server.crt"
environment:
EASYRSA_PKI: "{{ item.pki_dir }}"
loop: "{{ openvpn_instances }}"
- name: generate dh params if missing
ansible.builtin.command:
cmd: /opt/easy-rsa/easyrsa gen-dh
creates: "{{ item.pki_dir }}/dh.pem"
environment:
EASYRSA_PKI: "{{ item.pki_dir }}"
loop: "{{ openvpn_instances }}"
- name: check client certificates validity
ansible.builtin.command:
cmd: "openssl x509 -checkend 2592000 -in {{ item.pki_dir }}/issued/{{ item.client.name }}.crt"
register: cert_check
failed_when: false
changed_when: false
loop: "{{ cert_list }}"
- name: remove old cert file before reissue
ansible.builtin.file:
path: "{{ item.item.pki_dir }}/issued/{{ item.item.client.name }}.crt"
state: absent
loop: "{{ cert_check.results }}"
when: item.rc != 0
- name: remove old req file before reissue
ansible.builtin.file:
path: "{{ item.item.pki_dir }}/reqs/{{ item.item.client.name }}.req"
state: absent
loop: "{{ cert_check.results }}"
when: item.rc != 0
- name: remove old key file before reissue
ansible.builtin.file:
path: "{{ item.item.pki_dir }}/private/{{ item.item.client.name }}.key"
state: absent
loop: "{{ cert_check.results }}"
when: item.rc != 0
- name: issue or renew client certificates
ansible.builtin.command:
cmd: /opt/easy-rsa/easyrsa --batch build-client-full "{{ item.item.client.name }}" nopass
environment:
EASYRSA_PKI: "{{ item.item.pki_dir }}"
when: item.rc != 0
loop: "{{ cert_check.results }}"
+35
View File
@@ -0,0 +1,35 @@
---
- name: get latest easy-rsa release info
ansible.builtin.uri:
url: https://api.github.com/repos/OpenVPN/easy-rsa/releases/latest
return_content: true
register: easyrsa_release
run_once: true
check_mode: false
- name: set current easy-rsa version
ansible.builtin.set_fact:
easyrsa_version: "{{ easyrsa_release.json.tag_name | replace('v', '') }}"
easyrsa_asset_url: "{{ easyrsa_release.json.assets | selectattr('name', 'search', 'EasyRSA.*\\.tgz') | map(attribute='browser_download_url') | first }}"
- name: check easy-rsa installed version
ansible.builtin.command: /opt/easy-rsa/easyrsa version
register: easyrsa_current_version
changed_when: false
failed_when: false
- name: ensure easy-rsa directory exists
ansible.builtin.file:
path: /opt/easy-rsa
state: directory
mode: '0755'
check_mode: false
- name: update easy-rsa
ansible.builtin.unarchive:
src: "{{ easyrsa_asset_url }}"
dest: /opt/easy-rsa
remote_src: true
extra_opts:
- --strip-components=1
when: easyrsa_version not in (easyrsa_current_version.stdout | default(''))
+9
View File
@@ -0,0 +1,9 @@
---
- name: include install
ansible.builtin.include_tasks: install.yml
- name: include configure
ansible.builtin.include_tasks: configure.yml
- name: include client-certs.yml
ansible.builtin.include_tasks: client-certs.yml
@@ -0,0 +1,26 @@
client
dev tap0
proto tcp
remote 127.0.0.1 1195
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-256-GCM
verb 3
{% if item.1.ip is defined %}
route-metric {{ item.1.route_metric | default(50) }}
script-security 2
up "C:\\Windows\\System32\\netsh.exe interface ip set address name="OpenVPN TAP-Windows6" static {{ item.1.ip }} 255.255.255.0"
{% endif %}
<ca>
{{ lookup('file', item.0.pki_dir + '/ca.crt') }}
</ca>
<cert>
{{ lookup('file', item.0.pki_dir + '/issued/' + item.1.name + '.crt') }}
</cert>
<key>
{{ lookup('file', item.0.pki_dir + '/private/' + item.1.name + '.key') }}
</key>
@@ -0,0 +1,21 @@
client
dev tun0
proto tcp
remote 127.0.0.1 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-256-GCM
verb 3
<ca>
{{ lookup('file', item.0.pki_dir + '/ca.crt') }}
</ca>
<cert>
{{ lookup('file', item.0.pki_dir + '/issued/' + item.1.name + '.crt') }}
</cert>
<key>
{{ lookup('file', item.0.pki_dir + '/private/' + item.1.name + '.key') }}
</key>
+13
View File
@@ -0,0 +1,13 @@
---
- name: validate haproxy config
ansible.builtin.command: haproxy -c -f /etc/haproxy/haproxy.cfg
changed_when: false
listen: restart haproxy
- name: restart haproxy systemd service unit
ansible.builtin.systemd_service:
name: haproxy
daemon_reload: true
state: restarted
enabled: true
listen: restart haproxy
+10
View File
@@ -0,0 +1,10 @@
---
- name: render haproxy config
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/haproxy/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('fileglob', role_path + '/templates/' + inventory_hostname + '/*.cfg.j2') }}"
notify: restart haproxy
+6
View File
@@ -0,0 +1,6 @@
---
- name: install haproxy
ansible.builtin.apt:
name: haproxy
state: latest
update_cache: true
@@ -0,0 +1,90 @@
global
log /dev/log local2
chroot /var/lib/haproxy
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats mode 660 level admin
defaults
log global
mode tcp
option tcplog
option dontlognull
retries 3
timeout connect 5s
timeout client 1h
timeout server 1h
timeout check 10s
frontend http_frontend
bind 127.0.0.1:10080
mode http
option httplog
acl host_dttx hdr_end(host) -m end dttx.ru
use_backend dttx_http_srv if host_dttx
default_backend oyacoi_http_srv
backend oyacoi_http_srv
mode http
server oyacoi_srv {{ hostvars['nginx']['container_ip'] }}:81 send-proxy-v2
backend dttx_http_srv
mode http
server dttx_srv {{ hostvars['rbpi4']['container_ip'] }}:81 send-proxy-v2
frontend https_frontend
bind 127.0.0.1:10443
mode tcp
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl host_dttx req_ssl_sni -m end dttx.ru
acl host_telemt req_ssl_sni -m end regionculture.ru
use_backend dttx_https_srv if host_dttx
use_backend telemt_https_srv if host_telemt
default_backend oyacoi_https_srv
backend oyacoi_https_srv
mode tcp
server nginx_srv {{ hostvars['nginx']['container_ip'] }}:444 send-proxy-v2
backend dttx_https_srv
mode tcp
server dttx_srv {{ hostvars['rbpi4']['container_ip'] }}:444 send-proxy-v2
backend telemt_https_srv
mode tcp
option tcp-check
server telemt_srv {{ hostvars['vector']['container_ip'] }}:8080 check send-proxy-v2
server telemt_srv_backup {{ hostvars['dev']['container_ip'] }}:8080 check send-proxy-v2 backup
listen mcsmanager_service
bind {{ hostvars['liqueur']['container_ip'] }}:24444
mode tcp
server mcs_srv {{ hostvars['mcsmanager']['container_ip'] }}:24445 send-proxy-v2
listen xmpp_c2s
bind {{ hostvars['liqueur']['container_ip'] }}:5222
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5222
listen xmpp_legacy_ssl
bind {{ hostvars['liqueur']['container_ip'] }}:5223
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5223
listen xmpp_s2s
bind {{ hostvars['liqueur']['container_ip'] }}:5269
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5269
listen prosody_proxy65
bind {{ hostvars['liqueur']['container_ip'] }}:5000
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5000
listen prosody_components
bind {{ hostvars['liqueur']['container_ip'] }}:5270
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5270
listen prosody_bosh_http
bind {{ hostvars['liqueur']['container_ip'] }}:5280
server prosody_srv {{ hostvars['prosody']['container_ip'] }}:5280
+50
View File
@@ -0,0 +1,50 @@
auto lo
iface lo inet loopback
post-up ip rule add fwmark 0x1 lookup 100 2>/dev/null || true
post-up ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null || true
pre-down ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null || true
pre-down ip rule del fwmark 0x1 lookup 100 2>/dev/null || true
auto br-eth0
iface br-eth0 inet static
address 10.1.0.1/24
bridge_ports eth0 tap0
bridge_stp off
pre-up ip tuntap add dev tap0 mode tap || true
post-down ip tuntap del dev tap0 mode tap || true
auto eth0
iface eth0 inet manual
auto eth0.2
iface eth0.2 inet static
address 10.2.0.1/24
vlan-raw-device eth0
auto eth0.3
iface eth0.3 inet static
address 10.3.0.1/24
vlan-raw-device eth0
auto eth0.4
iface eth0.4 inet static
address 10.4.0.1/24
vlan-raw-device eth0
auto eth0.10
iface eth0.10 inet static
address 10.10.0.1/24
vlan-raw-device eth0
auto eth0.11
iface eth0.11 inet static
address 10.11.0.1/24
vlan-raw-device eth0
auto eth0.12
iface eth0.12 inet static
address 10.12.0.1/24
vlan-raw-device eth0
auto eth1
iface eth1 inet dhcp
@@ -1,7 +1,7 @@
---
- name: deploy ifupdown interfaces config
ansible.builtin.template:
src: interfaces
- name: deploy ifupdown interfaces
ansible.builtin.copy:
src: "{{ inventory_hostname }}/interfaces"
dest: /etc/network/interfaces
owner: root
group: root
+6 -2
View File
@@ -1,3 +1,7 @@
---
- name: include network configuration
include_tasks: network.yml
- name: include configure
ansible.builtin.include_tasks: configure.yml
- name: include prerequisites
ansible.builtin.include_tasks: prerequisites.yml
tags: ifupdown2_prereqs
+17
View File
@@ -0,0 +1,17 @@
---
- name: install bridge-utils
ansible.builtin.package:
name: bridge-utils
state: present
register: bridge_utils_install
- name: ensure rt_tables.d directory exists
ansible.builtin.file:
path: /etc/iproute2/rt_tables.d
state: directory
mode: "0755"
register: rt_tables_dir
- name: reload ifupdown2
ansible.builtin.command: ifreload -a
when: bridge_utils_install.changed or rt_tables_dir.changed
-20
View File
@@ -1,20 +0,0 @@
{% for item in ifupdown2 %}
auto {{ item.iface }}
iface {{ item.iface }}{% if item.method is defined %} inet {{ item.method }}
{% endif %}
{% if item.address is defined %}
address {{ item.address }}
{% endif %}
{% if item['vlan-raw-device'] is defined %}
vlan-raw-device {{ item['vlan-raw-device'] }}
{% endif %}
{% if item.routing is defined %}
{% for route in item.routing %}
{{ route }}
{% endfor %}
{% endif %}
{% if not loop.last %}
{% endif %}
{% endfor %}
-8
View File
@@ -5,14 +5,6 @@
state: present
loop: "{{ locales_list }}"
- name: configure /etc/default/locale
ansible.builtin.copy:
dest: /etc/default/locale
content: LANG={{ locale_default }}
owner: root
group: root
mode: '0644'
- name: configure /etc/locale.conf
ansible.builtin.copy:
dest: /etc/locale.conf
+9
View File
@@ -0,0 +1,9 @@
/var/log/xray-core/*.log {
daily
rotate 4
compress
delaycompress
missingok
notifempty
copytruncate
}
+6 -7
View File
@@ -1,9 +1,8 @@
---
- name: deploy logrotate config
ansible.builtin.template:
src: logrotate.conf.j2
dest: "/etc/logrotate.d/{{ item.name }}"
mode: "0644"
loop: "{{ logrotate }}"
loop_control:
label: "{{ item.name }}"
ansible.builtin.copy:
src: "{{ inventory_hostname }}/"
dest: "/etc/logrotate.d/"
owner: root
group: root
mode: '0644'
@@ -1,5 +0,0 @@
{{ item.paths | join(' ') }} {
{% for opt in item.options %}
{{ opt }}
{% endfor %}
}
-50
View File
@@ -1,50 +0,0 @@
flowtable ft {
hook ingress priority filter
devices = { eth0, eth1 }
}
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
meta mark 0x00000001 accept
iifname eth0 tcp dport 22 accept
iifname eth0.11 tcp dport 22 accept
iifname eth1 udp dport 51820 accept
iifname { eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } udp dport 53 accept
iifname { eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } tcp dport 53 accept
iifname eth0.3 udp dport 67 accept
iifname eth1 udp dport 68 accept
#include "/etc/nftables.d/90-input.nft"
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iifname { eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } oifname eth1 ct state new flow add @ft
iifname { eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } oifname eth1 accept
iifname "zt*" oifname "eth0" accept
iifname "eth0" oifname "zt*" accept
tcp flags syn tcp option maxseg size set rt mtu
include "/etc/nftables.d/90-forward.nft"
}
chain output {
type route hook output priority filter; policy accept;
#include "/etc/nftables.d/90-output.nft"
}
-35
View File
@@ -1,35 +0,0 @@
chain vpn_prerouting_dnat {
type nat hook prerouting priority dstnat - 5; policy accept;
iifname wg0 ip daddr 10.250.251.0/24 counter dnat ip prefix to 10.1.0.0/24
iifname wg0 ip daddr 10.250.252.0/24 counter dnat ip prefix to 10.2.0.0/24
iifname wg0 ip daddr 10.250.253.0/24 counter dnat ip prefix to 10.10.0.0/24
iifname wg0 ip daddr 10.250.254.0/24 counter dnat ip prefix to 10.11.0.0/24
iifname wg0 ip daddr 10.250.255.0/24 counter dnat ip prefix to 10.12.0.0/24
iifname wg0 ip daddr 10.250.249.0/24 counter dnat ip prefix to 10.13.0.0/24
}
chain vpn_postrouting_snat {
type nat hook postrouting priority srcnat; policy accept;
oifname wg0 ip saddr 10.1.0.0/24 counter snat ip prefix to 10.250.251.0/24
oifname wg0 ip saddr 10.2.0.0/24 counter snat ip prefix to 10.250.252.0/24
oifname wg0 ip saddr 10.10.0.0/24 counter snat ip prefix to 10.250.253.0/24
oifname wg0 ip saddr 10.11.0.0/24 counter snat ip prefix to 10.250.254.0/24
oifname wg0 ip saddr 10.12.0.0/24 counter snat ip prefix to 10.250.255.0/24
oifname wg0 ip saddr 10.13.0.0/24 counter snat ip prefix to 10.250.249.0/24
}
chain vpn_prerouting_pbr {
type filter hook prerouting priority mangle - 10; policy accept;
iifname wg0 ct state new counter ct mark set 0x000000c7
ip daddr 10.0.0.0/8 return
iifname != "wg0" ct mark 0x000000c7 counter mark set 0x000000c7
}
chain vpn_output_pbr {
type route hook output priority mangle - 10; policy accept;
ct mark 0x000000c7 counter meta mark set 0x000000c7
}
-15
View File
@@ -1,15 +0,0 @@
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
include "/etc/nftables.d/40-sets.nft"
include "/etc/nftables.d/90-sets.nft"
include "/etc/nftables.d/10-filter.nft"
include "/etc/nftables.d/20-vpn.nft"
include "/etc/nftables.d/30-proxy.nft"
}
table ip nat {
include "/etc/nftables.d/10-nat.nft"
}
@@ -2,7 +2,6 @@ chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname eth1 masquerade
}
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
include "/etc/nftables.d/90-dstnat.nft"
+34
View File
@@ -0,0 +1,34 @@
flowtable ft {
hook ingress priority filter
devices = { eth0, eth1 }
}
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
meta mark 0x00000001 accept
iifname br-eth0 tcp dport 22 accept
iifname eth0.11 tcp dport 22 accept
iifname tun0 tcp dport 22 accept
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } tcp dport 61219 accept
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } udp dport 61219 accept
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } udp dport 53 accept
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } tcp dport 53 accept
iifname eth0.3 udp dport 67 accept
iifname eth1 udp dport 68 accept
include "/etc/nftables.d/90-input.nft"
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } oifname eth1 ct state new flow add @ft
iifname { br-eth0, eth0.2, eth0.3, eth0.4, eth0.10, eth0.11, eth0.12 } oifname eth1 accept
tcp flags syn tcp option maxseg size set rt mtu
include "/etc/nftables.d/90-forward.nft"
}
chain output {
type route hook output priority filter; policy accept;
include "/etc/nftables.d/90-output.nft"
}
@@ -1,16 +1,11 @@
chain proxy_prerouting {
type filter hook prerouting priority filter - 50; policy accept;
fib daddr type local accept
meta mark 0x00000001 iif "lo" meta l4proto { tcp, udp } tproxy ip to :61219 counter accept
include "/etc/nftables.d/90-proxy-prerouting.nft"
}
chain proxy_output {
type route hook output priority mangle; policy accept;
meta mark != 0 return
include "/etc/nftables.d/90-proxy-output.nft"
}
+38 -21
View File
@@ -4,38 +4,55 @@
path: /etc/nftables.d
state: directory
mode: "0755"
when: nftables_bootstrap_files | default(false)
- name: deploy nftables rule
- name: bootstrap empty config files
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/nftables.d/{{ item }}"
content: ""
force: false
mode: "0644"
loop:
- 10-filter.nft
- 10-nat.nft
- 20-vpn.nft
- 30-proxy.nft
- 40-sets.nft
- 10-sets.nft
- 20-sets.nft
- 30-nat.nft
- 40-filter.nft
- 50-proxy.nft
- 90-dstnat.nft
- 90-forward.nft
- 90-input.nft
- 90-output.nft
- 90-proxy-output.nft
- 90-proxy-prerouting.nft
when: nftables_bootstrap_files | default(false)
- name: deploy nftables rules
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/nftables.d/{{ item | basename }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('ansible.builtin.fileglob', role_path + '/files/' + inventory_hostname + '/*.nft') }}"
notify: restart nftables
- name: render forward
- name: render nftable rules
ansible.builtin.template:
src: 90-forward.nft.j2
dest: /etc/nftables.d/90-forward.nft
mode: "0644"
notify: restart nftables
- name: render dstnat
ansible.builtin.template:
src: 90-dstnat.nft.j2
dest: /etc/nftables.d/90-dstnat.nft
mode: "0644"
src: "{{ item }}"
dest: "/etc/nftables.d/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('ansible.builtin.fileglob', role_path + '/templates/' + inventory_hostname + '/*.nft.j2') }}"
notify: restart nftables
- name: deploy nftables.conf
ansible.builtin.copy:
src: nftables.conf
dest: /etc/nftables.conf
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: "0644"
validate: "nft -c -f %s"
loop: "{{ query('ansible.builtin.fileglob', role_path + '/templates/' + inventory_hostname + '/*.conf.j2') }}"
notify: restart nftables
-19
View File
@@ -1,19 +0,0 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_dst' in client and client.nft_dst is not none %}
{% set target_ip = client.container_ip %}
{% for client in client.nft_dst %}
{% set ports = client.port if (client.port is iterable and client.port is not string) else [client.port] %}
{% set protos = client.proto if (client.proto is iterable and client.proto is not string) else [client.proto] %}
{% set ifaces = client.iface if (client.iface is iterable and client.iface is not string) else [client.iface] %}
{% for proto in protos %}
{% for port in ports %}
{% for iface in ifaces %}
iifname "{{ iface }}" {{ proto }} dport {{ port }} counter dnat ip to {{ target_ip }}:{{ port }} comment "{{ iface }} -> {{ item }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -1,47 +0,0 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_to' in client and client.nft_to is not none %}
{% set rules = client.nft_to if (client.nft_to is iterable and client.nft_to is not string) else [client.nft_to] %}
{% for rule in rules %}
{% set rule = rule if rule is mapping else {'to': rule} %}
{% set dests = rule.to if (rule.to is iterable and rule.to is not string) else [rule.to] %}
{% set protos = rule.proto if (rule.proto is iterable and rule.proto is not string) else [rule.proto | default(none)] %}
{% set ports = rule.port if (rule.port is iterable and rule.port is not string) else [rule.port | default(none)] %}
{% for dest in dests %}
{% if dest.startswith('zone:') %}
{% set oif = dest.split(':')[1] %}
{% set daddr = none %}
{% set dest_name = oif %}
{% else %}
{% set oif = hostvars[dest].zone_iface %}
{% set daddr = hostvars[dest].container_ip %}
{% set dest_name = dest %}
{% endif %}
{% for proto in protos %}
{% for port in ports %}
iifname "{{ client.zone_iface }}" ip saddr {{ client.container_ip }} oifname "{{ oif }}" {% if daddr %}ip daddr {{ daddr }} {% endif %}{% if proto and port %}{{ proto }} dport {{ port }} {% endif %}counter accept comment "{{ item }} -> {{ dest_name }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_from' in client and client.nft_from is not none %}
{% set rules = client.nft_from if (client.nft_from is iterable and client.nft_from is not string) else [client.nft_from] %}
{% for rule in rules %}
{% set ifaces = rule.iface if (rule.iface is iterable and rule.iface is not string) else [rule.iface] %}
{% set protos = rule.proto if (rule.proto is iterable and rule.proto is not string) else [rule.proto | default(none)] %}
{% set ports = rule.port if (rule.port is iterable and rule.port is not string) else [rule.port | default(none)] %}
{% for iface in ifaces %}
{% for proto in protos %}
{% for port in ports %}
iifname "{{ iface }}" oifname "{{ client.zone_iface }}" ip daddr {{ client.container_ip }} {% if proto and port %}{{ proto }} dport {{ port }} {% endif %}counter accept comment "{{ iface }} -> {{ item }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -0,0 +1,53 @@
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter;
policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
tcp dport 22 counter accept comment "ssh"
tcp dport 80 counter accept comment "http"
tcp dport 443 counter accept comment "https"
tcp dport 24444 counter accept comment "mcsmanager"
tcp dport { 5222, 5223, 5269, 5000, 5270, 5280 } counter accept comment "xmpp"
}
chain forward {
type filter hook forward priority filter;
policy drop;
ct state established,related accept
ip daddr {{ hostvars['coturn']['container_ip'] }} udp dport { 3478, 5349, 49152-65535 } counter accept
ip daddr {{ hostvars['coturn']['container_ip'] }} tcp dport { 3478, 5349 } counter accept
ip daddr {{ hostvars['mcsmanager']['container_ip'] }} tcp dport 25565 counter accept
ip daddr {{ hostvars['steamcmd']['container_ip'] }} udp dport 2456 counter accept
ip daddr {{ hostvars['steamcmd']['container_ip'] }} udp dport 2457 counter accept
ip daddr {{ hostvars['rbpi4']['container_ip'] }} udp dport 21116 counter accept
ip daddr {{ hostvars['rbpi4']['container_ip'] }} tcp dport 21114-21119 counter accept
iifname tun0 ip saddr {{ hostvars['workuter']['container_ip'] }} oifname tun0 ip daddr {{ hostvars['xiawrt']['container_ip'] }} tcp dport 22 counter accept
iifname tun0 ip saddr {{ hostvars['workuter']['container_ip'] }} oifname tun0 ip daddr {{ hostvars['rbpi4']['container_ip'] }} tcp dport 22 counter accept
iifname tun0 ip saddr {{ hostvars['oyacoi-odcm']['container_ip'] }} oifname tun0 ip daddr {{ hostvars['xiawrt']['container_ip'] }} tcp dport 22 counter accept
iifname tun0 ip saddr {{ hostvars['oyacoi-odcm']['container_ip'] }} oifname tun0 ip daddr {{ hostvars['rbpi4']['container_ip'] }} tcp dport 22 counter accept
}
chain output {
type filter hook output priority filter;
policy accept;
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat;
policy accept;
ip daddr {{ container_ip }} udp dport { 3478, 5349, 49152-65535 } counter dnat to {{ hostvars['coturn']['container_ip'] }}
ip daddr {{ container_ip }} tcp dport { 3478, 5349 } counter dnat to {{ hostvars['coturn']['container_ip'] }}
ip daddr {{ container_ip }} tcp dport 25565 counter dnat to {{ hostvars['mcsmanager']['container_ip'] }}
ip daddr {{ container_ip }} udp dport 2456 counter dnat to {{ hostvars['steamcmd']['container_ip'] }}
ip daddr {{ container_ip }} udp dport 2457 counter dnat to {{ hostvars['steamcmd']['container_ip'] }}
ip daddr {{ container_ip }} udp dport 21116 counter dnat to {{ hostvars['rbpi4']['container_ip'] }}
ip daddr {{ container_ip }} tcp dport 21114-21119 counter dnat to {{ hostvars['rbpi4']['container_ip'] }}
}
chain postrouting {
type nat hook postrouting priority srcnat;
policy accept;
}
}
@@ -0,0 +1,19 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_dst' in client and client.nft_dst is not none %}
{% set target_ip = client.container_ip %}
{% for client in client.nft_dst %}
{% set ports = client.port if (client.port is iterable and client.port is not string) else [client.port] %}
{% set protos = client.proto if (client.proto is iterable and client.proto is not string) else [client.proto] %}
{% set ifaces = client.iface if (client.iface is iterable and client.iface is not string) else [client.iface] %}
{% for proto in protos %}
{% for port in ports %}
{% for iface in ifaces %}
iifname "{{ iface }}" {{ proto }} dport {{ port }} counter dnat ip to {{ target_ip }}:{{ port }} comment "{{ iface }} -> {{ item }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -0,0 +1,47 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_to' in client and client.nft_to is not none %}
{% set rules = client.nft_to if (client.nft_to is iterable and client.nft_to is not string) else [client.nft_to] %}
{% for rule in rules %}
{% set rule = rule if rule is mapping else {'to': rule} %}
{% set dests = rule.to if (rule.to is iterable and rule.to is not string) else [rule.to] %}
{% set protos = rule.proto if (rule.proto is iterable and rule.proto is not string) else [rule.proto | default(none)] %}
{% set ports = rule.port if (rule.port is iterable and rule.port is not string) else [rule.port | default(none)] %}
{% for dest in dests %}
{% if dest.startswith('zone:') %}
{% set oif = dest.split(':')[1] %}
{% set daddr = none %}
{% set dest_name = oif %}
{% else %}
{% set oif = hostvars[dest].zone_iface %}
{% set daddr = hostvars[dest].container_ip %}
{% set dest_name = dest %}
{% endif %}
{% for proto in protos %}
{% for port in ports %}
iifname "{{ client.zone_iface }}" ip saddr {{ client.container_ip }} oifname "{{ oif }}" {% if daddr %}ip daddr {{ daddr }} {% endif %}{% if proto and port %}{{ proto }} dport {{ port }} {% endif %}counter accept comment "{{ item }} -> {{ dest_name }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
{% for item in nft_managed_group | sort %}
{% set client = hostvars[item] %}
{% if 'nft_from' in client and client.nft_from is not none %}
{% set rules = client.nft_from if (client.nft_from is iterable and client.nft_from is not string) else [client.nft_from] %}
{% for rule in rules %}
{% set ifaces = rule.iface if (rule.iface is iterable and rule.iface is not string) else [rule.iface] %}
{% set protos = rule.proto if (rule.proto is iterable and rule.proto is not string) else [rule.proto | default(none)] %}
{% set ports = rule.port if (rule.port is iterable and rule.port is not string) else [rule.port | default(none)] %}
{% for iface in ifaces %}
{% for proto in protos %}
{% for port in ports %}
iifname "{{ iface }}" oifname "{{ client.zone_iface }}" ip daddr {{ client.container_ip }} {% if proto and port %}{{ proto }} dport {{ port }} {% endif %}counter accept comment "{{ iface }} -> {{ item }}"
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -1,11 +1,11 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% macro set_daddr(rule) %}
{%- if rule in (xray_ip_sets | default([])) or rule in (xray_static_sets | default([])) -%}
{%- if rule in (xray_ip_sets | default([])) or rule in (xray_static_sets | default([])) -%}
{{ rule }}_ip
{%- elif rule in (xray_domain_sets | default([])) -%}
{%- elif rule in (xray_domain_sets | default([])) -%}
{{ rule }}_dom
{%- endif -%}
{%- endif -%}
{% endmacro %}
{% for rule in output_rules | default([]) | sort %}
ip daddr @{{ set_daddr(rule) }} meta mark set {{ xray_fwmark }} accept
{% endfor %}
ip daddr @{{ set_daddr(rule) }} meta mark set {{ xray_fwmark }} counter accept comment "router -> tproxy"
{% endfor %}
@@ -0,0 +1,28 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% macro set_daddr(name) -%}
{%- if name == 'all' -%}
0.0.0.0/0
{%- elif name in (xray_ip_sets | default([])) or name in (xray_static_sets | default([])) -%}
@{{ name }}_ip
{%- elif name in (xray_domain_sets | default([])) -%}
@{{ name }}_dom
{%- else -%}
invalid_xray_set_{{ name }}
{%- endif -%}
{%- endmacro -%}
{% for item in xray_managed_group | default([]) | sort %}
{% set client = hostvars[item] %}
{% if client.xray_policy is defined %}
{% set src_ip = client.container_ip %}
{% for rule in client.xray_policy %}
{% set target_set = rule.bypass | default(rule.proxy) %}
{% if rule.bypass is defined %}
meta l4proto tcp ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} counter accept comment "{{ item }} -> accept"
meta l4proto udp ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} counter accept comment "{{ item }} -> accept"
{% elif rule.proxy is defined %}
meta l4proto tcp ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} tproxy ip to :{{ xray_tproxy_port }} meta mark set {{ xray_fwmark }} counter accept comment "{{ item }} -> trpoxy"
meta l4proto udp ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} tproxy ip to :{{ xray_tproxy_port }} meta mark set {{ xray_fwmark }} counter accept comment "{{ item }} -> tproxy"
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -0,0 +1,11 @@
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
include "/etc/nftables.d/10-sets.nft"
include "/etc/nftables.d/20-sets.nft"
include "/etc/nftables.d/40-filter.nft"
include "/etc/nftables.d/50-proxy.nft"
}
table ip nat {
include "/etc/nftables.d/30-nat.nft"
}
+14
View File
@@ -0,0 +1,14 @@
# handlers/main.yml
---
- name: validate nginx config
ansible.builtin.command: nginx -t
changed_when: false
listen: restart nginx
- name: restart nginx systemd service unit
ansible.builtin.systemd_service:
name: nginx
daemon_reload: true
state: restarted
enabled: true
listen: restart nginx
+10
View File
@@ -0,0 +1,10 @@
---
- name: deploy nginx config
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/nginx/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('ansible.builtin.fileglob', role_path + '/templates/' + inventory_hostname + '/*.conf.j2') }}"
notify: restart nginx
+81
View File
@@ -0,0 +1,81 @@
---
- name: install prerequisites for nginx repository
ansible.builtin.apt:
name:
- curl
- gnupg2
- ca-certificates
- lsb-release
- debian-archive-keyring
state: present
update_cache: true
- name: check if nginx keyring already exists
ansible.builtin.stat:
path: /usr/share/keyrings/nginx-archive-keyring.gpg
register: nginx_keyring
- name: download nginx gpg key
ansible.builtin.get_url:
url: https://nginx.org/keys/nginx_signing.key
dest: /tmp/nginx_signing.key
mode: '0644'
when: not nginx_keyring.stat.exists
- name: dearmor nginx gpg key
ansible.builtin.command:
cmd: gpg --dearmor --yes -o /usr/share/keyrings/nginx-archive-keyring.gpg /tmp/nginx_signing.key
when: not nginx_keyring.stat.exists
- name: ensure /root/.gnupg exists
ansible.builtin.file:
path: /root/.gnupg
state: directory
mode: '0700'
owner: root
group: root
- name: verify nginx signing key fingerprint
ansible.builtin.command:
cmd: gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
register: nginx_key_check
changed_when: false
- name: check nginx signing key fingerprint
ansible.builtin.fail:
msg: "nginx signing key fingerprint mismatch! Got: {{ nginx_key_check.stdout }}"
when: "'573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62' not in nginx_key_check.stdout"
- name: add nginx apt repository
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/nginx.list
content: >-
deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg]
https://nginx.org/packages/{{ 'mainline/' if (nginx_use_mainline | default(false)) else '' }}debian
{{ ansible_facts['distribution_release'] }} nginx
owner: root
group: root
mode: '0644'
register: nginx_repo_file
- name: set up repository pinning for nginx
ansible.builtin.copy:
dest: /etc/apt/preferences.d/99nginx
content: |
Package: *
Pin: origin nginx.org
Pin: release o=nginx
Pin-Priority: 900
owner: root
group: root
mode: '0644'
- name: update apt cache
ansible.builtin.apt:
update_cache: true
when: nginx_repo_file.changed
- name: install nginx
ansible.builtin.apt:
name: nginx
state: present
+6
View File
@@ -0,0 +1,6 @@
---
- name: include install
ansible.builtin.include_tasks: install.yml
- name: include configure
ansible.builtin.include_tasks: configure.yml
@@ -0,0 +1,37 @@
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
stream {
upstream haproxy_http {
server 127.0.0.1:10080;
}
upstream haproxy_backend {
server 127.0.0.1:10443;
}
upstream stunnel_tun0_backend {
server 127.0.0.1:8443;
}
upstream stunnel_tap0_backend {
server 127.0.0.1:8444;
}
map $ssl_preread_server_name $backend {
liqueur.oyacoi.ru stunnel_tun0_backend;
absinthe.oyacoi.ru stunnel_tap0_backend;
default haproxy_backend;
}
server {
listen {{ container_ip }}:80;
proxy_pass haproxy_http;
}
server {
listen {{ container_ip }}:443;
proxy_pass $backend;
ssl_preread on;
}
}
@@ -0,0 +1 @@
iroute 192.168.1.0 255.255.255.0
@@ -0,0 +1,7 @@
iroute 10.1.0.0 255.255.255.0
iroute 10.2.0.0 255.255.255.0
iroute 10.3.0.0 255.255.255.0
iroute 10.4.0.0 255.255.255.0
iroute 10.10.0.0 255.255.255.0
iroute 10.11.0.0 255.255.255.0
iroute 10.12.0.0 255.255.255.0
+19
View File
@@ -0,0 +1,19 @@
---
- name: render openvpn client config
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/openvpn/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0600'
loop: "{{ query('fileglob', role_path + '/templates/' + inventory_hostname + '/*.conf.j2') }}"
register: openvpn_client_configs
- name: restart openvpn client
ansible.builtin.systemd_service:
name: "openvpn@{{ item.item | basename | regex_replace('\\.conf\\.j2$', '') }}"
state: restarted
enabled: true
daemon_reload: true
loop: "{{ openvpn_client_configs.results }}"
when: item.changed
+27
View File
@@ -0,0 +1,27 @@
---
- name: deploy ccd files
ansible.builtin.copy:
src: "{{ role_path }}/files/{{ inventory_hostname }}/ccd/"
dest: /etc/openvpn/ccd/
owner: root
group: root
mode: '0644'
- name: render openvpn config
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/openvpn/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0600'
loop: "{{ query('ansible.builtin.fileglob', role_path + '/templates/' + inventory_hostname + '/*.conf.j2') }}"
register: openvpn_configs
- name: restart openvpn
ansible.builtin.systemd_service:
name: "openvpn@{{ item.item | basename | regex_replace('\\.conf\\.j2$', '') }}"
state: restarted
enabled: true
daemon_reload: true
loop: "{{ openvpn_configs.results }}"
when: item.changed
+6
View File
@@ -0,0 +1,6 @@
---
- name: install openvpn
ansible.builtin.apt:
name: openvpn
state: latest
update_cache: true
+11
View File
@@ -0,0 +1,11 @@
---
- name: include install
ansible.builtin.include_tasks: install.yml
- name: include server configuration
ansible.builtin.include_tasks: configure-server.yml
when: openvpn_role == 'server'
- name: include client configuration
ansible.builtin.include_tasks: configure-client.yml
when: openvpn_role == 'client'
@@ -0,0 +1,27 @@
port 1195
proto tcp
dev tap0
dev-type tap
server-bridge nogw
client-to-client
keepalive 10 60
cipher AES-256-GCM
auth SHA256
persist-key
persist-tun
status openvpn-tap0-status.log
verb 6
tun-mtu 1500
mssfix 1300
<ca>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/ca.crt') }}
</ca>
<cert>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/issued/server.crt') }}
</cert>
<key>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/private/server.key') }}
</key>
<dh>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/dh.pem') }}
</dh>
@@ -0,0 +1,44 @@
port 1194
proto tcp
dev tun0
server 172.168.0.0 255.255.255.0
topology subnet
ifconfig-pool-persist ipp.txt
route 10.1.0.0 255.255.255.0
route 10.2.0.0 255.255.255.0
route 10.3.0.0 255.255.255.0
route 10.4.0.0 255.255.255.0
route 10.10.0.0 255.255.255.0
route 10.11.0.0 255.255.255.0
route 10.12.0.0 255.255.255.0
route 192.168.1.0 255.255.255.0
push "route 192.168.1.0 255.255.255.0"
push "route 10.1.0.0 255.255.255.0"
push "route 10.2.0.0 255.255.255.0"
push "route 10.3.0.0 255.255.255.0"
push "route 10.4.0.0 255.255.255.0"
push "route 10.10.0.0 255.255.255.0"
push "route 10.11.0.0 255.255.255.0"
push "route 10.12.0.0 255.255.255.0"
client-config-dir /etc/openvpn/ccd/liqueur
keepalive 10 60
cipher AES-256-GCM
auth SHA256
persist-key
persist-tun
status openvpn-status.log
verb 3
tun-mtu 1500
mssfix 1300
<ca>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/ca.crt') }}
</ca>
<cert>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/issued/server.crt') }}
</cert>
<key>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/private/server.key') }}
</key>
<dh>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/dh.pem') }}
</dh>
@@ -0,0 +1,24 @@
client
dev tap0
dev-type tap
proto tcp
remote 127.0.0.1 1195
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-256-GCM
tun-mtu 1500
mssfix 1300
verb 3
<ca>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/ca.crt') }}
</ca>
<cert>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/issued/ltrefilov.crt') }}
</cert>
<key>
{{ lookup('file', '/etc/easy-rsa/pki/tap0/private/ltrefilov.key') }}
</key>
@@ -0,0 +1,21 @@
client
dev tun0
proto tcp
remote 127.0.0.1 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-256-GCM
verb 3
<ca>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/ca.crt') }}
</ca>
<cert>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/issued/mur89.crt') }}
</cert>
<key>
{{ lookup('file', '/etc/easy-rsa/pki/tun0/private/mur89.key') }}
</key>
+5
View File
@@ -0,0 +1,5 @@
---
- name: restart sshd
ansible.builtin.service:
name: ssh
state: restarted
+16
View File
@@ -0,0 +1,16 @@
---
- name: disable password authentication
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PasswordAuthentication\s'
line: 'PasswordAuthentication no'
validate: '/usr/sbin/sshd -t -f %s'
notify: restart sshd
- name: enable root authentication
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin\s'
line: 'PermitRootLogin prohibit-password'
validate: '/usr/sbin/sshd -t -f %s'
notify: restart sshd
@@ -1,3 +1,3 @@
---
- name: include xray-core configurure
- name: include configure
ansible.builtin.include_tasks: configure.yml
@@ -0,0 +1,9 @@
setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel4/absinthe.pid
output = /var/log/stunnel4/absinthe.log
[openvpn]
cert = /etc/letsencrypt/live/absinthe.oyacoi.ru/fullchain.pem
key = /etc/letsencrypt/live/absinthe.oyacoi.ru/privkey.pem
accept = 127.0.0.1:8444
connect = 127.0.0.1:1195
@@ -0,0 +1,9 @@
setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel4/liqueur.pid
output = /var/log/stunnel4/liqueur.log
[openvpn]
cert = /etc/letsencrypt/live/liqueur.oyacoi.ru/fullchain.pem
key = /etc/letsencrypt/live/liqueur.oyacoi.ru/privkey.pem
accept = 127.0.0.1:8443
connect = 127.0.0.1:1194
+6
View File
@@ -0,0 +1,6 @@
---
- name: restart stunnel4
ansible.builtin.service:
name: stunnel4
state: restarted
listen: restart stunnel4
+36
View File
@@ -0,0 +1,36 @@
---
- name: ensure /var/run/stunnel exists
ansible.builtin.file:
path: /var/run/stunnel
owner: stunnel4
group: stunnel4
state: directory
mode: "0755"
- name: ensure /var/log/stunnel exists
ansible.builtin.file:
path: /var/log/stunnel
state: directory
owner: stunnel4
group: stunnel4
mode: "0755"
- name: deploy stunnel config
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/stunnel/{{ item | basename }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('fileglob', role_path + '/files/' + inventory_hostname + '/*.conf') }}"
notify: restart stunnel4
- name: render stunnel config
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/stunnel/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: root
group: root
mode: '0644'
loop: "{{ query('fileglob', role_path + '/templates/' + inventory_hostname + '/*.conf.j2') }}"
notify: restart stunnel4
+6
View File
@@ -0,0 +1,6 @@
---
- name: install stunnel4
ansible.builtin.apt:
name: stunnel4
state: latest
update_cache: true
+6
View File
@@ -0,0 +1,6 @@
---
- name: include install
ansible.builtin.include_tasks: install.yml
- name: include configure
ansible.builtin.include_tasks: configure.yml
@@ -0,0 +1,9 @@
setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel/absinthe.pid
output = /var/log/stunnel/absinthe.log
client = yes
[openvpn]
sni = absinthe.oyacoi.ru
accept = 127.0.0.1:1195
connect = {{ hostvars['liqueur'].container_ip }}:443
@@ -0,0 +1,9 @@
setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel/liqueur.pid
output = /var/log/stunnel/liqueur.log
client = yes
[openvpn]
sni = liqueur.oyacoi.ru
accept = 127.0.0.1:1194
connect = {{ hostvars['liqueur'].container_ip }}:443
@@ -0,0 +1,2 @@
net.ipv4.ip_forward = 1
net.ipv4.conf.all.route_localnet = 1
+6
View File
@@ -0,0 +1,6 @@
net.ipv4.ip_forward = 1
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-arptables = 0
+3 -3
View File
@@ -1,7 +1,7 @@
- name: deploy sysctl config
ansible.builtin.template:
src: sysctl.conf.j2
dest: "/etc/sysctl.d/99-custom.conf"
ansible.builtin.copy:
src: "{{ inventory_hostname }}/"
dest: "/etc/sysctl.d/"
owner: root
group: root
mode: '0644'
-3
View File
@@ -1,3 +0,0 @@
{% for key, value in sysctl.items() %}
{{ key }} = {{ value }}
{% endfor %}
-7
View File
@@ -1,7 +0,0 @@
---
- name: restart wg0 systemd service unit
ansible.builtin.systemd_service:
name: wg-quick@wg0
daemon_reload: true
state: restarted
enabled: true
-21
View File
@@ -1,21 +0,0 @@
---
- name: ensure /etc/wireguard exists
ansible.builtin.file:
path: /etc/wireguard
state: directory
mode: "0700"
- name: deploy wireguard config
ansible.builtin.template:
src: "wg0.conf.j2"
dest: "/etc/wireguard/wg0.conf"
mode: "0644"
register: wg0_conf
- name: restart wg0 systemd service unit
ansible.builtin.systemd_service:
name: wg-quick@wg0
daemon_reload: true
state: restarted
enabled: true
when: wg0_conf.changed
@@ -1,17 +0,0 @@
[Interface]
PrivateKey = {{ wg_private_key }}
Address = {{ wg_address }}
Table = off
PostUp = ip route add 10.250.250.0/24 dev wg0 2>/dev/null || true
PostUp = ip rule add fwmark 0xc7 lookup 199 2>/dev/null || true
PostUp = ip route add default dev wg0 table 199 2>/dev/null || true
PreDown = ip route del default dev wg0 table 199 2>/dev/null || true
PreDown = ip rule del fwmark 0xc7 lookup 199 2>/dev/null || true
PreDown = ip route del 10.250.250.0/24 dev wg0 2>/dev/null || true
[Peer]
PublicKey = {{ wg_public_key }}
PresharedKey = {{ wg_presharedkey }}
Endpoint = {{ wg_endpoint_address }}:{{ wg_endpoint_port }}
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0
-43
View File
@@ -1,43 +0,0 @@
---
- name: ensure /opt/xray-core/config exists
ansible.builtin.file:
path: /opt/xray-core/config
state: directory
mode: 0755
- name: ensure /var/log/xray-core exists
ansible.builtin.file:
path: /var/log/xray-core
state: directory
mode: 0755
- name: deploy static xray-core config
ansible.builtin.copy:
src: "{{ item }}"
dest: "/opt/xray-core/config/{{ item }}"
mode: 0744
loop:
- dns.jsonc
- inbounds.jsonc
- log.jsonc
- policy.jsonc
register: xray_core_static_config
- name: deploy dynamic xray-core config
ansible.builtin.template:
src: "{{ item }}.j2"
dest: "/opt/xray-core/config/{{ item }}"
mode: 0744
loop:
- observatory.jsonc
- outbounds.jsonc
- routing.jsonc
register: xray_core_dynamic_config
- name: restart xray-core systemd service unit
ansible.builtin.systemd_service:
name: xray-core
daemon_reload: true
state: restarted
enabled: true
when: xray_core_static_config.changed or xray_core_dynamic_config.changed
@@ -1,6 +1,7 @@
{
"inbounds": [
{
"tag": "tproxy-in",
"port": 61219,
"listen": "0.0.0.0",
"protocol": "dokodemo-door",
@@ -12,8 +13,7 @@
"sockopt": {
"tproxy": "tproxy"
}
},
"tag": "tproxy"
}
},
{
"tag": "socks-in",
+5 -1
View File
@@ -6,12 +6,16 @@ Wants=network-online.target
[Service]
Type=simple
User=root
User=xray-core
Group=xray-core
WorkingDirectory=/opt/xray-core
ExecStart=/opt/xray-core/xray -confdir /opt/xray-core/config
Restart=on-failure
RestartSec=3s
LimitNOFILE=65535
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
+13
View File
@@ -0,0 +1,13 @@
---
- name: validate xray-core config
ansible.builtin.command: su -s /bin/sh xray-core -c "/opt/xray-core/xray run -test -confdir /opt/xray-core/config"
changed_when: false
listen: restart xray-core
- name: restart xray-core systemd service unit
ansible.builtin.systemd_service:
name: xray-core
daemon_reload: true
state: restarted
enabled: true
listen: restart xray-core
+36
View File
@@ -0,0 +1,36 @@
---
- name: ensure /opt/xray-core/config exists
ansible.builtin.file:
path: /opt/xray-core/config
state: directory
owner: xray-core
group: xray-core
mode: "0755"
- name: ensure /var/log/xray-core exists
ansible.builtin.file:
path: /var/log/xray-core
state: directory
owner: xray-core
group: xray-core
mode: "0755"
- name: deploy xray-core static config
ansible.builtin.copy:
src: "{{ item }}"
dest: "/opt/xray-core/config/{{ item | basename }}"
owner: xray-core
group: xray-core
mode: "0644"
loop: "{{ query('ansible.builtin.fileglob', role_path + '/files/' + inventory_hostname + '/*.jsonc') }}"
notify: restart xray-core
- name: render xray-core dynamic config
ansible.builtin.template:
src: "{{ item }}"
dest: "/opt/xray-core/config/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: xray-core
group: xray-core
mode: "0644"
loop: "{{ query('ansible.builtin.fileglob', role_path + '/templates/' + inventory_hostname + '/*.jsonc.j2') }}"
notify: restart xray-core
+6 -1
View File
@@ -10,6 +10,7 @@
return_content: yes
register: xray_release
run_once: true
check_mode: false
- name: set current xray-core version
ansible.builtin.set_fact:
@@ -25,6 +26,8 @@
- name: ensure xray-core directory exists
ansible.builtin.file:
path: /opt/xray-core
owner: xray-core
group: xray-core
state: directory
mode: '0755'
@@ -33,10 +36,12 @@
src: "{{ xray_asset_url }}"
dest: /opt/xray-core
remote_src: yes
owner: xray-core
group: xray-core
when: xray_version not in (xray_current_version.stdout | default(''))
- name: deploy xray-core systemd service unit
ansible.builtin.copy:
src: xray-core.service
dest: /etc/systemd/system/xray-core.service
mode: 755
mode: 0644
+6
View File
@@ -1,3 +1,9 @@
---
- name: include xray-core user
ansible.builtin.include_tasks: user.yml
- name: include xray-core install
ansible.builtin.include_tasks: install.yml
- name: include xray-core configure
ansible.builtin.include_tasks: configure.yml
+16
View File
@@ -0,0 +1,16 @@
---
- name: create xray-core system group
ansible.builtin.group:
name: xray-core
system: true
state: present
- name: create xray-core system user
ansible.builtin.user:
name: xray-core
group: xray-core
system: true
shell: /usr/sbin/nologin
home: /opt/xray-core
create_home: false
state: present
@@ -33,9 +33,6 @@
"h3"
],
"fingerprint": "firefox"
},
"sockopt": {
"mark": 255
}
}
},
@@ -45,13 +42,6 @@
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 255,
"interface": "eth1",
"tcpFastOpen": true
}
}
},
{
@@ -31,7 +31,7 @@
{
"type": "field",
"inboundTag": [
"tproxy",
"tproxy-in",
"socks-in"
],
"balancerTag": "{{ 'balancer-vless' if xray_outbounds | length > 1 else 'vless-' ~ xray_outbounds[0].tag }}"
-32
View File
@@ -17,35 +17,3 @@
name: xray-lists.service
state: started
when: xray_lists_config.changed
- name: bootstrap empty config files
ansible.builtin.copy:
dest: "/etc/nftables.d/{{ item }}"
content: ""
force: false
mode: "0644"
loop:
- 90-sets.nft
- 90-proxy-prerouting.nft
- 90-proxy-output.nft
- name: render nft sets
ansible.builtin.template:
src: 90-sets.nft.j2
dest: /etc/nftables.d/90-sets.nft
mode: "0644"
notify: reload nftables
- name: render proxy prerouting
ansible.builtin.template:
src: 90-proxy-prerouting.nft.j2
dest: /etc/nftables.d/90-proxy-prerouting.nft
mode: "0644"
notify: reload nftables
- name: render proxy output
ansible.builtin.template:
src: 90-proxy-output.nft.j2
dest: /etc/nftables.d/90-proxy-output.nft
mode: "0644"
notify: reload nftables
@@ -1,26 +0,0 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% macro set_daddr(name) %}
{%- if name == 'all' %}
0.0.0.0/0
{%- elif name in (xray_ip_sets | default([])) or name in (xray_static_sets | default([])) %}
@{{ name }}_ip
{%- elif name in (xray_domain_sets | default([])) %}
@{{ name }}_dom
{%- else %}
invalid_xray_set_{{ name }}
{% endif %}
{% endmacro %}
{% for item in xray_managed_group | default([]) | sort %}
{% set client = hostvars[item] %}
{% if client.xray_policy is defined %}
{% set src_ip = client.container_ip %}
{% for rule in client.xray_policy %}
{% set target_set = rule.bypass | default(rule.proxy) %}
{% if rule.bypass is defined %}
meta l4proto { tcp, udp } ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} accept
{% elif rule.proxy is defined %}
meta l4proto { tcp, udp } ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} tproxy ip to :{{ xray_tproxy_port }} meta mark set {{ xray_fwmark }} accept
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
+26 -26
View File
@@ -3,49 +3,49 @@ global:
cache_dir: {{ xray_lists_global.cache_dir }}
output_dir: {{ xray_lists_global.output_dir }}
dnsmasq_output: {{ xray_lists_global.dnsmasq_output }}
{% if xray_lists_global.proxy is defined %}
{% if xray_lists_global.proxy is defined %}
proxy: "{{ xray_lists_global.proxy }}"
{% endif %}
{% if proxy_user is defined %}
{% endif %}
{% if proxy_user is defined %}
proxy_user: "{{ proxy_user }}"
proxy_pass: "{{ proxy_pass }}"
{% endif %}
{% endif %}
http_timeout: {{ xray_lists_global.http_timeout | default(20) }}
ip_sets:
{% for id, item in xray_ip_sets.items() %}
{% for id, item in xray_ip_sets.items() %}
- id: {{ id }}
output: {{ id }}_ip.elements.nft
{% if item.static is defined %}
{% if item.static is defined %}
static:
{% for s in item.static %}
{% for s in item.static %}
- {{ s }}
{% endfor %}
{% endif %}
{% if item.urls is defined %}
{% endfor %}
{% endif %}
{% if item.urls is defined %}
urls:
{% for u in item.urls %}
{% for u in item.urls %}
- {{ u }}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
domain_sets:
{% for id, item in xray_domain_sets.items() %}
{% for id, item in xray_domain_sets.items() %}
- id: {{ id }}
dnsmasq_target: "4#inet#filter#{{ id }}_dom"
{% if item.static is defined %}
{% if item.static is defined %}
static:
{% for s in item.static %}
{% for s in item.static %}
- {{ s }}
{% endfor %}
{% endif %}
{% if item.urls is defined %}
{% endfor %}
{% endif %}
{% if item.urls is defined %}
urls:
{% for u in item.urls %}
{% for u in item.urls %}
- {{ u }}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
output_rules:
{% for rule in output_rules %}
{% for rule in output_rules %}
- {{ rule }}
{% endfor %}
{% endfor %}
-10
View File
@@ -1,10 +0,0 @@
---
- name: reload nftables
ansible.builtin.command: nft -f /etc/nftables.conf
- name: restart zerotier-one systemd service unit
ansible.builtin.systemd_service:
name: zerotier-one
daemon_reload: true
state: restarted
enabled: true
-31
View File
@@ -1,31 +0,0 @@
---
- name: create networks.d directory
ansible.builtin.file:
path: /var/lib/zerotier-one/networks.d
state: directory
mode: 0700
owner: zerotier-one
group: zerotier-one
- name: check if zerotier-one network config exists
ansible.builtin.stat:
path: "/var/lib/zerotier-one/networks.d/{{ zerotier_network_id }}.conf"
register: zerotier_network_stat
- name: create zerotier-one network config
ansible.builtin.file:
path: "/var/lib/zerotier-one/networks.d/{{ zerotier_network_id }}.conf"
state: touch
mode: "0600"
owner: zerotier-one
group: zerotier-one
when: not zerotier_network_stat.stat.exists
register: zerotier_network
- name: restart zerotier-one systemd service unit
ansible.builtin.systemd_service:
name: zerotier-one
daemon_reload: true
state: restarted
enabled: true
when: zerotier_network.changed
-16
View File
@@ -1,16 +0,0 @@
---
- name: add zerotier repository
ansible.builtin.deb822_repository:
name: zerotier
types: deb
uris: "http://download.zerotier.com/debian/trixie"
suites: "trixie"
components: main
signed_by: "https://download.zerotier.com/contact%40zerotier.com.gpg"
state: present
- name: install zerotier-one
ansible.builtin.apt:
name: zerotier-one
state: latest
update_cache: true
-17
View File
@@ -1,17 +0,0 @@
[Interface]
PrivateKey = {{ wg_private_key }}
Address = {{ wg_address }}
Table = off
PostUp = ip route add 10.250.250.0/24 dev wg0 2>/dev/null || true
PostUp = ip rule add fwmark 0xc7 lookup 199 2>/dev/null || true
PostUp = ip route add default dev wg0 table 199 2>/dev/null || true
PreDown = ip route del default dev wg0 table 199 2>/dev/null || true
PreDown = ip rule del fwmark 0xc7 lookup 199 2>/dev/null || true
PreDown = ip route del 10.250.250.0/24 dev wg0 2>/dev/null || true
[Peer]
PublicKey = {{ wg_public_key }}
PresharedKey = {{ wg_presharedkey }}
Endpoint = {{ wg_endpoint_address }}:{{ wg_endpoint_port }}
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0