refactor: monorepo split into prowler-server/ and prowler-client/

Server infrastructure (Ansible, Docker, v1 docs) moves to prowler-server/.
Client application (PRD v2, SDD v2, design system) lives in prowler-client/.
Top-level README links both projects.

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
2026-04-21 20:04:11 +02:00
parent 376d7e72f9
commit dd792aa1c1
84 changed files with 116 additions and 147 deletions

164
README.md
View File

@@ -1,158 +1,30 @@
# Prowler
Anti-censorship proxy infrastructure. Two VPS nodes providing Layer 1 (direct proxy) and Layer 3 (domestic relay chain) connectivity for third-party clients (V2Box, sing-box).
Anti-censorship proxy infrastructure for private use. Multi-layer connectivity through EU exit nodes with a domestic relay chain surviving TSPU IP blocking.
See [AGENTS.md](AGENTS.md) for architecture details, conventions, and gotchas.
## Prerequisites
- Ansible >= 2.16 on your local machine
- Two VPS instances:
- **Exit**: Timeweb Cloud EU (Netherlands), Debian 12
- **Relay**: Yandex Cloud (Moscow), Debian 12
- Two domains (or one domain + one subdomain) with A records pointing to each VPS
- SSH key access to both VPS as root
## Setup
### 1. Configure host variables
Edit `ansible/host_vars/exit.yml`:
```yaml
exit_ip: "203.0.113.10" # Your Timeweb VPS IP
exit_domain: "yourdomain.com" # Domain pointing to exit VPS
```
Edit `ansible/host_vars/relay.yml`:
```yaml
relay_ip: "198.51.100.20" # Your Yandex Cloud VPS IP
relay_domain: "relay.yourdomain.com" # Domain pointing to relay VPS
```
### 2. Provision both VPS
This installs Docker, configures firewall, hardens SSH:
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/provision.yml
```
### 3. Obtain TLS certificates
The exit VPS needs a valid Let's Encrypt cert for the Reality self-steal domain.
**Before first deploy**, make sure port 80 is accessible and nothing else is listening on 443, then run on the exit VPS:
```bash
certbot certonly --standalone -d yourdomain.com --non-interactive --agree-tos -m admin@yourdomain.com
mkdir -p /opt/prowler/nginx/ssl
cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem /opt/prowler/nginx/ssl/cert.pem
cp /etc/letsencrypt/live/yourdomain.com/privkey.pem /opt/prowler/nginx/ssl/key.pem
```
For the relay VPS, obtain a cert for `relay.yourdomain.com` using the same method. Reality will forward unauthenticated traffic to this domain externally (no local Nginx on relay).
### 4. Deploy
```bash
ansible-playbook -i inventory.yml playbooks/deploy.yml
```
Or deploy individually:
```bash
ansible-playbook -i inventory.yml playbooks/deploy.yml --limit exit
ansible-playbook -i inventory.yml playbooks/deploy.yml --limit relay
```
### 5. Verify
See Acceptance Gates in AGENTS.md. Quick checks:
```bash
# From a Russian network:
curl -v https://yourdomain.com # Should show the static site
# Connect via V2Box/sing-box using Layer 1 config
# Connect via V2Box/sing-box using Layer 3 config (through relay)
```
## Client configuration
### Layer 1 (direct to exit)
## Monorepo Structure
```
Protocol: VLESS
Address: YOUR_EXIT_IP
Port: 443
UUID: ec7ded8f-a52e-4a8d-8c08-1ab86d0a86ee
Flow: xtls-rprx-vision
TLS: reality
SNI: YOUR_DOMAIN
Reality public key: mE05FJjaHpTcvcRvPRj+KZ7X1IpRkVWGU8HO5xUN0W8=
Reality short ID: fde5c620
Fingerprint: chrome
prowler/
├── prowler-server/ # v1 — Server infrastructure (shipped)
│ ├── ansible/ # Provisioning & deployment
│ ├── docs/ # Server PRD, SDD, brief
│ └── AGENTS.md # Server architecture & conventions
├── prowler-client/ # v2 — Client application (upcoming)
│ └── docs/ # Client PRD, SDD, design system
└── .planning/ # GSD project management
```
### Layer 3 (via relay)
## prowler-server
```
Protocol: VLESS
Address: YOUR_RELAY_IP
Port: 443
UUID: 7c3124a2-ad86-44bf-8920-445682ee3a1c
Flow: xtls-rprx-vision
TLS: reality
SNI: YOUR_RELAY_DOMAIN
Reality public key: OjtN/NrmHBHw2hVZxxDhh0A86EnH+bWM5ESPVZuqf0w=
Reality short ID: d026c6ba
Fingerprint: chrome
```
Two VPS nodes (EU exit + Russian relay) providing Layer 1 (direct proxy) and Layer 3 (domestic relay chain) connectivity. Serves third-party clients (V2Box, sing-box) via manually distributed configs.
## Certificate renewal
See [prowler-server/AGENTS.md](prowler-server/AGENTS.md) for full architecture, conventions, and gotchas.
Add a cron job on the exit VPS:
## prowler-client
```bash
0 3 * * * certbot renew --quiet --deploy-hook "cp /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem /opt/prowler/nginx/ssl/cert.pem && cp /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem /opt/prowler/nginx/ssl/key.pem && docker restart nginx"
```
Cross-platform client (Android + Windows) wrapping three escalation layers in a single app. Flutter UI + Go proxy core (libXray) + ByeDPI for client-side DPI bypass.
## Key files
```
ansible/
├── group_vars/all.yml # Shared secrets (UUIDs, keys)
├── host_vars/
│ ├── exit.yml # Exit VPS IP, domain, ports
│ └── relay.yml # Relay VPS IP, domain, ports
├── inventory.yml
├── playbooks/
│ ├── provision.yml # Base OS setup
│ └── deploy.yml # Deploy compose stacks
├── roles/
│ ├── base/ # Docker, firewall, SSH hardening
│ ├── exit/ # Xray + Nginx deployment
│ └── relay/ # Xray deployment
└── templates/ # Jinja2 configs for all services
```
## Troubleshooting
```bash
# Check container status
docker compose -f /opt/prowler/docker-compose.yml ps
# Xray logs
docker compose -f /opt/prowler/docker-compose.yml logs xray --tail 50
# Restart a service
docker compose -f /opt/prowler/docker-compose.yml restart xray
# Verify Xray is listening on 443
ss -tlnp | grep 443
# Check UFW status
ufw status verbose
```
See [prowler-client/docs/](prowler-client/docs/) for PRD, SDD, and design system.

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 867 B

After

Width:  |  Height:  |  Size: 867 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 665 B

After

Width:  |  Height:  |  Size: 665 B

View File

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 704 B

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -38,7 +38,7 @@ Client (Russia)
## Directory Structure
```
prowler/
prowler-server/
├── ansible/
│ ├── inventory.yml # Host groups: exit, relay
│ ├── group_vars/

