mirror of
https://github.com/r3bo0tbx1/tor-guard-relay.git
synced 2026-04-06 00:32:04 +02:00
📝 docs(v1.1.1): Refresh diagrams and update image size
- 🎨 Enhanced Mermaid diagrams with emoji and improved formatting - 📦 Updated SECURITY.md and ARCHITECTURE.md for ~17.1 MB image size and bumped docs to v1.0.1
This commit is contained in:
@@ -30,7 +30,7 @@ We actively support the following versions with security updates:
|
||||
- ✅ **NO monitoring HTTP endpoints** - Removed for maximum security
|
||||
- ✅ **NO exposed metrics ports** - All monitoring via `docker exec` only
|
||||
- ✅ **Only Tor protocol ports exposed** - ORPort, DirPort (configurable), obfs4 (bridge mode)
|
||||
- ✅ **~20 MB image** - Minimal attack surface
|
||||
- ✅ **~17.1 MB image** - Minimal attack surface
|
||||
|
||||
### Public Port Exposure (Configurable)
|
||||
|
||||
@@ -90,7 +90,7 @@ This project uses **host networking mode** (`--network host`) for best Tor perfo
|
||||
- ✅ Runs as non-root user (`tor` UID 100)
|
||||
- ✅ Drops all capabilities, adds only required ones
|
||||
- ✅ Uses `no-new-privileges:true`
|
||||
- ✅ Minimal Alpine Linux base (~20 MB)
|
||||
- ✅ Minimal Alpine Linux base (~17.1 MB)
|
||||
- ✅ No exposed monitoring ports
|
||||
- ✅ Automatic permission healing
|
||||
|
||||
@@ -428,7 +428,7 @@ echo "relay.conf" >> .gitignore
|
||||
* Drops all capabilities by default
|
||||
* Adds only NET_BIND_SERVICE, CHOWN, SETUID, SETGID, DAC_OVERRIDE
|
||||
* Uses `no-new-privileges:true`
|
||||
* Ultra-minimal Alpine base (~20 MB)
|
||||
* Ultra-minimal Alpine base (~17.1 MB)
|
||||
* NO monitoring HTTP endpoints to attack
|
||||
* Automatic permission healing
|
||||
* Configuration validation before start
|
||||
@@ -472,7 +472,7 @@ chown tor:tor /var/lib/tor
|
||||
### Built-in Protections
|
||||
|
||||
* ✅ Non-root operation (user `tor` UID 100)
|
||||
* ✅ Minimal base image (Alpine Linux ~20 MB)
|
||||
* ✅ Minimal base image (Alpine Linux ~17.1 MB)
|
||||
* ✅ Drops all capabilities, adds only required ones
|
||||
* ✅ Read-only configuration mount
|
||||
* ✅ Automatic permission healing
|
||||
|
||||
@@ -36,43 +36,44 @@ This container implements a production-ready Tor relay with three operational mo
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([Container Start]) --> Tini[/Tini Init PID 1/]
|
||||
Tini --> Entrypoint[docker-entrypoint.sh]
|
||||
Start([🟢 Container Start]) --> Tini[/🔧 Tini Init PID 1/]
|
||||
Tini --> Entrypoint[🚀 docker-entrypoint.sh]
|
||||
|
||||
Entrypoint --> Phase1[Phase 1: Directories]
|
||||
Phase1 --> Phase2[Phase 2: Permissions]
|
||||
Phase2 --> Phase3[Phase 3: Configuration]
|
||||
Phase3 --> Phase4[Phase 4: Validation]
|
||||
Phase4 --> Phase5[Phase 5: Build Info]
|
||||
Phase5 --> Phase6[Phase 6: Diagnostics Info]
|
||||
Phase6 --> TorStart[Launch Tor Process]
|
||||
Entrypoint --> Phase1[📁 Phase 1: Directories]
|
||||
Phase1 --> Phase2[🔐 Phase 2: Permissions]
|
||||
Phase2 --> Phase3[⚙️ Phase 3: Configuration]
|
||||
Phase3 --> Phase4[🧪 Phase 4: Validation]
|
||||
Phase4 --> Phase5[📄 Phase 5: Build Info]
|
||||
Phase5 --> Phase6[🩺 Phase 6: Diagnostics Info]
|
||||
Phase6 --> TorStart[🚀 Launch Tor Process]
|
||||
|
||||
TorStart --> Running{Container Running}
|
||||
Running -->|Signal: SIGTERM/SIGINT| Trap[Signal Handler]
|
||||
TorStart --> Running{🟦 Container Running}
|
||||
|
||||
Running -->|Signal: SIGTERM or SIGINT| Trap[🧹 Signal Handler]
|
||||
Running -->|Tor Exits| Cleanup
|
||||
Running -->|User Exec| DiagTools[Diagnostic Tools]
|
||||
Running -->|User Exec| DiagTools[🛠️ Diagnostic Tools]
|
||||
|
||||
DiagTools -->|status| StatusTool[tools/status]
|
||||
DiagTools -->|health| HealthTool[tools/health]
|
||||
DiagTools -->|fingerprint| FingerprintTool[tools/fingerprint]
|
||||
DiagTools -->|bridge-line| BridgeTool[tools/bridge-line]
|
||||
DiagTools -->|status| StatusTool[📝 tools/status]
|
||||
DiagTools -->|health| HealthTool[📊 tools/health]
|
||||
DiagTools -->|fingerprint| FingerprintTool[🆔 tools/fingerprint]
|
||||
DiagTools -->|bridge-line| BridgeTool[🌉 tools/bridge-line]
|
||||
|
||||
StatusTool --> Running
|
||||
HealthTool --> Running
|
||||
FingerprintTool --> Running
|
||||
BridgeTool --> Running
|
||||
|
||||
Trap --> StopTail[Kill tail -F PID]
|
||||
StopTail --> StopTor[Send SIGTERM to Tor]
|
||||
StopTor --> Wait[Wait for Tor Exit]
|
||||
Wait --> Cleanup[Cleanup & Exit]
|
||||
Cleanup --> End([Container Stop])
|
||||
Trap --> StopTail[🧽 Kill tail -F PID]
|
||||
StopTail --> StopTor[📨 Send SIGTERM to Tor]
|
||||
StopTor --> Wait[⏳ Wait for Tor Exit]
|
||||
Wait --> Cleanup[🧹 Cleanup and Exit]
|
||||
Cleanup --> End([🔴 Container Stop])
|
||||
|
||||
style Start fill:#90EE90
|
||||
style End fill:#FFB6C1
|
||||
style Running fill:#87CEEB
|
||||
style TorStart fill:#FFD700
|
||||
style Trap fill:#FFA500
|
||||
style Start fill:#b2fab4
|
||||
style End fill:#ffb3c6
|
||||
style Running fill:#90caf9
|
||||
style TorStart fill:#fff59d
|
||||
style Trap fill:#ffcc80
|
||||
```
|
||||
|
||||
---
|
||||
@@ -83,37 +84,37 @@ The entrypoint script (`docker-entrypoint.sh`) executes **6 distinct phases** in
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Banner[Startup Banner] --> P1
|
||||
Banner[🎉 Startup Banner] --> P1
|
||||
|
||||
subgraph P1[Phase 1: Directory Structure]
|
||||
P1_1[mkdir -p data/log/run/tmp] --> P1_2[Show disk space]
|
||||
subgraph P1["📁 Phase 1: Directory Structure"]
|
||||
P1_1[📂 mkdir -p data/log/run/tmp] --> P1_2[💽 Show disk space]
|
||||
end
|
||||
|
||||
subgraph P2[Phase 2: Permission Hardening]
|
||||
P2_1[chmod 700 data dir] --> P2_2[chmod 755 log dir]
|
||||
subgraph P2["🔐 Phase 2: Permission Hardening"]
|
||||
P2_1[🔒 chmod 700 data dir] --> P2_2[📁 chmod 755 log dir]
|
||||
end
|
||||
|
||||
subgraph P3[Phase 3: Configuration Setup]
|
||||
P3_1{Mounted config exists?} -->|Yes| P3_2[Use mounted file]
|
||||
P3_1 -->|No| P3_3{ENV vars set?}
|
||||
P3_3 -->|Yes| P3_4[Validate ENV] --> P3_5[Generate config]
|
||||
P3_3 -->|No| P3_6[ERROR: No config]
|
||||
subgraph P3["⚙️ Phase 3: Configuration Setup"]
|
||||
P3_1{🧩 Mounted config exists?} -->|Yes| P3_2[📄 Use mounted file]
|
||||
P3_1 -->|No| P3_3{🌐 ENV vars set?}
|
||||
P3_3 -->|Yes| P3_4[🧪 Validate ENV] --> P3_5[📝 Generate config]
|
||||
P3_3 -->|No| P3_6[❌ ERROR: No config]
|
||||
end
|
||||
|
||||
subgraph P4[Phase 4: Configuration Validation]
|
||||
P4_1[Check Tor binary] --> P4_2[Get Tor version]
|
||||
P4_2 --> P4_3[tor --verify-config]
|
||||
P4_3 -->|Invalid| P4_4[ERROR: Bad config]
|
||||
P4_3 -->|Valid| P4_5[Success]
|
||||
subgraph P4["🧪 Phase 4: Configuration Validation"]
|
||||
P4_1[🔍 Check Tor binary] --> P4_2[ℹ️ Get Tor version]
|
||||
P4_2 --> P4_3[🧯 tor --verify-config]
|
||||
P4_3 -->|Invalid| P4_4[❌ ERROR: Bad config]
|
||||
P4_3 -->|Valid| P4_5[✅ Success]
|
||||
end
|
||||
|
||||
subgraph P5[Phase 5: Build Information]
|
||||
P5_1[Read /build-info.txt] --> P5_2[Show version/arch]
|
||||
P5_2 --> P5_3[Show relay mode & config source]
|
||||
subgraph P5["📄 Phase 5: Build Information"]
|
||||
P5_1[📘 Read /build-info.txt] --> P5_2[🖥️ Show version and arch]
|
||||
P5_2 --> P5_3[📡 Show relay mode and config source]
|
||||
end
|
||||
|
||||
subgraph P6[Phase 6: Diagnostic Tools Info]
|
||||
P6_1[List available tools] --> P6_2[Show usage examples]
|
||||
subgraph P6["🛠️ Phase 6: Diagnostic Tools Info"]
|
||||
P6_1[🔧 List available tools] --> P6_2[📚 Show usage examples]
|
||||
end
|
||||
|
||||
P1 --> P2
|
||||
@@ -121,11 +122,11 @@ flowchart TD
|
||||
P3 --> P4
|
||||
P4 --> P5
|
||||
P5 --> P6
|
||||
P6 --> Launch[Launch Tor]
|
||||
P6 --> Launch[🚀 Launch Tor]
|
||||
|
||||
style P3_6 fill:#FFB6C1
|
||||
style P4_4 fill:#FFB6C1
|
||||
style Launch fill:#FFD700
|
||||
style P3_6 fill:#ffcdd2
|
||||
style P4_4 fill:#ffcdd2
|
||||
style Launch fill:#fff59d
|
||||
```
|
||||
|
||||
### Phase Details
|
||||
@@ -147,44 +148,53 @@ flowchart TD
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([Configuration Needed]) --> Check1{File exists at /etc/tor/torrc?}
|
||||
Start([🟢 Configuration Needed]) --> Check1{📄 File exists at /etc/tor/torrc?}
|
||||
|
||||
Check1 -->|Yes| Check2{File not empty?}
|
||||
Check2 -->|Yes| UseMounted[Use Mounted Config]
|
||||
Check1 -->|Yes| Check2{📏 File not empty?}
|
||||
Check2 -->|Yes| UseMounted[📁 Use Mounted Config]
|
||||
Check2 -->|No| Check3
|
||||
|
||||
Check1 -->|No| Check3{ENV vars set? TOR_NICKNAME and TOR_CONTACT_INFO}
|
||||
Check1 -->|No| Check3{🌐 ENV vars set? TOR_NICKNAME and TOR_CONTACT_INFO}
|
||||
|
||||
Check3 -->|Yes| Validate[Validate ENV Values]
|
||||
Validate -->|Valid| Generate[Generate torrc from ENV]
|
||||
Validate -->|Invalid| Error1[ERROR: Invalid ENV]
|
||||
Check3 -->|Yes| Validate[🧪 Validate ENV Values]
|
||||
Validate -->|Valid| Generate[✍️ Generate torrc from ENV]
|
||||
Validate -->|Invalid| Error1[❌ ERROR: Invalid ENV]
|
||||
|
||||
Generate --> ModeCheck{TOR_RELAY_MODE?}
|
||||
ModeCheck -->|guard/middle| GenGuard[Generate Guard Config]
|
||||
ModeCheck -->|exit| GenExit[Generate Exit Config]
|
||||
ModeCheck -->|bridge| GenBridge[Generate Bridge Config]
|
||||
Generate --> ModeCheck{⚙️ TOR_RELAY_MODE?}
|
||||
ModeCheck -->|guard/middle| GenGuard[🛡️ Generate Guard Config]
|
||||
ModeCheck -->|exit| GenExit[🚪 Generate Exit Config]
|
||||
ModeCheck -->|bridge| GenBridge[🌉 Generate Bridge Config]
|
||||
|
||||
GenBridge --> OBFS4Check{OBFS4_ENABLE_ADDITIONAL_VARIABLES?}
|
||||
OBFS4Check -->|Yes| ProcessOBFS4V[Process OBFS4V_* vars]
|
||||
GenBridge --> OBFS4Check{🔐 OBFS4_ENABLE_ADDITIONAL_VARIABLES?}
|
||||
OBFS4Check -->|Yes| ProcessOBFS4V[🧩 Process OBFS4V_* vars]
|
||||
OBFS4Check -->|No| UseEnv
|
||||
ProcessOBFS4V --> UseEnv[Use Generated Config]
|
||||
ProcessOBFS4V --> UseEnv[🧾 Use Generated Config]
|
||||
|
||||
GenGuard --> UseEnv
|
||||
GenExit --> UseEnv
|
||||
|
||||
Check3 -->|No| Error2[ERROR: No Config Found]
|
||||
Check3 -->|No| Error2[❌ ERROR: No Config Found]
|
||||
|
||||
UseMounted --> Success([Config Ready])
|
||||
UseMounted --> Success([✅ Config Ready])
|
||||
UseEnv --> Success
|
||||
Error1 --> Failure([Container Exit])
|
||||
Error1 --> Failure([⛔ Container Exit])
|
||||
Error2 --> Failure
|
||||
|
||||
style UseMounted fill:#90EE90
|
||||
style UseEnv fill:#90EE90
|
||||
style Success fill:#90EE90
|
||||
style Error1 fill:#FFB6C1
|
||||
style Error2 fill:#FFB6C1
|
||||
style Failure fill:#FFB6C1
|
||||
style Start fill:#c8e6c9
|
||||
style UseMounted fill:#b2fab4
|
||||
style UseEnv fill:#b2fab4
|
||||
style Success fill:#b2fab4
|
||||
style Error1 fill:#ffcdd2
|
||||
style Error2 fill:#ffcdd2
|
||||
style Failure fill:#ffcdd2
|
||||
style Validate fill:#fff9c4
|
||||
style Generate fill:#fff9c4
|
||||
style ModeCheck fill:#e1f5fe
|
||||
style GenGuard fill:#e3f2fd
|
||||
style GenExit fill:#fce4ec
|
||||
style GenBridge fill:#e8f5e9
|
||||
style OBFS4Check fill:#f3e5f5
|
||||
style ProcessOBFS4V fill:#ede7f6
|
||||
```
|
||||
|
||||
**Code Reference:** `docker-entrypoint.sh` lines 201-220 (phase_3_configuration)
|
||||
@@ -195,47 +205,53 @@ All ENV variables are validated before config generation:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([ENV Validation]) --> V1{TOR_RELAY_MODE}
|
||||
V1 --> V1_Check{Value in: guard/middle/exit/bridge?}
|
||||
Start([🟢 ENV Validation]) --> V1{⚙️ TOR_RELAY_MODE}
|
||||
V1 --> V1_Check{Value in: guard, middle, exit, bridge?}
|
||||
V1_Check -->|Yes| V2
|
||||
V1_Check -->|No| V1_Fail[ERROR: Invalid mode]
|
||||
V1_Check -->|No| V1_Fail[❌ ERROR: Invalid mode]
|
||||
|
||||
V2{TOR_NICKNAME} --> V2_1{Length 1-19?}
|
||||
V2{🏷️ TOR_NICKNAME} --> V2_1{Length 1-19?}
|
||||
V2_1 -->|Yes| V2_2{Alphanumeric only?}
|
||||
V2_2 -->|Yes| V2_3{Not reserved name?}
|
||||
V2_3 -->|Yes| V3
|
||||
V2_3 -->|No| V2_Fail[ERROR: Reserved name]
|
||||
V2_3 -->|No| V2_Fail[❌ ERROR: Reserved name]
|
||||
V2_2 -->|No| V2_Fail
|
||||
V2_1 -->|No| V2_Fail
|
||||
|
||||
V3{TOR_CONTACT_INFO} --> V3_1{Length >= 3?}
|
||||
V3{📨 TOR_CONTACT_INFO} --> V3_1{Length ≥ 3?}
|
||||
V3_1 -->|Yes| V3_2{No newlines?}
|
||||
V3_2 -->|Yes| V4
|
||||
V3_2 -->|No| V3_Fail[ERROR: Contains newlines]
|
||||
V3_2 -->|No| V3_Fail[❌ ERROR: Contains newlines]
|
||||
V3_1 -->|No| V3_Fail
|
||||
|
||||
V4{Ports: ORPORT/DIRPORT/OBFS4_PORT} --> V4_1{Valid integer?}
|
||||
V4{🔌 Ports: ORPORT, DIRPORT, OBFS4_PORT} --> V4_1{Valid integer?}
|
||||
V4_1 -->|Yes| V4_2{Range 1-65535 or DirPort=0?}
|
||||
V4_2 -->|Yes| V4_3{Port less than 1024?}
|
||||
V4_3 -->|Yes| V4_Warn[WARN: Privileged port]
|
||||
V4_3 -->|Yes| V4_Warn[⚠️ WARN: Privileged port]
|
||||
V4_3 -->|No| V5
|
||||
V4_Warn --> V5
|
||||
V4_2 -->|No| V4_Fail[ERROR: Out of range]
|
||||
V4_2 -->|No| V4_Fail[❌ ERROR: Out of range]
|
||||
V4_1 -->|No| V4_Fail
|
||||
|
||||
V5{Bandwidth: RATE/BURST} --> V5_1{Valid format?}
|
||||
V5_1 -->|Yes| Success([Validation Passed])
|
||||
V5_1 -->|No| V5_Fail[ERROR: Invalid format]
|
||||
V5{📶 Bandwidth: RATE, BURST} --> V5_1{Valid format?}
|
||||
V5_1 -->|Yes| Success([✅ Validation Passed])
|
||||
V5_1 -->|No| V5_Fail[❌ ERROR: Invalid format]
|
||||
|
||||
V1_Fail --> Failure([Container Exit])
|
||||
V1_Fail --> Failure([⛔ Container Exit])
|
||||
V2_Fail --> Failure
|
||||
V3_Fail --> Failure
|
||||
V4_Fail --> Failure
|
||||
V5_Fail --> Failure
|
||||
|
||||
style Success fill:#90EE90
|
||||
style Failure fill:#FFB6C1
|
||||
style V4_Warn fill:#FFD700
|
||||
style Success fill:#b2fab4
|
||||
style Failure fill:#ffcdd2
|
||||
style V4_Warn fill:#fff59d
|
||||
style Start fill:#c8e6c9
|
||||
style V1 fill:#e3f2fd
|
||||
style V2 fill:#e3f2fd
|
||||
style V3 fill:#e3f2fd
|
||||
style V4 fill:#e3f2fd
|
||||
style V5 fill:#e3f2fd
|
||||
```
|
||||
|
||||
**Code Reference:** `docker-entrypoint.sh` lines 115-198 (validate_relay_config)
|
||||
@@ -248,15 +264,15 @@ The container supports **two naming conventions** for maximum compatibility:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Official["Official Tor Project Bridge Naming"]
|
||||
NICKNAME["NICKNAME"]
|
||||
EMAIL["EMAIL"]
|
||||
OR_PORT["OR_PORT"]
|
||||
PT_PORT["PT_PORT"]
|
||||
OBFS4V["OBFS4V_*"]
|
||||
subgraph Official["🌐 Official Tor Project Bridge Naming"]
|
||||
NICKNAME["🏷️ NICKNAME"]
|
||||
EMAIL["📨 EMAIL"]
|
||||
OR_PORT["🔌 OR_PORT"]
|
||||
PT_PORT["🎛️ PT_PORT"]
|
||||
OBFS4V["🔐 OBFS4V_*"]
|
||||
end
|
||||
|
||||
subgraph Compat["Compatibility Layer (docker-entrypoint.sh:22-31)"]
|
||||
subgraph Compat["🔀 Compatibility Layer (docker-entrypoint.sh:22-31)"]
|
||||
Map1["Map NICKNAME"]
|
||||
Map2["Map EMAIL"]
|
||||
Map3["Map OR_PORT"]
|
||||
@@ -264,7 +280,7 @@ flowchart LR
|
||||
Auto["Auto-detect bridge mode"]
|
||||
end
|
||||
|
||||
subgraph Internal["Internal TOR_* Variables"]
|
||||
subgraph Internal["⚙️ Internal TOR_* Variables"]
|
||||
TOR_NICKNAME["TOR_NICKNAME"]
|
||||
TOR_CONTACT["TOR_CONTACT_INFO"]
|
||||
TOR_ORPORT["TOR_ORPORT"]
|
||||
@@ -279,16 +295,16 @@ flowchart LR
|
||||
PT_PORT --> Auto --> TOR_MODE
|
||||
OBFS4V -.->|Processed later if enabled| TOR_MODE
|
||||
|
||||
TOR_NICKNAME --> Config[Config Generation]
|
||||
TOR_NICKNAME --> Config[📝 Config Generation]
|
||||
TOR_CONTACT --> Config
|
||||
TOR_ORPORT --> Config
|
||||
TOR_OBFS4 --> Config
|
||||
TOR_MODE --> Config
|
||||
|
||||
style Official fill:#E6F3FF
|
||||
style Compat fill:#FFF4E6
|
||||
style Internal fill:#E8F5E9
|
||||
style Config fill:#FFD700
|
||||
style Official fill:#e3f2fd
|
||||
style Compat fill:#fff4e6
|
||||
style Internal fill:#e8f5e9
|
||||
style Config fill:#fff59d
|
||||
```
|
||||
|
||||
**Mapping Details:**
|
||||
@@ -317,15 +333,15 @@ flowchart LR
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([Generate Config]) --> Base[Write Base Config]
|
||||
Start([🟢 Generate Config]) --> Base[📝 Write Base Config]
|
||||
|
||||
Base --> Mode{TOR_RELAY_MODE}
|
||||
Base --> Mode{⚙️ TOR_RELAY_MODE}
|
||||
|
||||
Mode -->|guard/middle| Guard[Add Guard Config]
|
||||
Mode -->|exit| Exit[Add Exit Config]
|
||||
Mode -->|bridge| Bridge[Add Bridge Config]
|
||||
Mode -->|guard/middle| Guard[🛡️ Add Guard Config]
|
||||
Mode -->|exit| Exit[🚪 Add Exit Config]
|
||||
Mode -->|bridge| Bridge[🌉 Add Bridge Config]
|
||||
|
||||
subgraph GuardConfig["Guard/Middle Config (lines 247-257)"]
|
||||
subgraph GuardConfig["🛡️ Guard/Middle Config (lines 247-257)"]
|
||||
G1[DirPort TOR_DIRPORT] --> G2[ExitRelay 0]
|
||||
G2 --> G3[BridgeRelay 0]
|
||||
G3 --> G4{TOR_BANDWIDTH_RATE?}
|
||||
@@ -337,7 +353,7 @@ flowchart TD
|
||||
G7 --> GuardDone([Guard Config Done])
|
||||
end
|
||||
|
||||
subgraph ExitConfig["Exit Config (lines 260-273)"]
|
||||
subgraph ExitConfig["🚪 Exit Config (lines 260-273)"]
|
||||
E1[DirPort TOR_DIRPORT] --> E2[ExitRelay 1]
|
||||
E2 --> E3[BridgeRelay 0]
|
||||
E3 --> E4[Add Exit Policy]
|
||||
@@ -350,7 +366,7 @@ flowchart TD
|
||||
E8 --> ExitDone([Exit Config Done])
|
||||
end
|
||||
|
||||
subgraph BridgeConfig["Bridge Config (lines 276-343)"]
|
||||
subgraph BridgeConfig["🌉 Bridge Config (lines 276-343)"]
|
||||
B1[BridgeRelay 1] --> B2[PublishServerDescriptor bridge]
|
||||
B2 --> B3[ServerTransportPlugin obfs4]
|
||||
B3 --> B4[ServerTransportListenAddr obfs4]
|
||||
@@ -371,11 +387,16 @@ flowchart TD
|
||||
Exit --> ExitConfig
|
||||
Bridge --> BridgeConfig
|
||||
|
||||
GuardDone --> Complete([Config Written])
|
||||
GuardDone --> Complete([✅ Config Written])
|
||||
ExitDone --> Complete
|
||||
BridgeDone --> Complete
|
||||
|
||||
style Complete fill:#90EE90
|
||||
style Complete fill:#b2fab4
|
||||
style GuardConfig fill:#e3f2fd
|
||||
style ExitConfig fill:#fce4ec
|
||||
style BridgeConfig fill:#e8f5e9
|
||||
style Mode fill:#fff9c4
|
||||
style Base fill:#fff9c4
|
||||
```
|
||||
|
||||
**Base Config Includes:** Nickname, ContactInfo, ORPort, SocksPort 0, DataDirectory, Logging
|
||||
@@ -388,24 +409,24 @@ Security-critical whitelisting to prevent injection attacks:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([OBFS4V Processing]) --> Enable{OBFS4_ENABLE_ADDITIONAL_VARIABLES?}
|
||||
Enable -->|No| Skip([Skip OBFS4V Processing])
|
||||
Enable -->|Yes| GetVars[env | grep '^OBFS4V_']
|
||||
Start([🟢 OBFS4V Processing]) --> Enable{🔐 OBFS4_ENABLE_ADDITIONAL_VARIABLES?}
|
||||
Enable -->|No| Skip([⏭️ Skip OBFS4V Processing])
|
||||
Enable -->|Yes| GetVars[📥 env | grep '^OBFS4V_']
|
||||
|
||||
GetVars --> Loop{For each OBFS4V_* var}
|
||||
GetVars --> Loop{🔁 For each OBFS4V_* var}
|
||||
|
||||
Loop --> Strip[Strip OBFS4V_ prefix]
|
||||
Strip --> V1{Key valid? Alphanumeric only}
|
||||
V1 -->|No| Warn1[WARN: Invalid name] --> Next
|
||||
V1 -->|Yes| V2{Value has newlines?}
|
||||
Loop --> Strip[✂️ Strip OBFS4V_ prefix]
|
||||
Strip --> V1{🔤 Key valid? Alphanumeric only}
|
||||
V1 -->|No| Warn1[⚠️ WARN: Invalid name] --> Next
|
||||
V1 -->|Yes| V2{📄 Value has newlines?}
|
||||
|
||||
V2 -->|Yes| Warn2[WARN: Contains newlines] --> Next
|
||||
V2 -->|No| V3{Value has control chars?}
|
||||
V2 -->|Yes| Warn2[⚠️ WARN: Contains newlines] --> Next
|
||||
V2 -->|No| V3{🧪 Value has control chars?}
|
||||
|
||||
V3 -->|Yes| Warn3[WARN: Control characters] --> Next
|
||||
V3 -->|No| Whitelist{Key in whitelist?}
|
||||
V3 -->|Yes| Warn3[⚠️ WARN: Control characters] --> Next
|
||||
V3 -->|No| Whitelist{🛡️ Key in whitelist?}
|
||||
|
||||
subgraph WhitelistCheck["Whitelist (lines 325-331)"]
|
||||
subgraph WhitelistCheck["🧾 Whitelist (lines 325-331)"]
|
||||
WL1[AccountingMax/Start]
|
||||
WL2[Address/AddressDisableIPv6]
|
||||
WL3[Bandwidth*/RelayBandwidth*]
|
||||
@@ -415,20 +436,22 @@ flowchart TD
|
||||
WL7[ServerDNS*]
|
||||
end
|
||||
|
||||
Whitelist -->|Yes| Write[Write to torrc]
|
||||
Whitelist -->|No| Warn4[WARN: Not in whitelist]
|
||||
Whitelist -->|Yes| Write[📝 Write to torrc]
|
||||
Whitelist -->|No| Warn4[⚠️ WARN: Not in whitelist]
|
||||
|
||||
Write --> Next{More vars?}
|
||||
Warn4 --> Next
|
||||
Next -->|Yes| Loop
|
||||
Next -->|No| Done([OBFS4V Processing Done])
|
||||
Next -->|No| Done([✅ OBFS4V Processing Done])
|
||||
|
||||
style Write fill:#90EE90
|
||||
style Done fill:#90EE90
|
||||
style Warn1 fill:#FFD700
|
||||
style Warn2 fill:#FFD700
|
||||
style Warn3 fill:#FFD700
|
||||
style Warn4 fill:#FFD700
|
||||
style Write fill:#b2fab4
|
||||
style Done fill:#b2fab4
|
||||
style Warn1 fill:#fff59d
|
||||
style Warn2 fill:#fff59d
|
||||
style Warn3 fill:#fff59d
|
||||
style Warn4 fill:#fff59d
|
||||
style Start fill:#c8e6c9
|
||||
style Enable fill:#e3f2fd
|
||||
```
|
||||
|
||||
**Security Features (v1.1.1 Fix):**
|
||||
@@ -447,56 +470,56 @@ Four busybox-only diagnostic tools provide observability:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
User([User: docker exec]) --> Choice{Which tool?}
|
||||
User([👤 User: docker exec]) --> Choice{🛠️ Which tool?}
|
||||
|
||||
Choice -->|status| StatusFlow
|
||||
Choice -->|health| HealthFlow
|
||||
Choice -->|fingerprint| FingerprintFlow
|
||||
Choice -->|bridge-line| BridgeFlow
|
||||
|
||||
subgraph StatusFlow["tools/status - Full Health Report"]
|
||||
S1[Check Tor process running] --> S2[Read bootstrap %]
|
||||
S2 --> S3[Read reachability status]
|
||||
S3 --> S4[Show fingerprint]
|
||||
S4 --> S5[Show recent logs]
|
||||
S5 --> S6[Show resource usage]
|
||||
S6 --> S7[Output with emoji formatting]
|
||||
subgraph StatusFlow["📊 tools/status - Full Health Report"]
|
||||
S1[🔍 Check Tor process running] --> S2[📈 Read bootstrap %]
|
||||
S2 --> S3[🌐 Read reachability status]
|
||||
S3 --> S4[🆔 Show fingerprint]
|
||||
S4 --> S5[📝 Show recent logs]
|
||||
S5 --> S6[💽 Show resource usage]
|
||||
S6 --> S7[😁 Output with emoji formatting]
|
||||
end
|
||||
|
||||
subgraph HealthFlow["tools/health - JSON API"]
|
||||
H1[Check Tor process] --> H2[Parse log for bootstrap]
|
||||
H2 --> H3[Parse log for errors]
|
||||
H3 --> H4[Get fingerprint if exists]
|
||||
H4 --> H5[Output JSON]
|
||||
subgraph HealthFlow["📡 tools/health - JSON API"]
|
||||
H1[🔍 Check Tor process] --> H2[📈 Parse log for bootstrap]
|
||||
H2 --> H3[⚠️ Parse log for errors]
|
||||
H3 --> H4[🆔 Get fingerprint if exists]
|
||||
H4 --> H5[📤 Output JSON]
|
||||
end
|
||||
|
||||
subgraph FingerprintFlow["tools/fingerprint - Show Identity"]
|
||||
F1[Read /var/lib/tor/fingerprint] --> F2{File exists?}
|
||||
F2 -->|Yes| F3[Parse fingerprint]
|
||||
F3 --> F4[Output fingerprint]
|
||||
F4 --> F5[Output Tor Metrics URL]
|
||||
F2 -->|No| F6[Warn: Not ready yet]
|
||||
subgraph FingerprintFlow["🆔 tools/fingerprint - Show Identity"]
|
||||
F1[📄 Read /var/lib/tor/fingerprint] --> F2{File exists?}
|
||||
F2 -->|Yes| F3[🔎 Parse fingerprint]
|
||||
F3 --> F4[📤 Output fingerprint]
|
||||
F4 --> F5[🔗 Output Tor Metrics URL]
|
||||
F2 -->|No| F6[⚠️ Warn: Not ready yet]
|
||||
end
|
||||
|
||||
subgraph BridgeFlow["tools/bridge-line - Bridge Sharing"]
|
||||
B1{Bridge mode?} -->|No| B2[Error: Not a bridge]
|
||||
B1 -->|Yes| B3[Read pt_state/obfs4_state.json]
|
||||
subgraph BridgeFlow["🌉 tools/bridge-line - Bridge Sharing"]
|
||||
B1{Bridge mode?} -->|No| B2[❌ Error: Not a bridge]
|
||||
B1 -->|Yes| B3[📄 Read pt_state/obfs4_state.json]
|
||||
B3 --> B4{File exists?}
|
||||
B4 -->|Yes| B5[Parse cert/iat-mode]
|
||||
B5 --> B6[Get public IP]
|
||||
B6 --> B7[Output bridge line]
|
||||
B4 -->|No| B8[Warn: Not ready yet]
|
||||
B4 -->|Yes| B5[🔐 Parse cert and iat-mode]
|
||||
B5 --> B6[🌍 Get public IP]
|
||||
B6 --> B7[📤 Output bridge line]
|
||||
B4 -->|No| B8[⚠️ Warn: Not ready yet]
|
||||
end
|
||||
|
||||
StatusFlow --> Output1([Human-readable output])
|
||||
HealthFlow --> Output2([JSON output])
|
||||
FingerprintFlow --> Output3([Fingerprint + URL])
|
||||
BridgeFlow --> Output4([Bridge line or error])
|
||||
StatusFlow --> Output1([🟢 Human-readable output])
|
||||
HealthFlow --> Output2([🟢 JSON output])
|
||||
FingerprintFlow --> Output3([🟢 Fingerprint + URL])
|
||||
BridgeFlow --> Output4([🟢 Bridge line or error])
|
||||
|
||||
style Output1 fill:#90EE90
|
||||
style Output2 fill:#90EE90
|
||||
style Output3 fill:#90EE90
|
||||
style Output4 fill:#90EE90
|
||||
style Output1 fill:#b2fab4
|
||||
style Output2 fill:#b2fab4
|
||||
style Output3 fill:#b2fab4
|
||||
style Output4 fill:#b2fab4
|
||||
```
|
||||
|
||||
**JSON Output Fields:** status, bootstrap_pct, reachable, errors, fingerprint, nickname, uptime_seconds
|
||||
@@ -524,51 +547,51 @@ flowchart TD
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Root[/ Container Root] --> Etc[/etc]
|
||||
Root[/ 🗂️ Container Root ] --> Etc[/etc]
|
||||
Root --> Var[/var]
|
||||
Root --> Run[/run]
|
||||
Root --> Usr[/usr]
|
||||
Root --> Sbin[/sbin]
|
||||
|
||||
Etc --> TorEtc[/etc/tor]
|
||||
TorEtc --> TorRC[torrc]
|
||||
TorEtc --> TorRC[📝 torrc]
|
||||
TorEtc -.->|Deleted at build| TorRCSample[torrc.sample]
|
||||
|
||||
Var --> Lib[/var/lib]
|
||||
Lib --> TorData[/var/lib/tor - VOLUME]
|
||||
TorData --> Keys[keys/]
|
||||
TorData --> FingerprintFile[fingerprint]
|
||||
TorData --> PTState[pt_state/]
|
||||
TorData --> Keys[🔑 keys/]
|
||||
TorData --> FingerprintFile[🆔 fingerprint]
|
||||
TorData --> PTState[🔐 pt_state/]
|
||||
|
||||
Var --> Log[/var/log]
|
||||
Log --> TorLog[/var/log/tor - VOLUME]
|
||||
TorLog --> Notices[notices.log]
|
||||
TorLog --> Notices[📄 notices.log]
|
||||
|
||||
Run --> TorRun[/run/tor]
|
||||
TorRun --> TorPID[tor.pid]
|
||||
TorRun --> TorPID[📌 tor.pid]
|
||||
|
||||
Usr --> UsrLocal[/usr/local]
|
||||
UsrLocal --> Bin[/usr/local/bin]
|
||||
Bin --> Entrypoint[docker-entrypoint.sh]
|
||||
Bin --> Healthcheck[healthcheck.sh]
|
||||
Bin --> Status[status]
|
||||
Bin --> Health[health]
|
||||
Bin --> Fingerprint[fingerprint]
|
||||
Bin --> BridgeLine[bridge-line]
|
||||
Bin --> Entrypoint[🚀 docker-entrypoint.sh]
|
||||
Bin --> Healthcheck[🩺 healthcheck.sh]
|
||||
Bin --> Status[📊 status]
|
||||
Bin --> Health[📡 health]
|
||||
Bin --> Fingerprint[🆔 fingerprint]
|
||||
Bin --> BridgeLine[🌉 bridge-line]
|
||||
|
||||
Usr --> UsrBin[/usr/bin]
|
||||
UsrBin --> TorBin[tor]
|
||||
UsrBin --> Lyrebird[lyrebird]
|
||||
UsrBin --> TorBin[🌀 tor]
|
||||
UsrBin --> Lyrebird[🕊️ lyrebird]
|
||||
|
||||
Sbin --> Tini[/sbin/tini]
|
||||
|
||||
Root --> BuildInfo[/build-info.txt]
|
||||
|
||||
style TorData fill:#FFE6E6
|
||||
style TorLog fill:#FFE6E6
|
||||
style TorRC fill:#E6F3FF
|
||||
style Entrypoint fill:#FFD700
|
||||
style Tini fill:#90EE90
|
||||
style TorData fill:#ffe6e6
|
||||
style TorLog fill:#ffe6e6
|
||||
style TorRC fill:#e6f3ff
|
||||
style Entrypoint fill:#fff59d
|
||||
style Tini fill:#b2fab4
|
||||
```
|
||||
|
||||
### Ownership & Permissions
|
||||
@@ -591,40 +614,40 @@ graph TD
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph Container["Container Security"]
|
||||
NonRoot[Non-root Execution]
|
||||
Tini[Tini Init]
|
||||
Minimal[Minimal Image]
|
||||
NoCaps[Minimal Capabilities]
|
||||
NoPriv[no-new-privileges]
|
||||
subgraph Container["🛡️ Container Security"]
|
||||
NonRoot[👤 Non-root Execution]
|
||||
Tini[🔧 Tini Init]
|
||||
Minimal[📦 Minimal Image]
|
||||
NoCaps[🚫 Minimal Capabilities]
|
||||
NoPriv[🔒 no-new-privileges]
|
||||
end
|
||||
|
||||
subgraph CodeSec["Code Security"]
|
||||
POSIX[POSIX sh Only]
|
||||
SetE[set -e Exit on error]
|
||||
Validation[Input Validation]
|
||||
NoEval[No eval/exec]
|
||||
Whitelist[OBFS4V Whitelist]
|
||||
subgraph CodeSec["💻 Code Security"]
|
||||
POSIX[📜 POSIX sh Only]
|
||||
SetE[⚠️ set -e Exit on error]
|
||||
Validation[🧪 Input Validation]
|
||||
NoEval[🚫 No eval or exec]
|
||||
Whitelist[🛡️ OBFS4V Whitelist]
|
||||
end
|
||||
|
||||
subgraph NetworkSec["Network Security"]
|
||||
HostNet[--network host]
|
||||
NoPorts[No Exposed Monitoring]
|
||||
Configurable[Configurable Ports]
|
||||
subgraph NetworkSec["🌐 Network Security"]
|
||||
HostNet[🏠 --network host]
|
||||
NoPorts[🔕 No Exposed Monitoring Ports]
|
||||
Configurable[🧭 Configurable Ports]
|
||||
end
|
||||
|
||||
subgraph FileSec["File System Security"]
|
||||
ReadOnly[Read-only torrc mount]
|
||||
VolPerms[Volume Permissions]
|
||||
NoSecrets[No Hardcoded Secrets]
|
||||
subgraph FileSec["📁 File System Security"]
|
||||
ReadOnly[📄 Read-only torrc mount]
|
||||
VolPerms[🔐 Volume Permissions]
|
||||
NoSecrets[🙅 No Hardcoded Secrets]
|
||||
end
|
||||
|
||||
Container --> Secure([Defense in Depth])
|
||||
Container --> Secure([🟢 Defense in Depth])
|
||||
CodeSec --> Secure
|
||||
NetworkSec --> Secure
|
||||
FileSec --> Secure
|
||||
|
||||
style Secure fill:#90EE90
|
||||
style Secure fill:#b2fab4
|
||||
```
|
||||
|
||||
### Validation Points
|
||||
@@ -648,12 +671,12 @@ Graceful shutdown ensures relay reputation is maintained:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Docker
|
||||
participant Tini as Tini (PID 1)
|
||||
participant Entrypoint as docker-entrypoint.sh
|
||||
participant Tor as Tor Process
|
||||
participant Tail as tail -F Process
|
||||
participant User as 👤 User
|
||||
participant Docker as 🐳 Docker
|
||||
participant Tini as 🔧 Tini PID1
|
||||
participant Entrypoint as 🚀 docker-entrypoint.sh
|
||||
participant Tor as 🌀 Tor Process
|
||||
participant Tail as 📄 tail -F Process
|
||||
|
||||
User->>Docker: docker stop <container>
|
||||
Docker->>Tini: SIGTERM
|
||||
@@ -666,15 +689,15 @@ sequenceDiagram
|
||||
Tail-->>Entrypoint: Process exits
|
||||
|
||||
Entrypoint->>Tor: kill -TERM $TOR_PID
|
||||
Note over Tor: Graceful shutdown - Close circuits, notify directory, save state
|
||||
Note over Tor: 🔄 Graceful shutdown, close circuits, notify directory, save state
|
||||
|
||||
Tor-->>Entrypoint: Process exits (wait)
|
||||
Entrypoint->>Entrypoint: Success: Relay stopped cleanly
|
||||
Entrypoint->>Entrypoint: ✅ Success, relay stopped cleanly
|
||||
Entrypoint-->>Tini: exit 0
|
||||
Tini-->>Docker: Container stopped
|
||||
Docker-->>User: Stopped
|
||||
|
||||
Note over User,Tail: Total time 5-10 seconds. Tor gets 10s before SIGKILL
|
||||
Note over User,Tail: ⏱️ Total 5–10 seconds, Tor gets 10s before SIGKILL
|
||||
```
|
||||
|
||||
**Signal Flow:**
|
||||
@@ -696,41 +719,41 @@ sequenceDiagram
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Source["Source Files"]
|
||||
Dockerfile[Dockerfile]
|
||||
Scripts[Scripts]
|
||||
Tools[Diagnostic Tools]
|
||||
subgraph Source["📁 Source Files"]
|
||||
Dockerfile[📄 Dockerfile]
|
||||
Scripts[🧾 Scripts]
|
||||
Tools[🛠️ Diagnostic Tools]
|
||||
end
|
||||
|
||||
subgraph Build["Docker Build"]
|
||||
Alpine[Alpine 3.22.2]
|
||||
Install[apk add packages]
|
||||
Copy[Copy scripts & tools]
|
||||
Perms[Set permissions]
|
||||
User[Switch to USER tor]
|
||||
subgraph Build["🏗️ Docker Build"]
|
||||
Alpine[🐧 Alpine 3.22.2]
|
||||
Install[📦 apk add packages]
|
||||
Copy[📥 Copy scripts and tools]
|
||||
Perms[🔒 Set permissions]
|
||||
User[👤 Switch to USER tor]
|
||||
end
|
||||
|
||||
subgraph CI["CI/CD (GitHub Actions)"]
|
||||
Trigger{Trigger Type?}
|
||||
Trigger -->|Weekly| Weekly[Rebuild latest tag]
|
||||
Trigger -->|Git Tag| Release[New release build]
|
||||
Trigger -->|Manual| Manual[workflow_dispatch]
|
||||
subgraph CI["⚙️ CI/CD (GitHub Actions)"]
|
||||
Trigger{🚀 Trigger Type?}
|
||||
Trigger -->|Weekly| Weekly[📆 Rebuild latest tag]
|
||||
Trigger -->|Git Tag| Release[🏷️ New release build]
|
||||
Trigger -->|Manual| Manual[🖐 workflow_dispatch]
|
||||
|
||||
Weekly --> MultiArch[Multi-arch build]
|
||||
Weekly --> MultiArch[🌍 Multi-arch build]
|
||||
Release --> MultiArch
|
||||
Manual --> MultiArch
|
||||
|
||||
MultiArch --> Push[Push to registries]
|
||||
Release --> GHRelease[Create GitHub Release]
|
||||
MultiArch --> Push[📤 Push to registries]
|
||||
Release --> GHRelease[📦 Create GitHub Release]
|
||||
end
|
||||
|
||||
Source --> Build
|
||||
Build --> Image[Container Image]
|
||||
Build --> Image[🧱 Container Image]
|
||||
Image --> CI
|
||||
|
||||
style Image fill:#FFD700
|
||||
style Push fill:#90EE90
|
||||
style GHRelease fill:#90EE90
|
||||
style Image fill:#fff59d
|
||||
style Push fill:#b2fab4
|
||||
style GHRelease fill:#b2fab4
|
||||
```
|
||||
|
||||
**Weekly Rebuild Strategy:**
|
||||
@@ -749,35 +772,36 @@ Docker `HEALTHCHECK` runs every 10 minutes:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([Health Check Timer]) -->|Every 10 min| Script[/usr/local/bin/healthcheck.sh]
|
||||
Start([⏱️ Health Check Timer]) -->|Every 10 min| Script[/usr/local/bin/healthcheck.sh]
|
||||
|
||||
Script --> Check1{Tor process running?}
|
||||
Check1 -->|No| Unhealthy1[Exit 1: UNHEALTHY]
|
||||
Check1 -->|Yes| Check2{Config file exists?}
|
||||
Script --> Check1{🌀 Tor process running?}
|
||||
Check1 -->|No| Unhealthy1[❌ Exit 1: UNHEALTHY]
|
||||
Check1 -->|Yes| Check2{📄 Config file exists?}
|
||||
|
||||
Check2 -->|No| Unhealthy2[Exit 1: No config]
|
||||
Check2 -->|Yes| Check3{Config readable?}
|
||||
Check2 -->|No| Unhealthy2[❌ Exit 1: No config]
|
||||
Check2 -->|Yes| Check3{🔍 Config readable?}
|
||||
|
||||
Check3 -->|No| Unhealthy3[Exit 1: Unreadable config]
|
||||
Check3 -->|Yes| Check4{Bootstrap >= 75%?}
|
||||
Check3 -->|No| Unhealthy3[❌ Exit 1: Unreadable config]
|
||||
Check3 -->|Yes| Check4{📈 Bootstrap ≥ 75%?}
|
||||
|
||||
Check4 -->|Unknown| Healthy2[Exit 0: Can't determine]
|
||||
Check4 -->|No| Unhealthy4[Exit 1: Bootstrap stuck]
|
||||
Check4 -->|Yes| Healthy1[Exit 0: HEALTHY]
|
||||
Check4 -->|Unknown| Healthy2[⚪ Exit 0: Can't determine]
|
||||
Check4 -->|No| Unhealthy4[⚠️ Exit 1: Bootstrap stuck]
|
||||
Check4 -->|Yes| Healthy1[✅ Exit 0: HEALTHY]
|
||||
|
||||
Healthy1 --> Status([Container: healthy])
|
||||
Healthy1 --> Status([🟢 Container: healthy])
|
||||
Healthy2 --> Status
|
||||
Unhealthy1 --> Status2([Container: unhealthy])
|
||||
Unhealthy1 --> Status2([🔴 Container: unhealthy])
|
||||
Unhealthy2 --> Status2
|
||||
Unhealthy3 --> Status2
|
||||
Unhealthy4 --> Status2
|
||||
|
||||
style Healthy1 fill:#90EE90
|
||||
style Healthy2 fill:#90EE90
|
||||
style Unhealthy1 fill:#FFB6C1
|
||||
style Unhealthy2 fill:#FFB6C1
|
||||
style Unhealthy3 fill:#FFB6C1
|
||||
style Unhealthy4 fill:#FFB6C1
|
||||
style Healthy1 fill:#b2fab4
|
||||
style Healthy2 fill:#b2fab4
|
||||
|
||||
style Unhealthy1 fill:#ffcdd2
|
||||
style Unhealthy2 fill:#ffcdd2
|
||||
style Unhealthy3 fill:#ffcdd2
|
||||
style Unhealthy4 fill:#ffcdd2
|
||||
```
|
||||
|
||||
**Health Check Configuration:**
|
||||
@@ -813,6 +837,6 @@ flowchart TD
|
||||
|
||||
---
|
||||
|
||||
**Document Version:** 1.0.0
|
||||
**Document Version:** 1.0.1
|
||||
**Last Updated:** 2025-01-14
|
||||
**Container Version:** v1.1.1
|
||||
|
||||
Reference in New Issue
Block a user