Automatic interactive installer for mtproto proxy https://github.com/seriyps/mtproto_proxy
April 3, 2026 · View on GitHub
#!/bin/bash
Automatic interactive installer for mtproto proxy https://github.com/seriyps/mtproto_proxy
Supported OS:
- Ubuntu 24.xx
- Ubuntu 23.xx
- Ubuntu 22.xx
- Debian 11 bullseye
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 "{NC}: $1" }
warn() { echo -e "{NC}: $1" }
error() { echo -e "{NC}: $1" 1>&2 exit 1 }
usage() {
echo "MTProto proxy installer.
Install proxy:
${SELF} -p
Upgrade code to the latest version and restart, keeping config unchanged: ${SELF} upgrade
Interactively generate new config and reload proxy settings:
${SELF} reconfigure -p
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_SECRET:-""} TAG={MTP_DD_ONLY:-""} TLS_ONLY={MTP_TLS_DOMAIN:-""}
check command line options
while getopts "p:s:t:a:d:h" o; do case "{OPTARG} ;; s) SECRET={OPTARG} ;; a) case "{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 {VERSION_ID}"
do_configure_os() { # We need at least 'make' 'sed' 'diff' 'od' 'install' 'tar' 'base64' 'awk'
case "${ID}-${VERSION_ID}" in
ubuntu-22.*|ubuntu-23.*|ubuntu-24.*|debian-11)
info "Installing required APT packages"
sudo apt update
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
case "${ID}-${VERSION_ID}" in
ubuntu-22.*)
info "Downgrade rebar3 to 3.23.0"
curl -L -o $SRC_DIR/rebar3 https://github.com/erlang/rebar3/releases/download/3.23.0/rebar3
chmod +x $SRC_DIR/rebar3
;;
*)
;;
esac
}
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 {PORT} port" sudo firewall-cmd --zone=public --add-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
FRONTING_ARG=""
if [ -n "${TLS_DOMAIN}" ]; then
FRONTING_ARG='{domain_fronting, "'${TLS_DOMAIN}':443"},'
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}' '{FRONTING_ARG}' {ports, [#{name => mtp_handler_1, listen_ip => "0.0.0.0", port => '{SECRET}'">>, tag => <<"'${TAG}'">>} ]} ]},
%% Logging config {kernel, [{logger_level, info}, {logger, [{handler, default, logger_std_h, #{level => info, formatter => {logger_formatter, #{single_line => true}}, config => #{type => file, file => "/var/log/mtproto-proxy/application.log", max_no_bytes => 104857600, % 100MB max_no_files => 10, filesync_repeat_interval => no_repeat}}}, {handler, console, logger_std_h, #{level => critical, config => #{type => standard_io}}} ]}]}, {sasl, [{errlog_type, error}]} ].' >config/prod-sys.config
info "Config is generated with following properties:
port={SECRET} tag={TLS_ONLY} dd_only={TLS_DOMAIN}" }
do_backup_config() { cp 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.com || 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: {SECRET} Secure: {SECRET} Fake-TLS hex: {HEX_TLS_SECRET} Fake-TLS base64: {BASE64_TLS_SECRET} " }
info "Executing $CMD"
case "SRC_DIR/ do_build_config do_build do_install do_print_links info "Proxy is ready" ;; "reconfigure") 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