Initial commit

This commit is contained in:
Pavel 2021-06-18 18:17:13 +03:00
commit 400419b55b
9 changed files with 330 additions and 0 deletions

32
.env.dist Normal file
View File

@ -0,0 +1,32 @@
# Proxy password.
PASSWORD=B1922A0B-1D77-40C6-8119-497AB81BC7A4
# Encryption algorithm. Default is good enough for both powerful and low-end devices.
ENCRYPT=xchacha20-ietf-poly1305
# DNS servers which will be used by the proxy.
DNS_SERVERS=1.1.1.1,1.0.0.1
# Path to V2Ray. This path will be used during client configuration. I suggest using some random value, like CRC32.
V2_PATH=/v2ray
# Path to QR code and connection string. This will be accessible without any authentication, so, use long random string.
QR_PATH=/qr_code
# Set to "no" if you don't want to make connection data accessible via path provided in the previous value.
GENERATE_QR=yes
# Specify server domain here.
DOMAIN=example.com
# Specify server port here (443 is HIGHLY RECOMMENDED because HTTPS uses it).
PORT=443
# Path to domain's TLS ceritificate inside container.
TLS_CERT=/etc/ssl/ssl.pem
# Path to domain's TLS private key inside container.
TLS_KEY=/etc/ssl/ssl.key
# Path to dhparams.pem inside container. Can be generated automatically if it's not passed via volume or any other means.
TLS_DHPARAM=/etc/ssl/dhparams.pem

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.key
*.pem
.env

18
Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM alpine:latest
ARG V2RAY_VERSION=v1.3.1
RUN set -ex \
&& apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing wget libqrencode shadowsocks-libev nginx jq bash sudo \
&& mkdir -p /etc/shadowsocks-libev /v2raybin /wwwroot \
&& wget -O- "https://github.com/shadowsocks/v2ray-plugin/releases/download/${V2RAY_VERSION}/v2ray-plugin-linux-amd64-${V2RAY_VERSION}.tar.gz" | \
tar zx -C /v2raybin \
&& install /v2raybin/v2ray-plugin_linux_amd64 /usr/bin/v2ray-plugin \
&& rm -rf /v2raybin
COPY config/ /config
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD /entrypoint.sh

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# Shadowsocks + V2Ray in Docker
Preconfigured solution for running Shadowsocks proxy with V2Ray inside Docker container.
You'll need a working domain for this solution.
Usage:
1. Copy `.env.dist` to `.env`
2. Replace demo values with your own (especially password).
3. Add your domain certificate to the `cert.pem` file.
4. Add your domain private key to the `cert.key` file.
5. Generate dhparams.pem using command `openssl dhparam -out "${TLS_DHPARAM}" 4096` or just remove like `- ./dhparams.pem:${TLS_DHPARAM}` from the `docker-compose.yml`.
6. Run `docker-compose up -d`.

68
config/nginx.conf Normal file
View File

@ -0,0 +1,68 @@
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
pcre_jit on;
pid /run/nginx.pid;
worker_rlimit_nofile 131072;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 4000;
multi_accept on;
use epoll;
epoll_events 512;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;
client_body_timeout 12;
client_header_timeout 12;
send_timeout 30;
keepalive_requests 2000;
reset_timedout_connection on;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_max_size 4096;
client_body_buffer_size 128K;
client_header_buffer_size 3m;
client_body_in_single_buffer on;
client_max_body_size 8m;
large_client_header_buffers 4 256k;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log off;
error_log /var/log/nginx/error.log crit;
##
# Gzip Settings
##
gzip off;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*;
}

54
config/nginx_ss.conf.sh Normal file
View File

@ -0,0 +1,54 @@
#!/bin/bash
cat <<EOF
server {
listen ${PORT} ssl http2 reuseport backlog=131072 fastopen=256;
listen [::]:${PORT} ssl http2 reuseport backlog=131072 fastopen=256;
server_name ${DOMAIN}
add_header Allow "GET" always;
if ( \$request_method !~ ^(GET)$ ) {
return 444;
}
ssl_certificate ${TLS_CERT};
ssl_certificate_key ${TLS_KEY};
ssl_dhparam ${TLS_DHPARAM};
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve secp384r1;
# ssl_early_data on;
add_header Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'" always;
add_header Strict-Transport-Security 'max-age=63072000; includeSubdomains; preload' always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Xss-Protection "1; mode=block" always;
resolver localhost valid=300s;
ssl_buffer_size 8k;
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
root /wwwroot;
location / {
proxy_pass https://youtube.com;
limit_rate 1000k;
proxy_redirect off;
}
location ${QR_PATH} {
root /wwwroot;
}
location = ${V2_PATH} {
if (\$http_upgrade != "websocket") { # WebSocket return this when negotiation fails 404
return 404;
}
proxy_redirect off;
proxy_buffering off;
proxy_pass http://127.0.0.1:2333;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
}
}
EOF

View File

@ -0,0 +1,17 @@
#!/bin/bash
cat <<EOF
{
"server": "127.0.0.1",
"server_port": "2333",
"password": ${PASSWORD_JSON},
"timeout": 300,
"method": "${ENCRYPT}",
"mode": "tcp_only",
"fast_open": true,
"nameserver": "${DNS_SERVERS}",
"reuse_port": true,
"no_delay": true,
"plugin": "v2ray-plugin",
"plugin_opts": "server;path=${V2_PATH};loglevel=none"
}
EOF

