|
1 | 1 | # MegaProxyServer |
2 | 2 |
|
3 | | -Ansible roles and an interactive Python launcher for hardened MegaProxy HTTPS and SSH servers. |
| 3 | +Provision and operate hardened HTTPS and SSH proxy servers with Ansible. |
4 | 4 |
|
5 | | -The project supports multiple hosts, multiple users per service, HTTPS and SSH on the same host, |
6 | | -ACME certificates for domains or public IP addresses, a probe-resistant HTTPS decoy, and arbitrary |
7 | | -SSH jump chains. Jump pairs are not stored: any SSH-enabled host can be selected as the jump for |
8 | | -any other SSH-enabled host when profiles are exported. |
| 5 | +MegaProxyServer manages multiple Debian/Ubuntu hosts from one inventory, keeps proxy users global, |
| 6 | +issues and renews TLS certificates, supports SNI-routed HTTPS chains and exports ready-to-import |
| 7 | +client configurations for MegaProxy, FoxyProxy and SuperProxy. |
9 | 8 |
|
10 | | -Proxy users are global: the top-level `users.https` and `users.ssh` lists are applied to every host |
11 | | -where the corresponding service is enabled. Credentials therefore cannot silently diverge between |
12 | | -hosts. Inventories using the older per-host lists are migrated in memory; conflicting credentials |
13 | | -for the same login are rejected instead of being chosen implicitly. |
| 9 | +Documentation: **[English](docs/en/README.md)** · **[Русский](docs/ru/README.md)** |
14 | 10 |
|
15 | | -## Requirements |
| 11 | +## Quick start |
16 | 12 |
|
17 | | -- macOS or Linux control machine with `uv`, OpenSSH and Python available; |
18 | | -- a current Debian or Ubuntu server reachable by a sudo-capable SSH account; |
19 | | -- TCP 80 reachable for ACME issuance and TCP 443 for HTTPS; |
20 | | -- Certbot 5.4 or newer on servers using public-IP certificates. |
21 | | - |
22 | | -All Python and Ansible dependencies are declared in `pyproject.toml`, locked in `uv.lock`, and |
23 | | -installed by `uv`. Do not install them manually with pip. |
24 | | - |
25 | | -## Start |
| 13 | +Requirements: macOS or Linux, `uv`, OpenSSH, and a Debian or Ubuntu server reachable through a |
| 14 | +sudo-capable SSH account. |
26 | 15 |
|
27 | 16 | ```shell |
28 | | -./mega-proxy |
| 17 | +./mega-proxy inventory |
| 18 | +./mega-proxy plan |
| 19 | +./mega-proxy apply |
| 20 | +./mega-proxy verify |
29 | 21 | ``` |
30 | 22 |
|
31 | | -When no inventory exists, the launcher offers to create `inventory.yml` in the current directory |
32 | | -or use another path. An external path is remembered in `inventory-path`. Both files, generated |
33 | | -profiles and generated keys are excluded by `.gitignore`. |
34 | | - |
35 | | -`vault-secrets` encrypts password fields with tagged inline Ansible Vault values while keeping |
36 | | -hosts, ports, domains and flags editable as ordinary YAML. `mega-proxy` prompts for the Vault |
37 | | -password when it encounters the first encrypted value. For unattended runs, set |
38 | | -`ANSIBLE_VAULT_PASSWORD_FILE` to a protected password file. Subsequent inventory updates preserve |
39 | | -field-level encryption. Whole-file Ansible Vault inventories remain readable and are converted to |
40 | | -field-level encryption by `vault-secrets`. |
41 | | - |
42 | | -Useful commands: |
| 23 | +For an existing inventory, pass `--inventory PATH`. Generate client files and display credentials: |
43 | 24 |
|
44 | 25 | ```shell |
45 | | -./mega-proxy inventory |
46 | | -./mega-proxy check |
47 | | -./mega-proxy --inventory ./inventory.yml validate |
48 | | -./mega-proxy --inventory ./inventory.yml plan |
49 | | -./mega-proxy --inventory ./inventory.yml apply |
50 | | -./mega-proxy --inventory ./inventory.yml verify |
51 | | -./mega-proxy --inventory ./inventory.yml jumps |
52 | | -./mega-proxy --inventory ./inventory.yml summary |
53 | | -./mega-proxy --inventory ./inventory.yml summary alice |
54 | | -./mega-proxy --inventory ./inventory.yml remove-users |
55 | | -./mega-proxy --inventory ./inventory.yml configs |
56 | | -./mega-proxy --inventory ./inventory.yml export --all-jumps |
| 26 | +./mega-proxy configs |
| 27 | +./mega-proxy summary |
57 | 28 | ``` |
58 | 29 |
|
59 | | -`configs` writes four sensitive import files to `.generated/configs` by default: |
60 | | - |
61 | | -- `MegaProxy.json` — HTTPS, direct SSH, and every dynamic SSH Jump combination; |
62 | | -- `FoxyProxy.json` — HTTPS entries only; |
63 | | -- `SuperProxy.txt` — HTTPS entries only, with the Super Proxy v1 header; |
64 | | -- `ProxyList.txt` — URL-encoded HTTPS proxy URLs. |
65 | | - |
66 | | -Choose another directory with `configs --output-dir PATH`. Directories use mode `0700` and files |
67 | | -use mode `0600`. Generation is idempotent and never contacts configured servers. |
68 | | - |
69 | | -`summary` prints endpoints once, followed by global HTTPS and SSH credential lists. With a login |
70 | | -as its first positional argument, only exact matches are shown. Key-only SSH accounts show the |
71 | | -private-key path instead of a password; administrative accounts are included too. This command deliberately writes plaintext secrets to |
72 | | -stdout; do not run it in CI or redirect it to an unprotected file. |
73 | | - |
74 | | -`remove-users` selects one or more global proxy accounts. HTTPS accounts are removed from every |
75 | | -generated GOST configuration; SSH accounts are additionally retained in a global inventory |
76 | | -tombstone list so the next `apply` deletes the corresponding system accounts and root-owned |
77 | | -authorized-key files from every SSH-enabled host. |
78 | | - |
79 | | -Use `--limit HOST` and `--tags common,admin,firewall,ssh,https` with plan, apply, or verify. Always run |
80 | | -`plan` before applying to an existing server and keep the current administrative SSH session open. |
81 | | - |
82 | | -After a successful `apply`, executable `.hooks/post-config-change` and files in |
83 | | -`.hooks/post-config-change.d/` are run in name order. The ignored `.hooks` directory is intended for |
84 | | -machine-local integrations and secrets. Hooks receive `MEGAPROXY_INVENTORY`, |
85 | | -`MEGAPROXY_ANSIBLE_INVENTORY`, `MEGAPROXY_ROOT`, and `MEGAPROXY_EVENT`. Use `--no-hooks` before or |
86 | | -after the command to skip them, for example `./mega-proxy apply --no-hooks`. |
87 | | - |
88 | | -## HTTPS |
| 30 | +Inventory and generated exports contain secrets. Keep them private and do not commit them. |
89 | 31 |
|
90 | | -HTTPS uses a pinned GOST v3 container, TLS 1.2/1.3, Basic authentication and HTTP/2 CONNECT. Invalid |
91 | | -credentials receive a decoy page instead of the identifying `407 Proxy Authentication Required` |
92 | | -response. Domain deployments also reject missing or unrelated SNI before exposing a certificate. |
93 | | -GOST's API, metrics, profiling and destination access logs are not exposed. |
| 32 | +## Highlights |
94 | 33 |
|
95 | | -Domain certificates use Certbot standalone ACME. Public-IP certificates use Let's Encrypt's |
96 | | -short-lived profile and therefore require reliable automatic renewal. Self-signed certificates are |
97 | | -an explicit fallback and require disabling certificate validation in MegaProxy. |
| 34 | +- HTTPS CONNECT proxy with TLS 1.2/1.3 and probe-resistant decoy responses |
| 35 | +- ACME certificates for DNS names and public IP addresses, plus a self-signed fallback |
| 36 | +- SNI-based HTTPS chains through independently selected entry and exit servers |
| 37 | +- Restricted SSH forwarding accounts and dynamic SSH jump profiles |
| 38 | +- Global HTTPS and SSH users, with safe removal across every managed host |
| 39 | +- Inline Ansible Vault encryption that leaves non-secret inventory settings readable |
| 40 | +- Idempotent provisioning and integration tests on Ubuntu and Debian |
98 | 41 |
|
99 | | -Use a neutral hostname rather than one containing `proxy`, `vpn`, or `gost`. Probe resistance hides |
100 | | -the proxy role from unauthenticated scans; it cannot hide the IP or prevent IP/SNI-based blocking. |
| 42 | +See [`inventory.example.yml`](inventory.example.yml) and the |
| 43 | +[English](docs/en/README.md) or [Russian](docs/ru/README.md) guide for all options. |
101 | 44 |
|
102 | | -### HTTPS chains and SNI routing |
| 45 | +## Development |
103 | 46 |
|
104 | | -When `settings.https_chains_enabled` is enabled, HTTPS hosts may opt into `chain_entry` and |
105 | | -`chain_exit`. Every valid directed entry-to-exit pair is generated automatically. HAProxy listens |
106 | | -on the single public HTTPS port, inspects TLS SNI without terminating TLS, and forwards each name to |
107 | | -a dedicated loopback GOST listener. For example, `proxy_ru -> proxy_nl` becomes |
108 | | -`proxy-ru-via-proxy-nl.<https_chain_domain>`; underscores are converted to DNS-safe hyphens. |
109 | | - |
110 | | -All generated names must resolve to their entry host before `apply`. Chain hosts require domain |
111 | | -ACME certificates; Certbot expands the entry certificate to include every generated SNI hostname. |
112 | | -The exit authenticates entry nodes with a generated machine password that is never included in |
113 | | -summary or client exports. Client exports expose chain routes as ordinary HTTPS proxies on port 443. |
114 | | -An explicit `title` on an `https_chain_pairs` item names that route in client exports and px-manager; |
115 | | -without it, the entry HTTPS service `title` is used. When the service title is also absent, it is |
116 | | -derived from the inventory host name. |
117 | | - |
118 | | -## SSH |
119 | | - |
120 | | -The inventory distinguishes the provider's initial `bootstrap_user` from the permanent administrator. |
121 | | -The wizard defaults the administrator name to the local OS user and installs the selected public key |
122 | | -whether that account is new or already exists. After a successful full apply, `bootstrap_user` is |
123 | | -removed from inventory automatically and subsequent runs connect as the permanent administrator. |
124 | | -Keep the initial SSH session open until a new administrative login has been tested. |
125 | | - |
126 | | -SSH proxy accounts are separate from the administrative account. They cannot open a shell, TTY, |
127 | | -subsystem, agent forwarding, X11, remote forwarding, or a tunnel device. They can only create local |
128 | | -`direct-tcpip` channels. Key authentication is preferred; generated keys are dedicated Ed25519 keys |
129 | | -without a passphrase because MegaProxy currently accepts only unencrypted private keys. |
130 | | - |
131 | | -SSH remains recognizable as SSH. Passwords and private keys are included in exported client |
132 | | -profiles, so inventory, `.secrets`, and `.generated` must be treated as sensitive data. |
133 | | - |
134 | | -Root SSH login is disabled completely. Password and keyboard-interactive login are disabled globally; |
135 | | -password authentication is enabled only inside the restricted `megaproxy` group. Key-only proxy |
136 | | -accounts have a locked password, so that exception applies effectively only to proxy accounts whose |
137 | | -inventory authentication type is `password`. The administrator is key-only and receives sudo access. |
138 | | - |
139 | | -## Jump chains |
140 | | - |
141 | | -There is intentionally no `jump_pairs` section. Given SSH hosts A, B, and C, the CLI can produce all |
142 | | -directed combinations `A -> B`, `A -> C`, `B -> A`, and so on. A host is never its own jump. Each |
143 | | -side may use a different user and authentication method. |
144 | | - |
145 | | -This flexible model cannot apply pair-specific `PermitOpen` or source-IP firewall rules. Those |
146 | | -restrictions require declaring exact pairs and contradict dynamic chains. Every SSH account remains |
147 | | -restricted to local TCP forwarding and no interactive session. |
148 | | - |
149 | | -## Security notes |
| 47 | +```shell |
| 48 | +./mega-proxy check |
| 49 | +``` |
150 | 50 |
|
151 | | -- Inventory and exports have mode `0600`, but are plaintext local secrets, not a secret manager. |
152 | | -- Use one account/key per person or device so credentials can be revoked independently. |
153 | | -- Verify SSH host fingerprints in MegaProxy through a trusted channel on first connection. |
154 | | -- Review `.generated/megaproxy-profiles.json` before transferring it and delete it after import. |
155 | | -- Provider firewalls must match the host firewall; the project only manages UFW inside the VM. |
156 | | -- Administrative SSH ports are allowed before UFW is enabled to reduce lockout risk. |
| 51 | +This runs Ruff, pytest, Python byte-compilation and Ansible syntax checks with dependencies locked |
| 52 | +in `uv.lock`. |
157 | 53 |
|
158 | | -See `inventory.example.yml` for the complete data shape. |
159 | | - |
160 | | -## Continuous integration |
161 | | - |
162 | | -The GitHub Actions workflow runs the same `./mega-proxy check` command available locally. It verifies |
163 | | -Ruff, pytest, Python byte-compilation, and Ansible syntax on every push and pull request using the |
164 | | -locked dependency set. It needs no inventory, secrets, network hosts, or privileged containers. |
| 54 | +## License |
165 | 55 |
|
166 | | -`Host provisioning` additionally creates an isolated privileged LXD system and applies the real |
167 | | -playbook. It checks systemd, Docker, UFW, SSH forwarding, GOST, the HTTPS decoy, authenticated |
168 | | -CONNECT, and a second idempotent run. Ubuntu 24.04 runs on pushes and pull requests. A scheduled or |
169 | | -manually dispatched Debian 12 job provisions two hosts and verifies an SSH Jump tunnel between |
170 | | -them. CI uses self-signed TLS because hosted runners do not have a stable public address for ACME. |
| 56 | +See [LICENSE](LICENSE). |
0 commit comments