feat(ansible): extract playbooks and roles into standalone repository
This commit is contained in:
parent
99029986aa
commit
3344b1e530
6
common_setup.yml
Normal file
6
common_setup.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
- name: Run infrastructure setup
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
gather_facts: yes
|
||||||
|
roles:
|
||||||
|
- vhosts/common
|
||||||
6
k3s-cluster.yaml
Normal file
6
k3s-cluster.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
- name: Run K3S-cluster setup
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
gather_facts: yes
|
||||||
|
roles:
|
||||||
|
- roles/vhosts/k3s-cluster
|
||||||
6734
roles/grafana-dashboard/K8S-Dashboard-2025-01015.json
Normal file
6734
roles/grafana-dashboard/K8S-Dashboard-2025-01015.json
Normal file
File diff suppressed because it is too large
Load Diff
5890
roles/grafana-dashboard/Node-Exporter-Dashboard-202501015.json
Normal file
5890
roles/grafana-dashboard/Node-Exporter-Dashboard-202501015.json
Normal file
File diff suppressed because it is too large
Load Diff
18
roles/vhosts/common/defaults/main.yml
Normal file
18
roles/vhosts/common/defaults/main.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
enable_set_timezone: true # 默认启用 Set timezone
|
||||||
|
enable_set_hostname: true # 默认启用 Set hostname
|
||||||
|
enable_install_packages: true # 默认不安装额外的软件包
|
||||||
|
enable_all_hosts_update: false # 默认不更新所有主机的条目
|
||||||
|
|
||||||
|
rsyslog_log_rotation: # 可选的日志管理配置
|
||||||
|
enable: true # 启用 rsyslog 日志管理
|
||||||
|
rotate_count: 4 # 默认保留的日志文件数量
|
||||||
|
rotate_frequency: weekly # 默认每周轮换, 可选:daily, hourly
|
||||||
|
max_log_size: 100M # 默认日志文件最大大小
|
||||||
|
|
||||||
|
journald_log_rotation: # 启用 journald 日志管理
|
||||||
|
enable: true # 启用 journald 日志管理
|
||||||
|
max_log_size: 100M # 默认日志文件最大大小
|
||||||
|
max_files: 100 # 默认保留的最大日志文件数
|
||||||
|
max_file_sec: 1month # 默认日志文件保存的最大时长
|
||||||
|
system_max_use: 1G # 默认系统日志最大使用空间
|
||||||
|
runtime_max_use: 500M # 默认运行时日志最大使用空间
|
||||||
5
roles/vhosts/common/files/install-packages.sh
Normal file
5
roles/vhosts/common/files/install-packages.sh
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y vim iputils-ping rsync wireguard-tools
|
||||||
11
roles/vhosts/common/files/secure_ssh.sh
Normal file
11
roles/vhosts/common/files/secure_ssh.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 设置 ~/.ssh/ 目录的权限
|
||||||
|
sudo chmod 700 ~/.ssh
|
||||||
|
|
||||||
|
# 设置 ~/.ssh/authorized_keys 文件的权限
|
||||||
|
sudo chmod 600 ~/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# 使用 chattr +i 确保 authorized_keys 文件不能被删除
|
||||||
|
sudo chattr +i ~/.ssh/authorized_keys || true
|
||||||
|
|
||||||
10
roles/vhosts/common/handlers/main.yml
Normal file
10
roles/vhosts/common/handlers/main.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- name: Restart logrotate service
|
||||||
|
service:
|
||||||
|
name: logrotate
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: Restart systemd-journald service
|
||||||
|
service:
|
||||||
|
name: systemd-journald
|
||||||
|
state: restarted
|
||||||
7
roles/vhosts/common/tasks/configure_journald.yml
Normal file
7
roles/vhosts/common/tasks/configure_journald.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Configure journald log rotation using template
|
||||||
|
template:
|
||||||
|
src: journald_logrotate.j2
|
||||||
|
dest: /etc/systemd/journald.conf
|
||||||
|
when: journald_log_rotation.enable
|
||||||
|
notify: Restart systemd-journald service
|
||||||
7
roles/vhosts/common/tasks/configure_logrotate.yaml
Normal file
7
roles/vhosts/common/tasks/configure_logrotate.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Configure logrotate for rsyslog using template
|
||||||
|
template:
|
||||||
|
src: rsyslog_logrotate.j2
|
||||||
|
dest: /etc/logrotate.d/rsyslog
|
||||||
|
when: rsyslog_log_rotation.enable
|
||||||
|
notify: Restart logrotate service
|
||||||
27
roles/vhosts/common/tasks/disable-systemd-resolved.yml
Normal file
27
roles/vhosts/common/tasks/disable-systemd-resolved.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
- name: Stop systemd-resolved
|
||||||
|
systemd:
|
||||||
|
name: systemd-resolved
|
||||||
|
state: stopped
|
||||||
|
enabled: no
|
||||||
|
|
||||||
|
- name: Remove /etc/resolv.conf if it's a symlink
|
||||||
|
file:
|
||||||
|
path: /etc/resolv.conf
|
||||||
|
state: absent
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Create static /etc/resolv.conf
|
||||||
|
copy:
|
||||||
|
dest: /etc/resolv.conf
|
||||||
|
content: |
|
||||||
|
nameserver 8.8.8.8
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Optionally make resolv.conf immutable to prevent changes
|
||||||
|
command: chattr +i /etc/resolv.conf
|
||||||
|
args:
|
||||||
|
warn: false
|
||||||
|
when: make_resolv_conf_immutable | default(false)
|
||||||
17
roles/vhosts/common/tasks/include_gpu.yaml
Normal file
17
roles/vhosts/common/tasks/include_gpu.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
- name: Add NVIDIA repository
|
||||||
|
shell: |
|
||||||
|
add-apt-repository -y ppa:graphics-drivers
|
||||||
|
curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | apt-key add -
|
||||||
|
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
|
||||||
|
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | tee /etc/apt/sources.list.d/nvidia-container-runtime.list
|
||||||
|
apt-get update
|
||||||
|
|
||||||
|
- name: Install NVIDIA driver and container runtime
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nvidia-modprobe
|
||||||
|
- nvidia-driver-535
|
||||||
|
- nvidia-headless-535
|
||||||
|
- nvidia-container-runtime
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
38
roles/vhosts/common/tasks/main.yml
Normal file
38
roles/vhosts/common/tasks/main.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
- name: Set timezone
|
||||||
|
shell: "timedatectl set-timezone Asia/Shanghai"
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
shell: "hostname -F /etc/hostname"
|
||||||
|
|
||||||
|
- name: update /etc/hostname
|
||||||
|
template: src=templates/hostname dest=/etc/hostname owner=root group=root mode=0644 unsafe_writes=yes
|
||||||
|
|
||||||
|
- name: Update /etc/hosts
|
||||||
|
template: src=templates/hosts dest=/etc/hosts owner=root group=root mode=0644 force=yes unsafe_writes=yes
|
||||||
|
|
||||||
|
- name: Set systemd-resolved and set static DNS
|
||||||
|
include_tasks: setup-systemd-resolved.yml
|
||||||
|
|
||||||
|
- name: Install packages
|
||||||
|
script: files/install-packages.sh
|
||||||
|
when: (ansible_facts['distribution'] == "Ubuntu") or (ansible_facts['distribution'] == "Debian")
|
||||||
|
|
||||||
|
- name: Include Privoxy sub task for SOCKS5 to HTTP proxy (optional)
|
||||||
|
include_tasks: setup-privoxy.yml
|
||||||
|
when: privoxy.enable | default(false)
|
||||||
|
|
||||||
|
#- name: Include GPU Configuration
|
||||||
|
# include_tasks: include_gpu.yaml
|
||||||
|
# when: (ansible_facts['distribution'] == "Ubuntu") or (ansible_facts['distribution'] == "Debian")
|
||||||
|
# tags:
|
||||||
|
# - k3s
|
||||||
|
# - gpu
|
||||||
|
# - nvidia
|
||||||
|
|
||||||
|
#- name: enable ip_forward
|
||||||
|
# shell: 'echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf; echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf ; sysctl -p /etc/sysctl.conf'
|
||||||
|
|
||||||
|
|
||||||
|
#- name: Install packages
|
||||||
|
# shell: "yum makecache && yum install -y audit container-selinux"
|
||||||
|
# when: (ansible_facts['distribution'] != "Ubuntu") or (ansible_facts['distribution'] != "Debian")
|
||||||
12
roles/vhosts/common/tasks/set_hostname.yaml
Normal file
12
roles/vhosts/common/tasks/set_hostname.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
- name: Check if systemctl is available
|
||||||
|
command: which hostnamectl
|
||||||
|
register: systemctl_check
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Set hostname using systemctl if available
|
||||||
|
shell: "hostnamectl set-hostname {{ inventory_hostname }}"
|
||||||
|
when: systemctl_check.rc == 0
|
||||||
|
|
||||||
|
- name: Set hostname using hostname -F if systemctl is not available
|
||||||
|
shell: "hostname -F /etc/hostname"
|
||||||
|
when: systemctl_check.rc != 0
|
||||||
2
roles/vhosts/common/tasks/set_timezone.yaml
Normal file
2
roles/vhosts/common/tasks/set_timezone.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
- name: Set timezone
|
||||||
|
shell: "timedatectl set-timezone Asia/Shanghai"
|
||||||
24
roles/vhosts/common/tasks/setup-privoxy.yml
Normal file
24
roles/vhosts/common/tasks/setup-privoxy.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- name: Install privoxy (Debian)
|
||||||
|
apt:
|
||||||
|
name: privoxy
|
||||||
|
state: present
|
||||||
|
when: ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: Install privoxy (RedHat)
|
||||||
|
yum:
|
||||||
|
name: privoxy
|
||||||
|
state: present
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: Ensure SOCKS5 forwarding is configured in privoxy
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/privoxy/config
|
||||||
|
line: "forward-socks5t / {{ proxy.socks5_host }}:{{ proxcy.socks5_port }} ."
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Restart and enable privoxy
|
||||||
|
systemd:
|
||||||
|
name: privoxy
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
36
roles/vhosts/common/tasks/setup-systemd-resolved.yml
Normal file
36
roles/vhosts/common/tasks/setup-systemd-resolved.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# playbooks/setup-systemd-resolved.yml
|
||||||
|
- name: Ensure systemd-resolved is installed
|
||||||
|
package:
|
||||||
|
name: systemd-resolved
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Enable and start systemd-resolved
|
||||||
|
systemd:
|
||||||
|
name: systemd-resolved
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Configure /etc/systemd/resolved.conf
|
||||||
|
ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: "Resolve"
|
||||||
|
option: "{{ item.option }}"
|
||||||
|
value: "{{ item.value }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { option: "DNSStubListener", value: "no" }
|
||||||
|
- { option: "DNS", value: "" }
|
||||||
|
- { option: "FallbackDNS", value: "" }
|
||||||
|
|
||||||
|
- name: Restart systemd-resolved
|
||||||
|
systemd:
|
||||||
|
name: systemd-resolved
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Ensure /etc/resolv.conf points to /run/systemd/resolve/resolv.conf
|
||||||
|
file:
|
||||||
|
src: /run/systemd/resolve/resolv.conf
|
||||||
|
dest: /etc/resolv.conf
|
||||||
|
state: link
|
||||||
|
force: true
|
||||||
3
roles/vhosts/common/templates/authorized_keys
Executable file
3
roles/vhosts/common/templates/authorized_keys
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
{% for item in ssh_keys %}
|
||||||
|
{{ item }}
|
||||||
|
{% endfor %}
|
||||||
1
roles/vhosts/common/templates/hostname
Executable file
1
roles/vhosts/common/templates/hostname
Executable file
@ -0,0 +1 @@
|
|||||||
|
{{ inventory_hostname }}
|
||||||
26
roles/vhosts/common/templates/hosts
Normal file
26
roles/vhosts/common/templates/hosts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# IPv4 localhost configuration
|
||||||
|
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
|
||||||
|
|
||||||
|
# IPv6 localhost configuration
|
||||||
|
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
||||||
|
|
||||||
|
# IPv6 Local addresses (desirable for IPv6 capable hosts)
|
||||||
|
::1 ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
ff00::0 ip6-mcastprefix
|
||||||
|
ff02::1 ip6-allnodes
|
||||||
|
ff02::2 ip6-allrouters
|
||||||
|
|
||||||
|
{{ ansible_default_ipv4.address }} {{ inventory_hostname }}
|
||||||
|
|
||||||
|
{% if enable_all_hosts_update is defined and enable_all_hosts_update %}
|
||||||
|
{% for item in groups['all'] %}
|
||||||
|
{{ hostvars[item]['ansible_host'] }} {{ item }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if extra_domain is defined %}
|
||||||
|
{% for ip, domain_name in extra_domain.items() %}
|
||||||
|
{{ ip }} {{ domain_name }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
5
roles/vhosts/common/templates/journald_logrotate.j2
Normal file
5
roles/vhosts/common/templates/journald_logrotate.j2
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Journal]
|
||||||
|
SystemMaxUse={{ journald_log_rotation.system_max_use }} # 设置最大日志使用空间
|
||||||
|
SystemMaxFiles={{ journald_log_rotation.max_files }} # 设置最大日志文件数
|
||||||
|
MaxFileSec={{ journald_log_rotation.max_file_sec }} # 设置日志文件的轮换频率(例如 weekly, daily, hourly)
|
||||||
|
RuntimeMaxUse={{ journald_log_rotation.runtime_max_use }} # 设置运行时日志最大使用空间
|
||||||
8
roles/vhosts/common/templates/logrotate-monitor-agent
Normal file
8
roles/vhosts/common/templates/logrotate-monitor-agent
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/var/log/prometheus-agent.log
|
||||||
|
/var/log/prometheus-transfer.log {
|
||||||
|
rotate 12
|
||||||
|
monthly
|
||||||
|
compress
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
}
|
||||||
23
roles/vhosts/common/templates/rsyslog_logrotate.j2
Normal file
23
roles/vhosts/common/templates/rsyslog_logrotate.j2
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/var/log/syslog
|
||||||
|
/var/log/mail* # 包括所有以 mail 开头的日志文件
|
||||||
|
/var/log/daemon.log
|
||||||
|
/var/log/kern.log
|
||||||
|
/var/log/auth.log
|
||||||
|
/var/log/user.log
|
||||||
|
/var/log/lpr.log
|
||||||
|
/var/log/cron.log
|
||||||
|
/var/log/debug
|
||||||
|
/var/log/messages
|
||||||
|
{
|
||||||
|
rotate {{ rsyslog_log_rotation.rotate_count }}
|
||||||
|
{{ rsyslog_log_rotation.rotate_frequency }}
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
sharedscripts
|
||||||
|
postrotate
|
||||||
|
/usr/lib/rsyslog/rsyslog-rotate
|
||||||
|
endscript
|
||||||
|
maxsize {{ rsyslog_log_rotation.max_log_size }}
|
||||||
|
}
|
||||||
300
roles/vhosts/k3s-cluster/files/set-registry.sh
Normal file
300
roles/vhosts/k3s-cluster/files/set-registry.sh
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#https://github.com/containerd/nerdctl/releases/download/v2.0.2/nerdctl-2.0.2-linux-amd64.tar.gz
|
||||||
|
#https://github.com/containerd/nerdctl/releases/download/v2.0.2/nerdctl-full-2.0.2-linux-amd64.tar.gz
|
||||||
|
#wget https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
# ✅ 环境变量检查(可配置)
|
||||||
|
# =============================================
|
||||||
|
: "${REGISTRY_DOMAIN:=kube.registry.local}"
|
||||||
|
: "${REGISTRY_PORT:=5000}"
|
||||||
|
: "${NERDCTL_VERSION:=v2.0.2}"
|
||||||
|
: "${CNI_VERSION:=v1.6.2}"
|
||||||
|
: "${CNI_DIR:=/opt/cni/bin}"
|
||||||
|
: "${CERT_DIR:=/opt/registry/certs}"
|
||||||
|
: "${CONFIG_DIR:=/opt/registry/config}"
|
||||||
|
: "${REGISTRY_DATA:=/var/lib/registry}"
|
||||||
|
: "${REGISTRY_YAML:=registry.yaml}"
|
||||||
|
: "${COMPOSE_YAML:=compose.yaml}"
|
||||||
|
: "${TAR_FILE:=registry.tar}"
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
# ✅ 自动检测 containerd.sock
|
||||||
|
# =============================================
|
||||||
|
if [[ -S "/run/k3s/containerd/containerd.sock" ]]; then
|
||||||
|
export CONTAINERD_ADDRESS="/run/k3s/containerd/containerd.sock"
|
||||||
|
elif [[ -S "/run/containerd/containerd.sock" ]]; then
|
||||||
|
export CONTAINERD_ADDRESS="/run/containerd/containerd.sock"
|
||||||
|
elif [[ -S "/var/run/containerd/containerd.sock" ]]; then
|
||||||
|
export CONTAINERD_ADDRESS="/var/run/containerd/containerd.sock"
|
||||||
|
else
|
||||||
|
echo "❌ 未检测到有效的 containerd.sock,请确认 containerd 是否正常运行。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NERDCTL_NAMESPACE="k8s.io"
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "📦 准备 nerdctl 全功能版..."
|
||||||
|
if ! command -v nerdctl &>/dev/null; then
|
||||||
|
if [ ! -f /tmp/nerdctl-full.tgz ]; then
|
||||||
|
echo "⬇️ 下载 nerdctl..."
|
||||||
|
wget -O /tmp/nerdctl-full.tgz \
|
||||||
|
"https://github.com/containerd/nerdctl/releases/download/${NERDCTL_VERSION}/nerdctl-full-${NERDCTL_VERSION#v}-linux-amd64.tar.gz"
|
||||||
|
else
|
||||||
|
echo "📦 已存在 nerdctl-full.tgz,跳过下载"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📦 解压 nerdctl 到 /usr/local..."
|
||||||
|
sudo tar -C /usr/local -xzf /tmp/nerdctl-full.tgz
|
||||||
|
echo "✅ nerdctl 安装完成: $(nerdctl --version)"
|
||||||
|
else
|
||||||
|
echo "✅ nerdctl 已存在: $(nerdctl --version)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "📦 安装 CNI 插件..."
|
||||||
|
if [ ! -f "${CNI_DIR}/bridge" ]; then
|
||||||
|
if [ ! -f /tmp/cni.tgz ]; then
|
||||||
|
echo "⬇️ 下载 CNI 插件..."
|
||||||
|
wget -O /tmp/cni.tgz \
|
||||||
|
"https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz"
|
||||||
|
else
|
||||||
|
echo "📦 已存在 cni.tgz,跳过下载"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo mkdir -p "${CNI_DIR}"
|
||||||
|
sudo tar -C "${CNI_DIR}" -xzf /tmp/cni.tgz
|
||||||
|
echo "✅ CNI 插件已安装到: ${CNI_DIR}"
|
||||||
|
else
|
||||||
|
echo "✅ CNI 插件已存在: ${CNI_DIR}/bridge"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "📦 解压 SSL 证书..."
|
||||||
|
|
||||||
|
if [ ! -f "ssl_certificates.tar.gz" ]; then
|
||||||
|
echo "⬇️ 未找到 ssl_certificates.tar.gz,尝试从 GitHub 下载..."
|
||||||
|
wget -O ssl_certificates.tar.gz \
|
||||||
|
"https://github.com/svc-design/ansible/releases/download/release-self-signed-cert_kube.registry.local/ssl_certificates.tar.gz" || {
|
||||||
|
echo "❌ 无法下载 ssl_certificates.tar.gz,终止执行"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if [ -f "ssl_certificates.tar.gz" ]; then
|
||||||
|
mkdir -p "$CERT_DIR"
|
||||||
|
tar -xvpf ssl_certificates.tar.gz
|
||||||
|
tar -xvpf ssl_certificates.tar.gz -C "$CERT_DIR"
|
||||||
|
echo "✅ 证书已解压至: $CERT_DIR"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
|
||||||
|
# ============ 生成 registry-config ============
|
||||||
|
echo "⚙️ 准备 registry 配置..."
|
||||||
|
sudo mkdir -pv "$CONFIG_DIR"
|
||||||
|
sudo mkdir -pv "$REGISTRY_DATA"
|
||||||
|
echo "📝 写入 registry-config.yaml..."
|
||||||
|
sudo cat > "${CONFIG_DIR}/${REGISTRY_YAML}" <<EOF
|
||||||
|
version: 0.1
|
||||||
|
log:
|
||||||
|
fields:
|
||||||
|
service: registry
|
||||||
|
storage:
|
||||||
|
cache:
|
||||||
|
blobdescriptor: inmemory
|
||||||
|
filesystem:
|
||||||
|
rootdirectory: /var/lib/registry
|
||||||
|
delete:
|
||||||
|
enabled: true
|
||||||
|
http:
|
||||||
|
addr: :$REGISTRY_PORT
|
||||||
|
headers:
|
||||||
|
X-Content-Type-Options: [nosniff]
|
||||||
|
tls:
|
||||||
|
certificate: /etc/docker/registry/domain.crt
|
||||||
|
key: /etc/docker/registry/domain.key
|
||||||
|
health:
|
||||||
|
storagedriver:
|
||||||
|
enabled: true
|
||||||
|
interval: 10s
|
||||||
|
threshold: 3
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "✅ 写入完成: $REGISTRY_CONFIG"
|
||||||
|
|
||||||
|
# ========== 生成 registry.yaml ==========
|
||||||
|
echo "🛠️ 生成 registry 配置..."
|
||||||
|
sudo mkdir -p "$CONFIG_DIR"
|
||||||
|
cat <<EOF | sudo tee "${CONFIG_DIR}/registry.yaml" > /dev/null
|
||||||
|
version: 0.1
|
||||||
|
log:
|
||||||
|
fields:
|
||||||
|
service: registry
|
||||||
|
storage:
|
||||||
|
cache:
|
||||||
|
blobdescriptor: inmemory
|
||||||
|
filesystem:
|
||||||
|
rootdirectory: /var/lib/registry
|
||||||
|
delete:
|
||||||
|
enabled: true
|
||||||
|
http:
|
||||||
|
addr: :${REGISTRY_PORT}
|
||||||
|
headers:
|
||||||
|
X-Content-Type-Options: [nosniff]
|
||||||
|
tls:
|
||||||
|
certificate: /etc/docker/registry/domain.crt
|
||||||
|
key: /etc/docker/registry/domain.key
|
||||||
|
health:
|
||||||
|
storagedriver:
|
||||||
|
enabled: true
|
||||||
|
interval: 10s
|
||||||
|
threshold: 3
|
||||||
|
EOF
|
||||||
|
echo "✅ registry.yaml 已创建"
|
||||||
|
|
||||||
|
# ========== 生成 compose.yaml ==========
|
||||||
|
echo "🛠️ 生成 compose 配置..."
|
||||||
|
cat <<EOF | sudo tee "${CONFIG_DIR}/compose.yaml" > /dev/null
|
||||||
|
services:
|
||||||
|
registry:
|
||||||
|
image: registry:latest
|
||||||
|
container_name: registry
|
||||||
|
restart: always
|
||||||
|
network_mode: host
|
||||||
|
volumes:
|
||||||
|
- /var/lib/registry:/var/lib/registry
|
||||||
|
- ${CONFIG_DIR}/registry.yaml:/etc/docker/registry/config.yml
|
||||||
|
- ${CERT_DIR}/kube.registry.local.cert:/etc/docker/registry/domain.crt
|
||||||
|
- ${CERT_DIR}/kube.registry.local.key:/etc/docker/registry/domain.key
|
||||||
|
EOF
|
||||||
|
echo "✅ compose.yaml 已创建"
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "📦 导入本地 registry 镜像..."
|
||||||
|
if [ -f "/usr/local/deepflow/$TAR_FILE" ]; then
|
||||||
|
sudo CONTAINERD_ADDRESS="$CONTAINERD_ADDRESS" nerdctl --namespace $NERDCTL_NAMESPACE load -i "/usr/local/deepflow/$TAR_FILE"
|
||||||
|
else
|
||||||
|
echo "⚠️ 本地镜像文件不存在:/usr/local/deepflow/$TAR_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "🔁 重启 registry 服务..."
|
||||||
|
sudo CONTAINERD_ADDRESS="$CONTAINERD_ADDRESS" nerdctl --namespace $NERDCTL_NAMESPACE compose -f "$CONFIG_DIR/compose.yaml" down || true
|
||||||
|
sudo CONTAINERD_ADDRESS="$CONTAINERD_ADDRESS" nerdctl --namespace $NERDCTL_NAMESPACE compose -f "$CONFIG_DIR/compose.yaml" up -d
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "🔗 添加 hosts 映射..."
|
||||||
|
if ! grep -q "$REGISTRY_DOMAIN" /etc/hosts; then
|
||||||
|
echo "127.0.0.1 $REGISTRY_DOMAIN" | sudo tee -a /etc/hosts
|
||||||
|
echo "✅ /etc/hosts 已添加 $REGISTRY_DOMAIN"
|
||||||
|
else
|
||||||
|
echo "✅ hosts 中已存在 $REGISTRY_DOMAIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Registry 启动成功: https://$REGISTRY_DOMAIN:$REGISTRY_PORT"
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "🔐 安装 CA 证书到系统信任目录..."
|
||||||
|
|
||||||
|
CA_CERT="${CERT_DIR}/ca.cert"
|
||||||
|
if [ ! -f "$CA_CERT" ]; then
|
||||||
|
echo "❌ 未找到 CA 证书: $CA_CERT"
|
||||||
|
else
|
||||||
|
if grep -qi "ubuntu\|debian" /etc/os-release; then
|
||||||
|
sudo cp "$CA_CERT" "/usr/local/share/ca-certificates/kube-registry-ca.crt"
|
||||||
|
sudo update-ca-certificates
|
||||||
|
echo "✅ 已导入 CA 到 Ubuntu/Debian 系统信任目录"
|
||||||
|
elif grep -qi "rhel\|centos\|rocky" /etc/os-release; then
|
||||||
|
sudo cp "$CA_CERT" "/etc/pki/ca-trust/source/anchors/kube-registry-ca.crt"
|
||||||
|
sudo update-ca-trust extract
|
||||||
|
echo "✅ 已导入 CA 到 RHEL/CentOS 系统信任目录"
|
||||||
|
else
|
||||||
|
echo "⚠️ 未知发行版,跳过系统 CA 导入"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================
|
||||||
|
echo "🐳 安装 CA 到容器运行时 (Docker/Containerd)..."
|
||||||
|
|
||||||
|
# --- Docker CA ---
|
||||||
|
if command -v docker &>/dev/null; then
|
||||||
|
echo "🔧 配置 Docker..."
|
||||||
|
DOCKER_CA_DIR="/etc/docker/certs.d/kube.registry.local"
|
||||||
|
sudo mkdir -p "$DOCKER_CA_DIR"
|
||||||
|
sudo cp "$CA_CERT" "${DOCKER_CA_DIR}/ca.crt"
|
||||||
|
echo "✅ 已导入 CA 到 Docker: $DOCKER_CA_DIR"
|
||||||
|
sudo systemctl restart docker
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Containerd CA ---
|
||||||
|
if command -v containerd &>/dev/null || [ -S "$CONTAINERD_SOCK" ]; then
|
||||||
|
echo "🔧 配置 Containerd..."
|
||||||
|
|
||||||
|
# Alpine/K3s: /etc/containerd/certs.d
|
||||||
|
# cri-o/nerdctl: /etc/containerd/certs.d/kube.registry.local/ca.crt
|
||||||
|
CONTAINERD_CA_DIR="/etc/containerd/certs.d/kube.registry.local"
|
||||||
|
sudo mkdir -p "$CONTAINERD_CA_DIR"
|
||||||
|
sudo cp "$CA_CERT" "${CONTAINERD_CA_DIR}/ca.crt"
|
||||||
|
echo "✅ 已导入 CA 到 Containerd: $CONTAINERD_CA_DIR"
|
||||||
|
sudo systemctl restart containerd || echo "⚠️ containerd 重启失败,可能在 K3s 中不适用"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- K3s CA ---
|
||||||
|
if [[ -S "/run/k3s/containerd/containerd.sock" ]]; then
|
||||||
|
echo "🔧 检测到 K3s 环境,准备配置自定义 registry CA..."
|
||||||
|
|
||||||
|
# === 配置参数 ===
|
||||||
|
REGISTRY_DOMAIN="kube.registry.local"
|
||||||
|
REGISTRY_PORT="5000"
|
||||||
|
CA_CERT_PATH="/opt/registry/certs/ca.cert"
|
||||||
|
REGISTRIES_YAML="/etc/rancher/k3s/registries.yaml"
|
||||||
|
CA_DST_DIR="/etc/rancher/k3s/registries.d/${REGISTRY_DOMAIN}"
|
||||||
|
CA_DST_FILE="${CA_DST_DIR}/ca.crt"
|
||||||
|
|
||||||
|
# === 准备目录并拷贝证书 ===
|
||||||
|
sudo mkdir -p "${CA_DST_DIR}"
|
||||||
|
sudo cp "${CA_CERT_PATH}" "${CA_DST_FILE}"
|
||||||
|
|
||||||
|
# === 写入 registries.yaml ===
|
||||||
|
echo "[INFO] 写入 registries.yaml 配置..."
|
||||||
|
sudo tee "${REGISTRIES_YAML}" > /dev/null <<EOF
|
||||||
|
mirrors:
|
||||||
|
"${REGISTRY_DOMAIN}:${REGISTRY_PORT}":
|
||||||
|
endpoint:
|
||||||
|
- "https://${REGISTRY_DOMAIN}:${REGISTRY_PORT}"
|
||||||
|
|
||||||
|
configs:
|
||||||
|
"${REGISTRY_DOMAIN}:${REGISTRY_PORT}":
|
||||||
|
tls:
|
||||||
|
ca_file: "${CA_DST_FILE}"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat /etc/rancher/k3s/registries.yaml << EOF
|
||||||
|
mirrors:
|
||||||
|
"kube.registry.local:5000":
|
||||||
|
endpoint:
|
||||||
|
- "http://kube.registry.local:5000"
|
||||||
|
|
||||||
|
configs:
|
||||||
|
"kube.registry.local:5000":
|
||||||
|
tls:
|
||||||
|
insecure_skip_verify: true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# === 重启 K3s 生效 ===
|
||||||
|
echo "[INFO] 重启 K3s 服务..."
|
||||||
|
if systemctl list-units --type=service | grep -q 'k3s-agent'; then
|
||||||
|
sudo systemctl restart k3s-agent
|
||||||
|
else
|
||||||
|
sudo systemctl restart k3s
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[✅ SUCCESS] 已配置自定义 registry 并导入 CA:https://${REGISTRY_DOMAIN}:${REGISTRY_PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
37
roles/vhosts/k3s-cluster/files/setup_k3s.sh
Normal file
37
roles/vhosts/k3s-cluster/files/setup_k3s.sh
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# === 必要参数 ===
|
||||||
|
INSTALL_K3S_URL="https://get.k3s.io"
|
||||||
|
FLANNEL_IFACE=${FLANNEL_IFACE:-br0}
|
||||||
|
|
||||||
|
# === 安装命令拼接(最简)===
|
||||||
|
INSTALL_K3S_EXEC="server \
|
||||||
|
--disable=traefik,servicelb,local-storage \
|
||||||
|
--data-dir=/opt/rancher/k3s \
|
||||||
|
--advertise-address=$(hostname -I | awk '{print $1}') \
|
||||||
|
--kube-apiserver-arg=service-node-port-range=0-50000"
|
||||||
|
|
||||||
|
[[ -n "$FLANNEL_IFACE" ]] && INSTALL_K3S_EXEC+=" --flannel-iface=${FLANNEL_IFACE}"
|
||||||
|
|
||||||
|
# === 下载并执行安装 ===
|
||||||
|
curl -sfL ${INSTALL_K3S_URL} -o install_k3s.sh && chmod +x install_k3s.sh
|
||||||
|
INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" ./install_k3s.sh
|
||||||
|
|
||||||
|
# === 等待 CoreDNS 启动 ===
|
||||||
|
echo "⏳ 等待 CoreDNS 启动..."
|
||||||
|
until kubectl get pods -A 2>/dev/null | grep -q "coredns.*Running"; do
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
|
||||||
|
# === 设置本地 kubeconfig ===
|
||||||
|
mkdir -p ~/.kube
|
||||||
|
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
|
||||||
|
chmod 600 ~/.kube/config
|
||||||
|
export KUBECONFIG=~/.kube/config
|
||||||
|
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||||
|
|
||||||
|
echo "✅ K3s 安装完成,kubectl/helm 已就绪"
|
||||||
|
|
||||||
|
|
||||||
44
roles/vhosts/k3s-cluster/tasks/main.yml
Normal file
44
roles/vhosts/k3s-cluster/tasks/main.yml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure remote tmp directory exists
|
||||||
|
file:
|
||||||
|
path: /tmp/ansible-{{ ansible_user }}
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
|
||||||
|
- name: Sync setup_k3s.sh to remote
|
||||||
|
synchronize:
|
||||||
|
src: files/setup_k3s.sh
|
||||||
|
dest: /tmp/ansible-{{ ansible_user }}/setup_k3s.sh
|
||||||
|
mode: push
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
|
||||||
|
- name: Sync set-registry.sh to remote
|
||||||
|
synchronize:
|
||||||
|
src: files/set-registry.sh
|
||||||
|
dest: /tmp/ansible-{{ ansible_user }}/set-registry.sh
|
||||||
|
mode: push
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
|
||||||
|
- name: Ensure setup_k3s.sh is executable
|
||||||
|
file:
|
||||||
|
path: /tmp/ansible-{{ ansible_user }}/setup_k3s.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Ensure set-registry.sh is executable
|
||||||
|
file:
|
||||||
|
path: /tmp/ansible-{{ ansible_user }}/set-registry.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Run setup_k3s.sh
|
||||||
|
command: ./setup_k3s.sh
|
||||||
|
args:
|
||||||
|
chdir: /tmp/ansible-{{ ansible_user }}
|
||||||
|
|
||||||
|
- name: Run set-registry.sh
|
||||||
|
command: ./set-registry.sh
|
||||||
|
args:
|
||||||
|
chdir: /tmp/ansible-{{ ansible_user }}
|
||||||
6
roles/vhosts/vpn-overlay/setup-dnat/defaults/main.yml
Normal file
6
roles/vhosts/vpn-overlay/setup-dnat/defaults/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
# 从 vpn-overlay.yaml 加载 overlay 结构
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
|
||||||
|
# 脚本默认路径
|
||||||
|
dnat_script_path: /usr/local/bin/setup-dnat.sh
|
||||||
40
roles/vhosts/vpn-overlay/setup-dnat/tasks/main.yml
Normal file
40
roles/vhosts/vpn-overlay/setup-dnat/tasks/main.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
- name: 加载 overlay 配置(标准 YAML)
|
||||||
|
set_fact:
|
||||||
|
overlay_data: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: 提取当前节点信息(作为 current_node)
|
||||||
|
set_fact:
|
||||||
|
current_node: >-
|
||||||
|
{{ (overlay_data.sites + overlay_data.hubs)
|
||||||
|
| selectattr('name', 'equalto', inventory_hostname)
|
||||||
|
| list | first }}
|
||||||
|
|
||||||
|
- name: 设置本节点 DNAT 所需变量
|
||||||
|
set_fact:
|
||||||
|
dnat_public_ip: "{{ current_node.public_ip }}"
|
||||||
|
dnat_internal_ip: "{{ current_node.wg_ip }}"
|
||||||
|
pod_cidr: "{{ current_node.pod_cidr }}"
|
||||||
|
wireguard_cidr: "{{ current_node.wireguard_cidr }}"
|
||||||
|
|
||||||
|
- name: 模板渲染 DNAT 脚本
|
||||||
|
template:
|
||||||
|
src: setup-dnat.sh.j2
|
||||||
|
dest: "{{ dnat_script_path }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: 安装 systemd 服务
|
||||||
|
template:
|
||||||
|
src: dnat-rules.service.j2
|
||||||
|
dest: /etc/systemd/system/dnat-rules.service
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
command: systemctl daemon-reexec
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: 启动并启用 DNAT 服务
|
||||||
|
systemd:
|
||||||
|
name: dnat-rules.service
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Setup DNAT rules for exposing services via WireGuard
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart={{ dnat_script_path }}
|
||||||
|
RemainAfterExit=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ACTION=$1
|
||||||
|
|
||||||
|
if [[ "$ACTION" == "clean" ]]; then
|
||||||
|
echo "[DNAT] 清理规则..."
|
||||||
|
|
||||||
|
iptables -t nat -D PREROUTING -p tcp -d {{ dnat_public_ip }} --dport 80 -j DNAT --to-destination {{ dnat_internal_ip }}:80
|
||||||
|
iptables -t nat -D PREROUTING -p tcp -d {{ dnat_public_ip }} --dport 443 -j DNAT --to-destination {{ dnat_internal_ip }}:443
|
||||||
|
|
||||||
|
iptables -D FORWARD -p tcp -d {{ pod_cidr }} --dport 80 -j ACCEPT
|
||||||
|
iptables -D FORWARD -p tcp -d {{ pod_cidr }} --dport 443 -j ACCEPT
|
||||||
|
iptables -D FORWARD -p tcp -d {{ wireguard_cidr }} --dport 80 -j ACCEPT
|
||||||
|
iptables -D FORWARD -p tcp -d {{ wireguard_cidr }} --dport 443 -j ACCEPT
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "[DNAT] 添加规则..."
|
||||||
|
|
||||||
|
iptables -t nat -A PREROUTING -p tcp -d {{ dnat_public_ip }} --dport 80 -j DNAT --to-destination {{ dnat_internal_ip }}:80
|
||||||
|
iptables -t nat -A PREROUTING -p tcp -d {{ dnat_public_ip }} --dport 443 -j DNAT --to-destination {{ dnat_internal_ip }}:443
|
||||||
|
|
||||||
|
iptables -A FORWARD -p tcp -d {{ pod_cidr }} --dport 80 -j ACCEPT
|
||||||
|
iptables -A FORWARD -p tcp -d {{ pod_cidr }} --dport 443 -j ACCEPT
|
||||||
|
iptables -A FORWARD -p tcp -d {{ wireguard_cidr }} --dport 80 -j ACCEPT
|
||||||
|
iptables -A FORWARD -p tcp -d {{ wireguard_cidr }} --dport 443 -j ACCEPT
|
||||||
|
fi
|
||||||
7
roles/vhosts/vpn-overlay/vxlan/hub/defaults/main.yml
Normal file
7
roles/vhosts/vpn-overlay/vxlan/hub/defaults/main.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Default VXLAN settings for site nodes
|
||||||
|
vxlan_dev_if: wg0
|
||||||
|
vxlan_vni: 100
|
||||||
|
vxlan_cidr_suffix: 16
|
||||||
|
overlay_config_path: config/sit/vpn-overlay.yaml
|
||||||
|
|
||||||
83
roles/vhosts/vpn-overlay/vxlan/hub/files/setup_sit_vxlan.sh
Normal file
83
roles/vhosts/vpn-overlay/vxlan/hub/files/setup_sit_vxlan.sh
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 安全增强版 VXLAN Overlay 脚本(支持 wg0 作为通道设备 + 可选公网 DNAT 映射)
|
||||||
|
# 用法: ./setup_sit_vxlan.sh <dev_if> <local_ip> <remote_ip> <br0_ip> [cidr_suffix] [vxlan_id] [mtu] [expose_port]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
DEV_IF="$1"
|
||||||
|
LOCAL_IP="$2"
|
||||||
|
REMOTE_IP="$3"
|
||||||
|
BRIDGE_IP="$4"
|
||||||
|
CIDR_SUFFIX="${5:-16}"
|
||||||
|
VNI="${6:-100}"
|
||||||
|
MTU="${7:-1400}"
|
||||||
|
EXPOSE_PORT="${8:-443}"
|
||||||
|
|
||||||
|
if [[ -z "$DEV_IF" || -z "$LOCAL_IP" || -z "$REMOTE_IP" || -z "$BRIDGE_IP" ]]; then
|
||||||
|
echo "Usage: $0 <dev_if> <local_ip> <remote_ip> <br0_ip> [cidr_suffix] [vxlan_id] [mtu] [expose_port]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VXLAN_IF="vxlan${VNI}"
|
||||||
|
BR_IF="br0"
|
||||||
|
BRIDGE_CIDR="${BRIDGE_IP}/${CIDR_SUFFIX}"
|
||||||
|
SUBNET="$(echo "$BRIDGE_IP" | cut -d. -f1-2).0.0/${CIDR_SUFFIX}"
|
||||||
|
|
||||||
|
# 自动判断 dev 是否能用于 VXLAN(需支持广播)
|
||||||
|
function is_vxlan_dev_usable() {
|
||||||
|
[[ -d "/sys/class/net/$1" ]] && grep -q "broadcast" "/sys/class/net/$1/flags"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "🔍 检查 $DEV_IF 是否可用于 VXLAN..."
|
||||||
|
USE_DEV_PARAM=true
|
||||||
|
if ! is_vxlan_dev_usable "$DEV_IF"; then
|
||||||
|
echo "⚠️ $DEV_IF 不支持广播,将省略 dev 参数(通过路由走隧道)"
|
||||||
|
USE_DEV_PARAM=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 清理旧接口
|
||||||
|
for iface in "$VXLAN_IF" "$BR_IF"; do
|
||||||
|
ip link show "$iface" &>/dev/null && ip link set "$iface" down && ip link del "$iface"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 创建 VXLAN 接口
|
||||||
|
echo "🛠️ 创建 VXLAN 接口 $VXLAN_IF ..."
|
||||||
|
if $USE_DEV_PARAM; then
|
||||||
|
ip link add "$VXLAN_IF" type vxlan id "$VNI" dstport 4789 local "$LOCAL_IP" remote "$REMOTE_IP" dev "$DEV_IF"
|
||||||
|
else
|
||||||
|
ip link add "$VXLAN_IF" type vxlan id "$VNI" dstport 4789 local "$LOCAL_IP" remote "$REMOTE_IP"
|
||||||
|
fi
|
||||||
|
ip link set "$VXLAN_IF" mtu "$MTU"
|
||||||
|
ip link set "$VXLAN_IF" up
|
||||||
|
|
||||||
|
# 创建 br0 桥
|
||||||
|
ip link add "$BR_IF" type bridge
|
||||||
|
ip link set "$BR_IF" mtu "$MTU"
|
||||||
|
ip link set "$VXLAN_IF" master "$BR_IF"
|
||||||
|
ip link set "$BR_IF" up
|
||||||
|
|
||||||
|
# 配置 IP
|
||||||
|
ip addr add "$BRIDGE_CIDR" dev "$BR_IF"
|
||||||
|
|
||||||
|
# 启用转发 + SNAT(仅主机出网时)
|
||||||
|
sysctl -w net.ipv4.ip_forward=1
|
||||||
|
iptables -t nat -C POSTROUTING -s "$SUBNET" -o "$DEV_IF" -j MASQUERADE 2>/dev/null || \
|
||||||
|
iptables -t nat -A POSTROUTING -s "$SUBNET" -o "$DEV_IF" -j MASQUERADE
|
||||||
|
|
||||||
|
# ⚠️ 可选:仅在 EXPOSE_PORT 被定义时启用 DNAT 公网端口映射
|
||||||
|
if [[ -n "$EXPOSE_PORT" ]]; then
|
||||||
|
echo "🌐 添加 DNAT 映射规则:公网:$EXPOSE_PORT → ${BRIDGE_IP}:443"
|
||||||
|
|
||||||
|
iptables -t nat -C PREROUTING -p tcp -m tcp --dport "$EXPOSE_PORT" -j DNAT --to-destination "${BRIDGE_IP}:443" 2>/dev/null || \
|
||||||
|
iptables -t nat -A PREROUTING -p tcp -m tcp --dport "$EXPOSE_PORT" -j DNAT --to-destination "${BRIDGE_IP}:443"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 展示结果
|
||||||
|
echo ""
|
||||||
|
echo "✅ VXLAN Overlay 已建立"
|
||||||
|
echo " - bridge: $BR_IF ($BRIDGE_CIDR)"
|
||||||
|
echo " - vxlan: $VXLAN_IF ($LOCAL_IP ⇄ $REMOTE_IP, id=$VNI, mtu=$MTU)"
|
||||||
|
echo " - SNAT: $SUBNET → $DEV_IF"
|
||||||
|
if [[ -n "$EXPOSE_PORT" ]]; then
|
||||||
|
echo " - DNAT: 公网:$EXPOSE_PORT → ${BRIDGE_IP}:443"
|
||||||
|
fi
|
||||||
50
roles/vhosts/vpn-overlay/vxlan/hub/tasks/main.yml
Normal file
50
roles/vhosts/vpn-overlay/vxlan/hub/tasks/main.yml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
- name: Load site overlay config
|
||||||
|
set_fact:
|
||||||
|
overlay_data: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: Select current site from config
|
||||||
|
set_fact:
|
||||||
|
current_hub: "{{ overlay_data.hubs | selectattr('name', 'equalto', inventory_hostname) | list | first }}"
|
||||||
|
|
||||||
|
- name: Fail if no matching site found
|
||||||
|
fail:
|
||||||
|
msg: "当前主机 {{ inventory_hostname }} 未在 config 中定义"
|
||||||
|
when: current_hub is not defined
|
||||||
|
|
||||||
|
- name: Set VXLAN parameters
|
||||||
|
set_fact:
|
||||||
|
vxlan_dev_if: "{{ current_hub.interface}}"
|
||||||
|
vxlan_local_ip: "{{ current_hub.local_ip }}"
|
||||||
|
vxlan_remote_ip: "{{ current_hub.remote_ip }}"
|
||||||
|
vxlan_br_ip: "{{ current_hub.br_ip }}"
|
||||||
|
vxlan_cidr_suffix: "{{ overlay_data.vxlan_cidr_suffix | default(16) }}"
|
||||||
|
vxlan_vni: "{{ overlay_data.vxlan_id | default(100) }}"
|
||||||
|
|
||||||
|
- name: 使用 rsync 分发 VXLAN 脚本
|
||||||
|
synchronize:
|
||||||
|
src: "files/setup_sit_vxlan.sh"
|
||||||
|
dest: /tmp/setup_sit_vxlan.sh
|
||||||
|
mode: push
|
||||||
|
|
||||||
|
- name: 移动脚本并赋权到 /usr/local/bin
|
||||||
|
shell: |
|
||||||
|
mv /tmp/setup_sit_vxlan.sh /usr/local/bin/setup_sit_vxlan.sh
|
||||||
|
chmod +x /usr/local/bin/setup_sit_vxlan.sh
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Render systemd unit for VXLAN
|
||||||
|
template:
|
||||||
|
src: vxlan-setup.service.j2
|
||||||
|
dest: /etc/systemd/system/vxlan-setup.service
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Enable and start VXLAN overlay setup
|
||||||
|
systemd:
|
||||||
|
name: vxlan-setup
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=VXLAN Overlay Setup for {{ inventory_hostname }}
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/setup_sit_vxlan.sh {{ vxlan_dev_if }} {{ vxlan_local_ip }} {{ vxlan_remote_ip }} {{ vxlan_br_ip }} {{ vxlan_cidr_suffix }} {{ vxlan_vni }}
|
||||||
|
RemainAfterExit=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
7
roles/vhosts/vpn-overlay/vxlan/site/defaults/main.yml
Normal file
7
roles/vhosts/vpn-overlay/vxlan/site/defaults/main.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Default VXLAN settings for site nodes
|
||||||
|
vxlan_dev_if: wg0
|
||||||
|
vxlan_vni: 100
|
||||||
|
vxlan_cidr_suffix: 16
|
||||||
|
overlay_config_path: config/sit/vpn-overlay.yaml
|
||||||
|
|
||||||
104
roles/vhosts/vpn-overlay/vxlan/site/files/setup_sit_vxlan.sh
Normal file
104
roles/vhosts/vpn-overlay/vxlan/site/files/setup_sit_vxlan.sh
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 多 peer 自动化 VXLAN Overlay 脚本(读取 /etc/vxlan-config.yaml)
|
||||||
|
# 用法: ./setup_sit_vxlan.sh [reset]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CONFIG_FILE="/etc/vxlan-config.yaml"
|
||||||
|
BR_IF="br0"
|
||||||
|
|
||||||
|
# 需要 yq 解析 yaml
|
||||||
|
command -v yq >/dev/null 2>&1 || { echo >&2 "❌ 请安装 yq 命令(https://github.com/mikefarah/yq)"; exit 1; }
|
||||||
|
|
||||||
|
if [[ "$1" == "reset" ]]; then
|
||||||
|
echo "🔄 正在清理 VXLAN Overlay 配置..."
|
||||||
|
|
||||||
|
# 删除所有 vxlan 接口
|
||||||
|
ip -o link show | awk -F': ' '/vxlan[0-9]+/ {print $2}' | while read -r iface; do
|
||||||
|
ip link set "$iface" down
|
||||||
|
ip link del "$iface"
|
||||||
|
echo "🧹 已删除接口 $iface"
|
||||||
|
done
|
||||||
|
|
||||||
|
ip link show "$BR_IF" &>/dev/null && {
|
||||||
|
ip link set "$BR_IF" down
|
||||||
|
ip link del "$BR_IF"
|
||||||
|
echo "🧹 已删除桥接器 $BR_IF"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "✅ 清理完成"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解析 config
|
||||||
|
DEV_IF="$(yq e '.dev_if' "$CONFIG_FILE")"
|
||||||
|
BRIDGE_IP="$(yq e '.bridge_ip' "$CONFIG_FILE")"
|
||||||
|
CIDR_SUFFIX="$(yq e '.cidr_suffix' "$CONFIG_FILE")"
|
||||||
|
PEER_COUNT=$(yq e '.peers | length' "$CONFIG_FILE")
|
||||||
|
|
||||||
|
if [[ -z "$DEV_IF" || -z "$BRIDGE_IP" || "$PEER_COUNT" -eq 0 ]]; then
|
||||||
|
echo "❌ 配置错误:请检查 $CONFIG_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BRIDGE_CIDR="${BRIDGE_IP}/${CIDR_SUFFIX}"
|
||||||
|
|
||||||
|
# 检查 dev_if 是否可用于 VXLAN
|
||||||
|
function is_vxlan_dev_usable() {
|
||||||
|
[[ -d "/sys/class/net/$1" ]] && grep -q "broadcast" "/sys/class/net/$1/flags"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "🔍 检查 $DEV_IF 是否可用于 VXLAN..."
|
||||||
|
USE_DEV_PARAM=true
|
||||||
|
if ! is_vxlan_dev_usable "$DEV_IF"; then
|
||||||
|
echo "⚠️ $DEV_IF 不支持广播,将省略 dev 参数(通过路由走隧道)"
|
||||||
|
USE_DEV_PARAM=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建 bridge
|
||||||
|
if ! ip link show "$BR_IF" &>/dev/null; then
|
||||||
|
echo "🛠️ 创建桥接器 $BR_IF"
|
||||||
|
ip link add "$BR_IF" type bridge
|
||||||
|
ip link set "$BR_IF" up
|
||||||
|
ip addr add "$BRIDGE_CIDR" dev "$BR_IF"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 启用转发
|
||||||
|
sysctl -w net.ipv4.ip_forward=1
|
||||||
|
|
||||||
|
# 遍历 peers
|
||||||
|
for i in $(seq 0 $((PEER_COUNT - 1))); do
|
||||||
|
LOCAL_IP=$(yq e ".peers[$i].local_ip" "$CONFIG_FILE")
|
||||||
|
REMOTE_IP=$(yq e ".peers[$i].remote_ip" "$CONFIG_FILE")
|
||||||
|
VNI=$(yq e ".peers[$i].vxlan_id" "$CONFIG_FILE")
|
||||||
|
MTU=$(yq e ".peers[$i].mtu" "$CONFIG_FILE")
|
||||||
|
EXPOSE_PORT=$(yq e ".peers[$i].expose_port" "$CONFIG_FILE")
|
||||||
|
|
||||||
|
VXLAN_IF="vxlan${VNI}"
|
||||||
|
|
||||||
|
echo "🛠️ 创建 VXLAN 接口 $VXLAN_IF (local: $LOCAL_IP, remote: $REMOTE_IP, vni: $VNI)"
|
||||||
|
|
||||||
|
# 清理旧接口
|
||||||
|
ip link show "$VXLAN_IF" &>/dev/null && ip link set "$VXLAN_IF" down && ip link del "$VXLAN_IF"
|
||||||
|
|
||||||
|
# 创建 vxlan 接口
|
||||||
|
if $USE_DEV_PARAM; then
|
||||||
|
ip link add "$VXLAN_IF" type vxlan id "$VNI" dstport 4789 local "$LOCAL_IP" remote "$REMOTE_IP" dev "$DEV_IF"
|
||||||
|
else
|
||||||
|
ip link add "$VXLAN_IF" type vxlan id "$VNI" dstport 4789 local "$LOCAL_IP" remote "$REMOTE_IP"
|
||||||
|
fi
|
||||||
|
ip link set "$VXLAN_IF" mtu "$MTU"
|
||||||
|
ip link set "$VXLAN_IF" up
|
||||||
|
ip link set "$VXLAN_IF" master "$BR_IF"
|
||||||
|
|
||||||
|
# 可选添加 DNAT
|
||||||
|
if [[ -n "$EXPOSE_PORT" && "$EXPOSE_PORT" != "null" ]]; then
|
||||||
|
echo "🌐 添加 DNAT 规则:公网:$EXPOSE_PORT → ${BRIDGE_IP}:443"
|
||||||
|
iptables -t nat -C PREROUTING -p tcp --dport "$EXPOSE_PORT" -j DNAT --to-destination "${BRIDGE_IP}:443" 2>/dev/null || \
|
||||||
|
iptables -t nat -A PREROUTING -p tcp --dport "$EXPOSE_PORT" -j DNAT --to-destination "${BRIDGE_IP}:443"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ 所有 VXLAN Overlay 配置完成"
|
||||||
54
roles/vhosts/vpn-overlay/vxlan/site/tasks/main.yml
Normal file
54
roles/vhosts/vpn-overlay/vxlan/site/tasks/main.yml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
- name: Load site overlay config
|
||||||
|
set_fact:
|
||||||
|
overlay_data: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: Select current site from config
|
||||||
|
set_fact:
|
||||||
|
current_site: "{{ overlay_data.sites | selectattr('name', 'equalto', inventory_hostname) | list | first }}"
|
||||||
|
|
||||||
|
- name: Fail if no matching site found
|
||||||
|
fail:
|
||||||
|
msg: "当前主机 {{ inventory_hostname }} 未在 config 中定义"
|
||||||
|
when: current_site is not defined
|
||||||
|
|
||||||
|
- name: Select first hub as default
|
||||||
|
set_fact:
|
||||||
|
selected_hub: "{{ overlay_data.hubs[0] }}"
|
||||||
|
|
||||||
|
- name: Set VXLAN parameters
|
||||||
|
set_fact:
|
||||||
|
vxlan_dev_if: "{{ current_site.interface}}"
|
||||||
|
vxlan_local_ip: "{{ current_site.local_ip }}"
|
||||||
|
vxlan_remote_ip: "{{ current_site.remote_ip }}"
|
||||||
|
vxlan_br_ip: "{{ current_site.br_ip }}"
|
||||||
|
vxlan_cidr_suffix: "{{ overlay_data.vxlan_cidr_suffix | default(16) }}"
|
||||||
|
vxlan_vni: "{{ overlay_data.vxlan_id | default(100) }}"
|
||||||
|
|
||||||
|
- name: 使用 rsync 分发 VXLAN 脚本
|
||||||
|
synchronize:
|
||||||
|
src: "files/setup_sit_vxlan.sh"
|
||||||
|
dest: /tmp/setup_sit_vxlan.sh
|
||||||
|
mode: push
|
||||||
|
|
||||||
|
- name: 移动脚本并赋权到 /usr/local/bin
|
||||||
|
shell: |
|
||||||
|
mv /tmp/setup_sit_vxlan.sh /usr/local/bin/setup_sit_vxlan.sh
|
||||||
|
chmod +x /usr/local/bin/setup_sit_vxlan.sh
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Render systemd unit for VXLAN
|
||||||
|
template:
|
||||||
|
src: vxlan-setup.service.j2
|
||||||
|
dest: /etc/systemd/system/vxlan-setup.service
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Enable and start VXLAN overlay setup
|
||||||
|
systemd:
|
||||||
|
name: vxlan-setup
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
dev_if: eth0
|
||||||
|
bridge_ip: 10.253.253.1
|
||||||
|
cidr_suffix: 16
|
||||||
|
peers:
|
||||||
|
- local_ip: 172.30.0.1
|
||||||
|
remote_ip: 172.30.0.10
|
||||||
|
vxlan_id: 100
|
||||||
|
mtu: 1400
|
||||||
|
- local_ip: 172.30.0.1
|
||||||
|
remote_ip: 172.31.0.1
|
||||||
|
vxlan_id: 100
|
||||||
|
mtu: 1400
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=VXLAN Overlay Setup for {{ inventory_hostname }}
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/setup_sit_vxlan.sh add {{ vxlan_dev_if }} {{ vxlan_local_ip }} {{ vxlan_remote_ip }} {{ vxlan_br_ip }} {{ vxlan_cidr_suffix }} {{ vxlan_vni }}
|
||||||
|
RemainAfterExit=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
4
roles/vhosts/vpn-overlay/wireguard/hub/defaults/main.yml
Normal file
4
roles/vhosts/vpn-overlay/wireguard/hub/defaults/main.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
wg_interface: "wg0"
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
wg_port: "51820"
|
||||||
56
roles/vhosts/vpn-overlay/wireguard/hub/tasks/main.yml
Normal file
56
roles/vhosts/vpn-overlay/wireguard/hub/tasks/main.yml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
- name: 加载 overlay 配置(标准 YAML)
|
||||||
|
set_fact:
|
||||||
|
overlay_data: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: 加载密钥配置(支持 !vault)
|
||||||
|
include_vars:
|
||||||
|
file: "{{ overlay_keys_path }}"
|
||||||
|
name: overlay_keys
|
||||||
|
|
||||||
|
- name: 提取当前 Hub 节点信息
|
||||||
|
set_fact:
|
||||||
|
current_node: >-
|
||||||
|
{{ overlay_data.hubs | selectattr('name', 'equalto', inventory_hostname) | list | first }}
|
||||||
|
current_key: >-
|
||||||
|
{{ overlay_keys['keys'] | selectattr('name', 'equalto', inventory_hostname) | list | first }}
|
||||||
|
|
||||||
|
- name: 提取所有对端 Peer 信息
|
||||||
|
set_fact:
|
||||||
|
peer_nodes: >-
|
||||||
|
{{ (overlay_data.sites + overlay_data.hubs)
|
||||||
|
| selectattr('name', 'in', current_node.wireguard_peer) | list }}
|
||||||
|
peer_keys: >-
|
||||||
|
{{ overlay_keys['keys']
|
||||||
|
| selectattr('name', 'in', current_node.wireguard_peer) | list }}
|
||||||
|
|
||||||
|
- name: 校验 Peer 节点数量
|
||||||
|
fail:
|
||||||
|
msg: "没有找到任何对端节点或对应密钥,请检查 wireguard_peer 设置"
|
||||||
|
when: peer_nodes | length == 0 or peer_keys | length == 0
|
||||||
|
|
||||||
|
- name: Ensure wireguard-tools is installed (Debian/Ubuntu)
|
||||||
|
apt:
|
||||||
|
name: wireguard-tools
|
||||||
|
state: present
|
||||||
|
when: ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: Ensure wireguard-tools is installed (RHEL/CentOS)
|
||||||
|
yum:
|
||||||
|
name: wireguard-tools
|
||||||
|
state: present
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: 渲染 wg0.conf
|
||||||
|
template:
|
||||||
|
src: wg0.conf.j2
|
||||||
|
dest: /etc/wireguard/wg0.conf
|
||||||
|
mode: '0600'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: 启用并启动 wg-quick@wg0
|
||||||
|
systemd:
|
||||||
|
name: wg-quick@wg0
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
become: true
|
||||||
16
roles/vhosts/vpn-overlay/wireguard/hub/templates/wg0.conf.j2
Normal file
16
roles/vhosts/vpn-overlay/wireguard/hub/templates/wg0.conf.j2
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = {{ current_key.private_key }}
|
||||||
|
Address = {{ current_node.wg_ip }}/32
|
||||||
|
ListenPort = {{ wg_port }}
|
||||||
|
DNS = 8.8.8.8
|
||||||
|
MTU = 1400
|
||||||
|
|
||||||
|
{% for peer, key in peer_nodes | zip(peer_keys) %}
|
||||||
|
{% if peer.name != inventory_hostname %}
|
||||||
|
[Peer]
|
||||||
|
PublicKey = {{ key.public_key }}
|
||||||
|
AllowedIPs = {{ peer.wg_ip }}/32
|
||||||
|
Endpoint = {{ peer.public_ip }}:{{ overlay_data.hub_port | default(wg_port) }}
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
wg_interface: "wg0"
|
||||||
|
|
||||||
|
# 默认配置文件路径,可在 playbook 中覆盖
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
|
||||||
|
# WireGuard 默认端口(若 overlay_data.hub_port 未定义)
|
||||||
|
wg_port: "51820"
|
||||||
71
roles/vhosts/vpn-overlay/wireguard/site/tasks/main.yml
Normal file
71
roles/vhosts/vpn-overlay/wireguard/site/tasks/main.yml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
- name: 加载 overlay 配置(标准 YAML)
|
||||||
|
set_fact:
|
||||||
|
overlay_data: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: 加载密钥配置(支持 !vault)
|
||||||
|
include_vars:
|
||||||
|
file: "{{ overlay_keys_path }}"
|
||||||
|
name: overlay_keys
|
||||||
|
|
||||||
|
- name: 提取当前节点信息(作为 current)
|
||||||
|
set_fact:
|
||||||
|
current_node: >-
|
||||||
|
{{ (overlay_data.sites + overlay_data.hubs)
|
||||||
|
| selectattr('name', 'equalto', inventory_hostname)
|
||||||
|
| list | first }}
|
||||||
|
current_key: >-
|
||||||
|
{{ overlay_keys['keys']
|
||||||
|
| selectattr('name', 'equalto', inventory_hostname)
|
||||||
|
| list | first }}
|
||||||
|
features: "{{ overlay_data.features }}"
|
||||||
|
|
||||||
|
- name: 标准化 wireguard_peer 为列表
|
||||||
|
set_fact:
|
||||||
|
wireguard_peers: >-
|
||||||
|
{{ [current_node.wireguard_peer] if current_node.wireguard_peer is string else current_node.wireguard_peer }}
|
||||||
|
|
||||||
|
- name: 提取对端 peer 节点列表
|
||||||
|
set_fact:
|
||||||
|
peer_node_list: >-
|
||||||
|
{{ (overlay_data.sites + overlay_data.hubs)
|
||||||
|
| selectattr('name', 'in', wireguard_peers)
|
||||||
|
| list }}
|
||||||
|
peer_key_list: >-
|
||||||
|
{{ overlay_keys['keys']
|
||||||
|
| selectattr('name', 'in', wireguard_peers)
|
||||||
|
| list }}
|
||||||
|
|
||||||
|
- name: 校验 wireguard_peer 是否匹配成功
|
||||||
|
fail:
|
||||||
|
msg: "未找到对端节点 '{{ current_node.wireguard_peer }}' 或其密钥"
|
||||||
|
when: peer_node_list | length == 0 or peer_key_list | length == 0
|
||||||
|
|
||||||
|
- name: 设置对端节点与密钥
|
||||||
|
set_fact:
|
||||||
|
peer_nodes: "{{ peer_node_list }}"
|
||||||
|
peer_keys: "{{ peer_key_list }}"
|
||||||
|
|
||||||
|
- name: 提取最终配置变量(私钥、公钥、端口等)
|
||||||
|
set_fact:
|
||||||
|
wg_port: "{{ wg_port }}"
|
||||||
|
current_wg_ip: "{{ current_node.wg_ip }}"
|
||||||
|
current_interface: "{{ current_node.interface }}"
|
||||||
|
current_private_key: "{{ current_key.private_key }}"
|
||||||
|
current_allowed_ips: "{{ current_node.allowed_ips }}"
|
||||||
|
peer_public_key: "{{ peer_keys[0].public_key }}"
|
||||||
|
peer_endpoint: "{{ peer_nodes[0].public_ip }}:{{ overlay_data.hub_port | default(wg_port) }}"
|
||||||
|
|
||||||
|
- name: 渲染 wg0.conf
|
||||||
|
template:
|
||||||
|
src: wg0.conf.j2
|
||||||
|
dest: /etc/wireguard/wg0.conf
|
||||||
|
mode: '0600'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: 启用并启动 wg-quick@wg0
|
||||||
|
systemd:
|
||||||
|
name: wg-quick@wg0
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
become: true
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = {{ current_private_key }}
|
||||||
|
Address = {{ current_wg_ip }}/32
|
||||||
|
ListenPort = {{ wg_port }}
|
||||||
|
DNS = 8.8.8.8
|
||||||
|
MTU = 1400
|
||||||
|
|
||||||
|
PostUp = iptables -I FORWARD -o %i -j ACCEPT
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
|
||||||
|
PostUp = iptables -t nat -A POSTROUTING -o {{ current_interface }} -j MASQUERADE
|
||||||
|
|
||||||
|
PostDown = iptables -D FORWARD -o %i -j ACCEPT
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
|
||||||
|
PostDown = iptables -t nat -D POSTROUTING -o {{ current_interface }} -j MASQUERADE
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = {{ peer_public_key }}
|
||||||
|
AllowedIPs = {{ current_allowed_ips }}
|
||||||
|
{% if features.enable_vless %}
|
||||||
|
Endpoint = 127.0.0.1:51830
|
||||||
|
{% else %}
|
||||||
|
Endpoint = {{ peer_endpoint }}
|
||||||
|
{% endif %}
|
||||||
|
PersistentKeepalive = 25
|
||||||
5
roles/vhosts/vpn-overlay/xray/hub/defaults/main.yml
Normal file
5
roles/vhosts/vpn-overlay/xray/hub/defaults/main.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
xray_main_port: 1443
|
||||||
|
xray_cert_path: "/etc/ssl/onwalk.net.pem"
|
||||||
|
xray_key_path: "/etc/ssl/onwalk.net.key"
|
||||||
|
xray_bin_path: /usr/local/bin/xray
|
||||||
|
xray_config_dir: /usr/local/etc/xray
|
||||||
6
roles/vhosts/vpn-overlay/xray/hub/handlers/main.yml
Normal file
6
roles/vhosts/vpn-overlay/xray/hub/handlers/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Restart xray service
|
||||||
|
systemd:
|
||||||
|
name: xray.service
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
70
roles/vhosts/vpn-overlay/xray/hub/tasks/main.yml
Normal file
70
roles/vhosts/vpn-overlay/xray/hub/tasks/main.yml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
- name: Load overlay config from file
|
||||||
|
set_fact:
|
||||||
|
overlay_config: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: Convert overlay_config.hubs list to dict (hubs_map)
|
||||||
|
set_fact:
|
||||||
|
hubs_map: "{{ dict(overlay_config.hubs | map(attribute='name') | zip(overlay_config.hubs)) }}"
|
||||||
|
when: overlay_config.hubs is defined
|
||||||
|
|
||||||
|
- name: Convert overlay_config.sites list to dict (sites_map)
|
||||||
|
set_fact:
|
||||||
|
sites_map: "{{ dict(overlay_config.sites | map(attribute='name') | zip(overlay_config.sites)) }}"
|
||||||
|
when: overlay_config.sites is defined
|
||||||
|
|
||||||
|
- name: 显示主机名
|
||||||
|
debug:
|
||||||
|
var: overlay_config
|
||||||
|
when: debug | default(false)
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
xray_uuid: "{{ hubs_map[inventory_hostname].xray.uuid }}"
|
||||||
|
xray_remote_domain: "{{ hubs_map[inventory_hostname].xray.remote_domain }}"
|
||||||
|
xray_cert_path: "{{ hubs_map[inventory_hostname].xray.cert_path }}"
|
||||||
|
xray_key_path: "{{ hubs_map[inventory_hostname].xray.key_path }}"
|
||||||
|
|
||||||
|
- name: Install Xray using official script
|
||||||
|
shell: |
|
||||||
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)"
|
||||||
|
args:
|
||||||
|
creates: /usr/local/bin/xray
|
||||||
|
notify:
|
||||||
|
- Restart xray service
|
||||||
|
|
||||||
|
- name: Ensure required directories exist
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ xray_bin_path | dirname }}"
|
||||||
|
- "{{ xray_config_dir }}"
|
||||||
|
|
||||||
|
- name: Deploy Xray config templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "config.json.j2", dest: "{{ xray_config_dir }}/config.json" }
|
||||||
|
|
||||||
|
- name: Deploy systemd service templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "xray.service.j2", dest: "/etc/systemd/system/xray.service" }
|
||||||
|
|
||||||
|
- name: Reload systemd
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Enable and start xray services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- xray.service
|
||||||
84
roles/vhosts/vpn-overlay/xray/hub/templates/config.json.j2
Normal file
84
roles/vhosts/vpn-overlay/xray/hub/templates/config.json.j2
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "warning"
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"domainStrategy": "IPIfNonMatch",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"ip": [
|
||||||
|
"geoip:cn"
|
||||||
|
],
|
||||||
|
"outboundTag": "block"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"port": {{ xray_main_port }},
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"id": "{{ xray_uuid }}",
|
||||||
|
"flow": "xtls-rprx-vision"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decryption": "none",
|
||||||
|
"fallbacks": [
|
||||||
|
{
|
||||||
|
"dest": "8001",
|
||||||
|
"xver": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alpn": "h2",
|
||||||
|
"dest": "8002",
|
||||||
|
"xver": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "tcp",
|
||||||
|
"security": "tls",
|
||||||
|
"tlsSettings": {
|
||||||
|
"rejectUnknownSni": true,
|
||||||
|
"minVersion": "1.2",
|
||||||
|
"certificates": [
|
||||||
|
{
|
||||||
|
"ocspStapling": 3600,
|
||||||
|
"certificateFile": "{{ xray_cert_path }}",
|
||||||
|
"keyFile": "{{ xray_key_path }}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sniffing": {
|
||||||
|
"enabled": true,
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "freedom",
|
||||||
|
"tag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protocol": "blackhole",
|
||||||
|
"tag": "block"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"levels": {
|
||||||
|
"0": {
|
||||||
|
"handshake": 2,
|
||||||
|
"connIdle": 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
roles/vhosts/vpn-overlay/xray/hub/templates/xray.service.j2
Normal file
18
roles/vhosts/vpn-overlay/xray/hub/templates/xray.service.j2
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Xray Service
|
||||||
|
Documentation=https://github.com/xtls
|
||||||
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=nobody
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ExecStart=/usr/local/bin/xray run -config /usr/local/etc/xray/config.json
|
||||||
|
Restart=on-failure
|
||||||
|
RestartPreventExitStatus=23
|
||||||
|
LimitNPROC=10000
|
||||||
|
LimitNOFILE=1000000
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
6
roles/vhosts/vpn-overlay/xray/site/defaults/main.yml
Normal file
6
roles/vhosts/vpn-overlay/xray/site/defaults/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
xray_main_port: 1443
|
||||||
|
xray_tproxy_port: 51830
|
||||||
|
xray_cert_path: "/etc/ssl/onwalk.net.pem"
|
||||||
|
xray_key_path: "/etc/ssl/onwalk.net.key"
|
||||||
|
xray_bin_path: /usr/local/bin/xray
|
||||||
|
xray_config_dir: /usr/local/etc/xray
|
||||||
6
roles/vhosts/vpn-overlay/xray/site/handlers/main.yml
Normal file
6
roles/vhosts/vpn-overlay/xray/site/handlers/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Restart Xray-client service
|
||||||
|
systemd:
|
||||||
|
name: xray-client.service
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
70
roles/vhosts/vpn-overlay/xray/site/tasks/main.yml
Normal file
70
roles/vhosts/vpn-overlay/xray/site/tasks/main.yml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
- name: Load overlay config from file
|
||||||
|
set_fact:
|
||||||
|
overlay_config: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: Convert overlay_config.hubs list to dict (hubs_map)
|
||||||
|
set_fact:
|
||||||
|
hubs_map: "{{ dict(overlay_config.hubs | map(attribute='name') | zip(overlay_config.hubs)) }}"
|
||||||
|
when: overlay_config.hubs is defined
|
||||||
|
|
||||||
|
- name: Convert overlay_config.sites list to dict (sites_map)
|
||||||
|
set_fact:
|
||||||
|
sites_map: "{{ dict(overlay_config.sites | map(attribute='name') | zip(overlay_config.sites)) }}"
|
||||||
|
when: overlay_config.sites is defined
|
||||||
|
|
||||||
|
- name: 显示主机名
|
||||||
|
debug:
|
||||||
|
var: overlay_config
|
||||||
|
when: debug | default(false)
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
xray_uuid: "{{ sites_map[inventory_hostname].xray.uuid }}"
|
||||||
|
xray_remote_domain: "{{ sites_map[inventory_hostname].xray.remote_domain }}"
|
||||||
|
xray_cert_path: "{{ sites_map[inventory_hostname].xray.cert_path }}"
|
||||||
|
xray_key_path: "{{ sites_map[inventory_hostname].xray.key_path }}"
|
||||||
|
|
||||||
|
- name: Install Xray using official script
|
||||||
|
shell: |
|
||||||
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)"
|
||||||
|
args:
|
||||||
|
creates: /usr/local/bin/xray
|
||||||
|
notify:
|
||||||
|
- Restart xray service
|
||||||
|
|
||||||
|
- name: Ensure required directories exist
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ xray_bin_path | dirname }}"
|
||||||
|
- "{{ xray_config_dir }}"
|
||||||
|
|
||||||
|
- name: Deploy Xray config templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "client-config.json.j2", dest: "{{ xray_config_dir }}/client-config.json" }
|
||||||
|
|
||||||
|
- name: Deploy systemd service templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "xray-client.service.j2", dest: "/etc/systemd/system/xray-client.service" }
|
||||||
|
|
||||||
|
- name: Reload systemd
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Enable and start xray services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- xray-client.service
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "debug"
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"domainStrategy": "IPIfNonMatch",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"domain": [
|
||||||
|
"geosite:cn",
|
||||||
|
"geosite:private"
|
||||||
|
],
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"ip": [
|
||||||
|
"geoip:cn",
|
||||||
|
"geoip:private"
|
||||||
|
],
|
||||||
|
"outboundTag": "direct"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 1080,
|
||||||
|
"protocol": "socks",
|
||||||
|
"settings": {
|
||||||
|
"udp": true
|
||||||
|
},
|
||||||
|
"sniffing": {
|
||||||
|
"enabled": true,
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 1081,
|
||||||
|
"protocol": "http",
|
||||||
|
"settings": {},
|
||||||
|
"sniffing": {
|
||||||
|
"enabled": true,
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "{{ xray_remote_domain }}",
|
||||||
|
"port": {{ xray_main_port }},
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": "{{ xray_uuid }}",
|
||||||
|
"encryption": "none",
|
||||||
|
"flow": "xtls-rprx-vision"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "tcp",
|
||||||
|
"security": "tls",
|
||||||
|
"tlsSettings": {
|
||||||
|
"serverName": "{{ xray_remote_domain }}",
|
||||||
|
"allowInsecure": false,
|
||||||
|
"fingerprint": "chrome"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "proxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protocol": "freedom",
|
||||||
|
"tag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protocol": "blackhole",
|
||||||
|
"tag": "block"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Xray Client Service
|
||||||
|
Documentation=https://github.com/xtls
|
||||||
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=nobody
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ExecStart=/usr/local/bin/xray run -config /usr/local/etc/xray/client-config.json
|
||||||
|
Restart=on-failure
|
||||||
|
RestartPreventExitStatus=23
|
||||||
|
LimitNPROC=10000
|
||||||
|
LimitNOFILE=1000000
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
6
roles/vhosts/vpn-overlay/xray/tproxy/defaults/main.yml
Normal file
6
roles/vhosts/vpn-overlay/xray/tproxy/defaults/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
xray_main_port: 1443
|
||||||
|
xray_tproxy_port: 51830
|
||||||
|
xray_cert_path: "/etc/ssl/onwalk.net.pem"
|
||||||
|
xray_key_path: "/etc/ssl/onwalk.net.key"
|
||||||
|
xray_bin_path: /usr/local/bin/xray
|
||||||
|
xray_config_dir: /usr/local/etc/xray
|
||||||
6
roles/vhosts/vpn-overlay/xray/tproxy/handlers/main.yml
Normal file
6
roles/vhosts/vpn-overlay/xray/tproxy/handlers/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Restart xray-tproxy service
|
||||||
|
systemd:
|
||||||
|
name: xray-tproxy.service
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
82
roles/vhosts/vpn-overlay/xray/tproxy/tasks/main.yml
Normal file
82
roles/vhosts/vpn-overlay/xray/tproxy/tasks/main.yml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
- name: Load overlay config from file
|
||||||
|
set_fact:
|
||||||
|
overlay_config: "{{ lookup('file', overlay_config_path) | from_yaml }}"
|
||||||
|
|
||||||
|
- name: Convert overlay_config.hubs list to dict (hubs_map)
|
||||||
|
set_fact:
|
||||||
|
hubs_map: "{{ dict(overlay_config.hubs | map(attribute='name') | zip(overlay_config.hubs)) }}"
|
||||||
|
when: overlay_config.hubs is defined
|
||||||
|
|
||||||
|
- name: Convert overlay_config.sites list to dict (sites_map)
|
||||||
|
set_fact:
|
||||||
|
sites_map: "{{ dict(overlay_config.sites | map(attribute='name') | zip(overlay_config.sites)) }}"
|
||||||
|
when: overlay_config.sites is defined
|
||||||
|
|
||||||
|
- name: Convert all nodes (hubs + sites) to one dict as node_map
|
||||||
|
set_fact:
|
||||||
|
node_map: >-
|
||||||
|
{{ dict((overlay_config.hubs + overlay_config.sites)
|
||||||
|
| map(attribute='name')
|
||||||
|
| zip(overlay_config.hubs + overlay_config.sites)) }}
|
||||||
|
|
||||||
|
- name: 显示主机名
|
||||||
|
debug:
|
||||||
|
var: node_map
|
||||||
|
when: debug | default(true)
|
||||||
|
|
||||||
|
- name: Show value for this node
|
||||||
|
debug:
|
||||||
|
msg: "{{ node_map[inventory_hostname] }}"
|
||||||
|
when: debug | default(true)
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
xray_uuid: "{{ node_map[inventory_hostname].xray.uuid }}"
|
||||||
|
xray_remote_domain: "{{ node_map[inventory_hostname].xray.remote_domain }}"
|
||||||
|
xray_cert_path: "{{ node_map[inventory_hostname].xray.cert_path }}"
|
||||||
|
xray_key_path: "{{ node_map[inventory_hostname].xray.key_path }}"
|
||||||
|
|
||||||
|
- name: Install Xray using official script
|
||||||
|
shell: |
|
||||||
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)"
|
||||||
|
args:
|
||||||
|
creates: /usr/local/bin/xray
|
||||||
|
notify:
|
||||||
|
- Restart xray-tproxy service
|
||||||
|
|
||||||
|
- name: Ensure required directories exist
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ xray_bin_path | dirname }}"
|
||||||
|
- "{{ xray_config_dir }}"
|
||||||
|
|
||||||
|
- name: Deploy Xray config templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "tproxy-config.json.j2", dest: "{{ xray_config_dir }}/tproxy-config.json" }
|
||||||
|
|
||||||
|
- name: Deploy systemd service templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { src: "xray-tproxy.service.j2", dest: "/etc/systemd/system/xray-tproxy.service" }
|
||||||
|
|
||||||
|
- name: Reload systemd
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Enable and start xray services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- xray-tproxy.service
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "info"
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"rules": []
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 51830,
|
||||||
|
"protocol": "dokodemo-door",
|
||||||
|
"settings": {
|
||||||
|
"address": "{{ xray_remote_domain }}",
|
||||||
|
"port": 51820,
|
||||||
|
"network": "udp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "{{ xray_remote_domain }}",
|
||||||
|
"port": 1443,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": "{{ xray_uuid }}",
|
||||||
|
"encryption": "none",
|
||||||
|
"flow": "xtls-rprx-vision"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "tcp",
|
||||||
|
"security": "tls",
|
||||||
|
"tlsSettings": {
|
||||||
|
"serverName": "{{ xray_remote_domain }}",
|
||||||
|
"allowInsecure": false,
|
||||||
|
"fingerprint": "chrome"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "proxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protocol": "freedom",
|
||||||
|
"tag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protocol": "blackhole",
|
||||||
|
"tag": "block"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Xray Tproxy Service
|
||||||
|
Documentation=https://github.com/xtls
|
||||||
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=nobody
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ExecStart=/usr/local/bin/xray run -config /usr/local/etc/xray/tproxy-config.json
|
||||||
|
Restart=on-failure
|
||||||
|
RestartPreventExitStatus=23
|
||||||
|
LimitNPROC=10000
|
||||||
|
LimitNOFILE=1000000
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
8
vpn-overlay-dnat.yaml
Normal file
8
vpn-overlay-dnat.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup DNAT rules
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
gather_facts: no
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
roles:
|
||||||
|
- vhosts/vpn-overlay/setup-dnat
|
||||||
8
vpn-overlay-vxlan-hub.yaml
Normal file
8
vpn-overlay-vxlan-hub.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Run infrastructure setup
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
gather_facts: yes
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
roles:
|
||||||
|
- vhosts/vpn-overlay/vxlan/hub
|
||||||
8
vpn-overlay-vxlan-site.yaml
Normal file
8
vpn-overlay-vxlan-site.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Run infrastructure setup
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
gather_facts: yes
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
roles:
|
||||||
|
- vhosts/vpn-overlay/vxlan/site
|
||||||
8
vpn-wireguard-hub.yaml
Normal file
8
vpn-wireguard-hub.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup WireGuard for hub
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
roles:
|
||||||
|
- role: vhosts/vpn-overlay/wireguard/hub
|
||||||
8
vpn-wireguard-site.yaml
Normal file
8
vpn-wireguard-site.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup WireGuard for site
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
roles:
|
||||||
|
- vhosts/vpn-overlay/wireguard/site
|
||||||
8
vpn-xray-client.yaml
Normal file
8
vpn-xray-client.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup Xray for hub
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
roles:
|
||||||
|
- role: vhosts/vpn-overlay/xray/site
|
||||||
8
vpn-xray-hub.yaml
Normal file
8
vpn-xray-hub.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup Xray for hub
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
roles:
|
||||||
|
- role: vhosts/vpn-overlay/xray/hub
|
||||||
8
vpn-xray-tproxy.yaml
Normal file
8
vpn-xray-tproxy.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- name: Setup Xray for hub
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
overlay_config_path: "{{ playbook_dir }}/../../config/sit/vpn-overlay.yaml"
|
||||||
|
overlay_keys_path: "{{ playbook_dir }}/../../config/sit/vpn-keys.yaml"
|
||||||
|
roles:
|
||||||
|
- role: vhosts/vpn-overlay/xray/tproxy/
|
||||||
Loading…
Reference in New Issue
Block a user