{"id":2961,"date":"2022-06-12T21:34:29","date_gmt":"2022-06-12T21:34:29","guid":{"rendered":"https:\/\/dft.wiki\/?p=2961"},"modified":"2023-02-28T11:53:26","modified_gmt":"2023-02-28T16:53:26","slug":"setting-up-a-private-cdn-with-varnish-http-cache-on-ubuntu","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=2961","title":{"rendered":"Setting Up a Private CDN with Varnish HTTP Cache on Ubuntu"},"content":{"rendered":"<p>Varnish HTTP Cache is a dedicated opensource application for caching HTTP requests made by the client to the server.<br \/>\nIt can be located as main-in-the-middle as a reverse proxy (which it is), doing load balancing, and taking some of the load from the webserver for the static content (JavaScripts, images, etc.)<\/p>\n<p>A common use of this tool is to regionalize (in another country of continent, for example) part of the web-content (static\/immutable files). Improving the overall user experience.<\/p>\n<p>Another scenario is when a local server is placed in a company&#8217;s branch (or a big client&#8217;s office) to reduce the data traffic over the internet (excellent for metered or slow connections).<\/p>\n<p><strong>INITIAL SETUP<\/strong><\/p>\n<pre>sudo apt update &amp;&amp; sudo apt upgrade -y\r\nsudo apt install debian-archive-keyring curl gnupg apt-transport-https -y\r\ncurl -fsSL https:\/\/packagecloud.io\/varnishcache\/varnish70\/gpgkey|sudo gpg --dearmor -o \/etc\/apt\/trusted.gpg.d\/varnish.gpg<\/pre>\n<p><strong>IF:<\/strong> Ubuntu 20.04 LTS<\/p>\n<pre>sudo tee \/etc\/apt\/sources.list.d\/varnishcache_varnish70.list &gt; \/dev\/null &lt;&lt;-EOF\r\ndeb https:\/\/packagecloud.io\/varnishcache\/varnish70\/$ID\/ $VERSION_CODENAME main\r\ndeb-src https:\/\/packagecloud.io\/varnishcache\/varnish70\/$ID\/ $VERSION_CODENAME main\r\nEOF<\/pre>\n<p><strong>OR IF:<\/strong> Ubuntu 22.04 LTS<\/p>\n<pre>sudo tee \/etc\/apt\/sources.list.d\/varnishcache_varnish70.list &gt; \/dev\/null &lt;&lt;-EOF\r\ndeb https:\/\/packagecloud.io\/varnishcache\/varnish70\/ubuntu\/ focal main\r\ndeb-src https:\/\/packagecloud.io\/varnishcache\/varnish70\/ubuntu\/ focal main\r\nEOF<\/pre>\n<p><strong>INSTALLING VARNISH<\/strong><\/p>\n<pre>sudo apt update &amp;&amp; sudo apt install varnish -y<\/pre>\n<p>Configuring the service:<\/p>\n<pre>sudo cp \/lib\/systemd\/system\/varnish.service \/etc\/systemd\/system\/\r\nsudo nano \/etc\/systemd\/system\/varnish.service<\/pre>\n<pre>ExecStart=\/usr\/sbin\/varnishd \\\r\n\t  -a :<strong>6081<\/strong> \\\r\n\t  -a localhost:8443,PROXY \\\r\n\t  -p feature=+http2 \\\r\n\t  -f \/etc\/varnish\/default.vcl \\\r\n\t  -s malloc,<strong>1g<\/strong><\/pre>\n<p><strong>Note:<\/strong> here is where you can adjust the port Varnish is listening on and the amount of memory you want to allocate to the cache (e.g. <strong>256m<\/strong> or maybe <strong>2g<\/strong>). Highly recommended to set a limit because the default is unlimited.<\/p>\n<p>Configuring the Varnish Configuration Language (VCL):<\/p>\n<pre>sudo nano \/etc\/varnish\/default.vcl<\/pre>\n<pre>backend default {\r\n    .host = \"<strong>127.0.0.1<\/strong>\";\r\n    .port = \"<strong>8000<\/strong>\";\r\n}<\/pre>\n<p>OR (for multiple bakcends)<\/p>\n<pre>import directors;\r\n\r\nbackend backend1 {\r\n    .host = \"srv1.example.com\";\r\n    .port = \"80\";\r\n}\r\n\r\nbackend backend2 {\r\n    .host = \"srv2.example.com\";\r\n    .port = \"80\";\r\n}\r\n\r\nsub vcl_init {\r\n    new vdir = directors.round_robin();\r\n    vdir.add_backend(backend1);\r\n    vdir.add_backend(backend2);\r\n}\r\n\r\nsub vcl_recv {\r\n    set req.backend_hint = vdir.backend();\r\n}\r\n<\/pre>\n<p>Firing it up:<\/p>\n<pre>sudo systemctl daemon-reload\r\nsudo systemctl start varnish\r\nsudo systemctl enable varnish<\/pre>\n<p><strong>TESTING<\/strong><\/p>\n<p>Monitor the traffic between the Varnish and the web server in one terminal:<\/p>\n<pre>tcpdump -i <strong>lo<\/strong> dst host <strong>127.0.0.1<\/strong> and port <strong>8000<\/strong><\/pre>\n<p>On another terminal, make multiple HTTP requests to Varnish and confirm if it is going to the web server every time or not.<\/p>\n<pre>curl \"http:\/\/localhost:6081\/\"\r\ncurl \"http:\/\/localhost:6081\/\"\r\ncurl \"http:\/\/localhost:6081\/\"\r\ncurl \"http:\/\/localhost:6081\/\"\r\ncurl \"http:\/\/localhost:6081\/\"\r\ncurl \"http:\/\/localhost:6081\/\"<\/pre>\n<p>Also, print the headers for additional information:<\/p>\n<pre>curl -I \"http:\/\/localhost:6081\/\"<\/pre>\n<p><strong>BONUS<\/strong><\/p>\n<p>On the default VCL configuration file (<code>\/etc\/varnish\/default.vcl<\/code>) customize the internal request overwrite headers or define how long Varnish should cache the content:<\/p>\n<pre># Changes will be applied to the internal request (between Varnish and the web server).\r\nsub vcl_backend_response {\r\n    # Change Header\r\n    unset beresp.http.Cache-Control;\r\n    set beresp.http.Cache-Control = \"max-age=1209600\";\r\n\r\n    # Define Varnish Retention\r\n    set beresp.ttl = 2w;\r\n\r\n    # Defining Conditional Retention\r\n    If (bereq.url == \"\/VoD\") {\r\n        beresp.ttl = 2d;\r\n    }\r\n}<\/pre>\n<p>Serving multiple sites with\u00a0 Virtual Hosts:<\/p>\n<pre>sub vcl_recv {\r\n  if (server.ip == \"<strong>10.10.10.10<\/strong>\")\r\n  {\r\n    include \"\/etc\/varnish\/<strong>site-one<\/strong>.vcl\";\r\n  }\r\n  elsif (server.ip == \"<strong>10.20.30.40<\/strong>\")\r\n  {\r\n    include \"\/etc\/varnish\/<strong>site-two<\/strong>.vcl\";\r\n  }\r\n}<\/pre>\n<p>OR<\/p>\n<pre>sub vcl_recv {\r\n  if (! req.http.Host)\r\n  {\r\n    error 404 \"Need a host header\";\r\n  }\r\n  set req.http.Host = regsub(req.http.Host, \"^www\\.\", \"\");\r\n  set req.http.Host = regsub(req.http.Host, \":80$\", \"\");\r\n\r\n  if (req.http.Host == \"<strong>site-one.com<\/strong>\")\r\n  {\r\n    include \"\/etc\/varnish\/<strong>site-one<\/strong>.vcl\";\r\n  }\r\n  elsif (req.http.Host == \"<strong>site-two<\/strong>.com\")\r\n  {\r\n    include \"\/etc\/varnish\/<strong>site-two<\/strong>.vcl\";\r\n  }\r\n}<\/pre>\n<p>Than create the respective files (<code>\/etc\/varnish\/<strong>site-one<\/strong>.vcl<\/code> and <code>\/etc\/varnish\/<strong>site-two<\/strong>.vcl<\/code>) to specify individual configuration per IP\/domain.<\/p>\n<p>To cache everything:<\/p>\n<pre>sub vcl_recv {\r\n    unset req.http.Cookie;\r\n}\r\n\r\nsub vcl_backend_response {\r\n    # Force caching of all objects for 6 hours\r\n    set beresp.ttl = 6h;\r\n    set beresp.http.Cache-Control = \"max-age=21600\";\r\n}\r\n\r\nsub vcl_deliver {\r\n    unset resp.http.Cache-Control;\r\n}<\/pre>\n<p>To cache based on URL:<\/p>\n<pre>sub vcl_recv {\r\n    if (req.url ~ \"^\/path\/(A|B|C)$\") {\r\n        unset req.http.Cookie;\r\n        return (hash);\r\n    }\r\n}\r\nsub vcl_backend_response {\r\n    # Only set TTL and cache headers for specific URLs\r\n    if (bereq.url ~ \"^\/path\/(A|B|C)$\") {\r\n        set beresp.ttl = 6h;\r\n        set beresp.http.Cache-Control = \"max-age=21600\";\r\n    }\r\n}\r\nsub vcl_deliver {\r\n    if (req.url ~ \"^\/path\/(A|B|C)$\") {\r\n        unset resp.http.Cache-Control;\r\n    }\r\n}<\/pre>\n<hr \/>\n<p><strong>WATCH STATISTICS OF FORWARDED AND CACHED REQUESTS<\/strong><\/p>\n<pre>sudo watch -n 1 'varnishstat -1 | grep -E \"client_req|cache_hit\"'<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Varnish HTTP Cache is a dedicated opensource application for caching HTTP requests made by the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,6,7],"tags":[],"class_list":["post-2961","post","type-post","status-publish","format-standard","hentry","category-linux","category-raspberry-pi","category-web"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2961","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2961"}],"version-history":[{"count":14,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2961\/revisions"}],"predecessor-version":[{"id":3425,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2961\/revisions\/3425"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2961"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2961"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2961"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}