23
docker-compose.yml Normal file
View File

@ -0,0 +1,23 @@
version: "3"
services:
shadowsocks:
build:
context: .
environment:
PASSWORD: "${PASSWORD}"
ENCRYPT: "${ENCRYPT}"
V2_PATH: "${V2_PATH}"
QR_PATH: "${QR_PATH}"
GENERATE_QR: "${GENERATE_QR}"
DOMAIN: "${DOMAIN}"
PORT: ${PORT}
TLS_CERT: "${TLS_CERT}"
TLS_KEY: "${TLS_KEY}"
TLS_DHPARAM: "${TLS_DHPARAM}"
ports:
- "${PORT}:${PORT}"
volumes:
- ./cert.pem:${TLS_CERT}
- ./cert.key:${TLS_KEY}
- ./dhparams.pem:${TLS_DHPARAM}
restart: always

102
entrypoint.sh Normal file
View File

@ -0,0 +1,102 @@
#!/bin/bash
if [[ -z "${PASSWORD}" ]]; then
export PASSWORD="B1922A0B-1D77-40C6-8119-497AB81BC7A4"
echo WARNING: Default password is being used! Please replace default password with you own.
fi
export PASSWORD_JSON="$(echo -n "$PASSWORD" | jq -Rc)"
if [[ -z "${ENCRYPT}" ]]; then
export ENCRYPT="xchacha20-ietf-poly1305"
fi
if [[ -z "${V2_PATH}" ]]; then
export V2_PATH="/v2ray"
fi
if [[ -z "${QR_PATH}" ]]; then
export QR_PATH="/qr_code"
fi
if [[ -z "${GENERATE_QR}" ]]; then
export GENERATE_QR="yes"
fi
if [[ -z "${PORT}" ]]; then
export PORT="443"
fi
if [[ -z "${DOMAIN}" ]]; then
export DOMAIN="localhost"
fi
if [[ -z "${DNS_SERVERS}" ]]; then
export DNS_SERVERS="1.1.1.1,1.0.0.1"
fi
if [[ -z "${TLS_CERT}" ]]; then
export TLS_CERT="/etc/ssl/ssl.pem"
fi
if [[ -z "${TLS_KEY}" ]]; then
export TLS_KEY="/etc/ssl/ssl.key"
fi
if [[ -z "${TLS_DHPARAM}" ]]; then
export TLS_DHPARAM="/etc/ssl/dhparams.pem"
fi
echo Proxy domain: ${DOMAIN}
echo Proxy port: ${PORT}
echo Proxy password: ${PASSWORD}
echo Encryption: ${ENCRYPT}
echo TLS certificate path: ${TLS_CERT}
echo TLS private key path: ${TLS_KEY}
echo dhparams path: ${TLS_DHPARAM}
echo Path to V2Ray: ${V2_PATH}
echo Path to QR code page: ${QR_PATH}
echo Generate QR code: ${GENERATE_QR}
if [[ ! -f "${TLS_DHPARAM}" ]]; then
echo Cannot find existing dhparams.pem, it will be generated now.
openssl dhparam -out "${TLS_DHPARAM}" 4096
fi
if ! id www-data &>/dev/null; then
adduser -s /bin/false -S -D -H www-data
fi
if ! id shadowsocks &>/dev/null; then
adduser -s /bin/false -S -D -H shadowsocks
fi
bash /config/shadowsocks-libev_config.json.sh > /etc/shadowsocks-libev/config.json
echo /etc/shadowsocks-libev/config.json has been updated with following contents:
cat /etc/shadowsocks-libev/config.json
echo
mkdir -p /etc/nginx/conf.d
mv /config/nginx.conf /etc/nginx/nginx.conf
bash /config/nginx_ss.conf.sh > /etc/nginx/conf.d/ss.conf
echo /etc/nginx/conf.d/ss.conf has been updated with following contents:
cat /etc/nginx/conf.d/ss.conf
echo
if [[ "$GENERATE_QR" = "yes" ]]; then
[ ! -d /wwwroot/${QR_PATH} ] && mkdir /wwwroot/${QR_PATH}
plugin=$(echo -n "v2ray;path=${V2_PATH};host=${DOMAIN};tls;fast-open" | sed -e 's/\//%2F/g' -e 's/=/%3D/g' -e 's/;/%3B/g')
ss="ss://$(echo -n ${ENCRYPT}:${PASSWORD} | base64 -w 0)@${DOMAIN}:${PORT}?plugin=${plugin}"
echo "<!DOCTYPE html><html><head><title>Shadowsocks Account</title></head><body>" > /wwwroot/${QR_PATH}/index.html
echo "<p>${ss}</p>" | tr -d '\n' >> /wwwroot/${QR_PATH}/index.html
echo "<img src=\"${QR_PATH}/vpn.png\">" >> /wwwroot/${QR_PATH}/index.html
echo "</body></html>" >> /wwwroot/${QR_PATH}/index.html
echo -n "${ss}" | qrencode -s 6 -o /wwwroot/${QR_PATH}/vpn.png
fi
chown www-data:www-data -R /wwwroot
echo Running nginx and shadowsocks proxy...
sudo -u shadowsocks ss-server -c /etc/shadowsocks-libev/config.json &
rm -rf /etc/nginx/sites-enabled/default
nginx -g 'daemon off;'