upstream tor { server unix:/run/tor_pass1.sock weight=10 fail_timeout=30s; server unix:/run/tor_pass2.sock weight=10 fail_timeout=30s; keepalive 128; } access_by_lua_no_postpone on; lua_package_path "/etc/nginx/resty/?.lua;;"; init_by_lua_block { allowed_hosts = { "mainonion", "masterbalanceonion", } function in_array(tab, val) for index, value in ipairs(tab) do if value == val then return true end end return nil end function split(str, sep) local result = {} local regex = ("([^%s]+)"):format(sep) for each in str:gmatch(regex) do table.insert(result, each) end return result end local function calc_circuit(proxyheaderip) if not proxyheaderip then return end local cg = split(proxyheaderip, ":") local offset = #cg > 6 and 2 or 0 local g1 = cg[5 + offset] local g2 = cg[6 + offset] local function pad_to_four(val) while string.len(val) < 4 do val = "0" .. val end return val end g1 = pad_to_four(g1) g2 = pad_to_four(g2) local d1 = (string.sub(g1,1,1) .. string.sub(g1,2,2)) local d2 = (string.sub(g1,3,3) .. string.sub(g1,4,4)) local d3 = (string.sub(g2,1,1) .. string.sub(g2,2,2)) local d4 = (string.sub(g2,3,3) .. string.sub(g2,4,4)) local circuit_id = ((((bit.lshift(tonumber(d1, 16), 24)) + (bit.lshift(tonumber(d2, 16), 16))) + (bit.lshift(tonumber(d3, 16), 8))) + tonumber(d4, 16)) return circuit_id end function kill_circuit(premature, clientip, headerip) local circuitid = calc_circuit(headerip) if not circuitid then return end local sockfile = "unix:/etc/tor/c1" local response = "Closing circuit " .. circuitid .. " " local sock = ngx.socket.tcp() sock:settimeout(1000) local ok, err = sock:connect(sockfile) if not ok then ngx.log(ngx.ERR, "failed to connect to tor: " .. err) return end ngx.log(ngx.ERR, "connected to tor") local bytes, err = sock:send("authenticate \"torauthpassword\"\n") if not bytes then ngx.log(ngx.ERR, "failed authenticate to tor: " .. err) return end local data, err, partial = sock:receive() if not data then ngx.log(ngx.ERR, "failed receive data from tor: " .. err) return end local response = response .. " " .. data local bytes, err = sock:send("closecircuit " .. circuitid .. "\n") if not bytes then ngx.log(ngx.ERR, "failed send data to tor: " .. err) return end local data, err, partial = sock:receive() if not data then ngx.log(ngx.ERR, "failed receive data from tor: " .. err) return end local response = response .. " " .. data ngx.log(ngx.ERR, response) sock:close() return end } limit_req_zone $proxy_protocol_addr zone=circuits:50m rate=requestratelimitvaluer/s; limit_req_zone $cookie_dcap zone=capcookie:50m rate=requestratelimitvaluer/s; #proxy_cache_path /etc/nginx/cache/ levels=1:2 keys_zone=static:60m use_temp_path=off max_size=500m; #this area will kill any request going for port 80 but doesn't have a valid hostname, redirect if the domain is the main or master. server { listen unix:/var/run/nginx1 proxy_protocol bind; allow unix:; deny all; server_name _; if ($host = "mainonion") { return 301 https://$host$request_uri; } if ($host = "masterbalanceonion") { return 301 https://$host$request_uri; } location / { access_by_lua_block { local proxyip = "no_proxy" local torip = ngx.var.remote_addr if ngx.var.proxy_protocol_addr ~= nil then proxyip = ngx.var.proxy_protocol_addr end ngx.log(ngx.ERR, "Bad Host (No SSL) Blocked: " .. ngx.var.host .. ", TorIP: " .. torip .. ", ProxyIP: " .. proxyip) local cook = require "resty.cookie" local cookie, err = cook:new() if not cookie then ngx.log(ngx.ERR, "Failed to initialize resty.cookie: ", err) else local field, err = cookie:get("dcap") if field then local blocked_cookies = ngx.shared.blocked_cookies blocked_cookies:set(field, 1, 43200) end end if proxyip ~= "no_proxy" then local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip) if not ok then ngx.log(ngx.ERR, "Failed to create kill_circuit timer: ", err) end end -- terminate the connection. return ngx.exit(444) } # This return is required by Nginx but it will never be reached return 404; } } server { listen unix:/var/run/nginx_ssl1 proxy_protocol ssl bind; http2 on; allow unix:; deny all; server_name mainonion masterbalanceonion; ssl_certificate /etc/nginx/ssl/$ssl_server_name.crt; ssl_certificate_key /etc/nginx/ssl/$ssl_server_name.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparams.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # proxy_cache_key "$host$request_uri$is_args$args"; # proxy_cache_valid 200 1d; # proxy_cache_min_uses 1; # proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504; # proxy_ignore_headers X-Accel-Expires Expires Cache-Control; # proxy_set_header Host $host; # proxy_cache_lock on; # proxy_cache_background_update on; # proxy_cache_revalidate on; # proxy_cache_methods GET; more_clear_headers 'Server:*'; more_clear_headers 'Vary*'; more_clear_headers 'kill*'; location @ratelimit { error_log /var/log/nginx/ratelimit.log; access_by_lua_block { local pa = "no_proxy" if ngx.var.proxy_protocol_addr ~= nil then pa = ngx.var.proxy_protocol_addr end local cook = require "resty.cookie" local cookie, err = cook:new() if not cookie then ngx.log(ngx.ERR, err) return end local field, err = cookie:get("dcap") if field then local blocked_cookies = ngx.shared.blocked_cookies blocked_cookies:set(field, 1, sessionconfigvalue) end ngx.log(ngx.ERR, "Rate limited " .. ngx.var.remote_addr .. "|" .. pa) if pa ~= "no_proxy" then local ok, err = ngx.timer.at(0, kill_circuit, ngx.var.remote_addr, ngx.var.proxy_protocol_addr) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) return end end ngx.exit(444) } } location /waf { error_log /var/log/nginx/error.log; default_type text/html; content_by_lua_block { ngx.say("Error") ngx.say("") ngx.say("

Error

") ngx.say("

Your browser sent a request that this server could not understand.

") ngx.say("

Most likely your input contains invalid characters (\" , `, etc.) that except for passwords should not be used.

") ngx.say("

This may also happen if you are trying to send contact information or external links.

") ngx.say("

Please go back, check your input and try again.

") proxyip = "no_proxy" torip = ngx.var.remote_addr if ngx.var.proxy_protocol_addr ~= nil then proxyip = ngx.var.proxy_protocol_addr end ngx.log(ngx.ERR, "WAF triggered " .. torip .. "|" .. proxyip) if proxyip ~= "no_proxy" then local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) return end end } } location @502 { default_type text/html; content_by_lua_block { ngx.say("502 Timeout") ngx.say("") ngx.say("

502 Timeout

") ngx.say("

It seems this endgame front doesn't have a stable connection to the backend right now.

") ngx.say("

To fix it you can try to reload the page. If that doesn't work, and you end back here, try the following:

") ngx.say("

If getting a new circuit doesn't work, Try to get a brand new Tor identity. If that doesn't work come back later.

") } } location /kill { access_by_lua_block { proxyip = "no_proxy" torip = ngx.var.remote_addr if ngx.var.proxy_protocol_addr ~= nil then proxyip = ngx.var.proxy_protocol_addr end ngx.log(ngx.ERR, "Kill area visited" .. torip .. "|" .. proxyip) local cook = require "resty.cookie" local cookie, err = cook:new() if not cookie then ngx.log(ngx.ERR, err) return end local field, err = cookie:get("dcap") if field then local blocked_cookies = ngx.shared.blocked_cookies blocked_cookies:set(field, 1, sessionconfigvalue) end if proxyip ~= "no_proxy" then local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) return end end ngx.exit(444) } } location / { aio threads; aio_write on; error_log /var/log/nginx/error.log; limit_req zone=circuits burst=streamratelimitvalue nodelay; error_page 503 =503 @ratelimit; limit_req zone=capcookie burst=streamratelimitvalue nodelay; error_page 503 =503 @ratelimit; error_page 502 =502 @502; access_by_lua_file lua/cap.lua; SecRulesEnabled; LibInjectionSql; LibInjectionXss; DeniedUrl /waf; CheckRule "$SQL >= 8" BLOCK; CheckRule "$XSS >= 8" BLOCK; CheckRule "$RFI >= 8" BLOCK; CheckRule "$UWA >= 8" BLOCK; CheckRule "$EVADE >= 8" BLOCK; CheckRule "$UPLOAD >= 5" BLOCK; CheckRule "$TRAVERSAL >= 5" BLOCK; CheckRule "$LIBINJECTION_XSS >= 8" BLOCK; CheckRule "$LIBINJECTION_SQL >= 8" BLOCK; include "/etc/nginx/naxsi_whitelist.rules"; proxy_set_header Host $host; proxy_pass http://backendurl; header_filter_by_lua_block { local cook = require "resty.cookie" local cookie, err = cook:new() if not cookie then ngx.log(ngx.ERR, err) return end if ngx.resp.get_headers()['kill'] ~= nil then local field, err = cookie:get("dcap") if field then local blocked_cookies = ngx.shared.blocked_cookies blocked_cookies:set(field, 1, sessionconfigvalue) end end } } }