Last active
July 16, 2022 14:30
-
-
Save brycied00d/0be28e7cd48fd1611e75 to your computer and use it in GitHub Desktop.
Moving Speedtest.net's Logic Inside of Nginx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# My goal was two-fold: | |
# Avoid installing PHP for a single 12-line PHP file (only 5 actual LOC) | |
# Instead this utilises ngx_lua (and luaJIT) which avoids forking out and keeps the logic in-memory. | |
# Optimize where I could by moving static resources into the configuration/memory. | |
# The large download test files can also be moved into a ramdisk to eek out a bit more performance by reducing disk IO | |
# Serve the same speedtest from multiple domains using only relative URLs and traversing subdomains | |
# The idea is that speedtest.companyA.com can be served from the same server{} block as speedtest.companyB.com | |
# The index page has links to allow the user to force a connection over ipv4 or ipv6. A connection to /ipv4, for | |
# instance, will redirect the user to ipv4.speedtest.$X/ where $X is determined dynamically. Likewise for /ipv6, | |
# and there's /default to redirect to just speedtest.$X/ | |
# Note that this does assume that "ipv4.speedtest.$X" and "ipv6.speedtest.$X" are setup with A and AAAA | |
# recordsrespectively. | |
# From: https://gist.github.com/brycied00d/627ec6c4235405838247 | |
server { | |
set $ipv4addr "X.X.X.X"; | |
set $ipv6addr "[X:X:X:X::X]"; | |
# Only server, don't care about individual IPs. | |
listen 80 default_server; | |
listen [::]:80 default_server ipv6only=on; | |
root /var/www/html; | |
index index.html; | |
# Only server, don't care about hostname | |
server_name _; | |
location / { | |
try_files $uri $uri/ =404; | |
} | |
# Embedded index.html for extra awesome. | |
location = /index.html { | |
# awk '{$1=$1}{ print }' index.html.static | tr -d '\r\n' | |
more_set_headers 'Content-Type: text/html'; | |
return 200 '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Mini Bandwidth Speed Test</title></head><body><div style="text-align: center;"><!-- BEGIN SPEED TEST - DO NOT ALTER BELOW--><script type="text/javascript" src="speedtest/swfobject.js?v=2.2"></script><div id="mini-demo">Speedtest.net Mini requires at least version 8 of Flash. Please <a href="http://get.adobe.com/flashplayer/">update your client</a>.</div><!--/mini-demo--><script type="text/javascript">var flashvars = {upload_extension: "nginx"};var params = {wmode: "transparent",quality: "high",menu: "true",allowScriptAccess: "always"};var attributes = {};swfobject.embedSWF("speedtest.swf?v=2.1.8", "mini-demo", "560", "400", "9.0.0", "speedtest/expressInstall.swf", flashvars, params, attributes);</script><!-- END SPEED TEST - DO NOT ALTER ABOVE --></div><p><h1>Other Test Files</h1><a href="/200k">200k</a><br/><a href="/10m">10m</a><br/><a href="/100mb.bin">100mb.bin</a><br/><hr/><a href="/ipv4">Force IPv4</a><br/><a href="/ipv6">Force IPv6</a><br/><a href="/default">Browser IPv4/IPv6 choice</a><br/><hr/>Details on how the above links work can be found in <a href="https://gist.github.com/brycied00d/627ec6c4235405838247">this Gist</a><br/></p><!-- Todo: Automated traceroute back to originating IP? --></body></html>'; | |
} | |
# Embedded favicon - Just some goofy thing | |
location = /favicon.ico { | |
more_set_headers 'Content-Type: image/gif'; | |
expires max; | |
lua_need_request_body on; | |
content_by_lua 'ngx.say(ngx.decode_base64("R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7")); ngx.exit(ngx.HTTP_OK);'; | |
} | |
# Add expiration/cache control headers to all content under /speedtest, and redirect bare access to / | |
location ~ "^/speedtest" { | |
expires epoch; | |
location ~ "/speedtest/?$" { | |
return 301 /; | |
} | |
} | |
# Embed the upload.php logic in Nginx's configuration directly with ngx_lua | |
location = /speedtest/upload.nginx { | |
client_body_buffer_size 1m; | |
client_body_in_single_buffer on; | |
lua_need_request_body on; | |
content_by_lua ' | |
ngx.header.content_type = "text/html; charset=UTF-8"; | |
local args, err = ngx.req.get_post_args() | |
local size = 500; | |
for key, val in pairs(args) do | |
size = size + string.len(key) + string.len(val) + 3; | |
end | |
ngx.print("size=", size); | |
ngx.exit(ngx.HTTP_OK); | |
'; | |
} | |
# Embed this pointless and unused file anyways. | |
location = /speedtest/latency.txt { | |
more_set_headers 'Content-Type: text/plain'; | |
return 200 "test=test\n"; | |
} | |
location = /ipv4 { | |
# IP access requires a hard-coded IPv4 address for the redirect. | |
if ($host = "[$server_addr]") { return 302 $scheme://$ipv4addr/; } | |
if ($host = "$server_addr") { return 302 $scheme://$ipv4addr/; } | |
# A bare "speedtest.____" connection gets ipv4. prepended to the $host | |
if ($host ~* "^speedtest") { return 302 $scheme://ipv4.$host/; } | |
# A connection to our ipvX-prepended URL gets that ipvX. replaced with ipv4. | |
if ($host ~* "^ipv[46].(speedtest\..+)") { return 302 $scheme://ipv4.$1/; } | |
# Any unhandled patterns get bounced straight back to / | |
return 302 $scheme://$host/; | |
} | |
location = /ipv6 { | |
# IP access requires a hard-coded IPv6 address for the redirect. | |
if ($host = $server_addr) { return 302 $scheme://$ipv6addr/; } | |
# A bare "speedtest.____" connection gets ipv6. prepended to the $host | |
if ($host ~* "^speedtest") { return 302 $scheme://ipv6.$host/; } | |
# A connection to our ipvX-prepended URL gets that ipvX. replaced with ipv6. | |
if ($host ~* "^ipv[46].(speedtest\..+)") { return 302 $scheme://ipv6.$1/; } | |
# Any unhandled patterns get bounced straight back to / | |
return 302 $scheme://$host/; | |
} | |
location = /default { | |
#return 200 "Hello default. host=$host scheme=$scheme server_addr=$server_addr\n"; | |
if ($host ~* "^ipv[46].(speedtest\..+)") { return 302 $scheme://$1/; } | |
# All unhandled patterns, including direct IP and "speedtest." just get bounced back to themselves' / | |
return 302 $scheme://$host/; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment