jgtv/joncswebserver

By jgtv

Updated about 2 months ago

High-performant webserver with Static files, C#, PHP-FPM, reverse proxy, and WASM support. 500K+

Image
Networking
Developer tools
Web servers
1

5.5K

jgtv/joncswebserver repository overview

This performance-focused, yet feature-rich webserver in dotNET 10 (.NET 10 / C#) utilizes Kestrel for the main webserver, a high-performance focused Csharp webserver library. JonCsWebServer is able to handle 80 000 to 800 000 req/s (or ~15-28 Gbps) on Intel Xeon E5-2680 V4 (2016 CPU!), it also comes with a lot of additional features compared to barebones Kestrel!

  • Easy to setup: Use JonCsWebConfig.json to configure the webserver.
  • Supports command-line arguments that can be used to override the config values directly, such as --httpPort=80,8080 --httpsPort=443,8443 (multi-port support!)
  • Commands through STDIN (console where you can execute commands in).
  • Static-files support: Serve HTML, MP4, and more! (In-built support for partial content.)
  • Reverse-proxy: Using i.e. Node.Js for backend systems? You can setup proxying. Works with WebSockets.
  • High-performant PHP-FPM support using FastCGI.
  • Supports loading your own compiled C# code for super fast backend scripting (.dll, rename to ._csdll. This is to avoid collisions with normal .dll-files.)
  • Alternatively use ._cs-files with raw C# code; webserver compiles live outside of request loop. Should have no performance loss.

Read more on our open source GitHub and GitLab!

Simply replace HTTPd with JonCsWebServer, setup php-fpm, and keep using your setup with a huge performance boost. Be bottlenecked by your network setup, not your software. JonCsWebServer also matches Nginx in throughput, so unless you have use of more advanced Nginx features, you can just use JonCsWebServer.

Quick run command:

docker run -v /var/www:/var/www \
           -v /path/to/config:/app/JonCsWebConfig.json \
           -p 80:80 -p 443:443 -it \
           jgtv/joncswebserver:linux-amd64
docker run -it -d --name joncsweb \
  -p 80:80 -p 443:443 \
  jgtv/joncswebserver:linux-amd64 \
  --httpPort=80 \
  --httpsPort=443
docker run -it -p 80:80 -p 443:443 jgtv/joncswebserver:windows

Tested and working: jgtv/joncswebserver:linux-amd64 jgtv/joncswebserver:windows

Benchmarks (using k6 on the same machine) (without docker):

  • 2x Intel Xeon E5-2680 V4: ~95_000-105_000 req/s at ~500% CPU utilization (~75000 req/s for serving 11.5KB html file).
  • AMD Ryzen 5 5600X: ~50000 req/s (~20000 req/s for files that are read per request)
  • 1-core 2GHz: ~2000 req/s, while Apache were at 360 req/s (~950 req/s when optimized)

Benchmarks (using wrk on the same machine) (without docker):

  • 2x Intel Xeon E5-2680 V4: ~650_000-770_000 req/s at ~2000% CPU utilization. (~200_000-300_000 req/s for serving 11.5KB html file. Over 50000 req/s for PHP-fpm).
  • AMD Ryzen 5 5600X: ~470_000 req/s at ~500% CPU utilization.

For reference, Rust with barebones Actix reaches ~1.1m RPS on 2x Intel Xeon E5-2680 V4, and roughly double the sendFile throughput (490K rps instead of 200K. With no middleware like compression, etc)

Configuration

JonCsWebConfig.json

The json below contains comments about what each option does. The out-of-the-box settings should be very similar.
DO NOT USE! IT WILL BREAK JSON SYNTAX.

{
  "Logging": false, // will write errors to `joncserror.log`, useful when a C#-endpoint errors.
  "DebugPages": false, // Show error pages (displays error as a html) when request errors. Recommended to only use during development and not on production.
  "ServerMetrics": false, // Tracks total requests, and latest rps, rpm, rph
  "LoopFindEndpoint": false, // If true, it tracks backwards until it finds an index (otherwise err404): /path1/path2/index.html -> /path1/path2 -> /path1 -> /
  "EnableHtaccess": false, // .htaccess-support
  "Enable_CS": true, // C#/._csdll-backend support
  "Enable_WASM": false, // ._wasm-backend support
  "AllowSynchronousIO": false,
  "ForceTLS": false, // Force TLS when proxying?
  "Rproxy_SslProtocol": "Tls13", // Set TLS-Protocol for Reverse-Proxy.
  "BufferFastCGIResponse": false, // Tweak PHP performance depending on high/low scale
  "Max_QUIC_Streams": 0,
  "MaxConcurrentConnections": null, // Max global concurrent HTTP(S)-connections
  "MaxConcurrentUpgradedConnections": 10000, // Max global concurrent WS(S)-connections
  "MaxRequestBodySize": 8000000000, // Max POST-length
  "HttpProxyTimeout": 300.0,
  "bytesPerSecond": 1.0, // Minimum bytes-per-second before WebServer temporarily blocks user. Set it low to avoid false-positives from skimming through videofiles.
  "gracePeriod": 5,
  "MaxBytesPerSecond": 0, // Limit outbound bandwidth per-client-IP
  "RequestTimeout": 0,
  "KeepAliveTimeout": 130,
  "RequestHeadersTimeout": 30,
  "RateLimitTime": 1, // 1 second. CF default: 10
  "RateLimitReq": 0, // Amount of requests within RateLimitTime before it ratelimits specific IP. Recommended: 500
  "RateLimitRefill": 100,
  "RateLimitQueue": 0,
  "MaxFilePathLength": 512,
  "FCGI_ReceiveTimeout": 300000,
  "FCGI_SendTimeout": 300000,
  "FCGI_MaxPoolSize": 20,
  "FCGI_QueueTimeout": 10,
  "FCGI_MaxConcurrentConnections": 5000,
  "ClearSessEveryXMin": 5,
  "WebSocketTimeout": 300,
  "WebSocketEndpointTimeout": 30,
  "MaxDirDepth": 15, // Max amount of slashes in the URL. /path1/path2/path3...
  "HttpsPorts": [ // --httpsPort=443,8443
    443, 8443
  ],
  "HttpPorts": [ // --httpPort=80,8080
    80, 8080
  ],
  "CertDir": "certs/", // certs -> domain1, domain2 -> privkey.pem, fullchain.pem // override with --certPath=/etc/letsencrypt/live/
  "WWWdir": "", // Static-files exclusive mode // --webPath=/var/www
  "BackendDir": "www", // Hybrid mode (Static files + backend) // --backend=/var/www
  "SessionsDir": "sess/", // Used in C#-endpoints for saving/loading sessions from.
  "SessionCookieName": "SSID",
  "Rand_Alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", // Letters used for randomizing i.e. SSID
  "FilterFromDomain": "", // Optional: "."
  "DomainFilterTo": "", // If set to "", it will replace all "." with "" 
  "indexPriority": [ // Every directory tries to "copy" endpoint from the first file found within this list
    "index._csdll",
    "index._cs",
    "index.php",
    "index._wasm",
    "index.njs",
    "index.bun",
    "index.html"
  ],
  "DownloadIfExtension": [ // These file extensions tell client to download (through headers)
    "zip", "tar", "gz",
    "jar", "apk",
    "dll",
    "exe", "bat", "bash", "sh", "x86_64"
  ],
  "CompressionLevel": 0, // "Optimal" / 0, "Fastest" / 1, "NoCompression" / 2, "SmallestSize" / 3
  "ExtTypes": { // Set headers per-file extension
    "html,htm,xhtml": [
      "Content-Type: text/html",
      "Cache-Control: max-age=86400"
    ],
    "php": [
      "Content-Type: text/html"
    ],
    "txt,log": [
      "Content-Type: text/plain"
    ],
    "css": [
      "Content-Type: text/css"
    ],
    "svg": [
      "Content-Type: image/svg+xml"
    ],
    "mp3": [
      "Content-Type: audio/mpeg"
    ],
    "js": [
      "Content-Type: application/javascript"
    ],
    "json": [
      "Content-Type: application/json"
    ],
    "pdf": [
      "Content-Type: application/pdf"
    ],
    "zip": [
      "Content-Type: application/zip"
    ],
    "jar": [
      "Content-Type: application/jar"
    ],
    "dll": [
      "Content-Type: application/dll"
    ],
    "exe": [
      "Content-Type: application/exe"
    ],
    "apk": ["Content-Type: application/vnd.android.package-archive"],
    "wasm": ["Content-Type: application/wasm"],
    "png": [
      "Content-Type: image/png"
    ],
    "jpeg,jpg": [
      "Content-Type: image/jpeg"
    ],
    "gif": [
      "Content-Type: image/gif"
    ],
    "webp": [
      "Content-Type: image/webp"
    ],
    "ico": [
      "Content-Type: image/ico"
    ],
    "wav": [
      "Content-Type: audio/wav"
    ],
    "ogg": [
      "Content-Type: audio/ogg"
    ],
    "mp4": [
      "Content-Type: video/mp4"
    ],
    "flv": [
      "Content-Type: video/flv"
    ],
    "mkv": [
      "Content-Type: video/mkv"
    ],
    "wmf": [
      "Content-Type: video/wmf"
    ],
    "avi": [
      "Content-Type: video/avi"
    ],
    "webm": [
      "Content-Type: video/webm"
    ],
    "srt,vtt": ["Content-Type: text/plain; charset=utf-8"]
  },
  "ForwardExt": { // Reverse-proxy and FastCGI-support
    "njs": "http://{domain}:7001",
    "bun": "http://{domain}:3000",
    "php": "fcgi://127.0.0.1:9000"
  },
  "DefaultHeaders": { // Default headers for all non-404 requests
    "Server": "JH",
    "vary": "Accept-Encoding",
    "Accept-Ranges": "bytes",
    "Access-Control-Allow-Origin": "*",
    "cache-control": "max-age=300"
  },
  "DomainAlias": { // Lead www.domain to domain, etc.
    "www.example.com": "example.com",
    "127.0.0.1": "localhost",
    "www.jonhosting.com": "jonhosting.com",
    "www.jontv.me": "jontv.me"
  },
  "UrlAlias": {
    // "jonhosting.com/testing1234": "/test2_maybe_use_symlink_instead/useDomainAlias_for_changing_domain_virtually"
  }
}

CLI

Command-line interface

[] = optional

listfiles [path] | Lists full filePaths of every file that has been indexed.
countfiles [path] | Same as listfiles, but returns a number.
indexfiles [path] | Manually index from a directory. Can be useful in-case of any FileWatcher bugs.
clearcerts | Clears cached certificates
loadcerts | Loads certs (use clearcerts + loadcerts to reload certificates live)
listcerts | Lists domains that has certificates
reload | Reload from config file. You may want to use indexfiles after this if you changed ExtTypes or DownloadIfExtension
stats | Shows memory (RAM) and CPU usage. If ServerMetrics is turned on in config, it tells you total requests, and latest rps, rpm, rph.
gc | Manually force GC
shutdown | Shuts down the webserver

Tag summary

Content type

Image

Digest

sha256:6de06eece

Size

200.3 MB

Last updated

about 2 months ago

docker pull jgtv/joncswebserver:windows