<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Chetan Vaity on Medium]]></title>
        <description><![CDATA[Stories by Chetan Vaity on Medium]]></description>
        <link>https://medium.com/@chetanvaity?source=rss-9822e12d8dc2------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*HnxumWS_suWsUb7XBsqIsg.jpeg</url>
            <title>Stories by Chetan Vaity on Medium</title>
            <link>https://medium.com/@chetanvaity?source=rss-9822e12d8dc2------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 19 May 2026 12:48:30 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@chetanvaity/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Hosting HTTPS websites with SNI on AWS]]></title>
            <link>https://medium.com/@chetanvaity/hosting-https-websites-with-sni-on-aws-98c6e7eb00a1?source=rss-9822e12d8dc2------2</link>
            <guid isPermaLink="false">https://medium.com/p/98c6e7eb00a1</guid>
            <category><![CDATA[https]]></category>
            <category><![CDATA[lets-encrypt]]></category>
            <category><![CDATA[sni]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[nginx]]></category>
            <dc:creator><![CDATA[Chetan Vaity]]></dc:creator>
            <pubDate>Fri, 31 Mar 2017 23:36:06 GMT</pubDate>
            <atom:updated>2017-09-10T00:18:08.097Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*3Ntz8MAEObg_dW10I9-RfQ.png" /></figure><p>One of the key products of <a href="https://www.tablehero.com/?utm_source=medium_blog&amp;utm_medium=organic&amp;utm_campaign=https_sni_article">Tablehero</a> is automatic creation and hosting of beautiful and mobile friendly websites for restaurants.</p><h3>Hosting multiple websites</h3><p>Tablehero is completely hosted on <a href="https://aws.amazon.com/products/">AWS</a>. We started out with a typical setup to serve these websites — a set of application servers which fetch data from the database and render the restaurant website on the fly. These application servers decide which restaurant to render based on the hostname of the HTTP request. A classic Elastic Load Balancer (<a href="https://aws.amazon.com/elasticloadbalancing/">ELB</a>) was configured with HTTP listener forwarding the traffic to the set of application servers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/949/1*L2KvZe7bo7NEM8LS0bJDGw.png" /></figure><p>This was all well and good, but we decided that all the restaurant websites served by us should be HTTPS. Because, <a href="https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https">its</a> <a href="https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/">a</a><em> </em><a href="https://https.cio.gov/everything/"><strong><em>good</em></strong></a><strong><em> </em></strong><a href="https://security.googleblog.com/2014/08/https-as-ranking-signal_6.html"><strong><em>thing</em></strong></a>. Also, with more and more restaurants opting for <a href="https://www.tablehero.com/orders">Online orders</a>, Merchandise sale, etc — their website essentially becomes an online store where customers transact and hence HTTPS is essential.</p><h3>TLS and SNI</h3><p>Now, the problem:</p><blockquote>When making a TLS connection, the client (browser) requests a <a href="https://en.wikipedia.org/wiki/Digital_certificate">digital certificate</a> from the web server. Once the server sends the certificate, the client examines it and compares the name it was trying to connect to with the name(s) included in the certificate. If a match occurs, the connection proceeds as normal. If a match is not found, the user may be warned of the discrepancy and the connection may abort as the mismatch may indicate an attempted <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle attack</a>. …</blockquote><blockquote>A server that is responsible for multiple hostnames is likely to need to present a different certificate for each name. …</blockquote><blockquote><a href="https://en.wikipedia.org/wiki/Virtual_hosting#Name-based">Name-based virtual hosting</a> allows multiple DNS hostnames to be hosted by a single server (usually a web server) on the same IP address. To achieve this, the server uses a hostname presented by the client as part of the protocol (for HTTP the name is presented in the <a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requests">host header</a>). However, when using HTTPS, the TLS handshake happens before the server sees any HTTP headers. Therefore, it is not possible for the server to use the information in the HTTP host header to decide which certificate to present and as such only names covered by the same certificate can be served from the same IP address. …</blockquote><blockquote>SNI (Server Name Indication) addresses this issue by having the client send the name of the virtual domain as part of the TLS negotiation.This enables the server to select the correct virtual domain early and present the browser with the certificate containing the correct name. Therefore, with clients and servers that implement SNI, a server with a single IP address can serve a group of domain names for which it is impractical to get a common certificate.</blockquote><blockquote><em>— From the </em><a href="https://en.wikipedia.org/wiki/Server_Name_Indication"><em>Wikipedia page</em></a><em> on SNI (Server Name Indication)</em></blockquote><p>Since 2006, web browsers have been adding <a href="https://en.wikipedia.org/wiki/Server_Name_Indication">support for SNI</a> and now it is supported by most web browsers — on desktop and mobile devices.</p><p>Sounds well and good. The catch is that AWS ELB <a href="http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-https-load-balancers.html">does not support SNI </a>— <a href="https://forums.aws.amazon.com/thread.jspa?threadID=96534">at least not yet</a>. So, we cannot have the ELB handle the SSL termination. Enter <a href="http://nginx.org/en/docs/http/configuring_https_servers.html#sni">nginx with SNI support</a>.</p><h3>LetsEncrypt and nginx with SNI</h3><p>It is straightforward to configure <a href="http://nginx.org/">nginx</a> to handle multiple virtual hosts using <a href="http://nginx.org/en/docs/http/configuring_https_servers.html#name_based_https_servers">different server blocks</a> in its configuration.</p><p>What about the SSL certificates? Anyone who has purchased multiple SSL certificates from <a href="https://www.godaddy.com/web-security/ssl-certificate">traditional</a> <a href="https://comodosslstore.com/promoads/cheap-comodo-ssl.aspx">Certificate</a> <a href="https://www.websecurity.symantec.com/buy-renew">Authorities</a> (CAs) know that the experience is far from smooth. Imagine purchasing and managing hundreds of SSL certificates.</p><p>Enter <a href="https://letsencrypt.org/">LetsEncrypt</a>.</p><blockquote>Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit.</blockquote><p>Sponsored by <a href="https://letsencrypt.org/sponsors/">industry heavyweights</a>, and with a deliberate focus on transparency, it certainly is the way to go.</p><p>The certificates issued by LetsEncrypt are valid for 3 months and hence certificate renewal needs to be dealt with almost immediately. EFF’s <a href="https://certbot.eff.org/">Certbot</a> is a command line tool which makes getting new certificates and renewing them a relatively simple task.</p><blockquote>certbot-auto — nginx -d {{ domain_name }} -n — redirect</blockquote><p>When run the first time, it gets a new certificate for the domain and using the <em>renew</em> option, subsequent runs check if it is due for renewal and gets a new certificate if needed. All this while the nginx server is running — checkout the awesome <a href="https://letsencrypt.org/how-it-works/">ACME protocol</a>.</p><h3>Tying up</h3><p>Next, to eliminate the single point of failure of the nginx instance, we added a new ELB in front of a set of instances running nginx. This ELB has a TCP listener (not an HTTP listener) and it simply transfers all TCP traffic on port 80 and 443 transparently to the nginx servers at its backend. The final picture looks like this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/949/1*QeJVEcQ6KJ0Zl-M9kpq4PA.png" /></figure><p>There is still a problem to be taken care of. Forwarding requests from nginx to the HTTP ELB using a <strong>proxy_pass</strong> directive is not as straightforward as it sounds. This is because the IP address of the ELB endpoint may change quite frequently. And nginx does the DNS lookup once and uses the result till the configuration is reloaded. The way around this is to use the resolver directive as described <a href="https://tenzer.dk/nginx-with-dynamic-upstreams/">here</a>.</p><p>The remaining work was mainly writing <a href="https://www.ansible.com/">Ansible</a> roles and playbooks for doing tasks like adding new virtual hosts, getting and renewing certificates on the nginx instances and making it all available through good old <a href="https://jenkins.io/">Jenkins</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/885/1*ud04ufQ4tPShWUeFcR1FBA.png" /></figure><p>et voilà</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=98c6e7eb00a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[First story]]></title>
            <link>https://medium.com/@chetanvaity/first-story-81656bf5e352?source=rss-9822e12d8dc2------2</link>
            <guid isPermaLink="false">https://medium.com/p/81656bf5e352</guid>
            <category><![CDATA[comics]]></category>
            <category><![CDATA[poetry]]></category>
            <dc:creator><![CDATA[Chetan Vaity]]></dc:creator>
            <pubDate>Wed, 18 May 2016 11:57:53 GMT</pubDate>
            <atom:updated>2016-05-18T11:57:53.913Z</atom:updated>
            <content:encoded><![CDATA[<p>something</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=81656bf5e352" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>