22 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
Ara Sadoyan
162c5060c9 cleanup, minor fix 2026-06-10 11:46:30 +02:00
Ara Sadoyan
132cf45dfe cleanup, minor fix 2026-06-10 11:29:35 +02:00
Ara Sadoyan
77dcafbb4e tcp_keepalive options for kernel timer 2026-06-09 17:53:04 +02:00
Ara Sadoyan
649bd979f7 socker address #41 2026-06-07 12:07:06 +02:00
Ara Sadoyan
bd315106b9 Merge pull request #41 from Taqman-probe/fix/TcpListener-bind
Fix TcpListener binding and port availability check
2026-06-07 11:57:06 +02:00
Ara Sadoyan
3ba2ed33ae cargo.toml 2026-06-07 11:38:50 +02:00
Taqman-probe
c09efab9fd prevent panic when parsing invalid address without port 2026-06-07 00:47:43 +09:00
Taqman-probe
735d605f6d prevent panic when parsing invalid address without port 2026-06-06 22:32:32 +09:00
Ara Sadoyan
6773d0f502 Cargo 2026-06-04 19:12:50 +02:00
Ara Sadoyan
a8cb727da5 Cargo Licence 2026-06-04 18:39:02 +02:00
Ara Sadoyan
f81194aee7 Cargo Licence 2026-06-04 18:38:47 +02:00
Ara Sadoyan
0f09a2e02b Roll back to MiMalloc 2026-06-04 18:14:22 +02:00
Ara Sadoyan
27aca0a3a5 Roll back to MiMalloc 2026-06-04 17:03:19 +02:00
17 changed files with 413 additions and 284 deletions

7
.gitignore vendored
View File

@@ -5,13 +5,13 @@
*.dll
*.exe
*.sh
/docs/
*.yaml
/docs
/etc
assets/
assets
/target/
*.iml
.idea/
.etc/
*.ipr
*.iws
/out/
@@ -22,4 +22,5 @@ crashlytics.properties
crashlytics-build.properties
/target
/z_shpo
/configs
Makefile

212
Cargo.lock generated
View File

