├── hosts ├── .gitignore ├── roles ├── firewall │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── telegram_proxy │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ ├── user.yml │ │ └── dante.yml │ ├── templates │ │ └── danted.conf.j2 │ └── files │ │ └── danted └── common │ └── tasks │ └── main.yml ├── ansible.cfg ├── playbook.yml ├── LICENSE └── README.md /hosts: -------------------------------------------------------------------------------- 1 | [telegram] 2 | 123.45.67.89 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | *.swp 3 | *.retry 4 | -------------------------------------------------------------------------------- /roles/firewall/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | tport: 1080 3 | -------------------------------------------------------------------------------- /roles/telegram_proxy/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | tport: 1080 3 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | 4 | [ssh_connection] 5 | pipelining = True 6 | -------------------------------------------------------------------------------- /roles/firewall/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart ufw 3 | systemd: name=ufw state=restarted 4 | -------------------------------------------------------------------------------- /roles/telegram_proxy/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart danted 3 | service: name=danted state=restarted 4 | -------------------------------------------------------------------------------- /playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | become: yes 5 | remote_user: root 6 | roles: 7 | - common 8 | 9 | - hosts: all 10 | become: yes 11 | remote_user: root 12 | roles: 13 | - firewall 14 | - telegram_proxy 15 | -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install python for Ansible 3 | raw: test -e /usr/bin/python || (apt -qy update && apt install -y python-minimal) 4 | register: output 5 | changed_when: output.stdout 6 | 7 | - name: Ensure apt cache is up to date 8 | apt: update_cache=yes cache_valid_time=3600 upgrade=dist 9 | changed_when: False 10 | 11 | - name: install setfacl support 12 | apt: pkg=acl 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /roles/telegram_proxy/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install dante 3 | import_tasks: dante.yml 4 | 5 | - name: Init user 6 | when: user is defined 7 | import_tasks: user.yml 8 | 9 | - name: Copy danted.conf 10 | template: 11 | src: danted.conf.j2 12 | dest: /etc/danted.conf 13 | notify: restart danted 14 | 15 | - name: Upload danted script 16 | copy: 17 | src: danted 18 | dest: /etc/init.d/danted 19 | mode: 0755 20 | 21 | - name: Start danted 22 | service: 23 | name: danted 24 | state: started 25 | enabled: yes 26 | -------------------------------------------------------------------------------- /roles/telegram_proxy/tasks/user.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install pip 3 | apt: pkg=python-pip state=present 4 | 5 | - name: Install passlib 6 | pip: 7 | name: passlib 8 | state: present 9 | 10 | - name: Encrypt password 11 | command: python -c "from passlib.hash import sha512_crypt; print(sha512_crypt.using(rounds=5000).hash('{{ password }}'))" 12 | register: enc_password 13 | changed_when: False 14 | 15 | - name: Create user 16 | user: 17 | name: "{{ user }}" 18 | password: "{{ enc_password.stdout }}" 19 | shell: /usr/sbin/nologin 20 | create_home: no 21 | state: present 22 | -------------------------------------------------------------------------------- /roles/firewall/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install UFW 3 | apt: name=ufw state=present 4 | 5 | - name: Configure ufw defaults 6 | ufw: direction={{ item.direction }} policy={{ item.policy }} 7 | with_items: 8 | - { direction: 'incoming', policy: 'deny' } 9 | - { direction: 'outgoing', policy: 'allow' } 10 | notify: restart ufw 11 | 12 | - name: Open SOCKS5 and SSH ports 13 | ufw: 14 | port: "{{ item }}" 15 | proto: tcp 16 | rule: allow 17 | with_items: 18 | - ssh 19 | - "{{ tport }}" 20 | notify: restart ufw 21 | 22 | - name: Open UDP ports 23 | ufw: 24 | port: 40000:45000 25 | proto: udp 26 | rule: allow 27 | notify: restart ufw 28 | 29 | - name: Enable ufw logging 30 | ufw: logging=on 31 | notify: restart ufw 32 | 33 | - name: Enable ufw 34 | ufw: state=enabled 35 | -------------------------------------------------------------------------------- /roles/telegram_proxy/tasks/dante.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check that dante is installed 3 | stat: 4 | path: /usr/sbin/sockd 5 | register: sockd 6 | 7 | - name: Install packages for building dante 8 | when: not sockd.stat.exists 9 | apt: pkg={{item}} state=present 10 | with_items: 11 | - build-essential 12 | - libwrap0 13 | - libwrap0-dev 14 | - gcc 15 | - make 16 | 17 | - name: Download dante package 18 | when: not sockd.stat.exists 19 | get_url: 20 | url: https://www.inet.no/dante/files/dante-1.4.2.tar.gz 21 | checksum: md5:29c2931339655da51576c4d2b7bf16f3 22 | dest: /tmp/dante.tar.gz 23 | 24 | - name: Unpack dante 25 | when: not sockd.stat.exists 26 | unarchive: 27 | remote_src: yes 28 | src: /tmp/dante.tar.gz 29 | dest: /opt 30 | 31 | - name: Delete dante archive 32 | when: not sockd.stat.exists 33 | file: 34 | path: /tmp/dante.tar.gz 35 | state: absent 36 | 37 | - name: Configure dante 38 | when: not sockd.stat.exists 39 | command: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --disable-client 40 | args: 41 | chdir: /opt/dante-1.4.2 42 | creates: /opt/dante-1.4.2/Makefile 43 | 44 | - name: Make dante 45 | when: not sockd.stat.exists 46 | command: make 47 | args: 48 | chdir: /opt/dante-1.4.2 49 | 50 | - name: Install dante 51 | when: not sockd.stat.exists 52 | command: make install 53 | args: 54 | chdir: /opt/dante-1.4.2 55 | creates: /usr/sbin/sockd 56 | 57 | - name: Clean up dante 58 | when: not sockd.stat.exists 59 | file: 60 | path: /opt/dante-1.4.2 61 | state: absent 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SOCKS5 Server for Telegram 2 | 3 | This Ansible playbook initializes a SOCKS5 server on any Ubuntu 16.04 machine. 4 | For anonymous server, run: 5 | 6 | ansible-playbook -i '12.34.56.78,' playbook.yml 7 | 8 | Note that the IP address should have a trailing comma. When you want to specify 9 | user name and password, add relevant tags: 10 | 11 | ansible-playbook -i '12.34.56.78,' playbook.yml -e user=thatsme password=q1w2e3r4 12 | 13 | Finally, you can change port from the default 1080 by using `tport` variable: 14 | 15 | ansible-playbook -i '12.34.56.78,' playbook.yml -e tport=1089 16 | 17 | ## Testing 18 | 19 | Run this command to test a server without auth: 20 | 21 | curl -v -x socks5://12.34.56.78:1080 http://t.me 22 | 23 | And with auth: 24 | 25 | curl -v -x socks5://thatsme:q1w2e3r4@12.34.56.78:1080 http://t.me 26 | 27 | Try querying google.com to see that only telegram endpoints are allowed. 28 | 29 | ## Author 30 | 31 | This playbook was written by Ilya Zverev and published under WTFPL. 32 | 33 | ## See Also 34 | 35 | These articles and code were used to make this playbook (mostly in Russian): 36 | 37 | * [Installing Dante on Ubuntu 16](https://weril.me/index.php/2018/04/13/installation_and_using_dante_as_socks5_proxy_on_ubuntu_16/) by Petr Redkin 38 | * [How to deploy own socks5 server](https://robot-review.ru/%D0%B3%D0%B0%D0%B9%D0%B4-%D0%BA%D0%B0%D0%BA-%D0%BF%D0%BE%D0%B4%D0%BD%D1%8F%D1%82%D1%8C-%D1%81%D0%B2%D0%BE%D0%B9-socks5-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80-%D0%B4%D0%BB%D1%8F-telegram-e29761a68560) by Andrey Viktorov 39 | * [Setting up a Telegram proxy server for 2.94€](https://ubuntuclub.org/nastroika-lichnogho-proxy-servera-dlia-telegram-za-2-94-euro/) © Ubuntu Club 40 | * [Dockerized socks5 proxy for Telegram](https://github.com/schors/tgdante2) by Phil Kulin 41 | * [Telegram calls via Dante not working](https://stackoverflow.com/questions/49855516/telegram-calls-via-dante-socks5-proxy-server-not-working), answer by Kostya Esmukov 42 | -------------------------------------------------------------------------------- /roles/telegram_proxy/templates/danted.conf.j2: -------------------------------------------------------------------------------- 1 | # /etc/danted.conf 2 | 3 | logoutput: syslog /var/log/sockd.log 4 | 5 | internal: eth0 port = {{ tport }} 6 | external: eth0 7 | 8 | clientmethod: none 9 | {% if user is defined %} 10 | socksmethod: username 11 | {% else %} 12 | socksmethod: none 13 | {% endif %} 14 | 15 | user.privileged: root 16 | user.unprivileged: nobody 17 | user.libwrap: nobody 18 | 19 | client pass { 20 | from: 0.0.0.0/0 to: 0.0.0.0/0 21 | log: error 22 | } 23 | 24 | # AS62041 25 | socks pass { from: 0.0.0.0/0 to: 149.154.160.0/20 } 26 | socks pass { from: 0.0.0.0/0 to: 149.154.164.0/22 } 27 | socks pass { from: 0.0.0.0/0 to: 91.108.4.0/22 } 28 | socks pass { from: 0.0.0.0/0 to: 91.108.8.0/22 } 29 | socks pass { from: 0.0.0.0/0 to: 91.108.56.0/22 } 30 | socks pass { from: ::/0 to: 2001:67c:4e8::/48 } 31 | 32 | # AS44907 33 | socks pass { from: 0.0.0.0/0 to: 91.108.20.0/22 } 34 | socks pass { from: 0.0.0.0/0 to: 91.108.36.0/23 } 35 | socks pass { from: 0.0.0.0/0 to: 91.108.38.0/23 } 36 | socks pass { from: ::/0 to: 2001:b28:f23c::/48 } 37 | 38 | # AS62014 39 | socks pass { from: 0.0.0.0/0 to: 149.154.168.0/22 } 40 | socks pass { from: 0.0.0.0/0 to: 91.108.16.0/22 } 41 | socks pass { from: 0.0.0.0/0 to: 91.108.56.0/23 } 42 | socks pass { from: ::/0 to: 2001:b28:f23f::/48 } 43 | 44 | # AS59930 45 | socks pass { from: 0.0.0.0/0 to: 149.154.172.0/22 } 46 | socks pass { from: 0.0.0.0/0 to: 91.108.12.0/22 } 47 | socks pass { from: ::/0 to: 2001:b28:f23d::/48 } 48 | 49 | # Other 50 | socks pass { from: 0.0.0.0/0 to: 149.154.167.0/22 } 51 | socks pass { from: 0.0.0.0/0 to: 149.154.174.0/22 } 52 | 53 | socks pass { from: 0.0.0.0/0 to: .telegram.org } 54 | socks pass { from: 0.0.0.0/0 to: .stel.com } 55 | socks pass { from: 0.0.0.0/0 to: .t.me } 56 | socks pass { from: 0.0.0.0/0 to: .telegram.me } 57 | socks pass { from: 0.0.0.0/0 to: .telegram.dog } 58 | socks pass { from: 0.0.0.0/0 to: .telegra.ph } 59 | 60 | # UDP for calls 61 | socks pass { 62 | from: 0.0.0.0/0 63 | to: 0.0.0.0/0 64 | udp.portrange: 40000-45000 65 | command: udpassociate 66 | log: error connect disconnect 67 | } 68 | 69 | socks pass { 70 | from: 0.0.0.0/0 71 | to: 0.0.0.0/0 72 | command: udpreply 73 | log: error connect disconnect 74 | } 75 | -------------------------------------------------------------------------------- /roles/telegram_proxy/files/danted: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | ### BEGIN INIT INFO 3 | # Required-Start: $remote_fs $syslog 4 | # Required-Stop: $remote_fs $syslog 5 | # Default-Start: 2 3 4 5 6 | # Default-Stop: 0 1 6 7 | # Short-Description: Debian SOCKS (v5) proxy control (danted) 8 | ### END INIT INFO 9 | 10 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 11 | DAEMON="/usr/sbin/sockd" 12 | DESC="Dante SOCKS 5 daemon" 13 | PID_FILE="/var/run/sockd.pid" 14 | CONFIG_FILE="/etc/danted.conf" 15 | PASSWD_FILE="/etc/sockd.passwd" 16 | 17 | test -f $DAEMON || exit 0 18 | test -f $CONFIG_FILE || exit 0 19 | 20 | [ -f /etc/init.d/functions ] && . /etc/init.d/functions 21 | [ -f /etc/default/sockd ] && . /etc/default/sockd 22 | [ -f /etc/default/color ] && . /etc/default/color 23 | 24 | LOG_FILE=$(grep '^logoutput' ${CONFIG_FILE} | sed 's/.*logoutput: \(.*\).*/\1/g') 25 | 26 | start_daemon_all(){ 27 | if [ -z "$(command -v start-stop-daemon)" ];then 28 | echo -e "${CRED}start-stop-daemon not exist! ${CEND}" 29 | return 1 30 | fi 31 | 32 | if [ -s $PID_FILE ] && [ -n "$( ps aux | awk '{print $2}'| grep "^$(cat $PID_FILE)$" )" ];then 33 | echo -e "${CRED}Danted Server [ Running;Failed ] ${CEND}" 34 | return 0 35 | fi 36 | 37 | if ! egrep -cve '^ *(#|$)' \ 38 | -e '^(logoutput|user\.((not)?privileged|libwrap)):' $CONFIG_FILE > /dev/null 39 | then 40 | echo -e "${CRED}Danted Server [ not configured ] ${CEND}" 41 | return 0 42 | fi 43 | 44 | cp /dev/null $PID_FILE 45 | 46 | start-stop-daemon --start --quiet --background --oknodo --pidfile $PID_FILE \ 47 | --exec $DAEMON -- -f ${CONFIG_FILE} -D -p $PID_FILE 48 | 49 | sleep 3 50 | 51 | if [ -s $PID_FILE ];then 52 | echo -e "${CGREEN}Danted Server [ Running ] ${CEND}" 53 | else 54 | echo -e "${CRED}Danted Server [ Start Failed ] ${CEND}" 55 | fi 56 | } 57 | 58 | stop_daemon_all(){ 59 | if [ -z "$(command -v start-stop-daemon)" ];then 60 | echo -e "${CRED}start-stop-daemon not exist! ${CEND}" 61 | return 1 62 | fi 63 | 64 | if [ ! -s $PID_FILE ];then 65 | echo -e "${CRED}Danted Server [ PID.LOST;Unable ] ${CEND}" 66 | fi 67 | 68 | start-stop-daemon --stop --quiet --oknodo --pidfile $PID_FILE \ 69 | --exec $DAEMON -- -f ${CONFIG_FILE} -p $PID_FILE -N ${Start_Process} ${Sockd_Opts} 70 | 71 | if [ -s $PID_FILE ];then 72 | [ -n "$( ps aux | awk '{print $2}'| grep "^$(cat $PID_FILE)$" )" ] && \ 73 | echo -e "${CRED}Danted Server [ Stop Failed ] ${CEND}" || \ 74 | echo -e "${CYELLOW}Danted Server [ Stop Done ] ${CEND}" 75 | fi 76 | } 77 | 78 | force_stop_daemon(){ 79 | ps -ef | grep ${DAEMON} | grep -v 'grep' | awk '{print $2}' | \ 80 | while read pid; do kill -9 $pid > /dev/null 2>&1 ;done 81 | 82 | [ -f "$PID_FILE" ] && rm -f $PID_FILE 83 | } 84 | 85 | reload_daemon_all(){ 86 | if [ -z "$(command -v start-stop-daemon)" ];then 87 | echo -e "${CRED}start-stop-daemon not exist! ${CEND}" 88 | return 1 89 | fi 90 | 91 | if [ -s $PID_FILE ];then 92 | if [ -z "$( ps aux | awk '{print $2}'| grep "^$(cat $PID_FILE)$" )" ];then 93 | echo -e "${CRED}Danted Server [ PID.DIE;Unable ] ${CEND}" 94 | return 1 95 | fi 96 | else 97 | echo -e "${CRED}Danted Server [ PID.LOST;Unable ] ${CEND}" 98 | return 1 99 | fi 100 | 101 | start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile $PIDFILE \ 102 | --exec $DAEMON -- -f $CONFIGFILE -p $PIDFILE -N ${Start_Process} ${Sockd_Opts} 103 | 104 | 105 | [ -n "$( ps aux | awk '{print $2}'| grep "^$(cat $PIDFILE)$" )" ] \ 106 | && echo -e "${CGREEN}Danted Server [ Running ] ${CEND}" \ 107 | || echo -e "${CRED}Danted Server [ Failed ] ${CEND}" 108 | 109 | } 110 | 111 | status(){ 112 | VERSION=$([ -f "${DAEMON}" ] && ${DAEMON} -v) 113 | 114 | printf "%s\n" "${CCYAN}+-----------------------------------------+$CEND" 115 | 116 | if [ ! -s ${PID_FILE} ];then 117 | printf "%s\n" "${CRED} Dante Server [ Stop ] ${CEND}" 118 | else 119 | ( [ -n "$( ps aux | awk '{print $2}'| grep "^$(cat ${PID_FILE})$" )" ] \ 120 | && printf "%s\n" "${CGREEN} Dante Server [ Running ] ${CEND}" ) \ 121 | || printf "%s\n" "${CRED} Dante Server [ PID.DIE;Running ] ${CEND}" 122 | fi 123 | 124 | printf "%s\n" "${CCYAN}+-----------------------------------------+$CEND" 125 | printf "%-30s%s\n" "${CGREEN} Dante Version:${CEND}" "$CMAGENTA ${VERSION}${CEND}" 126 | printf "%-30s\n" "${CGREEN} Socks5 Info:${CEND}" 127 | 128 | grep '^internal:' ${CONFIG_FILE} | \ 129 | sed 's/internal:[[:space:]]*\([0-9.]*\).*port[[:space:]]*=[[:space:]]*\(.*\)/\1:\2/g' | \ 130 | while read proxy;do 131 | printf "%20s%s\n" "" "${CMAGENTA}${proxy}${CEND}" 132 | done 133 | 134 | if [ -s ${PASSWD_FILE} ];then 135 | SOCKD_USER=$(cat ${PASSWD_FILE} | while read line;do echo ${line} | sed 's/\(.*\):.*/\1/';done) 136 | printf "%-30s%s\n" "${CGREEN} Socks5 User:${CEND}" "$CMAGENTA ${SOCKD_USER}${CEND}" 137 | fi 138 | printf "%s\n" "${CCYAN}+_________________________________________+$CEND" 139 | } 140 | add_user(){ 141 | local User=$1 142 | local Password=$2 143 | ( [ -z "$User" ] || [ -z "$Password" ] ) && \ 144 | echo " Error: User or password can't be blank" && return 0 145 | [ ! -f "${PASSWD_FILE}" ] && opt=" -c " 146 | [ -f "/usr/bin/htpasswd" ] && /usr/bin/htpasswd ${opt} -d -b ${PASSWD_FILE} ${User} ${Password} || \ 147 | echo " Error: /usr/bin/htpasswd not exist. please install apache2-utils" 148 | } 149 | del_user(){ 150 | local User=$1 151 | [ -z "$User" ] && echo " Error: User Name can't be blank" && return 0 152 | [ -f "/usr/bin/htpasswd" ] && /usr/bin/htpasswd -D ${PASSWD_FILE} ${User} || \ 153 | echo " Error: /usr/bin/htpasswd not exist. please install apache2-utils" 154 | } 155 | clear_log(){ 156 | [ -f "$PID_FILE" ] && rm -f $PID_FILE 157 | [ -f "$LOG_FILE" ] && cp /dev/null $LOG_FILE 158 | } 159 | tail_log(){ 160 | local LOG_FILE="$1" 161 | [ -f ${LOG_FILE} ] && tail -f ${LOG_FILE} 162 | } 163 | case "$1" in 164 | start) 165 | echo "Starting $DESC: " 166 | start_daemon_all 167 | ;; 168 | stop) 169 | echo "Stopping $DESC: " 170 | stop_daemon_all 171 | ;; 172 | force-stop) 173 | echo "Stopping $DESC: [Force]" 174 | force_stop_daemon 175 | ;; 176 | reload) 177 | echo "Reloading $DESC configuration files." 178 | reload_daemon_all 179 | ;; 180 | restart) 181 | echo "Restarting $DESC: " 182 | stop_daemon_all 183 | force_stop_daemon 184 | sleep 1 185 | start_daemon_all 186 | ;; 187 | status|state) 188 | clear 189 | status 190 | ;; 191 | adduser) 192 | echo "Adding User For $DESC: " 193 | add_user "$2" "$3" 194 | ;; 195 | deluser) 196 | echo "Clearing User For $DESC: " 197 | del_user "$2" 198 | ;; 199 | tail) 200 | echo "==> ${LOG_FILE} <==" 201 | tail_log "${LOG_FILE}" 202 | ;; 203 | conf) 204 | echo "==> ${CONFIG_FILE} <==" 205 | cat ${CONFIG_FILE} 206 | ;; 207 | *) 208 | N=/etc/init.d/sockd 209 | echo " Usage: $N {start|stop|restart|reload|status|state|adduser|deluser|tail|conf|update}" >&2 210 | exit 1 211 | ;; 212 | esac 213 | exit 0 214 | --------------------------------------------------------------------------------