9 Commits

Author SHA1 Message Date
Ara Sadoyan
5815da6576 Merge pull request #43 from sadoyan/dev
Update main.yaml
2026-06-22 13:27:17 +02:00
Ara Sadoyan
1ab0916026 Merge branch 'dev' 2026-06-22 13:24:42 +02:00
Ara Sadoyan
707f725b88 Update main.yaml 2026-06-22 13:22:45 +02:00
Ara Sadoyan
eb4e73ece0 Basic access/error logging. Upgrade to Pingra 8.0.1 2026-06-22 13:20:56 +02:00
Ara Sadoyan
53e7dcfd33 Pid file follow symlink problem. 2026-06-19 11:14:40 +02:00
Ara Sadoyan
f3b346a28d Merge pull request #42 from sadoyan/dev
migrate from serde_yml to noyalib
2026-06-12 16:05:30 +02:00
Ara Sadoyan
c011800e1e migrate from serde_yml to noyalib 2026-06-12 16:03:49 +02:00
Ara Sadoyan
265ff6b774 cleanup 2026-06-12 13:33:21 +02:00
Ara Sadoyan
1c3d9a263f example configs 2026-06-12 13:12:39 +02:00
15 changed files with 254 additions and 245 deletions

7
.gitignore vendored
View File

@@ -5,12 +5,8 @@
*.dll
*.exe
*.sh
/docs/
*.yaml
/docs
/etc
/etc/
etc
.etc/
assets/
assets
/target/
@@ -26,4 +22,5 @@ crashlytics.properties
crashlytics-build.properties
/target
/z_shpo
/configs
Makefile

164
Cargo.lock generated
View File