View File

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDlDCCAxmgAwIBAgISBlq0sy/vQP6YoizaygAGJQOfMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
NzAeFw0yNjA0MjAxMTAyMTZaFw0yNjA3MTkxMTAyMTVaMB8xHTAbBgNVBAMTFG5k
dnRlY2huaXNjaGUub25saW5lMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwGRW
kmdjYisqJOH7aS8uddM/6DrPYgGOUPr00BDBaEqYfwRQKe3xq5ARQ1OFWxbfmOM4
oDSvUFY84wP57Bs3k6OCAiAwggIcMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
BggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT0DNvbeFJNFL9bWKgz
LWN5vBLBpTAfBgNVHSMEGDAWgBSuSJ7chx1EoG/aouVgdAR4wpwAgDAyBggrBgEF
BQcBAQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly9lNy5pLmxlbmNyLm9yZy8wHwYD
VR0RBBgwFoIUbmR2dGVjaG5pc2NoZS5vbmxpbmUwEwYDVR0gBAwwCjAIBgZngQwB
AgEwLQYDVR0fBCYwJDAioCCgHoYcaHR0cDovL2U3LmMubGVuY3Iub3JnLzMyLmNy
bDCCAQwGCisGAQQB1nkCBAIEgf0EgfoA+AB2ANdtfRDRp/V3wsfpX9cAv/mCyTNa
ZeHQswFzF8DIxWl3AAABnarDuT4AAAQDAEcwRQIgSxAcbq5boO0E0wTAlQQX23QL
MFuHH5G4TOTbRA8hH0gCIQDVGqukrMtIQYrmyu4mIVLYnpXQwKZn2LO22xZsx78l
sgB+AKgmy+MKxjUSRlM/4GXxTxnZbhkIE8Qd2W15ALMSPFUnAAABnarDu4kACAAA
BQAHmmwmBAMARzBFAiEA9hE5O11Y3kU2qU1ityP2ClGr3IdUvLQjxPJnBdBAvMQC
IB2w6ykkcVma+iFMXe01srTOrzik/meiaX0EeM+pJWJMMAoGCCqGSM49BAMDA2kA
MGYCMQD2ZSvdcTWWgqwgt0JMPWc5oLfA/WOILpE3Wa33SSZhv0o7M0zIF+HTA+u6
GpoDYb4CMQD2i0Q4OYfol+sIbeYCjqoKspQl1m49DMsxndmGrxotWWZKKY5Ck/z2
d/pGAqgAscc=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBCzCBswIBADAfMR0wGwYDVQQDDBRuZHZ0ZWNobmlzY2hlLm9ubGluZTBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABMBkVpJnY2IrKiTh+2kvLnXTP+g6z2IBjlD6
9NAQwWhKmH8EUCnt8auQEUNThVsW35jjOKA0r1BWPOMD+ewbN5OgMjAwBgkqhkiG
9w0BCQ4xIzAhMB8GA1UdEQQYMBaCFG5kdnRlY2huaXNjaGUub25saW5lMAoGCCqG
SM49BAMCA0cAMEQCIGqJNxTCEPbW+4VX4LXuXlyC4tJnOwCkHy3ixFCkiJm4AiAM
oLxRXyo4Vhr3NL498BcYTOBTwSsdEUPWD5I/iWVc5w==
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,48 @@
-----BEGIN CERTIFICATE-----
MIIDlDCCAxmgAwIBAgISBlq0sy/vQP6YoizaygAGJQOfMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
NzAeFw0yNjA0MjAxMTAyMTZaFw0yNjA3MTkxMTAyMTVaMB8xHTAbBgNVBAMTFG5k
dnRlY2huaXNjaGUub25saW5lMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwGRW
kmdjYisqJOH7aS8uddM/6DrPYgGOUPr00BDBaEqYfwRQKe3xq5ARQ1OFWxbfmOM4
oDSvUFY84wP57Bs3k6OCAiAwggIcMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
BggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT0DNvbeFJNFL9bWKgz
LWN5vBLBpTAfBgNVHSMEGDAWgBSuSJ7chx1EoG/aouVgdAR4wpwAgDAyBggrBgEF
BQcBAQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly9lNy5pLmxlbmNyLm9yZy8wHwYD
VR0RBBgwFoIUbmR2dGVjaG5pc2NoZS5vbmxpbmUwEwYDVR0gBAwwCjAIBgZngQwB
AgEwLQYDVR0fBCYwJDAioCCgHoYcaHR0cDovL2U3LmMubGVuY3Iub3JnLzMyLmNy
bDCCAQwGCisGAQQB1nkCBAIEgf0EgfoA+AB2ANdtfRDRp/V3wsfpX9cAv/mCyTNa
ZeHQswFzF8DIxWl3AAABnarDuT4AAAQDAEcwRQIgSxAcbq5boO0E0wTAlQQX23QL
MFuHH5G4TOTbRA8hH0gCIQDVGqukrMtIQYrmyu4mIVLYnpXQwKZn2LO22xZsx78l
sgB+AKgmy+MKxjUSRlM/4GXxTxnZbhkIE8Qd2W15ALMSPFUnAAABnarDu4kACAAA
BQAHmmwmBAMARzBFAiEA9hE5O11Y3kU2qU1ityP2ClGr3IdUvLQjxPJnBdBAvMQC
IB2w6ykkcVma+iFMXe01srTOrzik/meiaX0EeM+pJWJMMAoGCCqGSM49BAMDA2kA
MGYCMQD2ZSvdcTWWgqwgt0JMPWc5oLfA/WOILpE3Wa33SSZhv0o7M0zIF+HTA+u6
GpoDYb4CMQD2i0Q4OYfol+sIbeYCjqoKspQl1m49DMsxndmGrxotWWZKKY5Ck/z2
d/pGAqgAscc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEVzCCAj+gAwIBAgIRAKp18eYrjwoiCWbTi7/UuqEwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCRTcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARB6AST
CFh/vjcwDMCgQer+VtqEkz7JANurZxLP+U9TCeioL6sp5Z8VRvRbYk4P1INBmbef
QHJFHCxcSjKmwtvGBWpl/9ra8HW0QDsUaJW2qOJqceJ0ZVFT3hbUHifBM/2jgfgw
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSuSJ7chx1EoG/aouVgdAR4
wpwAgDAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAjx66fDdLk5ywFn3CzA1w1qfylHUD
aEf0QZpXcJseddJGSfbUUOvbNR9N/QQ16K1lXl4VFyhmGXDT5Kdfcr0RvIIVrNxF
h4lqHtRRCP6RBRstqbZ2zURgqakn/Xip0iaQL0IdfHBZr396FgknniRYFckKORPG
yM3QKnd66gtMst8I5nkRQlAg/Jb+Gc3egIvuGKWboE1G89NTsN9LTDD3PLj0dUMr
OIuqVjLB8pEC6yk9enrlrqjXQgkLEYhXzq7dLafv5Vkig6Gl0nuuqjqfp0Q1bi1o
yVNAlXe6aUXw92CcghC9bNsKEO1+M52YY5+ofIXlS/SEQbvVYYBLZ5yeiglV6t3S
M6H+vTG0aP9YHzLn/KVOHzGQfXDP7qM5tkf+7diZe7o2fw6O7IvN6fsQXEQQj8TJ
UXJxv2/uJhcuy/tSDgXwHM8Uk34WNbRT7zGTGkQRX0gsbjAea/jYAoWv0ZvQRwpq
Pe79D/i7Cep8qWnA+7AE/3B3S/3dEEYmc0lpe1366A/6GEgk3ktr9PEoQrLChs6I
tu3wnNLB2euC8IKGLQFpGtOO/2/hiAKjyajaBP25w1jF0Wl8Bbqne3uZ2q1GyPFJ
YRmT7/OXpmOH/FVLtwS+8ng1cAmpCujPwteJZNcDG0sF2n/sc0+SQf49fdyUK0ty
+VUwFj9tmWxyR/M=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgIUIn24EacSBu/Q25SXrgKc3A+NvQswDQYJKoZIhvcNAQEL
BQAwGjEYMBYGA1UEAwwPYWxleGV5dmFuZWVyLnJ1MB4XDTI2MDQyMDExNTM0OFoX
DTI3MDQyMDExNTM0OFowGjEYMBYGA1UEAwwPYWxleGV5dmFuZWVyLnJ1MIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm67SpIg2O/5Zo3M5DH88YSYfzrhF
PTlGV6xvsetmh9+3TJiSLAfvBdcTwrct3UQhSliaYWw+0fjHIpc8k/yedigN6Ij3
STQlqk3MxBT1zEvohqLG1binPmOISO6KKseFN8Ol1GfOo2V5cmaV3tMmGRkOAsGM
rH47jXhSqzqtKz6ewyqv8VnZMZ2n2tKohBaUMWcG0S3lSWVN4Vd9yT9rQlNHv2Zu
ByrtLVv1MaOHJZxnx7QEYBLWmnARVUqFIjyG7h5iqJPTjdUNxfRm5Zf+fywLK/ez
We46TZ2p1O4P0WxmZbDz0cUE6wK6vqelleyj50x8h6zQLoqxdDosxWrpWQIDAQAB
o1MwUTAdBgNVHQ4EFgQUt2k6qPpNhYrEOWK/H+8c6eyLYhwwHwYDVR0jBBgwFoAU
t2k6qPpNhYrEOWK/H+8c6eyLYhwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOCAQEAEYA3Bc9D+zy/qwoW8IDrc8GhxKjnsWUu+FHX1yMhZdt1SGaDMLF5
YUYdm8TpBGf0x2nnnkAncysp6EZNs4sNGIwhb80ZW4+QpXve8zSfAmGG1oSK9Eix
iOAcgCVfftZZ8im0+QmIBmLrUHFDPlnrtK1QWHn9FfF4ghjvGYsgpyiSbKS5kGtn
3Q5df6MqPkL+v3t31ysCwcMI+XFl/Qga9G2CfTFxb561eCdpEhWapX87BHFCsFzA
/DrEtKKYe4wzk8WKbulewKi1C9EPUJswS+Z2C7u1ooMkp30wNVjjVhKJGyS8tZBv
U/0O75JDo5HoGdZZq2ySbi8hogK5Ei9YqQ==
-----END CERTIFICATE-----