Skip to content

Commit

Permalink
Use vless+reality instead of shadowsocks
Browse files Browse the repository at this point in the history
  • Loading branch information
ed-asriyan committed Dec 2, 2024
1 parent bc0435c commit 6f0fe56
Show file tree
Hide file tree
Showing 52 changed files with 771 additions and 636 deletions.
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Proxy [![CI | pre-commit](https://github.com/ed-asriyan/proxy-server/actions/workflows/CI-pre-commit.yml/badge.svg)](https://github.com/ed-asriyan/proxy-server/actions/workflows/CI-pre-commit.yml) [![CD | Production](https://github.com/ed-asriyan/proxy-server/actions/workflows/CD-production.yml/badge.svg)](https://github.com/ed-asriyan/proxy-server/actions/workflows/CD-production.yml)
This is deployment for my personal server with [outline](http://getoutline.org)/[shadowsocks](http://shadowsocks.org) on board for me and my friends to bypass internet censorship.
# Proxy [![CI | pre-commit](https://github.com/ed-asriyan/xray-server/actions/workflows/CI-pre-commit.yml/badge.svg)](https://github.com/ed-asriyan/xray-server/actions/workflows/CI-pre-commit.yml) [![CD | Production](https://github.com/ed-asriyan/xray-server/actions/workflows/CD-production.yml/badge.svg)](https://github.com/ed-asriyan/xray-server/actions/workflows/CD-production.yml)
This is deployment for my personal server with [xray](https://xtls.github.io/en/) on board for me and my friends to bypass internet censorship.

## Shadowsocks clients that work with this setup
https://getoutline.org/get-started/#step-3
## Vless clients that work with this setup
https://hiddify.com#app

# Architecture
![digram](./diagram.svg)
Expand All @@ -13,8 +13,13 @@ each instance should have dedicated IP address and DNS record (if exists). All h

## GH Pages
Serves static content:
* static html pages with installation instructions. The user is provided with a private instruction link with a personal ShadowSocks configuration, which the user uses once to install the ShadowSocks configuration
* personal dynamic ShadowSocks configuration json files ([SIP008](https://shadowsocks.org/doc/sip008.html)) for each client, which is used by ShadowSocks client each time before connecting to a ShadowSocks server
* static html pages with installation instructions. The user is provided with a private instruction link with a personal vless
[subscription URL](https://hiddify.com/app/URL-Scheme), which the user uses once to install the vless configuration
* personal vless [subscription files](https://hiddify.com/app/URL-Scheme) for each client, which is used by Hiddify to refresh
list of available servers

Playbook: [users-configs.yml](./users-configs.yml). It just renders files locally, the should be uploaded got GitHub Pages using
Actions.

## Metrics
It is a single linux host with the prometheus installed. Users do not access this host. Host may have no domain name.
Expand All @@ -25,14 +30,15 @@ Playbook: [metrics.yml](./metrics.yml)
## Proxy
As many proxy hosts as needed could be deployed but each one should have its own IP address and/or DNS record.
Proxy(ies) is/are linux host(s) with installed
* [outline-ss-server](https://github.com/Jigsaw-Code/outline-ss-server) (role: `shadowsocks`): Shadowsocks implementation made by
https://jigsaw.google.com that supports multiple access keys
* [node-exporter](https://github.com/prometheus/node_exporter) (role: `node-exporter`): Prometheus exporter for hardware and OS metrics
* [nginx](https://nginx.org) (role: `shadowsocks-gateway`) that proxies traffic:
* port `config_servers[uuid].port`:
* if connection is recognized as TLS, request is handled as HTTPS connection
* otherwise; connection is proxied to ShadoSocks server
* port `config_servers[uuid].prometheus_metrics.port`: to outline-ss-server and node-exporter metrics endpoints
* [xray-core](https://github.com/xtls/xray-core) (role: `xray`) that proxies traffic:
* if it's valid vless connection, to the destination
* otherwise, to `server.fallback_proxy_target`
* [node-exporter](https://github.com/prometheus/node_exporter) (role: `node-exporter`): Prometheus exporter for hardware and OS
metrics. Exports metrics to TCP port available from localhost only
* xray-exporter (role: `node-exporter`): custom script that exports xray metrics. Exports metrics to TCP port available from
localhost only
* [nginx](https://nginx.org) (role: `metrics-exporter`) that proxies https requests on
`config_servers[uuid].prometheus_metrics.port` TCP port to *node-exporter* and *xray-exporter*:

Playbook: [proxies.yml](./proxies.yml)

Expand Down Expand Up @@ -69,7 +75,7 @@ Read code and find out
## How to apply changes to production
* If you changed deploy code: just push to master branch. GitHub Actions will automatically apply updates to the servers.
* If you changed list of users: manually trigger [CD | Production](https://github.com/ed-asriyan/proxy-server/actions/workflows/CD-production.yml)
* If you changed list of users: manually trigger [CD | Production](https://github.com/ed-asriyan/xray-server/actions/workflows/CD-production.yml)
# Development
## CD
Expand Down
4 changes: 2 additions & 2 deletions config/hosts.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ all:
# linux user to connect to ssh to the server as
ansible_user:
proxy1:
# uuid of the shadowsocks server that should be deployed (from config/servers.yml)
# uuid of the xray server that should be deployed (from config/servers.yml)
hosts_server_uuid:
# public domain or IP where shadowsocks should be deployed (if ssh and shadowsocks are on the same IP, it should be equal to config_servers[hosts_server_uuid].host value)
# public domain or IP where xray should be deployed (if ssh and xray are on the same IP, it should be equal to config_servers[hosts_server_uuid].host value)
ansible_host:
# linux user to connect to ssh to the server as
ansible_user:
Expand Down
87 changes: 41 additions & 46 deletions config/servers.example.yml
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
config_servers:
server1-uuid:
# domain of server that will be put into config
# domain of server that will be put into config (IP or domain users will connect to)
host:
# description or name of server
remarks:
# port of shadowsocks to be exposed and used publicly
# name of server (one line)
name:
# port of xray to be exposed and used publicly
port:
# cipher to use in shadowsocks
method:
# secret (any random string) to be used for generating client passwords
secret:
# prefix to use. read more: https://www.reddit.com/r/outlinevpn/wiki/index/prefixing
prefix:
# where regular https requests (non-shadowsocks requests) proxy to
fallback_proxy_target:
# if you don't want to install prometheus on the server, replace yaml object to boolean false:
# prometheus_metrics: false
prometheus_metrics:
# port where prometheus metrics endpoints should be exposed
port:
# content of self-signed cert and keys (SSL pem format)
tls:
certificate: |
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
key: |
-----BEGIN PRIVATE KEY-----
....
-----END PRIVATE KEY-----
shadowsocks:
# any random URL-valid string starting with "/"
url_path:
node_exporter:
# any random URL-valid string starting with "/"
url_path:
# flow parameter in https://xtls.github.io/en/config/outbounds/vless.html#serverobject (ideally xtls-rprx-vision)
flow:
# fingerprint parameters as `fingerprint` in https://xtls.github.io/ru/config/transport.html#tlsobject
fingerprints:
- chrome
- safari
- "..."
# private key. generate with ./xray x25519
private_key:
# public key. generate with ./xray x25519
public_key:
# where regular https requests proxy to and what website xray should pretent as
fallback_proxy_target: example.com
# list of sni should be accepter by xray. see serverNames in https://xtls.github.io/ru/config/transport.html#realityobject
supported_snis:
- example.com
- www.example.com

# second server (for instance)
server2-uuid:
# domain of server that will be put into config (IP or domain users will connect to)
host:
remarks:
# name of server (one line)
name:
# port of xray to be exposed and used publicly
port:
method:
secret:
prefix:
# flow parameter in https://xtls.github.io/en/config/outbounds/vless.html#serverobject (ideally xtls-rprx-vision)
flow:
# fingerprint parameter in https://xtls.github.io/ru/config/transport.html#tlsobject
fingerprints:
-
-
# private key. generate with ./xray x25519
private_key:
# public key. generate with ./xray x25519
public_key:
# where regular https requests proxy to and what website xray should pretent as
fallback_proxy_target:
prometheus_metrics:
port:
tls:
certificate_path:
key_path:
shadowsocks:
url_path:
node_exporter:
url_path:
# list of sni should be accepter by xray. see serverNames in https://xtls.github.io/ru/config/transport.html#realityobject
supported_snis:
-
-
6 changes: 6 additions & 0 deletions config/users-configs.example.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# where redirect to if user opened index page without valid parameters
config_users_configs_default_redirect:

# title users should we when open hiddify
config_users_title:

# support url. see https://hiddify.com/app/URL-Scheme
config_users_support_url:
2 changes: 1 addition & 1 deletion diagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 22 additions & 4 deletions proxies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,27 @@
vars_files:
- ./config/users.yml
- ./config/servers.yml
vars:
# do not worry. these ports are local
config_local_xray_metrics_port: 8081
config_local_node_exporter_metrics_port: 8082
config_local_xray_exporter_metrics_port: 8080
roles:
- role: shadowsocks-gateway
- role: xray
vars:
shadowsocks_gateway_server_uuid: "{{ hosts_server_uuid }}"
shadowsocks_gateway_server: "{{ config_servers[shadowsocks_gateway_server_uuid] }}"
shadowsocks_gateway_users: "{{ config_users }}"
xray_server_uuid: "{{ hosts_server_uuid }}"
xray_server: "{{ config_servers[xray_server_uuid] }}"
xray_users: "{{ config_users }}"
xray_metrics_port: "{{ config_local_xray_metrics_port }}"
- role: node-exporter
vars:
node_exporter_port: "{{ config_local_node_exporter_metrics_port }}"
- role: xray-exporter
vars:
xray_exporter_port: "{{ config_local_xray_exporter_metrics_port }}"
xray_exporter_fetch_port: "{{ config_local_xray_metrics_port }}"
- role: metrics-exporter
vars:
metrics_exporter_server: "{{ config_servers[hosts_server_uuid] }}"
metrics_exporter_node_exporter_metrics_port: "{{ config_local_node_exporter_metrics_port }}"
metrics_exporter_xray_metrics_port: "{{ config_local_xray_exporter_metrics_port }}"
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# shadowsocks-gateway
# metrics exporter
## Mandatory and optional variables
Find them in [./defaults/main.yml](./defaults/main.yml). Empty variables in the file are mandatory, pre-filled variables are optional.
8 changes: 8 additions & 0 deletions roles/metrics-exporter/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# one(!) server item as secribed in /servers-example.yml
metrics_exporter_server:

# localhost port xray metrics are available on
metrics_exporter_xray_metrics_port:

# localhost port node_exporter metrics are available on
metrics_exporter_node_exporter_metrics_port:
2 changes: 2 additions & 0 deletions roles/metrics-exporter/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dependencies:
- role: nginx
74 changes: 74 additions & 0 deletions roles/metrics-exporter/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

- name: Ensure required variables are defined
assert:
that:
- metrics_exporter_xray_metrics_port is number
- metrics_exporter_node_exporter_metrics_port is number

- name: Ensure metrics_exporter_server is defined correctly
include_tasks: tasks/assert-server.yml
vars:
server: "{{ metrics_exporter_server }}"

- name: Create user
user: name={{ metrics_exporter_user }}

- name: Render nginx config
template:
src: nginx.conf.j2
dest: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_nginx_conf_filename }}"
group: "{{ metrics_exporter_user }}"
owner: "{{ metrics_exporter_user }}"
mode: "600"
register: config

- name: Copy SSL key
copy:
content: "{{ metrics_exporter_server.prometheus_metrics.tls.key }}"
dest: "{{ metrics_exporter_key_path }}"
group: "{{ metrics_exporter_user }}"
owner: "{{ metrics_exporter_user }}"
mode: "600"
when: metrics_exporter_server.prometheus_metrics is mapping
register: ssl_key

- name: Copy SSL certificate
copy:
content: "{{ metrics_exporter_server.prometheus_metrics.tls.certificate }}"
dest: "{{ metrics_exporter_certificate_path }}"
group: "{{ metrics_exporter_user }}"
owner: "{{ metrics_exporter_user }}"
mode: "600"
when: metrics_exporter_server.prometheus_metrics is mapping
register: ssl_cert

- name: Remove unexpected files in home
include_tasks: tasks/remove-unexpected-files.yml
vars:
directory: "/home/{{ metrics_exporter_user }}"
files:
- nginx.conf
- "{{ metrics_exporter_certificate_filename }}"
- "{{ metrics_exporter_key_filename }}"
- "{{ metrics_exporter_pid_filename }}"
- "{{ metrics_exporter_nginx_conf_filename }}"
- "{{ metrics_exporter_access_log_filename }}"
- "{{ metrics_exporter_error_log_filename }}"

- name: Render systemd service config
template:
src: metrics-exporter.service.j2
dest: /etc/systemd/system/metrics-exporter.service
register: systemd

- name: Reload daemon
systemd:
daemon_reload: yes
when: systemd.changed

- name: Restart systemd app service
systemd:
name: metrics-exporter.service
state: restarted
enabled: yes
when: systemd.changed or config.changed or ssl_key.changed or ssl_cert.changed
10 changes: 10 additions & 0 deletions roles/metrics-exporter/templates/metrics-exporter.service.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=metrics-exporter

[Service]
User={{ metrics_exporter_user }}
ExecStart=/usr/sbin/nginx -c {{ metrics_exporter_nginx_conf_path }}
Restart=always

[Install]
WantedBy=multi-user.target
49 changes: 49 additions & 0 deletions roles/metrics-exporter/templates/nginx.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
daemon off;
worker_processes auto;

pid {{ metrics_exporter_pid_path }};

events {
worker_connections 4096;
}

http {
access_log {{ metrics_exporter_access_log_path }};
error_log {{ metrics_exporter_error_log_path }};

server {
listen *:80;
listen [::]:80;
server_name _;
return 301 https://{{ metrics_exporter_server.fallback_proxy_target }};
}

{% if metrics_exporter_server.prometheus_metrics is mapping %}
server {
listen *:{{ metrics_exporter_server.prometheus_metrics.port }} ssl http2;
listen [::]:{{ metrics_exporter_server.prometheus_metrics.port }} ssl http2;

ssl_certificate {{ metrics_exporter_certificate_path }};
ssl_certificate_key {{ metrics_exporter_key_path }};
ssl_protocols TLSv1.2 TLSv1.3;

location {{ metrics_exporter_server.prometheus_metrics.xray.url_path }} {
proxy_pass http://127.0.0.1:{{ metrics_exporter_xray_metrics_port }}/metrics;
}

location {{ metrics_exporter_server.prometheus_metrics.node_exporter.url_path }} {
proxy_pass http://127.0.0.1:{{ metrics_exporter_node_exporter_metrics_port }}/metrics;
}

location / {
return 444;
}

error_page 404 = @redirect;

location @redirect {
return 444;
}
}
{% endif %}
}
16 changes: 16 additions & 0 deletions roles/metrics-exporter/vars/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# linux user to run metrics_exporter as
metrics_exporter_user: metrics-exporter

metrics_exporter_nginx_conf_filename: nginx.conf
metrics_exporter_certificate_filename: cert.pem
metrics_exporter_key_filename: key.pem
metrics_exporter_access_log_filename: access.log
metrics_exporter_error_log_filename: error.log
metrics_exporter_pid_filename: nginx.pid

metrics_exporter_nginx_conf_path: /home/{{ metrics_exporter_user }}/{{metrics_exporter_nginx_conf_filename }}
metrics_exporter_certificate_path: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_certificate_filename }}"
metrics_exporter_key_path: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_key_filename }}"
metrics_exporter_access_log_path: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_access_log_filename }}"
metrics_exporter_error_log_path: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_error_log_filename }}"
metrics_exporter_pid_path: "/home/{{ metrics_exporter_user }}/{{ metrics_exporter_pid_filename }}"
2 changes: 1 addition & 1 deletion roles/node-exporter/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# the port node_exporter should locally (localhost) export http metrics on
node_exporter_port: 9092
node_exporter_port:
2 changes: 1 addition & 1 deletion roles/node-exporter/vars/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# linus user to run node-exporter as
node_exporter_user: node_exporter

# URL to download outline from
# URL to download node-exporter from
node_exporter_downloads:
x86_64:
url: https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
Expand Down
Loading

0 comments on commit 6f0fe56

Please sign in to comment.