If you’ve been working around web development for a while, you’ll know that the web has a need for speed. The truth is simple: speed matters and faster is considered better.
One “easy win” for increasing performance is using a CDN. We’ve discussed this several times at CSS-Tricks. It’s easy in that you aren’t rewriting a codebase or hand-editing content, but it’s an area of performance many of us might overlook because, well, hosting, servers and cPanels, oh my!
Thankfully, the process for integrating a CDN does not have to be hard. Ideally, you get things configured and then things like Google PageSpeed shriek with glee in the form of high performance scores which, in turn, yield to better search engine rankings, higher revenue, a raise for you and…you get the point.
This post is going to walk through the process for setting up a CDN to work on a custom web application, followed by some tricks we can use to get the most out of our work. Like I said, it doesn’t have to be hard, so let’s dive in and make the web faster!
It’s worth noting that setting up a CDN can be even simpler than what we’re covering here for those working with a CMS like WordPress, where plugins can help with the lift. We’re going to assume that not everyone has that luxury (shout out to web applications!) and proceed in the more traditional way.
Hold up, you lost me at CDN
It doesn’t hurt for us to review the basic concepts of what a CDN is and what they’re used for, so let’s start with that.
A CDN works by fetching static assets from your site’s server and caching them on their servers. When a browser makes a request to visit your site, the static contents are served via the CDN rather than by your site. This is faster because the CDN servers are globally distributed and serve as proxies that determine which server is located physically closest to your visitor, thus delivering content on a speedier, more convenient network. Hence the full name: Content Delivery Network.
data-recalc-dims=1A Content Delivery Network is globally distributed for optimized delivery of static assets
So, how does the browser know to get the resources from the CDN instead of your server? The URL of your static resources are replaced to point to the CDN server instead of the URL of your own site.
For example, say we want CDN to be configured as a subdomain. For CSS-Tricks, that might be something like cdn.css-tricks.com and that will be the relative URL for which we base all our assets.
Put more succinctly put, the URLs of assets on our site like this:
https://css-tricks.com/image.jpg
https://css-tricks.com/style.css
https://css-tricks.com/script.js
…would become:
http://cdn.css-tricks.com/image.jpg
http://cdn.css-tricks.com/style.css
http://cdn.css-tricks.com/script.js
The browser sends the requests to your CDN rather than your server, taking the load off your server and making your whole site faster as a result.
Wait, two servers for one site?
Yes, to a degree, but it doesn’t really mean that you’re managing two servers.
What we’re talking about instead is using the CDN as a virtual layer that stands between your server and a user’s browser. That virtual layer listens in on the request the browser is making to your server and gladly responds with cached assets on behalf of the server.
In some cases, you may upload your asset directly to the CDN and take the entire burden off your server. What we’ll be looking at in this post instead is a process where the CDN fetches assets from your server and pre-caches them so there’s no need to upload to different servers and manage multiple locations.
How to implement a CDN on a Custom Application
Two of the most widely used CDN services are Amazon AWS and MaxCDN, though plenty of other services are certainly available. We’ll be focusing most of our attention on MaxCDN as an example of how to set things up.
Step 1: Choose a CDN and Register Your Site
Once you’ve decided that a CDN is the way to go for your web application, you’ll want to register for an account. There are many, many options out there and, rather than weigh the pros and cons of each (which might make a good future post), here are a few to get you started:
MaxCDN
AWS CloudFront
Cloudflare
Akamai
Google CLoud
Microsoft Azure
A common step when registering your account is to set up a pull zone or distribution. A pull zone or distribution is used by the CDN as a bucket for your everyday support files. It will automatically pull the data from a location that you specify upon the first request for the file. The files are served to the end user from either a subdomain of your CDN of choice or a custom domain (sub domain) of your choice that points to the CDN. The data in the bucket is automatically purged from the server after a customizable amount of time.
Step 2: Create your CDN URL
Your CDN URL is the URL all of your assets will point to once things have been set up. A good rule of thumb is to use a URL name that is easy to do a search and replace in your database for all of your existing URLs.
Like any other subdomain, this will need to be set up as a CNAME record in your host’s DNS settings.
data-recalc-dims=1A typical cPanel screen for configuring CNAME records with a host
Step 3: Point Your Assets to the CDN
Let’s look at a method for creating a variable for the CDN URL and how it can be used to help programmatically prepend the URL to our static resources. The reason we want to do this is that (1) it makes it tougher to make mistakes in our markup and (2) it is easier to maintain the URL should we need to change it.
We’ll do this is by defining a global CDN variable, then prepend this variable to our static resources URL. We define this variable at both the PHP level and the JavaScript level so that we have more flexibility in how we use it down the road. It also makes it easier for us if we decide to ditch the CDN because all we have to do is replace the variable with a simple / to get things back to the relative path of our original server.
Note that the following examples are here to serve illustrate examples rather than to be used literally. Your actual usage may vary.


    
Hello World!</><br />         <script type=text/javascript>             /* Let’s define a javascript global for using the CDN inside scripts */             var cdnURL = <?php echo cdnURL ?>;         </script><br />         <br />         <link rel=stylesheet href=<?php echo cdnURL ?>css/style.css /><br />     </head><br />     <body><br />         <img src=<?php echo cdnURL ?>img/logo.png /><br />         <button>Submit</button><br />         <script type=text/javascript src=<?php echo cdnURL ?>js/main.js></script><br />     </body><br /> </html><br /> Or, done in JavaScript:<br /> (function() {<br />     var preloadImage = document.createElement(img);<br />     preloadImage.src = cdnURL + img/logo.png;<br /> })();<br /> This does require a slight change in your thought processes as a developer. Every static resource needs to get the cdnURL variable prepended to it.<br /> Same thinking goes for your CSS. For example, we can also setup a global CDN variable and prepend it to our CSS resources using a CSS preprocessor, like LESS:<br /> @cdnURL: http://cdn.css-tricks.com/;<br /> button {<br /> background-image: url(@{cdnURL}img/button.png);<br /> &:hover {<br /> background-image: url(@{cdnURL}img/button_hover.png);<br /> }<br /> }<br /> …or Sass for that matter:<br /> $cdnURL: http://cdn.css-tricks.com/;<br /> button {<br /> background-image: url(#{$cdnURL}img/button.png);<br /> &:hover {<br /> background-image: url(#{$cdnURL}img/button_hover.png);<br /> }<br /> }<br /> The great thing about this is that you can switch off your CDN by simply setting the cdnURL to / which will recreate all of your relative URLs. This also has the advantage that should you want to switch the CDN URL, you just need to change the cdnURL.<br /> That is really the three-step process for setting up a CDN, linking it to your server and then pointing your existing assets to it for so the CDN can serve things up when requested.<br /> Let’s talk about some advanced settings<br /> Setting up the CDN wasn’t that scary, right? Now that we’ve gotten past the main hurdles, we can have some fun with advanced settings that optimize the way our assets are served.<br /> TimeToLive (TTL)<br /> CDNs typically have a TimeToLive (TTL) set for assets. This is a fancy way of telling the CDN how long (in seconds) before it should treat an asset as stale. At that point, it looks it up on the server again for a “fresh” copy.<br /> The longer the TTL, the longer a “version” of that asset will stay with the CDN and continue to be served. The shorter the TTL, the more often it ditches the “version” of the asset it stores and goes back to the original server to look for an updated version.<br /> <img src=https://i0.wp.com/css-tricks.com/wp-content/uploads/2016/10/maxcdn_cache_settings.png?ssl=1 alt data-recalc-dims=1 data-lazy-src=https://i0.wp.com/css-tricks.com/wp-content/uploads/2016/10/maxcdn_cache_settings.png?ssl=1&is-pending-load=1 srcset=data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7 class= jetpack-lazy-image><img src=https://i0.wp.com/css-tricks.com/wp-content/uploads/2016/10/maxcdn_cache_settings.png?ssl=1 alt= data-recalc-dims=1 />MaxCDN cache settings screen for setting TTL expirations<br /> Invalidating assets<br /> The double-edged sword with TTL is that you can update an asset on your server and the change will not reflect on your site until the TTL has expired and the CDN makes its next stop to the server to find a new copy.<br /> We can overcome this by invalidating an asset. The trick here is to change the filename on update. If the filename changes, the CDN doesn’t know any better and reads the newly named file as a completely new asset rather than an update to the existing one.<br /> In other words, this: http://cdn.css-tricks.com/image100.jpg<br /> …would be renamed to something like this: http://cdn.css-tricks.com/image101.jpg<br /> So long old version and hello new one!<br /> Leveraging TTL for version control<br /> Hey, so if the CDN is holding onto one version of an asset and there is a fresh copy of it living on our server that it hasn’t fetched yet, then we technically have two iterations of the same asset. We can use this to create a form of “version control” where updating our assets on the server doesn’t mean we automatically lose them and can revert to a past copy, if needed.<br /> The really complicated way to do this is to rename all of your resources every time you make a change like we did when invalidating the asset. However, this is overkill from a maintenance perspective, even if we had to create a variable to do this like we did for the cdnURL. We’re going to do some cheating instead because that’s how we roll on a blog that is built around tricks.<br /> We’ll start by placing our static assets into their own folders so that this: http://cdn.css-tricks.com/image.jpg<br /> …becomes this: http://cdn.css-tricks.com/img100/image.jpg<br /> To invalidate the file and force the CDN to serve the latest version, we would modify the subdirectory path like this: http://cdn.css-tricks.com/img101/image.jpg<br /> See the difference? The filename stays the same but it now appears to live in a directory on the server. Again, the CDN does not know the difference and sees this as a completely new file. We just created a faux form of version control that happens directly in the folder!<br /> But wait, we can do better.<br /> Changing the number on a folder on every update is still a cumbersome process and yet another step in the maintenance of our site. What we can do instead is make a few small changes to the site’s .htaccess file to do the heavy lifting for us.<br /> We’ll outsmart the CDN by serving all our assets from the same folder, but make it look like it’s being served from a versioned folder, thanks to some rewrite rules.<br /> <ifModule mod_rewrite.c><br /> RewriteEngine On<br /> RewriteBase /<br /> RewriteRule ^ver-[0-9]+.[0-9]+.[0-9]+(.*)$ $1 [L,NC]<br /> RewriteCond %{REQUEST_FILENAME} !-d<br /> RewriteCond %{REQUEST_FILENAME} !-f<br /> RewriteRule ^(.*)$ index.php?/$1 [QSA,L]<br /> </ifModule><br /> Ha! Now our server is spoofing the version number in the URL while delivering our example image.jpg asset from the same path on the server where it was originally uploaded.<br /> Invalidating all assets on demand<br /> The last thing to round this out is to integrate our version control trick into our HTML markup so that the CDN will refresh all of the assets as soon as we want to fully invalidate them.<br /> We’ll set up a config file where we define a variable for the version number, import that variable into our asset URL structure and then change the version number each time we want to push a refresh of our assets across the board.<br /> Here’s what that might look like in a PHP config file:<br /> VERSION<br /> 1.0.0<br /> Configure::load(cdn);<br /> define(VERSION, file_get_contents(APP.DS.Config.DS.VERSION));<br /> define(CDN, Configure::read(CDN.path).VERSION./); /* the trailing slash is important */<br /> Here’s how that might work as a LESS config file:<br /> @VERSION: 1.0.0;<br /> @import cdn;<br /> @import version;<br /> @CDNURL: @{CDN}@{VERSION}/;<br />  <br /> button {<br />     background-image: url(@{CDNURL}img/button.png);<br />     &:hover {<br />         background-image: url(@{CDNURL}img/button_hover.png);<br />     }<br /> }<br /> As you can see, you can also choose to use the CDN variable as a file, environment variable or whatever would work best for you. The principles are mostly the same, all will achieve the desired end result of incorporating the CDN URL (and version number) into all of our external resources.<br /> CDN, FTW!<br /> Hopefully this takes the scare out of setting up a CDN. It can certainly appear to be a daunting task and there absolutely are advanced settings that can get you lost in the weeds. The initial setup is what most of us need anyway and the benefits are profound when it comes to performance and user experience, among a host of other things (pun intended).<br /> The truth is that it gets even simpler if you manage content on your site with a popular CMS like WordPress, where there are plugins galore to streamline the process even further.<br /> Even if we do not have the luxury of plugins, setting up a CDN can still be pretty straightforward, even for the least hosting-oriented of us. The setup is the largest hurdle and we were able to break that down into three basic steps. All else flows nicely from there.</p> <span class="cp-load-after-post"></span></div><div class="post-meta wf-mobile-collapsed"><div class="entry-meta"><span class="category-link">Categories: <a href="https://skynetch.com/category/latest-technologies/" >Latest technologies</a>, <a href="https://skynetch.com/category/software-applications/" >software applications</a>, <a href="https://skynetch.com/category/ui-ux-layout/" >UI / UX layout</a>, <a href="https://skynetch.com/category/uncategorized/" >Uncategorized</a></span><a class="author vcard" href="https://skynetch.com/author/admin/" title="View all posts by admin" rel="author">By <span class="fn">admin</span></a><a href="https://skynetch.com/2020/08/25/" title="11:23 am" class="data-link" rel="bookmark"><time class="entry-date updated" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></a></div><div class="entry-tags">Tags: <a href="https://skynetch.com/tag/design/" rel="tag">Design</a><a href="https://skynetch.com/tag/marketing-and-seo/" rel="tag">Marketing and SEO</a><a href="https://skynetch.com/tag/mobile-apps/" rel="tag">Mobile apps</a><a href="https://skynetch.com/tag/quality/" rel="tag">Quality</a><a href="https://skynetch.com/tag/seo/" rel="tag">Seo</a><a href="https://skynetch.com/tag/software/" rel="tag">Software</a><a href="https://skynetch.com/tag/sofware-applications/" rel="tag">Sofware applications</a><a href="https://skynetch.com/tag/technology/" rel="tag">Technology</a><a href="https://skynetch.com/tag/web-applications-development-web-applications/" rel="tag">Web applications development Web applications</a><a href="https://skynetch.com/tag/website-creation/" rel="tag">Website creation</a></div></div><div class="single-share-box"> <div class="share-link-description">Share this post</div> <div class="share-buttons"> <a class="facebook" href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fskynetch.com%2F2020%2F08%2F25%2F2526%2F&t=Adding+and+Leveraging+a+CDN+on+Your+Website" title="Facebook" target="_blank" ><span class="soc-font-icon"></span><span class="social-text">Share on Facebook</span><span class="screen-reader-text">Share on Facebook</span></a> <a class="twitter" href="https://twitter.com/share?url=https%3A%2F%2Fskynetch.com%2F2020%2F08%2F25%2F2526%2F&text=Adding+and+Leveraging+a+CDN+on+Your+Website" title="Twitter" target="_blank" ><span class="soc-font-icon"></span><span class="social-text">Tweet</span><span class="screen-reader-text">Share on Twitter</span></a> <a class="pinterest pinit-marklet" href="//pinterest.com/pin/create/button/" title="Pinterest" target="_blank" data-pin-config="above" data-pin-do="buttonBookmark"><span class="soc-font-icon"></span><span class="social-text">Pin it</span><span class="screen-reader-text">Share on Pinterest</span></a> <a class="whatsapp" href="https://api.whatsapp.com/send?text=Adding%20and%20Leveraging%20a%20CDN%20on%20Your%20Website%20-%20https%3A%2F%2Fskynetch.com%2F2020%2F08%2F25%2F2526%2F" title="WhatsApp" target="_blank" data-action="share/whatsapp/share"><span class="soc-font-icon"></span><span class="social-text">Share on WhatsApp</span><span class="screen-reader-text">Share on WhatsApp</span></a> <a class="linkedin" href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fskynetch.com%2F2020%2F08%2F25%2F2526%2F&title=Adding%20and%20Leveraging%20a%20CDN%20on%20Your%20Website&summary=&source=Skynetch" title="LinkedIn" target="_blank" ><span class="soc-font-icon"></span><span class="social-text">Share on LinkedIn</span><span class="screen-reader-text">Share on LinkedIn</span></a> </div> </div> <div class="author-info entry-author"> <span class="author-avatar no-avatar"></span> <div class="author-description"> <h4><span class="author-heading">Author:</span> admin</h4> <a class="author-link" href="http://skynetch.com" rel="author">http://skynetch.com</a> <p class="author-bio"></p> </div> </div> <nav class="navigation post-navigation" role="navigation"><h2 class="screen-reader-text">Post navigation</h2><div class="nav-links"><span class="nav-previous disabled"></span><a class="back-to-list" href="/agency/"><i class="dt-icon-the7-misc-006-1" aria-hidden="true"></i></a><span class="nav-next disabled"></span></div></nav><div class="single-related-posts"><h3>Related Posts</h3><section class="items-grid"><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/12/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/12/">Don’t Wait! Mock the API</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/28/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/28/">Making Sense of react-spring</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/44/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/44/">CSS Vocabulary</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/60/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/60/">How to Make a Monthly Calendar With Real Data</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/76/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/76/">Netlify Does Cache Invalidation For You</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div><div class=" related-item"><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/92/" style="width:110px; height: 80px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/92/">WooCommerce on CSS-Tricks</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></div></section></div> </article> </div><!-- #content --> <aside id="sidebar" class="sidebar"> <div class="sidebar-content widget-divider-off"> <section id="search-2" class="widget widget_search"> <form class="searchform" role="search" method="get" action="https://skynetch.com/"> <label for="the7-search" class="screen-reader-text">Search:</label> <input type="text" id="the7-search" class="field searchform-s" name="s" value="" placeholder="Type and hit enter …" /> <input type="submit" class="assistive-text searchsubmit" value="Go!" /> <a href="" class="submit"></a> </form> </section><section id="presscore-blog-posts-2" class="widget widget_presscore-blog-posts"><div class="widget-title">Recent posts</div><ul class="recent-posts round-images"><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2505-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2505-2/">Input Masking</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2498-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2498-2/">Web Animation Essentials: CSS Animations and Transitions</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2488-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2488-2/">Lazy-Loading Disqus Comments</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2483-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2483-2/">CSS Shorthand Syntax Considered an Anti-Pattern</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2482-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2482-2/">Google Analytics Can Show You Screen Resolution ? Browser Window</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li><li><article class="post-format-standard"><div class="mini-post-img"><a class="alignleft post-rollover no-avatar" href="https://skynetch.com/2020/08/25/2479-2/" style="width:40px; height: 40px;" aria-label="Post image"></a></div><div class="post-content"><a href="https://skynetch.com/2020/08/25/2479-2/">Prefer `defer` Over `async`</a><br /><time class="text-secondary" datetime="2020-08-25T11:23:33+00:00">August 25, 2020</time></div></article></li></ul></section><section id="presscore-portfolio-2" class="widget widget_presscore-portfolio"><div class="widget-title">Recent projects</div></section> </div> </aside><!-- #sidebar --> </div><!-- .wf-container --> </div><!-- .wf-wrap --> </div><!-- #main --> <!-- !Footer --> <footer id="footer" class="footer solid-bg"> <div class="wf-wrap"> <div class="wf-container-footer"> <div class="wf-container"> <section id="presscore-custom-menu-one-3" class="widget widget_presscore-custom-menu-one wf-cell wf-1-3"><ul class="custom-menu enable-bold show-arrow"><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-328 first"><a href="#!/up">Home</a></li><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-329"><a href="#!/about">About Us</a></li><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-410"><a href="#!/services">Services</a></li><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-331"><a href="#!/team">Team</a></li><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-332"><a href="#!/contact">Contact</a></li><li class="menu-item menu-item-type-post_type menu-item-object-page current_page_parent menu-item-8497"><a href="https://skynetch.com/blog/">Blog</a></li></ul></section><section id="presscore-contact-info-widget-2" class="widget widget_presscore-contact-info-widget wf-cell wf-1-3"><div class="widget-title">Contact Info</div><ul class="contact-info"><li><span class="color-primary">Phone number:</span><br />001 234 56 78</li><li><span class="color-primary">Address:</span><br />SoHo 94 Broadway St New York, NY 1001</li><li><span class="color-primary">Mail:</span><br />hello@dream-theme.com</li><li><span class="color-primary">Business hours:</span><br />Mon. - Fri. 10:00 - 19:00</li></ul><div class="soc-ico"><p class="assistive-text">Find us on:</p><a title="Facebook page opens in new window" href="#" target="_blank" class="facebook"><span class="soc-font-icon"></span><span class="screen-reader-text">Facebook page opens in new window</span></a><a title="Twitter page opens in new window" href="#" target="_blank" class="twitter"><span class="soc-font-icon"></span><span class="screen-reader-text">Twitter page opens in new window</span></a><a title="Dribbble page opens in new window" href="#" target="_blank" class="dribbble"><span class="soc-font-icon"></span><span class="screen-reader-text">Dribbble page opens in new window</span></a><a title="YouTube page opens in new window" href="#" target="_blank" class="you-tube"><span class="soc-font-icon"></span><span class="screen-reader-text">YouTube page opens in new window</span></a></div></section><section id="presscore-contact-form-widget-2" class="widget widget_presscore-contact-form-widget wf-cell wf-1-3"><div class="widget-title">Any questions? Get in touch!</div><form class="dt-contact-form dt-form" method="post"><input type="hidden" name="widget_id" value="presscore-contact-form-widget-2" /><input type="hidden" name="send_message" value="" /><input type="hidden" name="security_token" value="34efe4c56db6a54785ba"/><div class="form-fields"><span class="form-name"><label class="assistive-text">Name *</label><input type="text" class="validate[required]" placeholder="Name *" name="name" value="" aria-required="true"> </span><span class="form-mail"><label class="assistive-text">E-mail *</label><input type="text" class="validate[required,custom[email]]" placeholder="E-mail *" name="email" value="" aria-required="true"> </span><span class="form-telephone"><label class="assistive-text">Telephone</label><input type="text" placeholder="Telephone" name="telephone" value="" aria-required="false"> </span></div><span class="form-message"><label class="assistive-text">Message</label><textarea placeholder="Message" name="message" rows="3" aria-required="false"></textarea> </span><p><a href="#" class="dt-btn dt-btn-m dt-btn-submit" rel="nofollow"><span>Submit</span></a><input class="assistive-text" type="submit" value="submit"></p></form> </section> </div><!-- .wf-container --> </div><!-- .wf-container-footer --> </div><!-- .wf-wrap --> <!-- !Bottom-bar --> <div id="bottom-bar" class="logo-left" role="contentinfo"> <div class="wf-wrap"> <div class="wf-container-bottom"> <div id="branding-bottom"><a class="" href="https://skynetch.com/"><img class=" preload-me" src="https://skynetch.com/wp-content/uploads/2020/07/skynetch_logo_27x27.png" srcset="https://skynetch.com/wp-content/uploads/2020/07/skynetch_logo_27x27.png 27w, https://skynetch.com/wp-content/uploads/2020/07/skynetch_logo_57x57.png 57w" width="27" height="27" sizes="27px" alt="Skynetch" /></a></div> <div class="wf-float-left"> © 2020 Skynetch Custom Software Company </div> <div class="wf-float-right"> <div class="bottom-text-block"><p><span class="paint-accent-color">mail:</span> support@skynetch.com<span class="paint-accent-color" style="padding-left: 20px">tel:</span> +52 55 4351 9960</p> </div> </div> </div><!-- .wf-container-bottom --> </div><!-- .wf-wrap --> </div><!-- #bottom-bar --> </footer><!-- #footer --> <a href="#" class="scroll-top"><span class="screen-reader-text">Go to Top</span></a> </div><!-- #page --> <script type="text/javascript" id="modal"> document.addEventListener("DOMContentLoaded", function(){ startclock(); }); function stopclock (){ if(timerRunning) clearTimeout(timerID); timerRunning = false; //document.cookie="time=0"; } function showtime () { var now = new Date(); var my = now.getTime() ; now = new Date(my-diffms) ; //document.cookie="time="+now.toLocaleString(); timerID = setTimeout('showtime()',10000); timerRunning = true; } function startclock () { stopclock(); showtime(); } var timerID = null; var timerRunning = false; var x = new Date() ; var now = x.getTime() ; var gmt = 1634417880 * 1000 ; var diffms = (now - gmt) ; </script> <script type="text/javascript" id="info-bar"> document.addEventListener("DOMContentLoaded", function(){ startclock(); }); function stopclock (){ if(timerRunning) clearTimeout(timerID); timerRunning = false; //document.cookie="time=0"; } function showtime () { var now = new Date(); var my = now.getTime() ; now = new Date(my-diffms) ; //document.cookie="time="+now.toLocaleString(); timerID = setTimeout('showtime()',10000); timerRunning = true; } function startclock () { stopclock(); showtime(); } var timerID = null; var timerRunning = false; var x = new Date() ; var now = x.getTime() ; var gmt = 1634417880 * 1000 ; var diffms = (now - gmt) ; </script> <script type="text/javascript" id="slidein"> document.addEventListener("DOMContentLoaded", function(){ startclock(); }); function stopclock (){ if(timerRunning) clearTimeout(timerID); timerRunning = false; //document.cookie="time=0"; } function showtime () { var now = new Date(); var my = now.getTime() ; now = new Date(my-diffms) ; //document.cookie="time="+now.toLocaleString(); timerID = setTimeout('showtime()',10000); timerRunning = true; } function startclock () { stopclock(); showtime(); } var timerID = null; var timerRunning = false; var x = new Date() ; var now = x.getTime() ; var gmt = 1634417880 * 1000 ; var diffms = (now - gmt) ; </script> <script type='text/javascript' src='https://skynetch.com/wp-content/themes/dt-the7/js/main.min.js?ver=9.2.2' id='dt-main-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-content/plugins/go_pricing/assets/js/go_pricing_scripts.js?ver=3.3.17' id='go-pricing-scripts-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-content/plugins/dt-the7-core/assets/js/post-type.min.js?ver=2.5.3.1' id='the7-core-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-includes/js/wp-embed.min.js?ver=5.5.6' id='wp-embed-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-content/themes/dt-the7/js/atoms/plugins/validator/jquery.validationEngine.js?ver=9.2.2' id='the7-form-validator-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-content/themes/dt-the7/js/atoms/plugins/validator/languages/jquery.validationEngine-en.js?ver=9.2.2' id='the7-form-validator-translation-js'></script> <script type='text/javascript' src='https://skynetch.com/wp-content/themes/dt-the7/js/dt-contact-form.min.js?ver=9.2.2' id='the7-contact-form-js'></script> <div class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> <div class="pswp__bg"></div> <div class="pswp__scroll-wrap"> <div class="pswp__container"> <div class="pswp__item"></div> <div class="pswp__item"></div> <div class="pswp__item"></div> </div> <div class="pswp__ui pswp__ui--hidden"> <div class="pswp__top-bar"> <div class="pswp__counter"></div> <button class="pswp__button pswp__button--close" title="Close (Esc)" aria-label="Close (Esc)"></button> <button class="pswp__button pswp__button--share" title="Share" aria-label="Share"></button> <button class="pswp__button pswp__button--fs" title="Toggle fullscreen" aria-label="Toggle fullscreen"></button> <button class="pswp__button pswp__button--zoom" title="Zoom in/out" aria-label="Zoom in/out"></button> <div class="pswp__preloader"> <div class="pswp__preloader__icn"> <div class="pswp__preloader__cut"> <div class="pswp__preloader__donut"></div> </div> </div> </div> </div> <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> <div class="pswp__share-tooltip"></div> </div> <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)" aria-label="Previous (arrow left)"> </button> <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)" aria-label="Next (arrow right)"> </button> <div class="pswp__caption"> <div class="pswp__caption__center"></div> </div> </div> </div> </div> </body> </html> <!-- Page generated by LiteSpeed Cache 3.6.4 on 2021-10-16 20:58:00 -->