├── .gitignore ├── README.md ├── ansible.cfg ├── inventory.yml ├── plays ├── defaults │ ├── init_host.yml │ └── v2ray.yml └── v2ray.yml └── roles ├── fail2ban ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ └── etc │ └── fail2ban │ └── jail.d │ └── sshd.conf.j2 ├── iptables ├── defaults │ └── main.yml ├── files │ └── opt │ │ └── internal_setup │ │ ├── config │ │ └── setup.sh ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ └── etc │ └── iptables │ └── rules.v4.j2 ├── nginx ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── tasks │ ├── instances.yml │ └── main.yml └── templates │ └── etc │ ├── nginx │ ├── conf.d │ │ └── nginx.conf.j2 │ └── specific-conf.d │ │ └── specific.conf.j2 │ └── systemd │ └── system │ └── nginx.service.d │ └── override.conf.j2 ├── packages ├── defaults │ └── main.yml └── tasks │ └── main.yml ├── sysctl ├── defaults │ └── main.yml ├── tasks │ └── main.yml └── templates │ └── etc │ └── sysctl.d │ └── 99-sysctl.conf.j2 └── v2ray ├── defaults └── main.yml ├── files └── opt │ └── v2ray_toolbox │ └── v2ray.sh ├── handlers └── main.yml ├── tasks ├── instances.yml ├── main.yml └── nginx.yml └── templates ├── etc ├── nginx │ ├── conf.d │ │ └── nginx.conf.j2 │ ├── nginx.conf.j2 │ └── specific-conf.d │ │ └── specific.conf.j2 └── v2ray │ ├── config.json.j2 │ └── config.json.j2_org └── lib └── systemd └── system └── v2ray.service.j2 /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MortezaBashsiz/CFAnsible/5aea2696930ffe952c17c7a680081bcd988c6b97/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CFAnsible 2 | 3 | ## Video Guide 4 | You can find a video guide for this script on [youtube](https://youtu.be/Qp6oI_xd4B0 "youtube"). 5 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | # config file for ansible -- http://ansible.com/ 2 | # ============================================== 3 | 4 | # nearly all parameters can be overridden in ansible-playbook 5 | # or with command line flags. ansible will read ANSIBLE_CONFIG, 6 | # ansible.cfg in the current working directory, .ansible.cfg in 7 | # the home directory or /etc/ansible/ansible.cfg, whichever it 8 | # finds first 9 | 10 | [defaults] 11 | 12 | # some basic default values... 13 | 14 | inventory = ./inventory.yml 15 | remote_tmp = /tmp 16 | forks = 150 17 | sudo_user = root 18 | remote_user = root 19 | transport = smart 20 | 21 | # plays will gather facts by default, which contain information about 22 | # the remote system. 23 | # 24 | # smart - gather by default, but don't regather if already gathered 25 | # implicit - gather by default, turn off with gather_facts: False 26 | # explicit - do not gather by default, must say gather_facts: True 27 | gathering = smart 28 | 29 | # additional paths to search for roles in, colon separated 30 | roles_path = ./roles 31 | 32 | # uncomment this to disable SSH key host checking 33 | host_key_checking = False 34 | 35 | # logging is off by default unless this path is defined 36 | # if so defined, consider logrotate 37 | log_path = /var/log/ansible.log 38 | 39 | # default module name for /usr/bin/ansible 40 | module_name = shell 41 | 42 | # set plugin path directories here, separate with colons 43 | action_plugins = /usr/share/ansible_plugins/action_plugins:$HOME/.ansible/plugins/action_plugins 44 | callback_plugins = /usr/share/ansible_plugins/callback_plugins:$HOME/.ansible/plugins/callback_plugins 45 | connection_plugins = /usr/share/ansible_plugins/connection_plugins:$HOME/.ansible/plugins/connection_plugins 46 | lookup_plugins = /usr/share/ansible_plugins/lookup_plugins:$HOME/.ansible/plugins/lookup_plugins 47 | vars_plugins = /usr/share/ansible_plugins/vars_plugins:$HOME/.ansible/plugins/vars_plugins 48 | filter_plugins = /usr/share/ansible_plugins/filter_plugins:$HOME/.ansible/plugins/filter_plugins 49 | 50 | # by default callbacks are not loaded for /bin/ansible, enable this if you 51 | # want, for example, a notification or logging callback to also apply to 52 | # /bin/ansible runs 53 | #bin_ansible_callbacks = False 54 | 55 | # the CA certificate path used for validating SSL certs. This path 56 | # should exist on the controlling node, not the target nodes 57 | # common locations: 58 | # RHEL/CentOS: /etc/pki/tls/certs/ca-bundle.crt 59 | # Fedora : /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 60 | # Ubuntu : /usr/share/ca-certificates/cacert.org/cacert.org.crt 61 | ca_file_path = /usr/share/ca-certificates/cacert.org/cacert.org.crt 62 | 63 | # if set to a persistent type (not 'memory', for example 'redis') fact values 64 | # from previous runs in Ansible will be stored. This may be useful when 65 | # wanting to use, for example, IP information from one group of servers 66 | # without having to talk to them in the same playbook run to get their 67 | # current IP information. 68 | fact_caching = jsonfile 69 | fact_caching_connection = $HOME/.ansible/facts 70 | fact_caching_timeout = 600 71 | 72 | # retry files 73 | #retry_files_enabled = False 74 | retry_files_save_path = ~/.ansible/retry 75 | 76 | [privilege_escalation] 77 | #become=True 78 | #become_method=sudo 79 | #become_user=root 80 | #become_ask_pass=False 81 | 82 | [ssh_connection] 83 | 84 | # ssh arguments to use 85 | # Leaving off ControlPersist will result in poor performance, so use 86 | # paramiko on older platforms rather than removing it 87 | ssh_args = -o ControlMaster=auto -o ControlPersist=60s 88 | 89 | # The path to use for the ControlPath sockets. This defaults to 90 | # "%(directory)s/ansible-ssh-%%h-%%p-%%r", however on some systems with 91 | # very long hostnames or very long path names (caused by long user names or 92 | # deeply nested home directories) this can exceed the character limit on 93 | # file socket names (108 characters for most platforms). In that case, you 94 | # may wish to shorten the string below. 95 | # 96 | # Example: 97 | # control_path = %(directory)s/%%h-%%r 98 | control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r 99 | 100 | # Enabling pipelining reduces the number of SSH operations required to 101 | # execute a module on the remote server. This can result in a significant 102 | # performance improvement when enabled, however when using "sudo:" you must 103 | # first disable 'requiretty' in /etc/sudoers 104 | # 105 | # By default, this option is disabled to preserve compatibility with 106 | # sudoers configurations that have requiretty (the default on many distros). 107 | # 108 | pipelining = True 109 | 110 | # if True, make ansible use scp if the connection type is ssh 111 | # (default is sftp) 112 | scp_if_ssh = True 113 | 114 | [accelerate] 115 | accelerate_port = 5099 116 | accelerate_timeout = 30 117 | accelerate_connect_timeout = 5.0 118 | 119 | # The daemon timeout is measured in minutes. This time is measured 120 | # from the last activity to the accelerate daemon. 121 | accelerate_daemon_timeout = 30 122 | 123 | # If set to yes, accelerate_multi_key will allow multiple 124 | # private keys to be uploaded to it, though each user must 125 | # have access to the system via SSH to add a new key. The default 126 | # is "no". 127 | #accelerate_multi_key = yes 128 | 129 | [selinux] 130 | # file systems that require special treatment when dealing with security context 131 | # the default behaviour that copies the existing context or uses the user default 132 | # needs to be changed to use the file system dependent context. 133 | #special_context_filesystems=nfs,vboxsf,fuse,ramfs 134 | -------------------------------------------------------------------------------- /inventory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all: 4 | hosts: 5 | 1.1.1.1: 6 | 2.2.2.2: 7 | 8 | v2ray: 9 | hosts: 10 | 1.1.1.1: 11 | 2.2.2.2: 12 | -------------------------------------------------------------------------------- /plays/defaults/init_host.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | INPUT_CHAINS: 4 | - name: "INPUT_SSH" 5 | policy: "ACCEPT" 6 | rules: 7 | - "-s 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 8 | 9 | OUTPUT_CHAINS: 10 | - name: "OUTPUT_WEB" 11 | policy: "ACCEPT" 12 | rules: 13 | - "-d 0.0.0.0/0 -p tcp --dport 80 -j ACCEPT" 14 | - "-d 0.0.0.0/0 -p tcp --dport 443 -j ACCEPT" 15 | - name: "OUTPUT_SSH" 16 | policy: "ACCEPT" 17 | rules: 18 | - "-d 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 19 | 20 | FORWARD_CHAINS: 21 | - name: "FORWARD_DEFAULT" 22 | policy: "DROP" 23 | rules: 24 | - "-s 0.0.0.0/0 -d 0.0.0.0/0 -j DROP" 25 | 26 | -------------------------------------------------------------------------------- /plays/defaults/v2ray.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | MAIN_DOMAIN: "DOMAIN.COM" 4 | 5 | CERTBOT_EMAIL: "test@gmail.com" 6 | 7 | V2RAY_CFG_NAME: "Sudoer_VPN_bot" 8 | V2RAY_CFG_DOMAIN: "scheretest01.DOMAIN.COM" 9 | V2RAY_CFG_PREDOMAIN: "schere" 10 | 11 | V2RAY_PKGS_LIST: 12 | - v2ray 13 | - jq 14 | - uuid 15 | - bmon 16 | 17 | V2RAY_INSTANCES: 18 | - name: v2ray01 19 | listen: "127.0.0.1" 20 | port: 10801 21 | protocol: "vmess" 22 | wsurl: "api01" 23 | domain: "{{ ansible_hostname }}.{{ MAIN_DOMAIN }}" 24 | clients: 25 | - level: 1 26 | alterId: 0 27 | 28 | INPUT_CHAINS: 29 | - name: "INPUT_SSH" 30 | policy: "ACCEPT" 31 | rules: 32 | - "-s 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 33 | - name: "INPUT_WEB" 34 | policy: "ACCEPT" 35 | rules: 36 | - "-s 0.0.0.0/0 -p tcp --dport 80 -j ACCEPT" 37 | - "-s 0.0.0.0/0 -p tcp --dport 443 -j ACCEPT" 38 | 39 | OUTPUT_CHAINS: 40 | - name: "OUTPUT_WEB" 41 | policy: "ACCEPT" 42 | rules: 43 | - "-d 0.0.0.0/0 -p tcp --dport 80 -j ACCEPT" 44 | - "-d 0.0.0.0/0 -p tcp --dport 443 -j ACCEPT" 45 | - name: "OUTPUT_SSH" 46 | policy: "ACCEPT" 47 | rules: 48 | - "-d 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 49 | 50 | FORWARD_CHAINS: 51 | - name: "FORWARD_DEFAULT" 52 | policy: "DROP" 53 | rules: 54 | - "-s 0.0.0.0/0 -d 0.0.0.0/0 -j DROP" 55 | 56 | NGINX_INSTANCES: 57 | - domain: "{{ ansible_hostname }}.{{ MAIN_DOMAIN }}" 58 | email: "{{ CERTBOT_EMAIL }}" 59 | root: /usr/share/nginx/html 60 | 61 | SYSCTL_PARAMETERS: 62 | - name: "net.ipv4.ip_forward" 63 | value: "0" 64 | - name: "kernel.randomize_va_space" 65 | value: "0" 66 | - name: "net.core.netdev_max_backlog" 67 | value: "2500000" 68 | - name: "net.core.rmem_max" 69 | value: "413696000" 70 | - name: "net.core.wmem_max" 71 | value: "413696000" 72 | - name: "net.ipv4.tcp_congestion_control" 73 | value: "bbr" 74 | - name: "net.ipv4.tcp_fin_timeout" 75 | value: "1" 76 | - name: "net.ipv4.tcp_limit_output_bytes" 77 | value: "13107200" 78 | - name: "net.ipv4.tcp_low_latency" 79 | value: "0" 80 | - name: "net.ipv4.tcp_max_tw_buckets" 81 | value: "45000000" 82 | - name: "net.ipv4.tcp_rmem" 83 | value: "409600 8738000 413696000" 84 | - name: "net.ipv4.tcp_tw_reuse" 85 | value: "1" 86 | - name: "net.ipv4.tcp_wmem" 87 | value: "409600 1638400 413696000" 88 | 89 | -------------------------------------------------------------------------------- /plays/v2ray.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: v2ray 4 | 5 | vars_files: 6 | - defaults/v2ray.yml 7 | 8 | roles: 9 | - role: packages 10 | tags: 11 | - apt 12 | - role: fail2ban 13 | tags: 14 | - fail2ban 15 | - role: sysctl 16 | tags: 17 | - sysctl 18 | - role: iptables 19 | tags: 20 | - firewall 21 | - iptables 22 | - role: nginx 23 | tags: 24 | - nginx 25 | - role: v2ray 26 | tags: 27 | - v2ray 28 | -------------------------------------------------------------------------------- /roles/fail2ban/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | FAIL2BAN_PKGS_LIST: 4 | - fail2ban 5 | 6 | -------------------------------------------------------------------------------- /roles/fail2ban/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: restart fail2ban 4 | service: 5 | name: fail2ban 6 | state: restarted 7 | enabled: yes 8 | -------------------------------------------------------------------------------- /roles/fail2ban/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: packages role 4 | include_role: 5 | name: packages 6 | vars: 7 | PKGS_LIST: "{{ FAIL2BAN_PKGS_LIST }}" 8 | 9 | - name: fail2ban config 10 | template: 11 | src: etc/fail2ban/jail.d/sshd.conf.j2 12 | dest: /etc/fail2ban/jail.d/sshd.conf 13 | owner: root 14 | group: root 15 | mode: '0644' 16 | notify: 17 | restart fail2ban 18 | 19 | -------------------------------------------------------------------------------- /roles/fail2ban/templates/etc/fail2ban/jail.d/sshd.conf.j2: -------------------------------------------------------------------------------- 1 | [sshd] 2 | enabled = true 3 | bantime = 15m 4 | findtime = 10m 5 | maxretry = 3 6 | -------------------------------------------------------------------------------- /roles/iptables/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | IPTABLES_PKGS_LIST: 4 | - htop 5 | - net-tools 6 | - iptables-persistent 7 | - vim 8 | 9 | INPUT_CHAINS: 10 | - name: "INPUT_SSH" 11 | policy: "ACCEPT" 12 | rules: 13 | - "-s 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 14 | 15 | OUTPUT_CHAINS: 16 | - name: "OUTPUT_WEB" 17 | policy: "ACCEPT" 18 | rules: 19 | - "-d 0.0.0.0/0 -p tcp --dport 80 -j ACCEPT" 20 | - "-d 0.0.0.0/0 -p tcp --dport 443 -j ACCEPT" 21 | - name: "OUTPUT_SSH" 22 | policy: "ACCEPT" 23 | rules: 24 | - "-d 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT" 25 | 26 | FORWARD_CHAINS: 27 | - name: "FORWARD_DEFAULT" 28 | policy: "DROP" 29 | rules: 30 | - "-s 0.0.0.0/0 -d 0.0.0.0/0 -j DROP" 31 | 32 | -------------------------------------------------------------------------------- /roles/iptables/files/opt/internal_setup/config: -------------------------------------------------------------------------------- 1 | internalIP=192.168.122.1 2 | internalPort=443 3 | externalIP=192.168.122.130 4 | externalPort=4550 5 | -------------------------------------------------------------------------------- /roles/iptables/files/opt/internal_setup/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | #=============================================================================== 3 | # 4 | # FILE: setup.sh 5 | # 6 | # USAGE: ./setup.sh CONFIG_PATH 7 | # 8 | # DESCRIPTION: This script will install and configure shadowsocks on internal and external host 9 | # 10 | # OPTIONS: --- 11 | # REQUIREMENTS: Debian or Ubuntu, Bash 12 | # BUGS: --- 13 | # NOTES: --- 14 | # AUTHOR: Morteza Bashsiz (), morteza.bashsiz@gmail.com 15 | # ORGANIZATION: 16 | # CREATED: 10/05/2022 10:25:37 PM 17 | # REVISION: --- 18 | #=============================================================================== 19 | 20 | set -o nounset # Treat unset variables as an error 21 | 22 | config_path="${1}" 23 | 24 | _internalIP=$(grep "^internalIP" "${config_path}" | awk -F = '{print $2}') 25 | _internalPort=$(grep "^internalPort" "${config_path}" | awk -F = '{print $2}') 26 | _externalIP=$(grep "^externalIP" "${config_path}" | awk -F = '{print $2}') 27 | _externalPort=$(grep "^externalPort" "${config_path}" | awk -F = '{print $2}') 28 | 29 | echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-sysctl.conf 30 | sysctl -w net.ipv4.ip_forward=1 31 | systemctl restart iptables 32 | 33 | iptables -t filter -I INPUT -p tcp -d "$_internalIP" --dport "$_internalPort" -j ACCEPT 34 | iptables -t filter -I INPUT -p udp -d "$_internalIP" --dport "$_internalPort" -j ACCEPT 35 | iptables -t filter -I OUTPUT -d "$_externalIP" -j ACCEPT 36 | iptables -t filter -I FORWARD -s "$_externalIP" -j ACCEPT 37 | iptables -t filter -I FORWARD -d "$_externalIP" -j ACCEPT 38 | iptables -t nat -I POSTROUTING -j MASQUERADE 39 | iptables -t nat -I PREROUTING -p tcp -d "$_internalIP" --dport "$_internalPort" -j DNAT --to-destination "$_externalIP":"$_externalPort" 40 | iptables -t nat -I PREROUTING -p udp -d "$_internalIP" --dport "$_internalPort" -j DNAT --to-destination "$_externalIP":"$_externalPort" 41 | 42 | iptables-save > /etc/iptables/rules.v4 43 | -------------------------------------------------------------------------------- /roles/iptables/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: restart iptables 4 | service: 5 | name: iptables 6 | state: restarted 7 | enabled: yes 8 | 9 | -------------------------------------------------------------------------------- /roles/iptables/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: packages role 4 | include_role: 5 | name: packages 6 | vars: 7 | PKGS_LIST: "{{ IPTABLES_PKGS_LIST }}" 8 | 9 | - name: reload iptables 10 | shell: | 11 | iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 12 | iptables -I OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 13 | systemctl enable iptables 14 | iptables-restore < /etc/iptables/rules.v4 15 | changed_when: false 16 | 17 | - name: iptables config 18 | template: 19 | src: etc/iptables/rules.v4.j2 20 | dest: /etc/iptables/rules.v4 21 | owner: root 22 | group: root 23 | mode: '0644' 24 | notify: 25 | - restart iptables 26 | 27 | - name: Create directory if it does not exist 28 | file: 29 | path: /opt/internal_setup/ 30 | state: directory 31 | mode: '0755' 32 | 33 | - name: Copy internal scripts 34 | copy: 35 | src: opt/internal_setup/{{ item }} 36 | dest: /opt/internal_setup/{{ item }} 37 | owner: root 38 | group: root 39 | with_items: 40 | - setup.sh 41 | - config 42 | 43 | -------------------------------------------------------------------------------- /roles/iptables/templates/etc/iptables/rules.v4.j2: -------------------------------------------------------------------------------- 1 | # Generated by ansible 2 | *filter 3 | :INPUT ACCEPT [0:0] 4 | :FORWARD DROP [0:0] 5 | :OUTPUT ACCEPT [0:0] 6 | 7 | -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 8 | -A INPUT -i lo -j ACCEPT 9 | -A INPUT -p icmp -j ACCEPT 10 | 11 | {% for input_chain in INPUT_CHAINS %} 12 | :{{ input_chain.name }} {{ input_chain.policy }} [0:0] 13 | -A INPUT -j {{ input_chain.name }} 14 | {% for input_chain_rule in input_chain.rules %} 15 | -A {{ input_chain.name }} {{ input_chain_rule }} 16 | {% endfor %} 17 | -A {{ input_chain.name }} -j RETURN 18 | {% endfor %} 19 | -A INPUT -j DROP 20 | 21 | -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 22 | -A OUTPUT -o lo -j ACCEPT 23 | -A OUTPUT -p icmp -j ACCEPT 24 | -A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT 25 | -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT 26 | 27 | {% for output_chain in OUTPUT_CHAINS %} 28 | :{{ output_chain.name }} {{ output_chain.policy }} [0:0] 29 | -A OUTPUT -j {{ output_chain.name }} 30 | {% for output_chain_rule in output_chain.rules %} 31 | -A {{ output_chain.name }} {{ output_chain_rule }} 32 | {% endfor %} 33 | -A {{ output_chain.name }} -j RETURN 34 | {% endfor %} 35 | -A OUTPUT -j DROP 36 | 37 | {% for forward_chain in FORWARD_CHAINS %} 38 | :{{ forward_chain.name }} {{ forward_chain.policy }} [0:0] 39 | -A FORWARD -j {{ forward_chain.name }} 40 | {% for forward_chain_rule in forward_chain.rules %} 41 | -A {{ forward_chain.name }} {{ forward_chain_rule }} 42 | {% endfor %} 43 | -A {{ forward_chain.name }} -j RETURN 44 | {% endfor %} 45 | -A FORWARD -j DROP 46 | 47 | COMMIT 48 | 49 | -------------------------------------------------------------------------------- /roles/nginx/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | NGINX_PKGS_LIST: 4 | - nginx 5 | - certbot 6 | - python3-certbot-nginx 7 | 8 | NGINX_INSTANCES: 9 | - domain: "{{ MAIN_DOMAIN }}" 10 | email: morteza.bashsiz@gmail.com 11 | root: /usr/share/wordpress/ 12 | -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reload nginx 4 | service: 5 | name: nginx 6 | state: reloaded 7 | enabled: yes 8 | daemon_reload: true 9 | -------------------------------------------------------------------------------- /roles/nginx/tasks/instances.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: check if www dir exists {{ instance.name }} 4 | stat: 5 | path: /etc/letsencrypt/live/{{ instance.domain }}/ 6 | register: cert_file 7 | 8 | - name: get certificates 9 | shell: | 10 | iptables -F 11 | systemctl stop nginx 12 | certbot certonly --standalone --preferred-challenges http -d {{ instance.domain }} --non-interactive --agree-tos -m {{ instance.email }} 13 | systemctl start nginx 14 | systemctl restart iptables 15 | changed_when: false 16 | when: not cert_file.stat.exists 17 | 18 | - name: nginx config for {{ instance.domain }} 19 | template: 20 | src: etc/nginx/specific-conf.d/specific.conf.j2 21 | dest: /etc/nginx/specific-conf.d/{{ instance.domain }}-specific.conf 22 | owner: root 23 | group: root 24 | mode: '0644' 25 | 26 | - name: nginx config for {{ instance.domain }} 27 | template: 28 | src: etc/nginx/conf.d/nginx.conf.j2 29 | dest: /etc/nginx/conf.d/{{ instance.domain }}.conf 30 | owner: root 31 | group: root 32 | mode: '0644' 33 | notify: 34 | reload nginx 35 | -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: packages role 4 | include_role: 5 | name: packages 6 | vars: 7 | PKGS_LIST: "{{ NGINX_PKGS_LIST }}" 8 | 9 | - name: Create directory if it does not exist 10 | file: 11 | path: "{{ item }}" 12 | state: directory 13 | mode: '0755' 14 | with_items: 15 | - /etc/nginx/specific-conf.d/ 16 | - /etc/systemd/system/nginx.service.d/ 17 | 18 | - name: nginx config for {{ instance.domain }} 19 | template: 20 | src: etc/systemd/system/nginx.service.d/override.conf.j2 21 | dest: /etc/systemd/system/nginx.service.d/override.conf 22 | owner: root 23 | group: root 24 | mode: '0644' 25 | 26 | - name: configuring instances 27 | include_tasks: instances.yml 28 | loop: "{{ NGINX_INSTANCES }}" 29 | loop_control: 30 | loop_var: instance 31 | 32 | -------------------------------------------------------------------------------- /roles/nginx/templates/etc/nginx/conf.d/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | server_name {{ instance.domain }} www.{{ instance.domain }}; 5 | return 301 https://www.{{ instance.domain }}; 6 | } 7 | 8 | server { 9 | gzip on; 10 | gzip_disable "msie6"; 11 | gzip_vary on; 12 | gzip_proxied any; 13 | gzip_comp_level 6; 14 | gzip_buffers 16 8k; 15 | gzip_http_version 1.1; 16 | gzip_types application/javascript application/rss+xml application/vnd.ms-fontobject application/x-font application/x-font-opentype application/x-font-otf application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/opentype font/otf font/ttf image/svg+xml image/x-icon text/css text/javascript text/plain text/xml; 17 | if ($host !~ ^({{ instance.domain }}|www.{{ instance.domain }})$ ) { 18 | return 444; 19 | } 20 | if ($request_method !~ ^(GET|HEAD|POST)$ ) { 21 | return 444; 22 | } 23 | listen 443 ssl http2; 24 | server_name www.{{ instance.domain }} {{ instance.domain }}; 25 | 26 | root {{ instance.root }}; 27 | index index.php; 28 | ssl_certificate /etc/letsencrypt/live/{{ instance.domain }}/fullchain.pem; 29 | ssl_certificate_key /etc/letsencrypt/live/{{ instance.domain }}/privkey.pem; 30 | ssl_trusted_certificate /etc/letsencrypt/live/{{ instance.domain }}/chain.pem; 31 | access_log /var/log/nginx/{{ instance.domain }}.access.log; 32 | error_log /var/log/nginx/{{ instance.domain }}.error.log; 33 | 34 | location = /favicon.ico { 35 | log_not_found off; 36 | access_log off; 37 | } 38 | 39 | location = /robots.txt { 40 | allow all; 41 | log_not_found off; 42 | access_log off; 43 | } 44 | 45 | location / { 46 | try_files $uri $uri/ /index.php?q=$uri&$args; 47 | } 48 | 49 | location ~ \.php$ { 50 | try_files $uri =404; 51 | fastcgi_pass unix:/run/php/php-fpm.sock; 52 | fastcgi_index index.php; 53 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 54 | include fastcgi_params; 55 | include fastcgi.conf; 56 | } 57 | 58 | location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|flv)$ { 59 | expires max; 60 | log_not_found off; 61 | } 62 | 63 | include specific-conf.d/{{ instance.domain }}-specific.conf; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /roles/nginx/templates/etc/nginx/specific-conf.d/specific.conf.j2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MortezaBashsiz/CFAnsible/5aea2696930ffe952c17c7a680081bcd988c6b97/roles/nginx/templates/etc/nginx/specific-conf.d/specific.conf.j2 -------------------------------------------------------------------------------- /roles/nginx/templates/etc/systemd/system/nginx.service.d/override.conf.j2: -------------------------------------------------------------------------------- 1 | [Service] 2 | LimitNOFILE=65535 3 | 4 | -------------------------------------------------------------------------------- /roles/packages/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | PKGS_LIST: 4 | - htop 5 | - vim 6 | - tmux 7 | 8 | -------------------------------------------------------------------------------- /roles/packages/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install the latest version packages 4 | apt: 5 | name: "{{ item }}" 6 | state: latest 7 | update_cache: yes 8 | loop: 9 | - "{{ PKGS_LIST }}" 10 | 11 | - name: Update all packages 12 | apt: 13 | name: "*" 14 | state: latest 15 | -------------------------------------------------------------------------------- /roles/sysctl/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | SYSCTL_PARAMETERS: 4 | - name: "net.ipv4.ip_forward" 5 | value: "0" 6 | -------------------------------------------------------------------------------- /roles/sysctl/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: sysctl config 4 | template: 5 | src: etc/sysctl.d/99-sysctl.conf.j2 6 | dest: /etc/sysctl.d/99-sysctl.conf 7 | owner: root 8 | group: root 9 | mode: '0644' 10 | 11 | - name: apply sysctl 12 | shell: | 13 | sysctl -p /etc/sysctl.d/99-sysctl.conf 14 | -------------------------------------------------------------------------------- /roles/sysctl/templates/etc/sysctl.d/99-sysctl.conf.j2: -------------------------------------------------------------------------------- 1 | {% for sysctl_parameter in SYSCTL_PARAMETERS %} 2 | {{ sysctl_parameter.name }} = {{ sysctl_parameter.value }} 3 | {% endfor %} 4 | 5 | -------------------------------------------------------------------------------- /roles/v2ray/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | V2RAY_PKGS_LIST: 4 | - python3-urllib3 5 | - v2ray 6 | - uuid 7 | 8 | V2RAY_CFG_DOMAIN: "adas" 9 | V2RAY_CFG_PREDOMAIN: "nokhod" 10 | 11 | V2RAY_INSTANCES: 12 | - name: v2ray01 13 | listen: "127.0.0.1" 14 | port: 10801 15 | protocol: "vmess" 16 | wsurl: "/api01" 17 | clients: 18 | - level: 1 19 | alterId: 0 20 | - name: v2ray02 21 | listen: "127.0.0.1" 22 | port: 10802 23 | protocol: "vmess" 24 | wsurl: "/api02" 25 | clients: 26 | - level: 1 27 | alterId: 0 28 | -------------------------------------------------------------------------------- /roles/v2ray/files/opt/v2ray_toolbox/v2ray.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | #=============================================================================== 3 | # 4 | # FILE: v2ray.sh 5 | # 6 | # USAGE: ./v2ray.sh 7 | # 8 | # DESCRIPTION: 9 | # 10 | # OPTIONS: --- 11 | # REQUIREMENTS: --- 12 | # BUGS: --- 13 | # NOTES: --- 14 | # AUTHOR: Morteza Bashsiz (mb), morteza.bashsiz@gmail.com 15 | # ORGANIZATION: Linux 16 | # CREATED: 01/01/2023 10:14:30 PM 17 | # REVISION: --- 18 | #=============================================================================== 19 | 20 | set -o nounset # Treat unset variables as an error 21 | 22 | domain="$1" 23 | preDomain="$2" 24 | mainDomain="$3" 25 | configName="$4" 26 | mkdir -p /opt/v2ray_urls 27 | 28 | # shellcheck disable=SC2044 29 | for file in $(find /etc/v2ray/ -type f -iname "v2ray[0-9][0-9]*$configName.json"); 30 | do 31 | date=$(date '+%Y%m%d') 32 | endPoint=$(jq .inbounds < "$file" | jq .[].streamSettings.wsSettings.path) 33 | uuidList=$(jq .inbounds < "$file" | jq .[].settings.clients | jq .[].id) 34 | hostName=$(hostname) 35 | uuidSni=$(uuid) 36 | host="$preDomain$hostName.$mainDomain" 37 | sni="$uuidSni.$mainDomain" 38 | # shellcheck disable=SC2001 39 | apiName=$(echo "$endPoint" | sed 's/\"//g') 40 | rm -fr /opt/v2ray_urls/"$apiName" 41 | mkdir -p /opt/v2ray_urls/"$apiName" 42 | for uuId in $uuidList; 43 | do 44 | # shellcheck disable=SC2001 45 | name=$(echo "$uuId" | sed 's/\"//g') 46 | if [[ "$preDomain" == "schere" ]] 47 | then 48 | jsonClient_1=$(cat << EOF 49 | { 50 | "add":"$domain", 51 | "aid":"0", 52 | "alpn":"", 53 | "host":"$host", 54 | "id":$uuId, 55 | "net":"ws", 56 | "path":$endPoint, 57 | "port":"443", 58 | "ps":"$configName", 59 | "scy":"auto", 60 | "sni":"$sni", 61 | "tls":"tls", 62 | "type":"", 63 | "v":"2" 64 | } 65 | EOF 66 | ) 67 | fi 68 | if [[ "$preDomain" == "gheychi" ]] 69 | then 70 | jsonClient_1=$(cat << EOF 71 | { 72 | "add":"$host", 73 | "aid":"0", 74 | "alpn":"", 75 | "host":"$host", 76 | "id":$uuId, 77 | "net":"ws", 78 | "path":$endPoint, 79 | "port":"443", 80 | "ps":"$configName", 81 | "scy":"auto", 82 | "sni":"$sni", 83 | "tls":"tls", 84 | "type":"", 85 | "v":"2" 86 | } 87 | EOF 88 | ) 89 | fi 90 | encoded=$(echo "$jsonClient_1" | base64 -w 0) 91 | echo "vmess://$encoded" > /opt/v2ray_urls/"$apiName"/"$date"_"$name"".url" 92 | done 93 | done 94 | 95 | -------------------------------------------------------------------------------- /roles/v2ray/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reload systemd 4 | systemd: 5 | daemon_reload: yes 6 | -------------------------------------------------------------------------------- /roles/v2ray/tasks/instances.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: check if config file exists {{ instance.name }} 4 | stat: 5 | path: /etc/v2ray/{{ instance.name }}.json 6 | register: config_file 7 | 8 | - name: check if service file exists {{ instance.name }} 9 | stat: 10 | path: /lib/systemd/system/{{ instance.name }}.service 11 | register: service_file 12 | 13 | - name: v2ray service {{ instance.name }} 14 | template: 15 | src: lib/systemd/system/v2ray.service.j2 16 | dest: /lib/systemd/system/{{ instance.name }}.service 17 | owner: root 18 | group: root 19 | mode: '0644' 20 | # when: not service_file.stat.exists 21 | 22 | - name: v2ray config {{ instance.name }} 23 | template: 24 | src: etc/v2ray/config.json.j2 25 | dest: /etc/v2ray/{{ instance.name }}_{{ V2RAY_CFG_NAME }}.json 26 | owner: root 27 | group: root 28 | mode: '0644' 29 | # when: not config_file.stat.exists 30 | 31 | - name: restart service 32 | shell: | 33 | systemctl daemon-realod 34 | systemctl enable "{{ instance.name }}" 35 | systemctl restart "{{ instance.name }}" 36 | # when: not config_file.stat.exists 37 | 38 | -------------------------------------------------------------------------------- /roles/v2ray/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: packages role 4 | include_role: 5 | name: packages 6 | vars: 7 | PKGS_LIST: "{{ V2RAY_PKGS_LIST }}" 8 | 9 | - name: Create directory if it does not exist 10 | file: 11 | path: /opt/v2ray_toolbox/ 12 | state: directory 13 | mode: '0755' 14 | 15 | - name: Copy v2ray_toolbox 16 | copy: 17 | src: opt/v2ray_toolbox/{{ item }} 18 | dest: /opt/v2ray_toolbox/{{ item }} 19 | owner: root 20 | group: root 21 | with_items: 22 | - v2ray.sh 23 | 24 | - name: nginx config for v2ray 25 | template: 26 | src: etc/nginx/nginx.conf.j2 27 | dest: /etc/nginx/nginx.conf 28 | owner: root 29 | group: root 30 | mode: '0644' 31 | 32 | - name: configuring nginx instances 33 | include_tasks: nginx.yml 34 | loop: "{{ NGINX_INSTANCES }}" 35 | loop_control: 36 | loop_var: instance 37 | 38 | - name: configuring instances 39 | include_tasks: instances.yml 40 | loop: "{{ V2RAY_INSTANCES }}" 41 | loop_control: 42 | loop_var: instance 43 | 44 | - name: generate vmess url 45 | shell: | 46 | bash /opt/v2ray_toolbox/v2ray.sh "{{ V2RAY_CFG_DOMAIN }}" "{{ V2RAY_CFG_PREDOMAIN }}" "{{ MAIN_DOMAIN }}" "{{ V2RAY_CFG_NAME }}" 47 | changed_when: false 48 | -------------------------------------------------------------------------------- /roles/v2ray/tasks/nginx.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: nginx config for {{ instance.domain }} 4 | template: 5 | src: etc/nginx/specific-conf.d/specific.conf.j2 6 | dest: /etc/nginx/specific-conf.d/{{ instance.domain }}-specific.conf 7 | owner: root 8 | group: root 9 | mode: '0644' 10 | 11 | - name: nginx config for {{ instance.domain }} 12 | template: 13 | src: etc/nginx/conf.d/nginx.conf.j2 14 | dest: /etc/nginx/conf.d/{{ instance.domain }}.conf 15 | owner: root 16 | group: root 17 | mode: '0644' 18 | -------------------------------------------------------------------------------- /roles/v2ray/templates/etc/nginx/conf.d/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | server_name gheychi{{ instance.domain }} schere{{ instance.domain }} {{ instance.domain }} ; 5 | return 301 https://schere{{ instance.domain }}; 6 | } 7 | 8 | server { 9 | gzip on; 10 | gzip_disable "msie6"; 11 | gzip_vary on; 12 | gzip_proxied any; 13 | gzip_comp_level 6; 14 | gzip_buffers 16 8k; 15 | gzip_http_version 1.1; 16 | gzip_types application/javascript application/rss+xml application/vnd.ms-fontobject application/x-font application/x-font-opentype application/x-font-otf application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/opentype font/otf font/ttf image/svg+xml image/x-icon text/css text/javascript text/plain text/xml; 17 | if ($host !~ ^(gheychi{{ instance.domain }}|schere{{ instance.domain }}|{{ instance.domain }})$ ) { 18 | return 444; 19 | } 20 | if ($request_method !~ ^(GET|HEAD|POST)$ ) { 21 | return 444; 22 | } 23 | listen 443 ssl http2; 24 | server_name gheychi{{ instance.domain }} schere{{ instance.domain }} {{ instance.domain }}; 25 | 26 | root {{ instance.root }}; 27 | index index.html; 28 | ssl_certificate /etc/letsencrypt/live/{{ instance.domain }}/fullchain.pem; 29 | ssl_certificate_key /etc/letsencrypt/live/{{ instance.domain }}/privkey.pem; 30 | ssl_trusted_certificate /etc/letsencrypt/live/{{ instance.domain }}/chain.pem; 31 | access_log /var/log/nginx/{{ instance.domain }}.access.log; 32 | error_log /var/log/nginx/{{ instance.domain }}.error.log; 33 | 34 | location = /favicon.ico { 35 | log_not_found off; 36 | access_log off; 37 | } 38 | 39 | location = /robots.txt { 40 | allow all; 41 | log_not_found off; 42 | access_log off; 43 | } 44 | 45 | include specific-conf.d/{{ instance.domain }}-specific.conf; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /roles/v2ray/templates/etc/nginx/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes auto; 3 | pid /run/nginx.pid; 4 | include /etc/nginx/modules-enabled/*.conf; 5 | 6 | events { 7 | worker_connections 16000; 8 | } 9 | 10 | http { 11 | sendfile on; 12 | tcp_nopush on; 13 | types_hash_max_size 2048; 14 | client_body_buffer_size 10K; 15 | client_header_buffer_size 1k; 16 | client_max_body_size 8m; 17 | large_client_header_buffers 4 4k; 18 | client_body_timeout 12; 19 | client_header_timeout 12; 20 | keepalive_timeout 15; 21 | send_timeout 10; 22 | 23 | include /etc/nginx/mime.types; 24 | default_type application/octet-stream; 25 | 26 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE 27 | ssl_prefer_server_ciphers on; 28 | 29 | access_log /var/log/nginx/access.log; 30 | error_log /var/log/nginx/error.log; 31 | 32 | include /etc/nginx/conf.d/*.conf; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /roles/v2ray/templates/etc/nginx/specific-conf.d/specific.conf.j2: -------------------------------------------------------------------------------- 1 | {% set instances = V2RAY_INSTANCES %} 2 | {% for instance in instances %} 3 | location /{{ instance.wsurl }} { 4 | proxy_redirect off; 5 | proxy_pass http://localhost:{{ instance.port }}; 6 | proxy_http_version 1.1; 7 | proxy_set_header Upgrade $http_upgrade; 8 | proxy_set_header Connection "upgrade"; 9 | proxy_set_header Host $http_host; 10 | 11 | } 12 | {% endfor %} 13 | 14 | -------------------------------------------------------------------------------- /roles/v2ray/templates/etc/v2ray/config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "loglevel": "info" 4 | }, 5 | "inbounds": [{ 6 | "listen": "{{ instance.listen }}", 7 | "port": {{ instance.port }}, 8 | "protocol": "{{ instance.protocol }}", 9 | "streamSettings": { 10 | {% if instance.wsurl != "null" %} 11 | "network": "ws", 12 | "wsSettings": { 13 | "path": "/{{ instance.wsurl }}" 14 | } 15 | {% endif %} 16 | }, 17 | "settings": { 18 | "clients": [ 19 | {% for client in instance.clients %} 20 | { 21 | "id": "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}", 22 | "level": {{ client.level }}, 23 | "alterId": {{ client.alterId }} 24 | } 25 | {% if not loop.last %} 26 | , 27 | {% endif %} 28 | {% endfor %} 29 | ] 30 | } 31 | }], 32 | "outbounds": [{ 33 | "protocol": "freedom", 34 | "settings": {} 35 | },{ 36 | "protocol": "blackhole", 37 | "settings": {}, 38 | "tag": "blocked" 39 | }] 40 | } 41 | 42 | -------------------------------------------------------------------------------- /roles/v2ray/templates/etc/v2ray/config.json.j2_org: -------------------------------------------------------------------------------- 1 | { 2 | "inbounds": [{ 3 | "listen": "{{ instance.listen }}", 4 | "port": {{ instance.port }}, 5 | "protocol": "{{ instance.protocol }}", 6 | "streamSettings": {}, 7 | "settings": { 8 | "clients": [ 9 | {% for client in {{ instance.clients }} %} 10 | { 11 | "id": "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}", 12 | "level": {{ client.level }}, 13 | "alterId": {{ client.alterId }} 14 | }, 15 | {% endfor %} 16 | ] 17 | } 18 | }], 19 | "outbounds": [{ 20 | "protocol": "freedom", 21 | "settings": {} 22 | },{ 23 | "protocol": "blackhole", 24 | "settings": {}, 25 | "tag": "blocked" 26 | }] 27 | } 28 | 29 | -------------------------------------------------------------------------------- /roles/v2ray/templates/lib/systemd/system/v2ray.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=V2Ray Service {{ instance.name }} 3 | Documentation=https://www.v2ray.com/ https://www.v2fly.org/ 4 | After=network-online.target nss-lookup.target 5 | 6 | [Service] 7 | Type=simple 8 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 9 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 10 | DynamicUser=true 11 | NoNewPrivileges=true 12 | Environment=V2RAY_LOCATION_ASSET=/etc/v2ray 13 | ExecStart=/usr/bin/v2ray -config /etc/v2ray/{{ instance.name }}_{{ V2RAY_CFG_NAME }}.json 14 | Restart=on-failure 15 | LimitNOFILE=65535 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | 20 | --------------------------------------------------------------------------------