@@ -127,7 +127,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "aralez"
version = "0.9.2"
version = "0.92.11"
dependencies = [
"ahash",
"arc-swap",
@@ -139,10 +139,13 @@ dependencies = [
"futures",
"instant-acme",
"jsonwebtoken",
"libc",
"log",
"log4rs",
"mimalloc",
"moka",
"notify",
"noyalib",
"pingora",
"pingora-core",
"pingora-http",
@@ -157,15 +160,12 @@ dependencies = [
"sd-notify",
"serde",
"serde_json",
"serde_yml",
"sha2 0.11.0",
"signal-hook",
"subtle",
"tikv-jemalloc-ctl",
"tikv-jemallocator",
"tokio",
"tonic",
"tower-http",
"tower-http 0.7.0",
"urlencoding",
"x509-parser",
]
@@ -473,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",
@@ -1713,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",
@@ -1872,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",
@@ -1882,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",
@@ -1918,13 +1918,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libyml"
version = "0.0.5"
name = "libmimalloc-sys"
version = "0.1.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
dependencies = [
"anyhow",
"version_check",
"cc",
]
[[package]]
@@ -2043,6 +2042,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "mimalloc"
version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
dependencies = [
"libmimalloc-sys",
]
[[package]]
name = "mime"
version = "0.3.17"
@@ -2202,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"
@@ -2428,12 +2452,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pem"
version = "3.0.6"
@@ -2497,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",
@@ -2511,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",
@@ -2548,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",
@@ -2600,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",
@@ -2622,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",
@@ -2633,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",
@@ -2673,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",
@@ -2685,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",
@@ -2698,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",
@@ -2713,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",
@@ -2736,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",
@@ -2748,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",
@@ -3173,7 +3191,7 @@ dependencies = [
"tokio-rustls",
"tokio-util",
"tower",
"tower-http",
"tower-http 0.6.11",
"tower-service",
"url",
"wasm-bindgen",
@@ -3497,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"
@@ -3546,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"
@@ -3880,37 +3893,6 @@ dependencies = [
"trackable",
]
[[package]]
name = "tikv-jemalloc-ctl"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a184c43b8ab2f41df2733b55556e3f5f632f4aeaa205b1bb018f574b7f5f142"
dependencies = [
"libc",
"paste",
"tikv-jemalloc-sys",
]
[[package]]
name = "tikv-jemalloc-sys"
version = "0.7.1+5.3.1-0-g81034ce1f1373e37dc865038e1bc8eeecf559ce8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a2825c78386b4ae0314074867860ba9577875de945f05992c38815cbec327f0"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "tikv-jemallocator"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "249f09e49ab1609436f34c776e84231bead18d6a955f119f939bdc1d847561bd"
dependencies = [
"libc",
"tikv-jemalloc-sys",
]
[[package]]
name = "time"
version = "0.3.47"
@@ -4104,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",
@@ -4120,10 +4120,8 @@ dependencies = [
"pin-project-lite",
"tokio",
"tokio-util",
"tower",
"tower-layer",
"tower-service",
"url",
]
[[package]]

View File

@@ -1,7 +1,11 @@
[package]
name = "aralez"
version = "0.9.2"
version = "0.92.11"
edition = "2021"
license = "Apache-2.0"
description = "Reverse proxy built on top of Cloudflare's Pingora"
exclude = ["configs/*"]
repository = "https://github.com/sadoyan/aralez"
[profile.release]
opt-level = 3
@@ -12,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"] }
@@ -37,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"
@@ -46,8 +50,7 @@ ahash = "0.8.12"
instant-acme = "0.8.5"
rcgen = "0.14.8"
log4rs = "1.4.0"
#mimalloc = { version = "0.1.52", default-features = false }
tikv-jemallocator = "0.7.0"
tikv-jemalloc-ctl = { version = "0.7.0", features = ["stats"] }
mimalloc = { version = "0.1.52", default-features = false }
signal-hook = "0.4.4"
sd-notify = "0.5.0"
libc = "0.2.186"

View File

@@ -9,13 +9,23 @@
Aralez is a high-performance Rust reverse proxy with zero-configuration automatic protocol handling, TLS, and upstream management,
featuring Consul and Kubernetes integration for dynamic pod discovery and health-checked routing, acting as a lightweight ingress-style proxy.
---
What Aralez means ?
**Aralez = Արալեզ** <ins>Named after the legendary Armenian guardian spirit, winged dog-like creature, that descend upon fallen heroes to lick their wounds and resurrect them</ins>.
Built on Rust, on top of **Cloudflares Pingora engine**, **Aralez** delivers world-class performance, security and scalability — right out of the box.
[![Buy Me A Coffee](https://img.shields.io/badge/☕-Buy%20me%20a%20coffee-orange)](https://www.buymeacoffee.com/sadoyan)
---
## Links
- [**Documentation**](https://aralez.rs) : The manual you should read
- [**Downloads**](https://github.com/sadoyan/aralez/releases) : Binary downloads
- [**Issues**](https://github.com/sadoyan/aralez/issues) : Issues and requests
- [**Crates**](https://crates.io/crates/aralez) : The Rust crate registry
- [**DockerHUB**](https://hub.docker.com/r/sadoyan/aralez) : DockerHUB official repository
- [**GitHUB Packages**](https://github.com/sadoyan/aralez/pkgs/container/aralez) : GitHUB ghcr.io images
---
@@ -64,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) |
@@ -107,6 +118,9 @@ For getting the best performance on newer hardware use `aralez-x86_64-*.gz`.
```shell
docker run -d -v /path/to/config:/etc/aralez:rw -p 80:80 -p 443:443 sadoyan/aralez
docker run -d -v /path/to/config:/etc/aralez:rw -p 80:80 -p 443:443 sadoyan/aralez:compat
docker run -d -v /path/to/config:/etc/aralez:rw -p 80:80 -p 443:443 ghcr.io/sadoyan/aralez:latest
docker run -d -v /path/to/config:/etc/aralez:rw -p 80:80 -p 443:443 ghcr.io/sadoyan/aralez:compat
```
**Dockerfile :**
@@ -554,10 +568,3 @@ The results show requests per second performed by Load balancer. You can see 3 b
1. Requests via http1.1 to plain text endpoint.
2. Requests to via http2 to SSL endpoint.
3. Mixed workload with plain http1.1 and htt2 SSL.
## Links
- [**Documentation**](https://aralez.rs) : The manual you should read
- [**Downloads**](https://github.com/sadoyan/aralez/releases) : Binary downloads
- [**Issues**](https://github.com/sadoyan/aralez/issues) : Issues and requests

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
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: /opt/storage # 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.
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

@@ -1,49 +1,44 @@
# The file under watch and hot reload, changes are applied immediately, no need to restart or reload.
provider: "file" # "file" "consul" "kubernetes"
sticky_sessions: 8600
sticky_sessions: 172000
to_https: false
rate_limit: 300
x4xx_limit: 200
rate_limit: 500000
x4xx_limit: 100000
server_headers:
- "X-Forwarded-Proto:https"
- "X-Forwarded-Port:443"
- "Y-Global-Something: Something For Servers"
client_headers:
- "Access-Control-Allow-Origin:*"
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
- "Access-Control-Max-Age:86400"
- "X-Global-Something: Something For Clients"
#authorization:
# type: "jwt"
# creds: "910517d9-f9a1-48de-8826-dbadacbd84af-cb6f830e-ab16-47ec-9d8f-0090de732774"
# type: "basic"
# creds: "username:Pa$$w0rd"
# data: "root:toor"
# type: "jwt"
# data: "910517d9-f9a1-48de-8826-dbadacbd84af-cb6f830e-ab16-47ec-9d8f-0090de732774"
# type: "apikey"
# creds: "5ecbf799-1343-4e94-a9b5-e278af5cd313-56b45249-1839-4008-a450-a60dc76d2bae"
# data: "5ecbf799-1343-4e94-a9b5-e278af5cd313-56b45249-1839-4008-a450-a60dc76d2bae"
consul:
servers:
- "http://192.168.1.199:8500"
- "http://192.168.1.200:8500"
- "http://192.168.1.201:8500"
- "http://consul1:8500"
services: # hostname: The hostname to access the proxy server, upstream : The real service name in Consul database.
- hostname: "webapi-service"
upstream: "webapi-service-health"
- hostname: "nconsul"
upstream: "nginx-consul-NginX-health"
path: "/one"
client_headers:
- "X-Some-Thing:Yaaaaaaaaaaaaaaa"
- "X-Proxy-From:Aralez"
rate_limit: 1
to_https: false
- hostname: "webapi-service"
upstream: "webapi-service-health"
- hostname: "nconsul"
upstream: "nginx-consul-NginX-health"
path: "/"
token: "8e2db809-845b-45e1-8b47-2c8356a09da0-a4370955-18c2-4d6e-a8f8-ffcc0b47be81" # Consul server access token, If Consul auth is enabled
kubernetes:
servers:
- "192.168.1.55:443" #For testing only, overrides with KUBERNETES_SERVICE_HOST : KUBERNETES_SERVICE_PORT_HTTPS env variables.
- "172.16.0.11:5443" # Gets KUBERNETES_SERVICE_HOST : KUBERNETES_SERVICE_PORT_HTTPS env variables.
services:
- hostname: "webapi-service"
- hostname: "api-service"
upstream: "api-service"
path: "/"
upstream: "webapi-service"
- hostname: "webapi-service"
- hostname: "api-service"
upstream: "console-service"
path: "/one"
client_headers:
@@ -51,71 +46,92 @@ kubernetes:
- "X-Proxy-From:Aralez"
rate_limit: 100
to_https: false
- hostname: "webapi-service"
upstream: "rambul-service"
- hostname: "api-service"
upstream: "feed-fanout-service"
path: "/two"
- hostname: "websocket-service"
upstream: "websocket-service"
path: "/"
tokenpath: "/path/to/kubetoken.txt" #If not set, will default to /var/run/secrets/kubernetes.io/serviceaccount/token
tokenpath: "/opt/Rust/Projects/asyncweb/etc/kubetoken.txt" # Defaults to /var/run/secrets/kubernetes.io/serviceaccount/token
upstreams:
myip.mydomain.com:
www.example.com:
paths:
"/":
rate_limit: 200
rate_limit: 50
x4xx_limit: 100
to_https: false
client_headers:
- "X-Proxy-From:Aralez"
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"
"/ping":
authorization: # Will be ignored if global authentication is enabled.
authorization:
type: "basic"
creds: "admin:admin"
to_https: false
data: "root:toor"
server_headers:
- "X-Forwarded-Proto:https"
- "X-Forwarded-Port:443"
- "Y-Proxy-Server-Some:Yaaaaaaaaaaaaaaa"
- "Y-Proxy-Server-From:Aralez"
- "Y-Proxy-Server-Vers:Aralez v-xxx"
client_headers:
- "X-Some-Thing:Yaaaaaaaaaaaaaaa"
- "X-Proxy-From:Aralez"
- "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"
"/draw":
servers:
- "192.168.1.1:8000"
polo.mydomain.com:
paths:
"/":
to_https: false
client_headers:
- "X-Some-Thing:Yaaaaaaaaaaaaaaa"
servers:
- "192.168.1.1:8000"
- "192.168.1.10:8000"
- "127.0.0.1:8000"
- "127.0.0.2:8000"
- "127.0.0.3:8000"
- "127.0.0.4:8000"
apt.mydomain.com:
"/ping":
to_https: true
client_headers:
- "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://127.0.0.1:8899/admin/login"
servers:
- "127.0.0.10:8000"
example.com:
paths:
"/":
redirect_to: "https://www.example.com:443"
servers:
- "192.168.1.10:443"
- "127.0.0.1:80"
h2.example.com:
paths:
"/":
server_headers:
- "Y-Global-Something: Yes this is something"
client_headers:
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
rate_limit: 60
x4xx_limit: 30
authorization:
type: "jwt"
servers:
- "127.0.0.1:8000"
- "127.0.0.2:8000"
"/.well-known/acme-challenge":
healthcheck: false
servers:
- "127.0.0.1:8001"
rdr.mydomain.com:
paths:
"/":
redirect_to: "https://som.other.domain:6194"
"/400":
rate_limit: 4
x4xx_limit: 2
servers:
- "127.0.0.1:8899"
"/500":
healthcheck: false
servers:
- "127.0.0.1:8080"
- "127.0.0.1:8899"
DEFAULT:
paths:
"/":
healthcheck: false
servers:
- "127.0.0.1:3000"
"/.well-known/acme-challenge":
healthcheck: false
servers:
- "127.0.0.1:3000"

View File

@@ -1,14 +1,16 @@
use tikv_jemallocator::Jemalloc;
mod tls;
mod utils;
mod web;
#[global_allocator]
static ALLOC: Jemalloc = Jemalloc;
// static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
// pub static A: CountingAllocator = CountingAllocator;
fn main() {
if std::env::args().any(|a| a == "--version" || a == "-v") {
println!("aralez {}", env!("CARGO_PKG_VERSION"));
std::process::exit(0);
}
web::start::run();
}

View File

@@ -5,7 +5,6 @@ use prometheus::{register_histogram, register_int_counter, register_int_counter_
use std::sync::Arc;
use std::sync::LazyLock;
use std::time::Duration;
use tikv_jemalloc_ctl::{epoch, stats};
pub struct MetricTypes {
pub method: Method,
@@ -66,9 +65,17 @@ pub fn calc_metrics(metric_types: &MetricTypes) {
RESPONSE_LATENCY.observe(metric_types.latency.as_secs_f64());
}
pub fn get_memory_usage() -> usize {
epoch::mib().unwrap().advance().unwrap(); // refresh stats
stats::allocated::mib().unwrap().read().unwrap() // bytes allocated
pub(crate) fn get_memory_usage() -> usize {
std::fs::read_to_string("/proc/self/status")
.ok()
.and_then(|s| {
s.lines()
.find(|l| l.starts_with("VmRSS:"))
.and_then(|l| l.split_whitespace().nth(1))
.and_then(|v| v.parse::<usize>().ok())
})
.unwrap_or(0)
* 1024
}
pub fn get_open_files() -> usize {

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,8 @@ 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,
pub proxy_address_http: String,
@@ -130,6 +132,9 @@ pub struct AppConfig {
pub runuser: Option<String>,
pub rungroup: Option<String>,
pub log_file: Option<String>,
pub tcp_keepalive_idle: Option<u64>,
pub tcp_keepalive_interval: Option<u64>,
pub tcp_keepalive_count: Option<usize>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]

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};
@@ -274,7 +277,7 @@ pub fn drop_priv(user: String, group: String, http_addr: String, tls_addr: Optio
}
pub fn check_priv(addr: &str) {
let port = SocketAddr::from_str(addr).map(|sa| sa.port()).unwrap();
let port = SocketAddr::from_str(addr).map(|sa| sa.port()).expect("Failed to parse address port ");
if port < 1024 {
let meta = std::fs::metadata("/proc/self").map(|m| m.uid()).unwrap();
if meta != 0 {
@@ -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);
}
}
@@ -177,6 +173,20 @@ impl ProxyHttp for LB {
peer.options.verify_cert = false;
peer.options.verify_hostname = false;
}
/*
Experimental optionsv
The following TCP optimizations were tested but caused performance degrade under heavy load:
peer.options.tcp_keepalive = Some(TcpKeepalive {
idle: Duration::from_secs(60),
interval: Duration::from_secs(10),
count: 5,
user_timeout: Duration::from_secs(30),
});
peer.options.idle_timeout = Some(Duration::from_secs(300));
peer.options.tcp_recv_buf = Some(128 * 1024);
End of experimental options
*/
if let Some(_) = ctx.extraparams.sticky_sessions {
let mut s = String::with_capacity(64);
write!(
@@ -267,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());
}
}
@@ -289,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),
@@ -300,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,13 +4,16 @@ 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;
use log::info;
use pingora::tls::ssl::{SslAlert, SslRef};
use pingora_core::listeners::tls::TlsSettings;
use pingora_core::listeners::TcpSocketOptions;
use pingora_core::prelude::{background_service, Opt};
use pingora_core::protocols::TcpKeepalive;
use pingora_core::server::Server;
use privdrop::reexports::libc::SIGQUIT;
use sd_notify::NotifyState;
@@ -21,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");
@@ -57,17 +60,41 @@ 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);
let bg_srvc = background_service("bgsrvc", lb.clone());
let mut proxy = pingora_proxy::http_proxy_service(&server.configuration, lb.clone());
let bind_address_http = cfg.proxy_address_http.clone();
let bind_address_tls = cfg.proxy_address_tls.clone();
let mut proxy = pingora_proxy::http_proxy_service(&server.configuration, lb.clone());
check_priv(bind_address_http.as_str());
// let mut tcp_options: Option<TcpSocketOptions> = Some(TcpSocketOptions::default());
// let mut tcp_options = TcpSocketOptions::default();
let mut tcp_options: Option<TcpSocketOptions> = None;
if let Some(idle) = cfg.tcp_keepalive_idle {
let mut to = TcpSocketOptions::default();
to.tcp_keepalive = Some(TcpKeepalive {
idle: Duration::from_secs(idle),
interval: Duration::from_secs(cfg.tcp_keepalive_interval.unwrap_or(10)),
user_timeout: Default::default(),
count: cfg.tcp_keepalive_count.unwrap_or(5usize),
});
tcp_options = Some(to);
info!(
"Applying kernel tcp_keepalive parameters: idle {}, interval {}, count {}",
idle,
cfg.tcp_keepalive_interval.unwrap_or(60),
cfg.tcp_keepalive_count.unwrap_or(5),
);
}
if let Some(bind_address_tls) = bind_address_tls {
check_priv(bind_address_tls.as_str());
let (tx, rx): (Sender<Vec<CertificateConfig>>, Receiver<Vec<CertificateConfig>>) = channel();
@@ -95,7 +122,7 @@ pub fn run() {
tls_settings.set_servername_callback(move |ssl_ref: &mut SslRef, ssl_alert: &mut SslAlert| certs_for_callback.load().server_name_callback(ssl_ref, ssl_alert));
tls_settings.set_alpn_select_callback(grades::prefer_h2);
proxy.add_tls_with_settings(&bind_address_tls, None, tls_settings);
proxy.add_tls_with_settings(&bind_address_tls, tcp_options.clone(), tls_settings);
let certs_for_watcher = certificates.clone();
thread::spawn(move || {
@@ -107,8 +134,13 @@ pub fn run() {
}
});
}
info!("Running HTTP listener on :{}", bind_address_http.as_str());
proxy.add_tcp(bind_address_http.as_str());
info!("Running HTTP listener on :{}", bind_address_http);
if let Some(tc) = tcp_options {
proxy.add_tcp_with_settings(&bind_address_http, tc);
} else {
proxy.add_tcp(&bind_address_http)
}
server.add_service(proxy);
server.add_service(bg_srvc);
thread::spawn(move || server.run_forever());
@@ -117,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("/tmp/aralez.pid", 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

@@ -18,6 +18,8 @@ use prometheus::{gather, Encoder, TextEncoder};
use serde::Serialize;
use signal_hook::{consts::SIGQUIT, iterator::Signals};
use std::collections::HashMap;
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::net::TcpListener;
@@ -67,16 +69,14 @@ pub async fn run_server(config: &APIUpstreamProvider, mut to_return: Sender<Conf
let mut static_handle: Option<tokio::task::JoinHandle<()>> = None;
if let (Some(address), Some(folder)) = (&config.file_server_address, &config.file_server_folder) {
port_is_available("File Server", &address).await;
let static_listen = port_is_available("File Server", &address).await;
let static_files = ServeDir::new(folder);
let static_serve: Router = Router::new().fallback_service(static_files);
let static_listen = TcpListener::bind(address).await.unwrap();
// drop(tokio::spawn(async move { axum::serve(static_listen, static_serve).await.unwrap() }));
static_handle = Some(tokio::spawn(async move { axum::serve(static_listen, static_serve).await.unwrap() }))
}
port_is_available("Config API", &config.address).await;
let listener = TcpListener::bind(config.address.clone()).await.unwrap();
let listener = port_is_available("Config API", &config.address).await;
info!("Starting the API server on: {}", config.address);
let api_server = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() });
@@ -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") {
@@ -227,20 +227,18 @@ async fn status(State(st): State<AppState>, Query(params): Query<HashMap<String,
.unwrap()
}
pub async fn port_is_available(name: &str, address: &str) {
let addr_port = address.split(":").collect::<Vec<&str>>();
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 t = Duration::from_secs(2);
let mut a = addr_port[0];
if address == "0.0.0.0" {
a = "127.0.0.1";
}
let p = addr_port[1].parse::<u16>().unwrap();
//if addr.ip() == IpAddr::V4(Ipv4Addr::UNSPECIFIED) {
// addr.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
//}
let p = addr.port();
loop {
match TcpListener::bind((a, p)).await {
Ok(_) => {
break;
match TcpListener::bind(addr).await {
Ok(listener) => {
return listener;
}
Err(_) => {
warn!("{} port is not available: {} will try again in {:?}", name, p, t);