diff --git a/config/nginx/dev/localhost.conf b/config/nginx/dev/localhost.conf new file mode 100644 index 0000000..7a32915 --- /dev/null +++ b/config/nginx/dev/localhost.conf @@ -0,0 +1,17 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + server_tokens off; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + + proxy_pass http://varnish:80; + proxy_redirect off; + } +} \ No newline at end of file diff --git a/config/varnish/default.vcl b/config/varnish/default.vcl index 3b077ca..68924e3 100644 --- a/config/varnish/default.vcl +++ b/config/varnish/default.vcl @@ -9,52 +9,53 @@ backend default { .port = "5000"; } -acl purge { - "localhost"; - "nginx"; - "127.0.0.1"; -} - sub vcl_recv { - set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); - unset req.http.proxy; - set req.url = std.querysort(req.url); - set req.url = regsub(req.url, "\?$", ""); - set req.http.Surrogate-Capability = "key=ESI/1.0"; - - if (req.url ~ "/purge-cache") { - if (!client.ip ~ purge) { - return(synth(403, "Not allowed.")); - } - ban("req.http.host == rstat.net"); - return(synth(200, "Cache cleared")); + if (req.method != "GET" && + req.method != "HEAD" && + req.method != "PUT" && + req.method != "POST" && + req.method != "TRACE" && + req.method != "OPTIONS" && + req.method != "DELETE") { + /* Non-RFC2616 or CONNECT which is weird. */ + return (pipe); } - if (!req.http.X-Forwarded-Proto) { - if(std.port(server.ip) == 443 || std.port(server.ip) == 8443) { - set req.http.X-Forwarded-Proto = "https"; - } else { - set req.http.X-Forwarded-Proto = "https"; - } + # We only deal with GET and HEAD by default + if (req.method != "GET" && req.method != "HEAD") { + return (pass); } - - # Cache static files - if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { + + set req.url = regsub(req.url, "^http[s]?://", ""); + + # static files are always cacheable. remove SSL flag and cookie + if (req.url ~ "^/(pub/)?(media|static)/.*\.(ico|jpg|jpeg|png|gif|tiff|bmp|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)$") { + unset req.http.Https; + unset req.http.X-Forwarded-Proto; unset req.http.Cookie; - return(hash); + unset req.http.css; + unset req.http.js; } - - # Remove all cookies for other requests - unset req.http.Cookie; - return(hash); + + return (hash); } sub vcl_hash { + if (req.http.host) { + hash_data(req.http.host); + } else { + hash_data(server.ip); + } + + # To make sure http users don't see ssl warning + if (req.http.X-Forwarded-Proto) { hash_data(req.http.X-Forwarded-Proto); + } } sub vcl_backend_response { - # Cache static files and other content in Varnish for 1 min + set beresp.http.X-Host = bereq.http.host; + set beresp.ttl = 1m; # Enable stale content serving set beresp.grace = 24h; @@ -62,6 +63,30 @@ sub vcl_backend_response { if (beresp.http.Cache-Control) { set beresp.http.X-Orig-Cache-Control = beresp.http.Cache-Control; } + + # validate if we need to cache it and prevent from setting cookie + # images, css and js are cacheable by default so we have to remove cookie also + if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) { + unset beresp.http.set-cookie; + unset beresp.http.set-css; + unset beresp.http.set-js; + if (bereq.url !~ "\.(ico|jpg|jpeg|png|gif|tiff|bmp|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)(\?|$)") { + set beresp.http.Pragma = "no-cache"; + set beresp.http.Expires = "-1"; + set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0"; + set beresp.grace = 1m; + } + } + + # If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass + if (beresp.ttl <= 0s || + beresp.http.Surrogate-control ~ "no-store" || + (!beresp.http.Surrogate-Control && beresp.http.Vary == "*")) { + # Mark as Hit-For-Pass for the next 2 minutes + set beresp.ttl = 120s; + set beresp.uncacheable = true; + } + return (deliver); } sub vcl_deliver { @@ -73,4 +98,8 @@ sub vcl_deliver { # If no Cache-Control was set by the origin, we'll set a default set resp.http.Cache-Control = "no-cache, must-revalidate"; } -} + + unset resp.http.Server; + unset resp.http.Via; + unset resp.http.Link; +} \ No newline at end of file diff --git a/config/varnish/dev.vcl b/config/varnish/dev.vcl new file mode 100644 index 0000000..68924e3 --- /dev/null +++ b/config/varnish/dev.vcl @@ -0,0 +1,105 @@ +vcl 4.1; + +# https://github.com/varnish/toolbox/tree/master/vcls/hit-miss +include "hit-miss.vcl"; +import std; + +backend default { + .host = "rstat-dashboard"; + .port = "5000"; +} + +sub vcl_recv { + if (req.method != "GET" && + req.method != "HEAD" && + req.method != "PUT" && + req.method != "POST" && + req.method != "TRACE" && + req.method != "OPTIONS" && + req.method != "DELETE") { + /* Non-RFC2616 or CONNECT which is weird. */ + return (pipe); + } + + # We only deal with GET and HEAD by default + if (req.method != "GET" && req.method != "HEAD") { + return (pass); + } + + set req.url = regsub(req.url, "^http[s]?://", ""); + + # static files are always cacheable. remove SSL flag and cookie + if (req.url ~ "^/(pub/)?(media|static)/.*\.(ico|jpg|jpeg|png|gif|tiff|bmp|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)$") { + unset req.http.Https; + unset req.http.X-Forwarded-Proto; + unset req.http.Cookie; + unset req.http.css; + unset req.http.js; + } + + return (hash); +} + +sub vcl_hash { + if (req.http.host) { + hash_data(req.http.host); + } else { + hash_data(server.ip); + } + + # To make sure http users don't see ssl warning + if (req.http.X-Forwarded-Proto) { + hash_data(req.http.X-Forwarded-Proto); + } +} + +sub vcl_backend_response { + set beresp.http.X-Host = bereq.http.host; + + set beresp.ttl = 1m; + # Enable stale content serving + set beresp.grace = 24h; + # Preserve the origin's Cache-Control header for client-side caching + if (beresp.http.Cache-Control) { + set beresp.http.X-Orig-Cache-Control = beresp.http.Cache-Control; + } + + # validate if we need to cache it and prevent from setting cookie + # images, css and js are cacheable by default so we have to remove cookie also + if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) { + unset beresp.http.set-cookie; + unset beresp.http.set-css; + unset beresp.http.set-js; + if (bereq.url !~ "\.(ico|jpg|jpeg|png|gif|tiff|bmp|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)(\?|$)") { + set beresp.http.Pragma = "no-cache"; + set beresp.http.Expires = "-1"; + set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0"; + set beresp.grace = 1m; + } + } + + # If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass + if (beresp.ttl <= 0s || + beresp.http.Surrogate-control ~ "no-store" || + (!beresp.http.Surrogate-Control && beresp.http.Vary == "*")) { + # Mark as Hit-For-Pass for the next 2 minutes + set beresp.ttl = 120s; + set beresp.uncacheable = true; + } + return (deliver); +} + +sub vcl_deliver { + # Restore the origin's Cache-Control header for the browser + if (resp.http.X-Orig-Cache-Control) { + set resp.http.Cache-Control = resp.http.X-Orig-Cache-Control; + unset resp.http.X-Orig-Cache-Control; + } else { + # If no Cache-Control was set by the origin, we'll set a default + set resp.http.Cache-Control = "no-cache, must-revalidate"; + } + + unset resp.http.Server; + unset resp.http.Via; + unset resp.http.Link; +} \ No newline at end of file diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml new file mode 100644 index 0000000..87baf0e --- /dev/null +++ b/docker-compose-dev.yml @@ -0,0 +1,31 @@ +name: rstat + +services: + + rstat-dashboard: + build: + context: . + dockerfile: Dockerfile + restart: always + volumes: + - ./reddit_stocks.db:/usr/src/app/reddit_stocks.db:ro + ports: + - "5000:5000" + + nginx: + image: nginx:1.29.0 + restart: always + volumes: + - ./config/nginx/dev:/etc/nginx/conf.d:ro + - ./public:/usr/share/nginx:ro + ports: + - "80:80" + + varnish: + image: varnish:7.7.1 + restart: always + volumes: + - ./config/varnish/dev.vcl:/etc/varnish/default.vcl:ro" + - ./config/varnish/hit-miss.vcl:/etc/varnish/hit-miss.vcl:ro" + tmpfs: + - /var/lib/varnish/varnishd:exec diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png new file mode 100644 index 0000000..6871469 Binary files /dev/null and b/static/apple-touch-icon.png differ diff --git a/static/favicon-96x96.png b/static/favicon-96x96.png new file mode 100644 index 0000000..658c9fa Binary files /dev/null and b/static/favicon-96x96.png differ diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..de36b00 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..70167f2 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/static/site.webmanifest b/static/site.webmanifest new file mode 100644 index 0000000..ccf313a --- /dev/null +++ b/static/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "MyWebSite", + "short_name": "MySite", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/static/web-app-manifest-192x192.png b/static/web-app-manifest-192x192.png new file mode 100644 index 0000000..420c5c3 Binary files /dev/null and b/static/web-app-manifest-192x192.png differ diff --git a/static/web-app-manifest-512x512.png b/static/web-app-manifest-512x512.png new file mode 100644 index 0000000..9748561 Binary files /dev/null and b/static/web-app-manifest-512x512.png differ diff --git a/templates/dashboard_base.html b/templates/dashboard_base.html index acb0cb4..ed3bad1 100644 --- a/templates/dashboard_base.html +++ b/templates/dashboard_base.html @@ -5,6 +5,13 @@