@@ -127,7 +127,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "aralez"
version = "0.92.10"
version = "0.92.11"
dependencies = [
"ahash",
"arc-swap",
@@ -139,11 +139,13 @@ dependencies = [
"futures",
"instant-acme",
"jsonwebtoken",
"libc",
"log",
"log4rs",
"mimalloc",
"moka",
"notify",
"noyalib",
"pingora",
"pingora-core",
"pingora-http",
@@ -158,13 +160,12 @@ dependencies = [
"sd-notify",
"serde",
"serde_json",
"serde_yml",
"sha2 0.11.0",
"signal-hook",
"subtle",
"tokio",
"tonic",
"tower-http",
"tower-http 0.7.0",
"urlencoding",
"x509-parser",
]
@@ -472,27 +473,27 @@ dependencies = [
[[package]]
name = "cf-rustracing"
version = "1.3.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6565523d8145e63e0cf1b397a5f1bd4e90d5652a7dffb2de8cec460ff23ef6b1"
checksum = "93f85c3824e4191621dec0551e3cef3d511f329da9a8990bf3e450a85651d97e"
dependencies = [
"backtrace",
"rand 0.10.1",
"rand 0.8.6",
"tokio",
"trackable",
]
[[package]]
name = "cf-rustracing-jaeger"
version = "1.3.0"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c0e4d8cce27f6a6eaff58d2b66f063a18b8ed0d6ef0947ae7a263afa3b7c08"
checksum = "a6a5f80d44c257c3300a7f45ada676c211e64bbbac591bbec19344a8f61fbcab"
dependencies = [
"cf-rustracing",
"hostname",
"local-ip-address",
"percent-encoding",
"rand 0.10.1",
"rand 0.9.4",
"thrift_codec",
"tokio",
"trackable",
@@ -1712,9 +1713,9 @@ dependencies = [
[[package]]
name = "inotify"
version = "0.11.1"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199"
checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1"
dependencies = [
"bitflags 2.11.1",
"inotify-sys",
@@ -1871,9 +1872,9 @@ dependencies = [
[[package]]
name = "kqueue"
version = "1.1.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5"
dependencies = [
"kqueue-sys",
"libc",
@@ -1881,9 +1882,9 @@ dependencies = [
[[package]]
name = "kqueue-sys"
version = "1.1.0"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7b65860415f949f23fa882e669f2dbd4a0f0eeb1acdd56790b30494afd7da2f"
checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087"
dependencies = [
"bitflags 2.11.1",
"libc",
@@ -1925,16 +1926,6 @@ dependencies = [
"cc",
]
[[package]]
name = "libyml"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
dependencies = [
"anyhow",
"version_check",
]
[[package]]
name = "libz-ng-sys"
version = "1.1.28"
@@ -2219,6 +2210,22 @@ dependencies = [
"bitflags 2.11.1",
]
[[package]]
name = "noyalib"
version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14057395c16a4230575c6f86bfa074db87e8458626d3e56b20c2454334a7e50c"
dependencies = [
"indexmap 2.14.0",
"itoa",
"memchr",
"rustc-hash",
"ryu",
"serde",
"serde_ignored",
"smallvec",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
@@ -2508,9 +2515,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pingora"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "844a13b16e556293f4ea96dc5ac0923ac6f36855a9dfc13b640d0da183f6b5b7"
checksum = "54a75f2ff8e122aa80ab202dc865294fe59cd856c2a5dab2d3df6e122c93b941"
dependencies = [
"pingora-cache",
"pingora-core",
@@ -2522,9 +2529,9 @@ dependencies = [
[[package]]
name = "pingora-cache"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59d8c4c939a3a193a3da0e061aa7acf7432431f92ee62a26f5a9e5167a0ade2"
checksum = "527735ac204efb9fa3884bfd9224d016c5735fabe1d394ebed145b40e7545b99"
dependencies = [
"ahash",
"async-trait",
@@ -2559,9 +2566,9 @@ dependencies = [
[[package]]
name = "pingora-core"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08973c4853cef4c682f7a592907e81a32dcad69476c4846e5de079f16448b177"
checksum = "6a7ffe2f5acf9f94fd255cfd1438866bc9124f8f0c7d42562bd3f853df2094b7"
dependencies = [
"ahash",
"async-trait",
@@ -2611,15 +2618,15 @@ dependencies = [
[[package]]
name = "pingora-error"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9fa97a500e7e5c27a7b8609b9294c8922c9656322285268bfad9520f12feb38"
checksum = "b23f7bc013de67e44ed902a82843f6157460b89d11da882bcc6f09f8ae380af1"
[[package]]
name = "pingora-header-serde"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2705feb8b50d4e734e0c7d3879aa040e655a45656276323ff530e254585dd816"
checksum = "828c0e53e74160cbfe8e67dd3a811eb6a253c36acbaf7a39a01d9aacfb9ac139"
dependencies = [
"bytes",
"http",
@@ -2633,9 +2640,9 @@ dependencies = [
[[package]]
name = "pingora-http"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbb52d4651b687fab6abf669539cfd97b7cd94b301fde8f57c63354f9c9cc5e2"
checksum = "d553d310a15ec88107b9388a02885f798efc57764d8e9bdaaf32a76722927a10"
dependencies = [
"bytes",
"http",
@@ -2644,27 +2651,27 @@ dependencies = [
[[package]]
name = "pingora-ketama"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0286fb5a0359dca1e2e137dfe14ca4d94f676635a5eae4616bb3d8d4ce06d120"
checksum = "3e2a2e43a14f1d291fba7905542c7c1d1f89528f470b3cd48b6806e702ea772f"
dependencies = [
"crc32fast",
]
[[package]]
name = "pingora-limits"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7568624fc0e2f11fa32d27053ac862048b40bad98140b07a11d82f1b4989700"
checksum = "4bafc633ceb95dc8b39a0d1b52d105758ae0913d360ef3a3365a6f6494d0fe17"
dependencies = [
"ahash",
]
[[package]]
name = "pingora-load-balancing"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2606e9e22e72927a69772cefe56b0d41d251c3ffdfcd548a6020fe157fb79ad"
checksum = "361b69af0234d2e4d10234e2efd106bb3b8147c575d52f45604a46aaf26def7a"
dependencies = [
"arc-swap",
"async-trait",
@@ -2684,9 +2691,9 @@ dependencies = [
[[package]]
name = "pingora-lru"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91bb5030596a3d442c0866ac68afe29c14ba558e77c726dcdf7016b0dbb359d9"
checksum = "6705a26ad89d241a989a5395641931ba37076f5ab5fbd19ee92402414a43af32"
dependencies = [
"arrayvec",
"hashbrown 0.17.0",
@@ -2696,9 +2703,9 @@ dependencies = [
[[package]]
name = "pingora-openssl"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb7f135948a5c5a28a634e40fabd40c2588c757372f8a358bfca634a56514a6"
checksum = "5f288cacd77196168db0f6ae80817bc4844a8dd1448b75bb2da935eb6d9c3118"
dependencies = [
"foreign-types",
"libc",
@@ -2709,9 +2716,9 @@ dependencies = [
[[package]]
name = "pingora-pool"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67f034be36772f318370d058913db43dbd22c3763ad974c995ba2e4afb2bb52a"
checksum = "feb1237893b15a9cf6b371bee8d7e2e1c10742e4be6eb00ed38cfe87fd1363f8"
dependencies = [
"crossbeam-queue",
"log",
@@ -2724,9 +2731,9 @@ dependencies = [
[[package]]
name = "pingora-proxy"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e1e070a98a70d0d05f2fdcfb706237e06a043b2fbc9261e8772a3459cc2175e"
checksum = "8a92ee756ecf6ecb6419864da651cad6cecd933b6d420a26877031efa16bef57"
dependencies = [
"async-trait",
"bytes",
@@ -2747,9 +2754,9 @@ dependencies = [
[[package]]
name = "pingora-runtime"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e371315b1c44c2e5a8788fdc61577527b785e121e6ff49144755f40d86511430"
checksum = "41815a13691a3e7d9ad0e34767d4140284132e31b95a4481f5e73ab6f407f834"
dependencies = [
"once_cell",
"rand 0.8.6",
@@ -2759,9 +2766,9 @@ dependencies = [
[[package]]
name = "pingora-timeout"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a853fee5ce510a7f5db2561f99c752724112ed13fc3820e70d462d278d704ea"
checksum = "8e3e321452eaa461e0b6c5aaa35b7e42527ee89df33710279f37fae7f066b68e"
dependencies = [
"once_cell",
"parking_lot",
@@ -3184,7 +3191,7 @@ dependencies = [
"tokio-rustls",
"tokio-util",
"tower",
"tower-http",
"tower-http 0.6.11",
"tower-service",
"url",
"wasm-bindgen",
@@ -3508,6 +3515,16 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "serde_ignored"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798"
dependencies = [
"serde",
"serde_core",
]
[[package]]
name = "serde_json"
version = "1.0.150"
@@ -3557,21 +3574,6 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "serde_yml"
version = "0.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
dependencies = [
"indexmap 2.14.0",
"itoa",
"libyml",
"memchr",
"ryu",
"serde",
"version_check",
]
[[package]]
name = "sfv"
version = "0.10.4"
@@ -4084,6 +4086,24 @@ name = "tower-http"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
"futures-util",
"http",
"http-body",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
"url",
]
[[package]]
name = "tower-http"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
dependencies = [
"bitflags 2.11.1",
"bytes",
@@ -4100,10 +4120,8 @@ dependencies = [
"pin-project-lite",
"tokio",
"tokio-util",
"tower",
"tower-layer",
"tower-service",
"url",
]
[[package]]

View File

@@ -1,10 +1,10 @@
[package]
name = "aralez"
version = "0.92.10"
version = "0.92.11"
edition = "2021"
license = "Apache-2.0"
description = "Reverse proxy built on top of Cloudflare's Pingora"
exclude = ["etc/*"]
exclude = ["configs/*"]
repository = "https://github.com/sadoyan/aralez"
[profile.release]
@@ -16,20 +16,20 @@ strip = true
[dependencies]
tokio = { version = "1.52.3", features = ["full"] }
pingora = { version = "0.8.0", features = ["lb", "openssl"] } # openssl, rustls, boringssl
serde = { version = "1.0.228", features = ["derive"] }
pingora = { version = "0.8.1", features = ["lb", "openssl"] } # openssl, rustls, boringssl
pingora-core = "0.8.1"
pingora-proxy = "0.8.1"
pingora-http = "0.8.1"
pingora-limits = "0.8.1"
dashmap = "7.0.0-rc2"
pingora-core = "0.8.0"
pingora-proxy = "0.8.0"
pingora-http = "0.8.0"
pingora-limits = "0.8.0"
async-trait = "0.1.89"
log = "0.4.30"
futures = "0.3.32"
notify = "9.0.0-rc.4"
axum = { version = "0.8.9" }
reqwest = { version = "0.13.4", features = ["json", "stream", "blocking"] }
serde_yml = "0.0.12"
serde = { version = "1.0.228", features = ["derive"] }
noyalib = { version = "0.0.8", features = ["compat-serde-yaml"] }
rand = "0.10.1"
base64 = "0.22.1"
jsonwebtoken = { version = "10.4.0", default-features = false, features = ["use_pem", "rust_crypto"] }
@@ -41,7 +41,7 @@ arc-swap = "1.9.1"
prometheus = "0.14.0"
x509-parser = "0.18.1"
rustls-pemfile = "2.2.0"
tower-http = { version = "0.6.11", features = ["fs"] }
tower-http = { version = "0.7.0", features = ["fs"] }
privdrop = "0.5.6"
serde_json = "1.0.150"
subtle = "2.6.1"
@@ -53,3 +53,4 @@ log4rs = "1.4.0"
mimalloc = { version = "0.1.52", default-features = false }
signal-hook = "0.4.4"
sd-notify = "0.5.0"
libc = "0.2.186"

View File

@@ -74,6 +74,7 @@ Built on Rust, on top of **Cloudflares Pingora engine**, **Aralez** delivers
| **proxy_address_tls** | 0.0.0.0:6194 | Aralez HTTPS bind address (Optional) |
| **proxy_configs** | /etc/aralez/ | Direcotry containing configuration files, must be writeable by user `aralez` |
| **upstreams_conf** | /etc/aralez/upstreams.yaml | Location of the upstreams file |
| **access_log** | access | Configure access logging. Values: `access, error` |
| **log_level** | info | Log level: `info`, `warn`, `error`, `debug`, `trace`, `off` |
| **log_file** | /full/path/to/aralez.log | Optional, the location of log file. If thi entry does not exist logs will be emitted to stdout. |
| **hc_method** | HEAD | Healthcheck method: HEAD, GET, POST (UPPERCASE) |

View File

@@ -1,23 +1,25 @@
# Main configuration file, applied on startup
threads: 12 # Number of daemon threads default setting
#runuser: pastor # Username for running aralez after dropping root privileges, requires program to start as root
#rungroup: pastor # Group for running aralez after dropping root privileges, requires program to start as root
#daemon: false # Run in background
runuser: aralez # Username for running aralez after dropping root privileges, requires program to start as root
rungroup: aralez # Group for running aralez after dropping root privileges, requires program to start as root
upstream_keepalive_pool_size: 500 # Pool size for upstream keepalive connections
#pid_file: /tmp/aralez.pid # Path to PID file
#error_log: /tmp/aralez_err.log # Path to error log
pid_file: /tmp/aralez.pid # Path to PID file
upgrade_sock: /tmp/aralez.sock # Path to socket file
config_api_enabled: true # Boolean to enable/disable remote config push capability.
config_address: 0.0.0.0+3000 # HTTP API address for pushing upstreams.yaml from remote location
proxy_address_http: 0.0.0.0:6193 # Proxy HTTP bind address
proxy_address_tls: 0.0.0.0:6194 # Optional, Proxy TLS bind address
proxy_configs: /opt/Rust/Projects/asyncweb/etc # Mandatory if proxy_address_tls set, should contain a certificate and key files strictly in a format {NAME}.crt, {NAME}.key.
config_address: 127.0.0.1:3000 # HTTP API address for pushing upstreams.yaml from remote location
proxy_address_http: 0.0.0.0:80 # Proxy HTTP bind address
proxy_address_tls: 0.0.0.0:443 # Optional, Proxy TLS bind address
proxy_configs: /opt/aralez/asyncweb/etc # Mandatory if proxy_address_tls set, should contain a certificate and key files strictly in a format {NAME}.crt, {NAME}.key.
proxy_tls_grade: high # Grade of TLS suite for proxy (high, medium, unsafe), matching grades of Qualys SSL Labs
upstreams_conf: /opt/Rust/Projects/asyncweb/etc/upstreams.yaml # the location of upstreams file
file_server_folder: /tmp/gazan # Optional, local folder to serve
file_server_address: 127.0.0.1:3002 # Optional, Local address for file server. Can set as upstream for public access.
upstreams_conf: /opt/aralez/etc/upstreams.yaml # the location of upstreams file
file_server_folder: /opt/aralez/public # Optional, local folder to serve
file_server_address: 0.0.0.0:3002 # Optional, Local address for file server. Can set as upstream for public access.
log_level: info # info, warn, error, debug, trace, off
#log_file: /tmp/aralez.log # Optional, the location of log file. If this entry does not exist logs will be emitted to stdout.
log_file: /tmp/aralez.log # Optional, the location of log file. If this entry does not exist logs will be emitted to stdout.
access_log: error # all, error, (Off if commented)
hc_method: HEAD # Healthcheck method (HEAD, GET, POST are supported) UPPERCASE
hc_interval: 2 #Interval for health checks in seconds
#master_key: 910517d9-f9a1-48de-8826-dbadacbd84af-cb6f830e-ab16-47ec-9d8f-0090de732774 # Mater key for working with API server and JWT Secret
tcp_keepalive_idle: 60 # Seconds of inactivity before the kernel starts sending keepalive probes to a downstream client
tcp_keepalive_interval: 10 # Seconds between individual keepalive probes if the client does not respond
tcp_keepalive_count: 5 # Number of unanswered probes before the kernel declares the connection dead and closes it

View File

@@ -1,19 +0,0 @@
provider: "file"
globals:
headers:
- "Access-Control-Allow-Origin:*"
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
- "Access-Control-Max-Age:86400"
- "X-Custom-Header:Something Special"
upstreams:
myip.netangels.net:
paths:
"/":
ssl: false
headers:
- "X-Proxy-From:Aralez"
servers:
- "192.168.221.213:8000"
- "192.168.221.214:8000"
- "192.168.221.210:8000"
- "192.168.221.212:8000"

View File

@@ -4,13 +4,10 @@ sticky_sessions: 172000
to_https: false
rate_limit: 500000
x4xx_limit: 100000
#server_headers:
# - "Y-Global-Something: Yes this is something"
#client_headers:
# - "Access-Control-Allow-Origin:*"
# - "Access-Control-Allow-Methods:POST, GET, OPTIONS"
# - "Access-Control-Max-Age:86400"
# - "Strict-Transport-Security:max-age=31536000; includeSubDomains; preload"
server_headers:
- "Y-Global-Something: Something For Servers"
client_headers:
- "X-Global-Something: Something For Clients"
#authorization:
# type: "basic"
# data: "root:toor"
@@ -38,10 +35,10 @@ kubernetes:
servers:
- "172.16.0.11:5443" # Gets KUBERNETES_SERVICE_HOST : KUBERNETES_SERVICE_PORT_HTTPS env variables.
services:
- hostname: "api-service-v2"
upstream: "api-service-v2"
- hostname: "api-service"
upstream: "api-service"
path: "/"
- hostname: "api-service-v2"
- hostname: "api-service"
upstream: "console-service"
path: "/one"
client_headers:
@@ -49,7 +46,7 @@ kubernetes:
- "X-Proxy-From:Aralez"
rate_limit: 100
to_https: false
- hostname: "api-service-v2"
- hostname: "api-service"
upstream: "feed-fanout-service"
path: "/two"
- hostname: "websocket-service"
@@ -57,65 +54,51 @@ kubernetes:
path: "/"
tokenpath: "/opt/Rust/Projects/asyncweb/etc/kubetoken.txt" # Defaults to /var/run/secrets/kubernetes.io/serviceaccount/token
upstreams:
myip.netangels.net:
www.example.com:
paths:
"/":
# rate_limit: 50
# x4xx_limit: 100
# to_https: false
# authorization:
# type: "basic"
# data: "root:toor"
rate_limit: 50
x4xx_limit: 100
to_https: false
authorization:
type: "basic"
data: "root:toor"
server_headers:
- "Y-Proxy-Server-Some:Yaaaaaaaaaaaaaaa"
- "Y-Proxy-Server-From:Aralez"
- "Y-Proxy-Server-Vers:Aralez v0.89"
- "Y-Proxy-Server-Vers:Aralez v-xxx"
client_headers:
- "X-Proxy-From:Aralezzzzzzzzzzz"
- "X-Hopar-From:Hopaaaaaaaaaaaar"
- "X-Proxy-Some:X-Proxy-Somebody"
- "Access-Control-Allow-Origin:*"
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
- "Access-Control-Max-Age:86400"
- "Strict-Transport-Security:max-age=31536000; includeSubDomains; preload"
servers:
- "127.0.0.1:8000"
- "127.0.0.2:8000"
- "127.0.0.3:8000"
- "127.0.0.4:8000"
- "127.0.0.5:8000"
- "192.168.1.1:8000"
"/ping":
to_https: false
to_https: true
client_headers:
- "X-Some-Thing:Yaaaaaaaaaaaaaaa"
- "X-Proxy-From:Aralez"
servers:
- "127.0.0.1:8000"
- "127.0.0.2:8000"
"/pong":
to_https: false
client_headers:
- "X-Some-Thing:Yaaaaaaaaaaaaaaa"
- "X-Proxy-From:Aralez"
- "X-Some-Thing:Something Else"
- "Access-Control-Allow-Origin:*"
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
- "Access-Control-Max-Age:86400"
- "Strict-Transport-Security:max-age=31536000; includeSubDomains; preload"
servers:
- "127.0.0.1:8000"
"/secret":
authorization:
type: "forward"
data: "http://192.168.1.1:8899/admin/login"
#data: "https://netangels.net/admin/login"
data: "http://127.0.0.1:8899/admin/login"
servers:
- "192.168.1.10:8000"
netangels.net:
- "127.0.0.10:8000"
example.com:
paths:
"/":
redirect_to: "https://www.netangels.net:6194"
redirect_to: "https://www.example.com:443"
servers:
- "192.168.1.1:80"
www.netangels.net:
paths:
"/":
to_https: true
servers:
- "192.168.1.1:80"
apt.netangels.net:
- "127.0.0.1:80"
h2.example.com:
paths:
"/":
server_headers:
@@ -124,9 +107,8 @@ upstreams:
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
rate_limit: 60
x4xx_limit: 30
#authorization:
# type: "jwt"
# data: "SOMETHING"
authorization:
type: "jwt"
servers:
- "127.0.0.1:8000"
- "127.0.0.2:8000"
@@ -138,51 +120,12 @@ upstreams:
rate_limit: 4
x4xx_limit: 2
servers:
- "192.168.1.1:8899"
- "127.0.0.1:8899"
"/500":
healthcheck: false
servers:
- "192.168.1.1:8899"
# grafanalocal:
# paths:
# "/":
# healthcheck: false
# servers:
# - "95.211.203.222:443"
# "/.well-known/acme-challenge":
# healthcheck: false
# servers:
# - "127.0.0.1:8001"
localpost:
paths:
"/":
to_https: true
servers:
- "127.0.0.1:9000"
# 192.168.177.2:
# paths:
# "/":
# servers:
# - "127.0.0.1:8000"
ara.matyan.org:
paths:
"/":
servers:
- "127.0.0.1:8000"
"/.well-known/acme-challenge":
healthcheck: false
servers:
- "127.0.0.1:3000"
aro.matyan.org:
paths:
"/":
servers:
- "127.0.0.1:8000"
"/.well-known/acme-challenge":
healthcheck: false
servers:
- "127.0.0.1:3000"
DEFAUwLT:
- "127.0.0.1:8899"
DEFAULT:
paths:
"/":
healthcheck: false

View File

@@ -108,7 +108,7 @@ pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>,
}
};
let mut parsed: Config = match serde_yml::from_str(&yaml_data) {
let mut parsed: Config = match noyalib::from_str(&yaml_data) {
Ok(cfg) => cfg,
Err(e) => {
error!("Failed to parse upstreams file: {}", e);
@@ -118,7 +118,7 @@ pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>,
if let Some(ref mut upstreams) = parsed.upstreams {
for uconf in conf_files {
let p: HashMap<String, HostConfig> = match serde_yml::from_str(&uconf) {
let p: HashMap<String, HostConfig> = match noyalib::from_str(&uconf) {
Ok(ucfg) => ucfg,
Err(e) => {
error!("Failed to parse upstreams file: {}", e);
@@ -264,19 +264,13 @@ async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
}
pub fn parce_main_config(path: &str) -> AppConfig {
let data = fs::read_to_string(path).unwrap();
let reply = DashMap::new();
let cfg: HashMap<String, String> = serde_yml::from_str(&data).expect("Failed to parse main config file");
let mut cfo: AppConfig = serde_yml::from_str(&data).expect("Failed to parse main config file");
let mut cfo: AppConfig = noyalib::from_str(&data).expect("Failed to parse main config file");
if let Ok(jwt_key) = env::var("JWT_KEY") {
cfo.master_key = Some(jwt_key);
};
log_builder(&cfo, &cfo.log_file);
cfo.hc_method = cfo.hc_method.to_uppercase();
for (k, v) in cfg {
reply.insert(k.to_string(), v.to_string());
}
if let Some((ip, port_str)) = cfo.config_address.split_once(':') {
if let Ok(port) = port_str.parse::<u16>() {
cfo.local_server = Option::from((ip.to_string(), port));

View File

@@ -112,6 +112,7 @@ pub struct AppConfig {
pub hc_method: String,
pub upstreams_conf: String,
pub log_level: String,
pub access_log: Option<String>,
pub pid_file: Option<String>,
pub master_key: Option<String>,
pub config_address: String,

View File

@@ -10,9 +10,12 @@ use sha2::{Digest, Sha256};
use std::any::type_name;
use std::collections::{HashMap, HashSet};
use std::fmt::Write;
use std::fs::OpenOptions;
use std::io::Write as IoWrite;
use std::net::SocketAddr;
use std::net::TcpListener;
use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::OpenOptionsExt;
use std::str::FromStr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender};
@@ -380,3 +383,14 @@ pub fn prepend(prefix: &str, val: &Option<Arc<str>>, uri: &str, port: &str) -> O
buf
})
}
pub fn write_pid_file(path: &str) -> std::io::Result<()> {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.custom_flags(libc::O_NOFOLLOW) // refuse to follow symlinks
.open(path)?;
file.write_all(process::id().to_string().as_bytes())?;
Ok(())
}

View File

@@ -1,6 +1,7 @@
pub mod acme;
pub mod bgservice;
pub mod gethosts;
pub mod logging;
pub mod proxyhttp;
pub mod start;
pub mod webserver;

57
src/web/logging.rs Normal file
View File

@@ -0,0 +1,57 @@
use log::info;
use pingora_proxy::Session;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::OnceLock;
pub static ACCESS_LOG: OnceLock<LogLevel> = OnceLock::new();
pub fn init_access_log(level_str: &str) {
let level = LogLevel::from_str(level_str);
let _ = ACCESS_LOG.set(level);
}
pub enum LogLevel {
Access,
Error,
None,
}
impl LogLevel {
pub fn from_str(s: &str) -> Self {
match s {
"all" => LogLevel::Access,
"error" => LogLevel::Error,
_ => LogLevel::None,
}
}
}
pub fn access_log(response_code: u16, summary: &str, session: &Session) {
let level = ACCESS_LOG.get().unwrap_or(&LogLevel::None);
let should_log = match level {
LogLevel::Access => true,
LogLevel::None => false,
LogLevel::Error => !(100..=399).contains(&response_code),
};
if !should_log {
return;
}
let ip = session
.client_addr()
.and_then(|addr| addr.as_inet())
.map(|addr| addr.ip())
.unwrap_or(IpAddr::V4(Ipv4Addr::LOCALHOST));
let user_agent = session.req_header().headers.get("user-agent").and_then(|v| v.to_str().ok()).unwrap_or("-");
info!(
"{}, response code: {response_code}, client: {}, version: {:?}, useragent: {}",
summary,
ip,
session.req_header().version,
user_agent,
);
}

View File

@@ -3,10 +3,11 @@ use crate::utils::lazylock::{LOCALHOST, RATE_LIMITER, REQUESTS_4XX, REVERSE_STOR
use crate::utils::metrics::*;
use crate::utils::structs::{AppConfig, Extraparams, Headers, InnerMap, UpstreamsDashMap, UpstreamsIdMap};
use crate::web::gethosts::{GetHost, GetHostsReturHeaders};
use crate::web::logging::access_log;
use arc_swap::ArcSwap;
use async_trait::async_trait;
use axum::body::Bytes;
use log::{debug, error, warn};
use log::error;
use pingora::http::{RequestHeader, ResponseHeader, StatusCode};
use pingora::prelude::*;
use pingora::ErrorSource::Upstream;
@@ -20,10 +21,6 @@ use std::sync::Arc;
use tokio::time::Instant;
thread_local! {static IP_BUFFER: RefCell<String> = RefCell::new(String::with_capacity(50));}
// static REVERSE_STORE: LazyLock<DashMap<String, String>> = LazyLock::new(DashMap::new);
// pub static RATE_LIMITER: LazyLock<Rate> = LazyLock::new(|| Rate::new(Duration::from_secs(1)));
// pub static REQUESTS_4XX: LazyLock<Cache<IpAddr, u32>> = LazyLock::new(|| Cache::builder().time_to_live(Duration::from_secs(1)).build());
// pub static LOCALHOST: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("localhost"));
#[derive(Clone)]
pub struct LB {
@@ -86,7 +83,6 @@ impl ProxyHttp for LB {
if let Some(auth) = _ctx.extraparams.authentication.as_ref().or(innermap.authorization.as_ref()) {
if !authenticate(&auth, session).await {
let _ = session.respond_error(401).await;
warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path());
return Ok(true);
}
}
@@ -99,9 +95,9 @@ impl ProxyHttp for LB {
let header = ResponseHeader::build(429, None)?;
session.set_keepalive(None);
session.write_response_header(Box::new(header), true).await?;
if let (Some(oi), Some(oa)) = (&_ctx.hostname, rate_key) {
warn!("Limit 4XX: {}-rps exceed on {} from {} path {}", rate, oi, oa, session.req_header().uri.path());
}
// if let (Some(oi), Some(oa)) = (&_ctx.hostname, rate_key) {
// warn!("Limit 4XX: {}-rps exceed on {} from {} path {}", rate, oi, oa, session.req_header().uri.path());
// }
return Ok(true);
}
}
@@ -113,9 +109,9 @@ impl ProxyHttp for LB {
let header = ResponseHeader::build(429, None)?;
session.set_keepalive(None);
session.write_response_header(Box::new(header), true).await?;
if let (Some(oi), Some(oa)) = (&_ctx.hostname, rate_key) {
warn!("Limit: {}-rps exceed on {} from {}", rate, oi, oa);
}
// if let (Some(oi), Some(oa)) = (&_ctx.hostname, rate_key) {
// warn!("Limit: {}-rps exceed on {} from {}", rate, oi, oa);
// }
return Ok(true);
}
}
@@ -281,14 +277,12 @@ impl ProxyHttp for LB {
REVERSE_STORE.insert(hh.clone(), bid.clone());
hh
};
// let _ = _upstream_response.insert_header("set-cookie", format!("backend_id={}; Path=/; Max-Age=600; HttpOnly; SameSite=Lax", tt));
let mut buf = String::with_capacity(80);
buf.push_str("backend_id=");
buf.push_str(&tt);
buf.push_str("; Path=/; Max-Age=");
buf.push_str(&val.to_string());
buf.push_str("; HttpOnly; SameSite=Lax");
// buf.push_str("; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax");
let _ = _upstream_response.insert_header("set-cookie", buf.as_str());
}
}
@@ -303,7 +297,6 @@ impl ProxyHttp for LB {
async fn logging(&self, session: &mut Session, _e: Option<&pingora::Error>, ctx: &mut Self::CTX) {
let response_code = session.response_written().map_or(0, |resp| resp.status.as_u16());
debug!("{}, response code: {response_code}", self.request_summary(session, ctx));
let m = &MetricTypes {
method: session.req_header().method.clone(),
code: session.response_written().map(|resp| resp.status),
@@ -314,13 +307,14 @@ impl ProxyHttp for LB {
calc_metrics(m);
ACTIVE_SESSIONS.dec();
if let Some(_) = ctx.x4xx_limit.or(ctx.extraparams.x4xx_limit) {
if 400 <= response_code && response_code <= 499 {
if (400..=499).contains(&response_code) {
if let Some(ip) = session.client_addr().and_then(|a| a.as_inet()).map(|i| i.ip()) {
let current = REQUESTS_4XX.get(&ip).unwrap_or(0);
REQUESTS_4XX.insert(ip, current + 1);
}
}
}
access_log(response_code, &self.request_summary(session, ctx), session);
}
}

View File

@@ -4,6 +4,7 @@ use crate::tls::load;
use crate::tls::load::CertificateConfig;
use crate::utils::structs::Extraparams;
use crate::utils::tools::*;
use crate::web::logging::init_access_log;
use crate::web::proxyhttp::LB;
use arc_swap::ArcSwap;
use dashmap::DashMap;
@@ -23,7 +24,7 @@ use signal_hook::{
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::time::Duration;
use std::{fs, process, thread};
use std::{fs, thread};
pub fn run() {
// default_provider().install_default().expect("Failed to install rustls crypto provider");
@@ -59,6 +60,8 @@ pub fn run() {
server_headers: sh_config,
extraparams: ec_config,
};
let al = cfg.access_log.clone().unwrap_or("none".to_string());
init_access_log(al.as_str());
let grade = cfg.proxy_tls_grade.clone().unwrap_or("medium".to_string());
info!("TLS grade set to: [ {} ]", grade);
@@ -146,8 +149,11 @@ pub fn run() {
drop_priv(user, group, cfg.proxy_address_http.clone(), cfg.proxy_address_tls.clone());
}
let _ = sd_notify::notify(&[NotifyState::Ready]);
let _ = fs::write(cfg.pid_file.clone().unwrap_or("/tmp/aralez.pid".to_string()), process::id().to_string());
let pf = cfg.pid_file.clone().unwrap_or("/tmp/aralez.pid".to_string());
if let Err(e) = write_pid_file(pf.as_str()) {
panic!("Failed to write PID file: {} : {}", pf, e);
}
let mut signals = Signals::new(&[SIGINT, SIGTERM, SIGQUIT]).unwrap();
for sig in signals.forever() {
match sig {

View File

@@ -102,7 +102,7 @@ async fn conf(State(st): State<AppState>, Query(params): Query<HashMap<String, S
}
let strcontent = content.as_str();
let parsed = serde_yml::from_str::<Config>(strcontent);
let parsed = noyalib::from_str::<Config>(strcontent);
match parsed {
Ok(_) => {
if let Some(_) = params.get("save") {
@@ -228,8 +228,7 @@ async fn status(State(st): State<AppState>, Query(params): Query<HashMap<String,
}
pub async fn port_is_available(name: &str, address: &str) -> TcpListener {
let addr = SocketAddr::from_str(address)
.unwrap_or_else(|e| panic!("{}: Invalid address format: {:?}", name, e));
let addr = SocketAddr::from_str(address).unwrap_or_else(|e| panic!("{}: Invalid address format: {:?}", name, e));
let t = Duration::from_secs(2);
//if addr.ip() == IpAddr::V4(Ipv4Addr::UNSPECIFIED) {