Skip to content

Instantly share code, notes, and snippets.

@seriyps
Last active December 20, 2023 14:51
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save seriyps/dc00ad91bfd8a2058f30845cd0daed83 to your computer and use it in GitHub Desktop.
Save seriyps/dc00ad91bfd8a2058f30845cd0daed83 to your computer and use it in GitHub Desktop.
Interactive MTProto proxy installer
#!/bin/bash
# Automatic interactive installer for mtproto proxy https://github.com/seriyps/mtproto_proxy
# Supported OS:
# - Ubuntu 18.xx
# - Ubuntu 19.xx
# - Ubuntu 20.xx
# - Ubuntu 21.xx
# - Ubuntu 22.xx
# - Debian 11 bullseye
# - Debian 10 buster
# - Debian 9 stretch
# - Debinn 8 jessie (not well-tested)
# - CentOS 7
RED='\033[0;31m'
GR='\033[0;32m'
YE='\033[0;33m'
NC='\033[0m'
WORKDIR=`pwd`
SRC_DIR=mtproto_proxy
SELF="$0"
info() {
echo -e "${GR}INFO${NC}: $1"
}
warn() {
echo -e "${YE}WARNING${NC}: $1"
}
error() {
echo -e "${RED}ERROR${NC}: $1" 1>&2
exit 1
}
usage() {
echo "MTProto proxy installer.
Install proxy:
${SELF} -p <port> -s <secret> -t <ad tag> -a dd -a tls -d <fake-tls domain>
Upgrade code to the latest version and restart, keeping config unchanged:
${SELF} upgrade
Interactively generate new config and reload proxy settings:
${SELF} reconfigure -p <port> -s <secret> -t <ad tag> -a dd -a tls -d <fake-tls domain>
Reload proxy settings after manual changes in config/prod-sys.cnfig:
${SELF} reload
"
}
to_hex() {
od -A n -t x1 -w128 | sed 's/ //g'
}
case "$1" in
reconfigure|reload|upgrade|install)
CMD="$1"
shift
;;
*)
CMD="install"
esac
PORT=${MTP_PORT:-""}
SECRET=${MTP_SECRET:-""}
TAG=${MTP_TAG:-""}
DD_ONLY=${MTP_DD_ONLY:-""}
TLS_ONLY=${MTP_TLS_ONLY:-""}
TLS_DOMAIN=${MTP_TLS_DOMAIN:-""}
# check command line options
while getopts "p:s:t:a:d:h" o; do
case "${o}" in
p)
PORT=${OPTARG}
;;
s)
SECRET=${OPTARG}
;;
t)
TAG=${OPTARG}
;;
a)
case "${OPTARG}" in
"dd")
DD_ONLY="y"
;;
"tls")
TLS_ONLY="y"
;;
*)
error "Invalid -a value: '${OPTARG}'"
esac
;;
d)
TLS_DOMAIN=${OPTARG}
;;
h)
usage
exit 0
esac
done
echo "Interactive MTProto proxy installer."
echo "You can make the process fully automated by calling this script as 'echo \"y\ny\ny\ny\ny\ny\" | $0'."
echo "Try $0 -h for more options."
set -e
source /etc/os-release
info "Detected OS is ${ID} ${VERSION_ID}"
do_configure_os() {
# We need at least 'make' 'sed' 'diff' 'od' 'install' 'tar' 'base64' 'awk'
case "${ID}-${VERSION_ID}" in
ubuntu-19.*|ubuntu-20.*|ubuntu-21.*|ubuntu-22.*|debian-10|debian-11)
info "Installing required APT packages"
sudo apt update
sudo apt install erlang-nox erlang-dev make sed diffutils tar
;;
debian-9|debian-8|ubuntu-18.*)
info "Installing extra repositories"
curl -L https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb -o erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt update
info "Installing required APT packages"
sudo apt install erlang-nox erlang-dev make sed diffutils tar
;;
centos-7)
info "Installing extra repositories"
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
wget \
https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
info "Installing required RPM packages"
sudo yum install chrony erlang-compiler erlang-erts erlang-kernel erlang-stdlib erlang-syntax_tools \
erlang-crypto erlang-inets erlang-sasl erlang-ssl
;;
*)
error "Your OS ${ID} ${VERSION_ID} is not supported!"
esac
info "Making sure clock synchronization is enabled"
if [ `systemctl is-active ntp` = "active" ]; then
info "Replacing ntpd with systemd-timesyncd"
systemctl disable ntp
systemctl stop ntp
fi
sudo timedatectl set-ntp on
info "Current time: `date`"
}
do_get_source() {
info "Downloading proxy source code"
curl -L https://github.com/seriyps/mtproto_proxy/archive/master.tar.gz -o mtproto_proxy.tar.gz
info "Unpacking source code"
tar -xaf mtproto_proxy.tar.gz
mv -T --backup=t mtproto_proxy-master $SRC_DIR
}
# cd mtproto_proxy/
do_build_config() {
info "Interactively generating config-file"
# So, we ask for port/secret/ad_tag/protocols only if they are not specified via
# command-line or env vars
if [ -z "${PORT}" ]; then
PORT=443
read -p "Use default proxy port 443? [y/n] " yn
case $yn in
[Nn]*)
read -p "Enter port number: 1-32000: " PORT
;;
*)
info "Using default port 443"
;;
esac
fi
if [ "${ID}" = "centos" -a "`sudo firewall-cmd --state 2>&1`" = "running" ]; then
read -p "Should I configure firewall?
'd' to disable firewall completely
'n' if you will setup firewall by yourself [y/n/d] " yn
case $yn in
[Yy]*)
info "Opening ${PORT} port"
sudo firewall-cmd --zone=public --add-port=${PORT}/tcp --permanent
sudo firewall-cmd --reload
;;
[Dd]*)
warning "Stopping firewalld"
sudo systemctl stop firewalld
sudo systemctl disable firewalld
;;
*)
warn "Please make sure proxy port ${PORT} is open on firewall!
Use smth like:
firewall-cmd --zone=public --add-port=${PORT}/tcp --permanent
firewall-cmd --reload"
;;
esac
fi
if [ -z "${SECRET}" ]; then
SECRET=`head -c 16 /dev/urandom | to_hex`
read -p "Use randomly generated secret '${SECRET}'? [y/n] " yn
case $yn in
[Nn]*)
read -p "Enter your secret: 16 hex characters 0-9a-f: " SECRET
;;
*)
info "Using random secret ${SECRET}"
;;
esac
fi
if [ -z "${TAG}" ]; then
TAG="8b081275ec12abd306faeb2f13efbdcb"
read -p "Use empty @MTProxybot AD TAG? Answer 'n' to set AD TAG [y/n] " yn
case $yn in
[Nn]*)
read -p "Enter your ad tag from @MTProxybot: " TAG
;;
*)
info "Using no AD TAG"
esac
fi
if [ -z "${DD_ONLY}" ]; then
DD_ONLY="y"
read -p "Enable dd-only mode? (recommended) [y/n] " yn
case $yn in
[Nn]*)
DD_ONLY=""
warn "dd-only mode disabled"
;;
*)
info "Using dd-only mode"
esac
fi
if [ -z "${TLS_ONLY}" ]; then
TLS_ONLY="y"
read -p "Enable TLS-only mode? (recommended) [y/n] " yn
case $yn in
[Nn]*)
TLS_ONLY=""
warn "TLS-only mode disabled"
;;
*)
info "Using TLS-only mode"
esac
fi
if [ -z "${TLS_DOMAIN}" -a \( -n "${TLS_ONLY}" -o -z "${DD_ONLY}" \) ]; then
# If tls_domain is not set and fake-tls is enabled, ask for domain
TLS_DOMAIN="s3.amazonaws.com"
read -p "Use '${TLS_DOMAIN}' as domain name for fake-tls? Answer 'n' to change to another [y/n] " yn
case $yn in
[Nn]*)
read -p "Enter domain name: " TLS_DOMAIN
;;
*)
;;
esac
info "Using '${TLS_DOMAIN}' for fake-TLS SNI"
fi
PROTO_ARG=""
if [ -n "${DD_ONLY}" -a -n "${TLS_ONLY}" ]; then
PROTO_ARG='{allowed_protocols, [mtp_fake_tls,mtp_secure]},'
elif [ -n "${DD_ONLY}" ]; then
PROTO_ARG='{allowed_protocols, [mtp_secure]},'
elif [ -n "${TLS_ONLY}" ]; then
PROTO_ARG='{allowed_protocols, [mtp_fake_tls]},'
fi
[ -z "${PORT}" -o -z "${SECRET}" -o -z "${TAG}" ] && \
error "Not enough options: port='${PORT}' secret='${SECRET}' ad_tag='${TAG}'"
[ ${PORT} -gt 0 -a ${PORT} -lt 65535 ] || \
error "Invalid port value: ${PORT}"
[ -n "`echo $SECRET | grep -x '[[:xdigit:]]\{32\}'`" ] || \
error "Invalid secret. Should be 32 chars of 0-9 a-f"
[ -n "`echo $TAG | grep -x '[[:xdigit:]]\{32\}'`" ] || \
error "Invalid tag. Should be 32 chars of 0-9 a-f"
[ -z "${TLS_DOMAIN}" -o -n "`echo $TLS_DOMAIN | grep -xE '^([0-9a-z_-]+\.)+[a-z]{2,6}$'`" ] || \
error "Invalid TLS domain '${TLS_DOMAIN}'. Should be valid domain name!"
echo '
%% -*- mode: erlang -*-
[
{mtproto_proxy,
%% see src/mtproto_proxy.app.src for examples.
[
'${PROTO_ARG}'
{ports,
[#{name => mtp_handler_1,
listen_ip => "0.0.0.0",
port => '${PORT}',
secret => <<"'${SECRET}'">>,
tag => <<"'${TAG}'">>}
]}
]},
%% Logging config
{lager,
[{log_root, "/var/log/mtproto-proxy"},
{crash_log, "crash.log"},
{handlers,
[
{lager_console_backend,
[{level, critical}]},
{lager_file_backend,
[{file, "application.log"},
{level, info},
%% Do fsync only on critical messages
{sync_on, critical},
%% If we logged more than X messages in a second, flush the rest
{high_water_mark, 300},
%% If we hit hwm and msg queue len is >X, flush the queue
{flush_queue, true},
{flush_threshold, 2000},
%% How often to check if log should be rotated
{check_interval, 5000},
%% Rotate when file size is 100MB+
{size, 104857600}
]}
]}]},
{sasl, [{errlog_type, error}]}
].' >config/prod-sys.config
info "Config is generated with following properties:
port=${PORT} secret=${SECRET} tag=${TAG} tls_only=${TLS_ONLY} dd_only=${DD_ONLY} domain=${TLS_DOMAIN}"
}
do_backup_config() {
cp $SRC_DIR/config/prod-sys.config $WORKDIR/prod-sys.config.bak
}
do_restore_config() {
cp $WORKDIR/prod-sys.config.bak config/prod-sys.config
}
do_reload_config() {
sudo make update-sysconfig
sudo systemctl reload mtproto-proxy
}
do_build() {
info "Generating Erlang interpreter options"
make config/prod-vm.args
info "Compiling"
make
}
do_install() {
# Try to stop proxy in case this script is run not for the first time
sudo systemctl stop mtproto-proxy || true
info "Installing"
sudo make install
info "Starting"
sudo systemctl enable mtproto-proxy
sudo systemctl start mtproto-proxy
}
do_print_links() {
info "Detecting IP address"
IP=`curl -s -4 -m 10 http://ipv4.seriyps.ru || curl -s -4 -m 10 https://digitalresistance.dog/myIp`
info "Detected external IP is ${IP}"
URL_PREFIX="https://t.me/proxy?server=${IP}&port=${PORT}&secret="
ESCAPED_SECRET=$(echo -n $SECRET | sed 's/../\\x&/g') # bytes
ESCAPED_TLS_SECRET="\xee${ESCAPED_SECRET}"${TLS_DOMAIN}
BASE64_TLS_SECRET=`echo -ne $ESCAPED_TLS_SECRET | base64 -w 0 | tr '+/' '-_'`
HEX_TLS_SECRET=`echo -ne $ESCAPED_TLS_SECRET | to_hex`
info "Logs: /var/log/mtproto-proxy/application.log"
info "Secret: ${SECRET}"
info "Proxy links:
Normal: ${URL_PREFIX}${SECRET}
Secure: ${URL_PREFIX}dd${SECRET}
Fake-TLS hex: ${URL_PREFIX}${HEX_TLS_SECRET}
Fake-TLS base64: ${URL_PREFIX}${BASE64_TLS_SECRET}
"
}
# info "Executing $CMD"
case "$CMD" in
"install")
do_configure_os
do_get_source
cd $SRC_DIR/
do_build_config
do_build
do_install
do_print_links
info "Proxy is ready"
;;
"reconfigure")
cd $SRC_DIR/
do_build_config
do_reload_config
do_print_links
info "Config updated"
;;
"reload")
cd $SRC_DIR/
do_reload_config
info "Config updated"
;;
"upgrade")
do_backup_config
do_get_source
cd $SRC_DIR/
do_restore_config
do_build
do_install
info "Code upgraded"
esac
@alirbara
Copy link

I forked and modified debian apt install with -y to bypass prompt in the script. I appreciate revising it for public use as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment