386 lines
50 KiB
HTML
386 lines
50 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
|
||
|
||
<head profile="http://gmpg.org/xfn/11">
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<meta name="google-site-verification" content="whOaX6xOzqoxW14AY8ztu6BwBnHG2YZH4qj3MECaEwk" />
|
||
<meta name="description" content="The personal Web site, CV and blog of Simon Fredsted. Posts about Web development, devops, and more." />
|
||
|
||
<title>Optimizing a web app for a 400x traffic increase – Blog post – Simon Fredsted</title>
|
||
|
||
<link rel="stylesheet" href="https://simonfredsted.com/wp-content/themes/fredsted2/style.css" type="text/css" media="screen" />
|
||
<link rel="alternate" type="application/rss+xml" title="Simon Fredsted RSS Feed" href="https://simonfredsted.com/feed" />
|
||
<link rel="alternate" type="application/atom+xml" title="Simon Fredsted Atom Feed" href="https://simonfredsted.com/feed/atom" />
|
||
<link rel="pingback" href="https://simonfredsted.com/xmlrpc.php" />
|
||
|
||
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/wp-content/themes/fredsted2/icons/apple-touch-icon.png">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/wp-content/themes/fredsted2/icons/favicon-32x32.png">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/wp-content/themes/fredsted2/icons/favicon-16x16.png">
|
||
<link rel="manifest" href="/wp-content/themes/fredsted2/icons/site.webmanifest">
|
||
<link rel="mask-icon" href="/wp-content/themes/fredsted2/icons/safari-pinned-tab.svg" color="#333333">
|
||
<link rel="shortcut icon" href="/wp-content/themes/fredsted2/icons/favicon.ico">
|
||
<meta name="msapplication-TileColor" content="#ffc40d">
|
||
<meta name="msapplication-config" content="/wp-content/themes/fredsted2/icons/browserconfig.xml">
|
||
<meta name="theme-color" content="#ffffff">
|
||
|
||
<meta name='robots' content='max-image-preview:large' />
|
||
<link rel="alternate" type="application/rss+xml" title="Simon Fredsted » Optimizing a web app for a 400x traffic increase Comments Feed" href="https://simonfredsted.com/1721/feed" />
|
||
<link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://simonfredsted.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fsimonfredsted.com%2F1721" />
|
||
<link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://simonfredsted.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fsimonfredsted.com%2F1721&format=xml" />
|
||
<style id="wp-img-auto-sizes-contain-inline-css">
|
||
img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
|
||
/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
|
||
</style>
|
||
<style id="wp-emoji-styles-inline-css">
|
||
|
||
img.wp-smiley, img.emoji {
|
||
display: inline !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
height: 1em !important;
|
||
width: 1em !important;
|
||
margin: 0 0.07em !important;
|
||
vertical-align: -0.1em !important;
|
||
background: none !important;
|
||
padding: 0 !important;
|
||
}
|
||
/*# sourceURL=wp-emoji-styles-inline-css */
|
||
</style>
|
||
<style id="wp-block-library-inline-css">
|
||
:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style*=border-color]){border-style:solid}html :where([style*=border-top-color]){border-top-style:solid}html :where([style*=border-right-color]){border-right-style:solid}html :where([style*=border-bottom-color]){border-bottom-style:solid}html :where([style*=border-left-color]){border-left-style:solid}html :where([style*=border-width]){border-style:solid}html :where([style*=border-top-width]){border-top-style:solid}html :where([style*=border-right-width]){border-right-style:solid}html :where([style*=border-bottom-width]){border-bottom-style:solid}html :where([style*=border-left-width]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}
|
||
|
||
/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */
|
||
</style>
|
||
<style id="classic-theme-styles-inline-css">
|
||
/*! This file is auto-generated */
|
||
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}
|
||
/*# sourceURL=/wp-includes/css/classic-themes.min.css */
|
||
</style>
|
||
|
||
<style id="global-styles-inline-css">
|
||
:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}:where(body) { margin: 0; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #32373c;border-width: 0;color: #fff;font-family: inherit;font-size: inherit;font-style: inherit;font-weight: inherit;letter-spacing: inherit;line-height: inherit;padding-top: calc(0.667em + 2px);padding-right: calc(1.333em + 2px);padding-bottom: calc(0.667em + 2px);padding-left: calc(1.333em + 2px);text-decoration: none;text-transform: inherit;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
|
||
/*# sourceURL=global-styles-inline-css */
|
||
</style>
|
||
|
||
<link rel='stylesheet' id='slb_core-css' href='https://simonfredsted.com/wp-content/plugins/simple-lightbox/client/css/app.css?ver=2.9.5' media='all' />
|
||
<link rel="https://api.w.org/" href="https://simonfredsted.com/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://simonfredsted.com/wp-json/wp/v2/posts/1721" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://simonfredsted.com/xmlrpc.php?rsd" />
|
||
<meta name="generator" content="WordPress 7.0.4" />
|
||
<link rel="canonical" href="https://simonfredsted.com/1721" />
|
||
<link rel='shortlink' href='https://simonfredsted.com/?p=1721' />
|
||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||
<script type="text/javascript">
|
||
|
||
var _gaq = _gaq || [];
|
||
_gaq.push(['_setAccount', 'UA-5230636-8']);
|
||
_gaq.push(['_trackPageview']);
|
||
|
||
(function() {
|
||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||
ga.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js';
|
||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||
})();
|
||
|
||
</script>
|
||
<link rel='stylesheet' id='prismcss-css' href='https://simonfredsted.com/wp-content/plugins/pastacode/css/prism.css?ver=3.0.1' media='all' />
|
||
|
||
</head>
|
||
<body>
|
||
|
||
<div id="page">
|
||
<div id="top"></div>
|
||
<div id="header">
|
||
|
||
<h1><a href="https://simonfredsted.com/">Simon Fredsted <div class="description"></div></a></h1>
|
||
|
||
|
||
<div id="sidebar">
|
||
<ul>
|
||
<li id="nav_menu-3" class="widget widget_nav_menu"><h2 class="widgettitle">Content</h2><div class="menu-sidebarmenu-container"><ul id="menu-sidebarmenu" class="menu"><li id="menu-item-1219" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home menu-item-1219"><a href="https://simonfredsted.com/" title="Information about me and the site">About</a></li>
|
||
<li id="menu-item-2111" class="menu-item menu-item-type-post_type menu-item-object-page current_page_parent menu-item-2111"><a href="https://simonfredsted.com/blog" title="Blog Archive">Blog</a></li>
|
||
</ul></div></li><li id="archives-3" class="widget widget_archive"><h2 class="widgettitle">Archives</h2>
|
||
<ul>
|
||
<li><a href='https://simonfredsted.com/date/2026/07'>July 2026</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2026/01'>January 2026</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2025/12'>December 2025</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2021/06'>June 2021</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2020/01'>January 2020</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2019/11'>November 2019</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2019/08'>August 2019</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2019/06'>June 2019</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2019/05'>May 2019</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2019/02'>February 2019</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2018/09'>September 2018</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2018/08'>August 2018</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2018/07'>July 2018</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2018/05'>May 2018</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2017/05'>May 2017</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2017/04'>April 2017</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2017/01'>January 2017</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2016/09'>September 2016</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2016/08'>August 2016</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2014/11'>November 2014</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2014/09'>September 2014</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2014/06'>June 2014</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2013/12'>December 2013</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2013/04'>April 2013</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2013/02'>February 2013</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2012/04'>April 2012</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2012/02'>February 2012</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2011/08'>August 2011</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2011/04'>April 2011</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2011/02'>February 2011</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2010/12'>December 2010</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2010/11'>November 2010</a></li>
|
||
<li><a href='https://simonfredsted.com/date/2010/09'>September 2010</a></li>
|
||
</ul>
|
||
|
||
</li> </ul>
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<br style="clearfix" />
|
||
|
||
<div id="content" class="narrowcolumn single">
|
||
|
||
|
||
|
||
|
||
<div class="post" id="post-1721">
|
||
|
||
<p class="postdata">
|
||
<span class="postcomments">
|
||
4
|
||
<img src="/wp-content/themes/fredsted2/images/comment.svg" border="0" class="sbubble" />
|
||
</span>
|
||
<span class="posttime">May 6, 2019</span>
|
||
<span class="posturl" style="text-transform: none; font-variant: normal;">
|
||
— https://sf.gl/1721 </span>
|
||
</p>
|
||
|
||
<h2><a href="https://simonfredsted.com/1721" rel="bookmark"
|
||
title="Permanent Link to Optimizing a web app for a 400x traffic increase">
|
||
Optimizing a web app for a 400x traffic increase </a></h2>
|
||
|
||
<div class="entry">
|
||
<p>Running my service/hobby project <a href="https://webhook.site">Webhook.site</a> (<a href="https://github.com/fredsted/webhook.site">GitHub page</a>) has presented me with quite a few challenges regarding optimising the VPS (virtual private server) the site is running on, squeezing as much performance as possible out of it.</p>
|
||
<p>Originally, when it launched, Webhook.site was using a completely different datastore and Web server software than it is now.</p>
|
||
<p>In this post I'll try to chronicle some of the challenges of keeping up with increasing traffic going from 20 to almost 8000 weekly users – a 400x increase!</p>
|
||
<h3>March 2016</h3>
|
||
<p>The first line of code was committed to Git on 21st March 2016, during which I committed the basic Laravel framework files, database migrations, models, etc.</p>
|
||
<p>SQLite was chosen as the datastore since it was easy to get started with (I planned on migrating to either MariaDB or Postgres later on, but – spoiler alert – that never happened.)</p>
|
||
<p>For the Websocket/push functionality, I chose Pusher, a SaaS that specialises in hosting this kind of service. The free plan was more than enough!</p>
|
||
<p>For hosting, I placed it on my personal server, a 1 GB DigitalOcean VPS which hosts a bunch of other stuff.</p>
|
||
<h3>November 2016 – Pusher running out of connections</h3>
|
||
<p>I <a href="https://news.ycombinator.com/item?id=12952692">posted the site on Hacker News</a>, and the site got it its first surge (around 4000 unique users) in traffic, which it handled acceptably (considering almost all visitors just loaded the front page and closed it after a couple seconds.) I got a good amount of feedback, and also noticed that my free Pusher membership was running out of the allotted connections I had available. Fortunately, someone at Pusher was reading Hacker News and bumped up my connection count!</p>
|
||
<h3>Early 2017 – Lawyers & moving out for the first time</h3>
|
||
<p>Traffic was growing, and I started implementing a max amount of requests on a URL (500), since the SQLite database was getting very large (several gigabytes), and some users often forgot to remove the URL after they were done testing and moved to production! Around here I also noticed that the site was getting slow, and I noticed I had forgotten to add some indices in the database! After I added those, the site was a lot faster.</p>
|
||
<p>Around this time, I was also contacted by a lawyer representing a company where a developer had used Webhook.site for testing a credential validation and upload service. They forgot that webhook subscription was still in place when it was transferred to production, which had resulted in some very personal data being uploaded, and they wanted me to make sure it was removed. I removed the URL and related data and never heard from them again.</p>
|
||
<p>On the server side, I decided it was time to move the site to its own server, since it started interfering with my primary one. I chose the smallest size on DigitalOcean (512MB RAM), on which I installed Debian. Nginx was chosen as the Web server serving PHP 7.1 via FPM.</p>
|
||
<p>At this point, Webhook.site had around 70 daily users.</p>
|
||
<h3>Late 2017 – Caching issues</h3>
|
||
<p>I started running into various performance problems regarding Laravel, caching and Redis connectivity.</p>
|
||
<p>First, I couldn't figure out why the site was so slow. I had enabled Laravel's rate limiting feature, which by default caches a users' IP address and stores the amount of connection attempts so it can rate limit the connections.</p>
|
||
<p>As it turns out, I had forgot to change the default caching mechanism, which was disk cache. So each visit to the site caused Laravel to read and write a file to disk, which took up a bunch of IO.</p>
|
||
<p>As a result, I installed Redis and pointed the cache to it, which immediately improved performance.</p>
|
||
<h3>Early 2018 – New year, new datastore</h3>
|
||
<p>Traffic was now growing steadily, and the site had around 300-400 daily users at this point.</p>
|
||
<p>From the commit logs, I can see that I enabled Redis to use a UNIX socket instead of TCP connectivity. This improved performance quite a bit, since it didn't take up precious TCP connections that could be used to serve the site.</p>
|
||
<p>In March 2018, the amount of users had doubled again – around 600 daily active users – and SQLite just wasn't cutting it anymore; the database file was getting very large.</p>
|
||
<p>I had to switch to a different datastore. Considering the options – moving data from SQLite to MySQL wasn't as straightforward as I'd hoped – I chose Redis, since I calculated that total amount of data could fit on RAM if I only stored the last few days worth, which would be easy since Redis supports expiring keys.</p>
|
||
<p>I re-wrote a large portion of the application (including a <a href="https://github.com/fredsted/webhook.site/blob/1.1/app/Console/Commands/MigrateToRedis.php">migration script</a>) and temporarily upgraded the DigitalOcean VPS to a 16 GB instance so it could store all the data in memory until the bulk of it expired. After a week or so, I downgraded to 1 GB RAM now that everything could fit in memory.</p>
|
||
<h3>Mid 2018 – Self-hosted Socket.io</h3>
|
||
<p>The amount of users doubled again, and even the increased amount of connections allowed to me by Pusher now wasn't enough, which resulted in users having to reload the app manually instead of being able to stream new requests in real-time.</p>
|
||
<p>I switched over to <a href="https://github.com/tlaverdure/laravel-echo-server">Laravel Echo Server</a>, a Socket.io server written in Node.js, which has served me well to this day. I proxied it through Nginx and the site kept humming along.</p>
|
||
<h3>Late 2018 – Accidental DDoS & HAProxy to the rescue</h3>
|
||
<p>The site started taking up lots of time to keep running mainly due to a few users who accidentally deployed URLs to production, causing the site to be hit by large amounts of requests from many different IP addresses at once (or few IP addresses sending tons of traffic.)</p>
|
||
<p>I tried to implement a blocking mechanism in the firewall since even though Laravel's rate limiter worked fine, I wanted something that worked at the firewall level, so connections would be discarded before hitting PHP, which was eating up resources.</p>
|
||
<p>I also upgraded the server in December to 4 GB ram, which was just barely able to fit all the data in RAM. It mostly ran at close to 100% CPU.</p>
|
||
<p>The firewall blocking mechanism worked for a little while, but turned out to be very buggy – I was running iptables and UFW commands from PHP! – and I disabled the functionality and started thinking of alternative solutions.</p>
|
||
<p>At around this time, a user had apparently forgot to remove the URL from a test version of some sort of advertising solution deployed on mobile phones. Tens of thousands of mobile phones were constantly requesting the same endpoint, and it was ruining the site for everybody. Something had to be done. I needed something that could quickly drop incoming connections that matched the URL in question.</p>
|
||
<p>Having had experience with HAProxy in the past, I was well aware of how efficient it is compared to Nginx at acting as a proxy – up until now I had also used Nginx to forward Laravel Echo Server traffic. So I decided to try putting HAProxy in front of Nginx, and moving the Echo server proxy to HAProxy, and adding rules to the HAProxy configuration file that immediately dropped requests to the URL that caused trouble. That turned out to be a good decision.</p>
|
||
<p>CPU usage fell to under 30% immediately, resulting in the site loading instantly even though it was getting bombarded by requests – success.</p>
|
||
<h3>April 2019 "DDoS" – nitty-gritty kernel tweaking</h3>
|
||
<p>Around April 11, another surge of accidental traffic hit the server, apparently also from some sort of advertising software, where a bunch of popular apps were loading the same Webhook.site URL. I assumed this was just forgetfulness; someone forgot to remove a snippet of code before pushing to production.</p>
|
||
<p>Still running on a relatively small 4 GB/2-core VPS, I took a look at tweaking various default Linux configuration files, namely <span class="code-text">/etc/sysctl.conf</span> and <span class="code-text">/etc/security/limits</span>. At the bottom of this post, I've listed some links to resources that helped me find the right values.</p>
|
||
<p>Here's what I ended up with (I'll save a deeper explanation for a later post):</p>
|
||
<div class="code-embed-wrapper"> <pre class="language-c code-embed-pre" data-start="1" data-line-offset="0"><code class="language-c code-embed-code">vm.overcommit_memory = 1<br/>fs.file-max = 2097152<br/>net.core.somaxconn = 4096<br/>net.ipv4.ip_local_port_range = 2000 65000<br/>net.ipv4.tcp_rfc1337 = 1<br/>net.ipv4.tcp_fin_timeout = 15<br/>net.ipv4.tcp_tw_recycle = 1<br/>net.ipv4.tcp_tw_reuse = 1<br/>net.netfilter.nf_conntrack_generic_timeout = 60<br/>net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 54000<br/>net.core.netdev_max_backlog = 4000<br/>net.ipv4.tcp_max_syn_backlog = 2048<br/>net.netfilter.nf_conntrack_tcp_timeout_close_wait = 20<br/>net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20<br/>net.netfilter.nf_conntrack_tcp_timeout_time_wait = 20<br/>net.netfilter.nf_conntrack_max = 524288<br/>net.ipv4.tcp_mem = 65536 131072 262144<br/>net.ipv4.udp_mem = 65536 131072 262144</code></pre> <div class="code-embed-infos"> <span class="code-embed-name">/etc/sysctl.conf</span> </div> </div>
|
||
<p>Then, around 10 days later, the same thing happened, but this time, the site was able to keep serving visitors even though it was getting hammered. I had blocked the URL directly in HAProxy – which basically means it's returning a short error code, saving CPU cycles and bandwidth – and the server was able to keep up and saturate the 100mbit network connection.</p>
|
||
<div id="attachment_1722" style="width: 650px" class="wp-caption aligncenter"><a href="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-19.55.06.png" data-slb-active="1" data-slb-asset="1320974314" data-slb-internal="0" data-slb-group="1721"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-1722" class="wp-image-1722" src="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-19.55.06-300x82.png" alt="" width="640" height="175" srcset="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-19.55.06-300x82.png 300w, https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-19.55.06-768x209.png 768w, https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-19.55.06.png 1001w" sizes="(max-width: 640px) 100vw, 640px" /></a><p id="caption-attachment-1722" class="wp-caption-text">Bandwidth graph during the days Webhook.site experienced very large amounts of traffic</p></div>
|
||
<p>After a few days, someone must have realised that they were bombarding Webhook.site with traffic and shut it off. So far, it hasn't happened again, and the site consumes its usual few megabits per second in traffic.</p>
|
||
<p>As of writing this article, Webhook.site now runs on a 4-core 8GB VPS and handles thousands of connections per second without breaking a sweat.</p>
|
||
<div id="attachment_1725" style="width: 650px" class="wp-caption aligncenter"><a href="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42.png" data-slb-active="1" data-slb-asset="1260000700" data-slb-internal="0" data-slb-group="1721"><img decoding="async" aria-describedby="caption-attachment-1725" class="wp-image-1725" src="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42-300x57.png" alt="" width="640" height="122" srcset="https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42-300x57.png 300w, https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42-768x146.png 768w, https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42-1024x195.png 1024w, https://simonfredsted.com/wp-content/uploads/2019/05/Screenshot-2019-05-06-at-20.16.42.png 1596w" sizes="(max-width: 640px) 100vw, 640px" /></a><p id="caption-attachment-1725" class="wp-caption-text">Daily and weekly unique users on Webhook.site from Google Analytics</p></div>
|
||
<h3>Future plans</h3>
|
||
<p>Thanks to the very generous supporters of the site on <a href="https://www.patreon.com/webhooktester">Patreon</a>, I've been able to pour some money at upgrading the server to keep handling more traffic instead of just shutting it down. That, along with the various optimizations, has kept the site online, helping tens of thousands of visitors a month while still being fairly inexpensive to run as a hobby project.</p>
|
||
<p>It's also worth mentioning DigitalOcean again – <a href="https://m.do.co/c/d4112f89cfdd">here's my referral link where you can get $100 in credit</a> – during all of this I've never heard a single complaint from them, even when the server was consuming 100mbit/s traffic for days!</p>
|
||
<p>With that being said, it has become quite clear that lots of people simply forget that they subscribed something to Webhook.site, and as a result, accidentally spamming the service in such a manner that is basically a DDoS. The longer Webhook.site keeps running, the more the server will keep receiving those old, long-forgotten webhook subscriptions. My plan for this is at some point to switch to using a wildcard CNAME record so that URLs will be in the format <span class="code-text">https://<UUID>.webhook.site</span>. This will let me create an A record pointing to 127.0.0.1 (redirecting the traffic back to the sender) on a case by case basis, somewhat sidestepping the issue.</p>
|
||
<p>Additionally, lots can be done for scalability regarding infrastructure: I've kept everything on a single, smaller server basically as a matter of stubbornness and wanting to see how far I can push a single VPS. It would probably be more efficient to separate the services so that HAProxy, Redis, Nginx and Echo Server aren't competing for resources.</p>
|
||
<p>Finally, this has already taught me a lot, and I'm looking forward to see what else I can do to keep Webhook.site humming along if the visitor count keeps increasing.</p>
|
||
<h3>Appendix: Resources for tweaking <span class="code-text">sysctl.conf</span></h3>
|
||
<ul>
|
||
<li><a href="https://wiki.mikejung.biz/Sysctl_tweaks">https://wiki.mikejung.biz/Sysctl_tweaks</a></li>
|
||
<li><a href="http://www.tweaked.io/guide/kernel/">http://www.tweaked.io/guide/kernel/</a></li>
|
||
<li><a href="https://blog.confirm.ch/sysctl-tuning-linux/">https://blog.confirm.ch/sysctl-tuning-linux/</a></li>
|
||
</ul>
|
||
|
||
|
||
<p class="postmetadata alt">
|
||
This entry was posted on Monday, May 6th, 2019 at 19:38 and is filed under <a href="https://simonfredsted.com/category/articles" rel="category tag">Articles</a>. You can follow any responses to this entry through the <a href='https://simonfredsted.com/1721/feed'>RSS 2.0</a> feed.
|
||
You can <a href="#respond">leave a response</a>, or <a href="https://simonfredsted.com/1721/trackback" rel="trackback">trackback</a> from your own site.
|
||
</p>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="navigation">
|
||
<div class="alignleft"><a href="https://simonfredsted.com/1680" rel="prev">Solving Kubernetes DNS issues on systemd servers</a></div>
|
||
<div class="alignright"><a href="https://simonfredsted.com/1745" rel="next">Why is the Mac Pro so expensive?</a></div>
|
||
</div>
|
||
<br />
|
||
|
||
|
||
<!-- You can start editing here. -->
|
||
|
||
<h3 id="comments">4 Responses to “Optimizing a web app for a 400x traffic increase”</h3>
|
||
|
||
<ol class="commentlist">
|
||
|
||
|
||
<li class="alt" id="comment-304600">
|
||
<cite><a href="http://sreweekly.com/sre-weekly-issue-173/" class="url" rel="ugc external nofollow">SRE Weekly Issue #173 – SRE WEEKLY</a></cite> <br />
|
||
|
||
<small class="commentmetadata"><a href="#comment-304600" title="">Jun 17, 2019 at 0:33</a> </small>
|
||
|
||
<p>[…] How Webhook.site handles 100 mbit/s traffic on a single VPS […]</p>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
<li id="comment-370956">
|
||
<img alt='' src='https://secure.gravatar.com/avatar/155a815576f088d4f6617a6878877ce00558efb32bbe6debf9527523a521059c?s=32&r=g' srcset='https://secure.gravatar.com/avatar/155a815576f088d4f6617a6878877ce00558efb32bbe6debf9527523a521059c?s=64&r=g 2x' class='avatar avatar-32 photo' height='32' width='32' loading='lazy' decoding='async'/> <cite><a href="http://vemidoc.com" class="url" rel="ugc external nofollow">JP Garcia</a></cite> <br />
|
||
|
||
<small class="commentmetadata"><a href="#comment-370956" title="">Sep 22, 2020 at 7:11</a> </small>
|
||
|
||
<p>Fantastic Story. it is very inspiring. Wishing you the best. -JP</p>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
<li class="alt" id="comment-440540">
|
||
<img alt='' src='https://secure.gravatar.com/avatar/37437a1aee47c8ed936449e4bea3e204e160c1385f5b496f91971c607eaff398?s=32&r=g' srcset='https://secure.gravatar.com/avatar/37437a1aee47c8ed936449e4bea3e204e160c1385f5b496f91971c607eaff398?s=64&r=g 2x' class='avatar avatar-32 photo' height='32' width='32' loading='lazy' decoding='async'/> <cite><a href="http://FC%20Mobile%20Pro" class="url" rel="ugc external nofollow">Elsultanali</a></cite> <br />
|
||
|
||
<small class="commentmetadata"><a href="#comment-440540" title="">Aug 17, 2024 at 10:47</a> </small>
|
||
|
||
<p>mau Download<br />
|
||
FC Mobile Pro</p>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
<li id="comment-453627">
|
||
<img alt='' src='https://secure.gravatar.com/avatar/9a77927b18b1e57f1e72410a5d4629c0161e4130007ad1213b064dd73fdac986?s=32&r=g' srcset='https://secure.gravatar.com/avatar/9a77927b18b1e57f1e72410a5d4629c0161e4130007ad1213b064dd73fdac986?s=64&r=g 2x' class='avatar avatar-32 photo' height='32' width='32' loading='lazy' decoding='async'/> <cite>webhooksite user :)</cite> <br />
|
||
|
||
<small class="commentmetadata"><a href="#comment-453627" title="">Jul 11, 2025 at 21:28</a> </small>
|
||
|
||
<p>6 years later, probably worth mentioning, if you’re not using the ipset or nft facilities in the Linux kernel for firewall management (instead of iptables), you should be. That will save you considerable CPU cycles on processing traffic.</p>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
</ol>
|
||
|
||
|
||
|
||
|
||
<h3 id="respond">Leave a Comment</h3>
|
||
|
||
|
||
<form action="https://simonfredsted.com/wp-comments-post.php" method="post" id="commentform">
|
||
|
||
|
||
<p><label for="author">Name </label> <br />
|
||
<input type="text" name="author" id="author" value="" size="22" tabindex="1" />
|
||
</p>
|
||
|
||
<p><label for="email">Mail (will not be published) </label> <br /><input type="text" name="email" id="email" value="" size="22" tabindex="2" />
|
||
</p>
|
||
|
||
<p><label for="url">Website</label> <br /> <input type="text" name="url" id="url" value="" size="22" tabindex="3" />
|
||
</p>
|
||
|
||
|
||
<!--<p><small><strong>XHTML:</strong> You can use these tags: <code><a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> </code></small></p>-->
|
||
|
||
<p><label for="comment">Your comment</label><textarea name="comment" id="comment" cols="40" rows="10" tabindex="4"></textarea></p>
|
||
|
||
<p><p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="7ea9b8386a" /></p><p style="display: none !important;" class="akismet-fields-container" data-prefix="ak_"><label>Δ<textarea name="ak_hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label><input type="hidden" id="ak_js_1" name="ak_js" value="157"/><script>
|
||
document.getElementById( "ak_js_1" ).setAttribute( "value", ( new Date() ).getTime() );
|
||
</script>
|
||
</p></p>
|
||
|
||
<div class="g-recaptcha" data-sitekey="6Lc9R_8SAAAAANTO36W50FlMiJ_Ah-uj55644cce" data-theme="light"></div>
|
||
<p><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment" />
|
||
<input type="hidden" name="comment_post_ID" value="1721" />
|
||
</p>
|
||
|
||
<p style="font-style: italic; font-size: 80%; opacity: 0.4;">Note: Your comment will be shown after it has been approved.</p>
|
||
|
||
</form>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
<div id="footer">
|
||
Copyright © Simon Fredsted 2010–2026. All rights reserved.
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<script type="speculationrules">
|
||
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/fredsted2/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
|
||
</script>
|
||
<script id="script-js" src="https://simonfredsted.com/wp-content/themes/fredsted2/js.js?ver=1"></script>
|
||
<script id="prismjs-js" src="https://simonfredsted.com/wp-content/plugins/pastacode/js/prism.js?ver=3.0.1"></script>
|
||
<script id="prism-normalize-whitespace-js" src="https://simonfredsted.com/wp-content/plugins/pastacode/plugins/normalize-whitespace/prism-normalize-whitespace.min.js?ver=3.0.1"></script>
|
||
<script defer id="akismet-frontend-js" src="https://simonfredsted.com/wp-content/plugins/akismet/_inc/akismet-frontend.js?ver=1787210047"></script>
|
||
<script id="jquery-core-js" src="https://simonfredsted.com/wp-includes/js/jquery/jquery.min.js?ver=3.7.1"></script>
|
||
<script id="jquery-migrate-js" src="https://simonfredsted.com/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1"></script>
|
||
<script id="slb_core-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/client/js/prod/lib.core.js?ver=2.9.5"></script>
|
||
<script id="slb_view-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/client/js/prod/lib.view.js?ver=2.9.5"></script>
|
||
<script id="slb-asset-slb_baseline-base-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/themes/baseline/js/prod/client.js?ver=2.9.5"></script>
|
||
<script id="slb-asset-slb_default-base-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/themes/default/js/prod/client.js?ver=2.9.5"></script>
|
||
<script id="slb-asset-item-base-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/template-tags/item/js/prod/tag.item.js?ver=2.9.5"></script>
|
||
<script id="slb-asset-ui-base-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/template-tags/ui/js/prod/tag.ui.js?ver=2.9.5"></script>
|
||
<script id="slb-asset-image-base-js" src="https://simonfredsted.com/wp-content/plugins/simple-lightbox/content-handlers/image/js/prod/handler.image.js?ver=2.9.5"></script>
|
||
<script id="wp-emoji-settings" type="application/json">
|
||
{"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://simonfredsted.com/wp-includes/js/wp-emoji-release.min.js?ver=7.0.4"}}
|
||
</script>
|
||
<script type="module">
|
||
/*! This file is auto-generated */
|
||
var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))});
|
||
//# sourceURL=https://simonfredsted.com/wp-includes/js/wp-emoji-loader.min.js
|
||
</script>
|
||
<script type="text/javascript" id="slb_footer">/* <![CDATA[ */if ( !!window.jQuery ) {(function($){$(document).ready(function(){if ( !!window.SLB && SLB.has_child('View.init') ) { SLB.View.init({"ui_autofit":true,"ui_animate":false,"slideshow_autostart":true,"slideshow_duration":"6","group_loop":true,"ui_overlay_opacity":"0.8","ui_title_default":false,"theme_default":"slb_default","ui_labels":{"loading":"Loading","close":"Close","nav_next":"Next","nav_prev":"Previous","slideshow_start":"Start slideshow","slideshow_stop":"Stop slideshow","group_status":"Item %current% of %total%"}}); }
|
||
if ( !!window.SLB && SLB.has_child('View.assets') ) { {$.extend(SLB.View.assets, {"1320974314":{"id":1722,"type":"image","internal":true,"source":"https:\/\/simonfredsted.com\/wp-content\/uploads\/2019\/05\/Screenshot-2019-05-06-at-19.55.06.png","title":"Webhook.site traffic graph","caption":"","description":""},"1260000700":{"id":1725,"type":"image","internal":true,"source":"https:\/\/simonfredsted.com\/wp-content\/uploads\/2019\/05\/Screenshot-2019-05-06-at-20.16.42.png","title":"Daily and weekly unique users on Webhook.site","caption":"Daily and weekly unique users on Webhook.site","description":""}});} }
|
||
/* THM */
|
||
if ( !!window.SLB && SLB.has_child('View.extend_theme') ) { SLB.View.extend_theme('slb_baseline',{"name":"Baseline","parent":"","styles":[{"handle":"base","uri":"https:\/\/simonfredsted.com\/wp-content\/plugins\/simple-lightbox\/themes\/baseline\/css\/style.css","deps":[]}],"layout_raw":"<div class=\"slb_container\"><div class=\"slb_content\">{{item.content}}<div class=\"slb_nav\"><span class=\"slb_prev\">{{ui.nav_prev}}<\/span><span class=\"slb_next\">{{ui.nav_next}}<\/span><\/div><div class=\"slb_controls\"><span class=\"slb_close\">{{ui.close}}<\/span><span class=\"slb_slideshow\">{{ui.slideshow_control}}<\/span><\/div><div class=\"slb_loading\">{{ui.loading}}<\/div><\/div><div class=\"slb_details\"><div class=\"inner\"><div class=\"slb_data\"><div class=\"slb_data_content\"><span class=\"slb_data_title\">{{item.title}}<\/span><span class=\"slb_group_status\">{{ui.group_status}}<\/span><div class=\"slb_data_desc\">{{item.description}}<\/div><\/div><\/div><div class=\"slb_nav\"><span class=\"slb_prev\">{{ui.nav_prev}}<\/span><span class=\"slb_next\">{{ui.nav_next}}<\/span><\/div><\/div><\/div><\/div>"}); }if ( !!window.SLB && SLB.has_child('View.extend_theme') ) { SLB.View.extend_theme('slb_default',{"name":"Default (Light)","parent":"slb_baseline","styles":[{"handle":"base","uri":"https:\/\/simonfredsted.com\/wp-content\/plugins\/simple-lightbox\/themes\/default\/css\/style.css","deps":[]}]}); }})})(jQuery);}/* ]]> */</script>
|
||
<script type="text/javascript" id="slb_context">/* <![CDATA[ */if ( !!window.jQuery ) {(function($){$(document).ready(function(){if ( !!window.SLB ) { {$.extend(SLB, {"context":["public","user_guest"]});} }})})(jQuery);}/* ]]> */</script>
|
||
<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"1e529dab25ae44ed8728fe2164bcc5ee","r":1,"spa":2}' crossorigin="anonymous"></script>
|
||
</body>
|
||
</html>
|
||
<!-- Dynamic page generated in 0.356 seconds. -->
|
||
<!-- Cached page generated by WP-Super-Cache on 2026-09-09 19:10:48 -->
|
||
|
||
<!-- Compression = gzip --> |