Jekyll2019-07-12T00:27:34+02:00https://blog.adragunov.com/feed.xmlAlexander DragunovIT consultant by day. Photographer by night.Alexander DragunovCost of running personal static website on AWS2019-06-28T00:00:00+02:002019-06-28T00:00:00+02:00https://blog.adragunov.com/cost-of-running-peronal-static-website-on-aws<p>It’s been more than two months since I moved my photo portfolio website and this blog to AWS. And I wanted to share my experience in running it, some statistics and, the most important, how much did I pay for it.</p>
<p>In short, what do I have/use:</p>
<ul>
<li>Amazon Route 53 with two hosted zones (my photo web site domain and one playground domain)</li>
<li>AWS Certificate Manager for enabling https</li>
<li>Amazon S3 for storing static assets and for static website hosting</li>
<li>Amazon CloudFront for content delivery / content caching</li>
</ul>
<p>So, in total, how much did I pay last month (my photo portfolio web site and blog):</p>
<hr />
<h1 id="086-per-month-including-vat">0.86$ per month including VAT!</h1>
<hr />
<p>If we go into details per each specific service:</p>
<p><img src="/images/cost-of-running-peronal-static-website-on-aws/cost_s3.gif" alt="01" /></p>
<p>PLease note, that I have one more hosted zone for my playground domain, which is included in screenshot below.</p>
<p><img src="/images/cost-of-running-peronal-static-website-on-aws/cost_route53.gif" alt="02" /></p>
<p>As I use base price class of CloudFront, I use only US, Canada and Europe as edge locations.</p>
<p><img src="/images/cost-of-running-peronal-static-website-on-aws/cost_cloudfront.gif" alt="03" /></p>
<p>By looking at Google Analytics, I can see that I have other traffic sources like Asia.</p>
<p><img src="/images/cost-of-running-peronal-static-website-on-aws/cost_google_analytics.gif" alt="04" /></p>
<p>As next step I’ll change price class for the CloudFront distributions to include more edge locations and compare the bill at the end of next month.</p>Alexander DragunovIt’s been more than two months since I moved my photo portfolio website and this blog to AWS. And I wanted to share my experience in running it, some statistics and, the most important, how much did I pay for it.Static website hosting with custom domain and https2019-04-07T00:00:00+02:002019-04-07T00:00:00+02:00https://blog.adragunov.com/static-website-hosting-with-custom-domain-and-https<p>In this post I will describe how I configured static website hosting using Amazon S3 with custom domain, secured website using https, and also configured redirects from naked domain to <code class="highlighter-rouge">www</code> and protocol redirects from <code class="highlighter-rouge">http</code> to <code class="highlighter-rouge">https</code>.</p>
<p>As result user can request the following URLs:</p>
<ul>
<li>http://adragunov.com</li>
<li>http://www.adragunov.com</li>
<li>https://adragunov.com</li>
<li>https://www.adragunov.com</li>
</ul>
<p>And every time ends up at:</p>
<ul>
<li>https://www.adragunov.com</li>
</ul>
<h3 id="step-1-get-certificate">Step 1: Get certificate.</h3>
<p>First of all you need to get https certificate (it’s free!). Go to AWS Console and open <code class="highlighter-rouge">Certificate Manager</code>.</p>
<blockquote>
<p>IMPORTANT: Switch region and create certificate in <code class="highlighter-rouge">us-east-1</code> region, otherwise it will not be available in CloudFront.</p>
</blockquote>
<p><img src="/images/configuring-https-and-protocol-redirects/certificate_1_manager.gif" alt="01" />
<img src="/images/configuring-https-and-protocol-redirects/certificate_2_request.gif" alt="02" /></p>
<p>Enter both naked domain and also wildcard subdomain.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/certificate_3_domains.gif" alt="03" /></p>
<p>Next choose <code class="highlighter-rouge">DNS validation</code> as validation method. As the domain is already registered in Route 53, this is the simplest validation option.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/certificate_4_dns_validation.gif" alt="04" /></p>
<p>Expand the domain name and click <code class="highlighter-rouge">Create record in Route 53</code>. This will automatically create CNAME records in Route 53 and the domain will be verified.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/certificate_5_validate.gif" alt="05" />
<img src="/images/configuring-https-and-protocol-redirects/certificate_6_create_record.gif" alt="06" /></p>
<p>Few minutes later certificate will change status from <code class="highlighter-rouge">Pending validation</code> to <code class="highlighter-rouge">Issued</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/certificate_7_done.gif" alt="07" /></p>
<h3 id="step-2-configure-s3-buckets">Step 2: Configure S3 buckets</h3>
<p>Next you need to create a S3 bucket to host static website.</p>
<p>Go to AWS Console and open <code class="highlighter-rouge">Amazon S3</code>. Click <code class="highlighter-rouge">Create bucket</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_1_buckets.gif" alt="01" /></p>
<p>Choose domain name with www prefix as bucket name, in my case <code class="highlighter-rouge">www.adragunov.com</code>. This bucket will contain all static assets like html pages, styles and images.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_2_create_bucket.gif" alt="02" /></p>
<p>Next be sure to uncheck two <code class="highlighter-rouge">public bucket policies</code> options. This is intended to make this bucket public and you need to be able to add policy to allow public access later.
If you keep these two options checked, you will receive <code class="highlighter-rouge">Access denied</code> error when try to add public access policy.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_3_bucket_properties.gif" alt="03" /></p>
<p>After the bucket is created, you should enable public access to it (as it will be a public website). Open newly created bucket, go to
<code class="highlighter-rouge">Permissions</code> tab, and then <code class="highlighter-rouge">Bucket policy</code> tab.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_4_policy.gif" alt="04" /></p>
<p>Enter the following policy (replace YOUR_BUCKET_NAME with your bucket name) and save it:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"Version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2012-10-17"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Statement"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="s2">"Sid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PublicReadGetObject"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Effect"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Allow"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Principal"</span><span class="p">:</span><span class="w"> </span><span class="s2">"*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Action"</span><span class="p">:</span><span class="w"> </span><span class="s2">"s3:GetObject"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Resource"</span><span class="p">:</span><span class="w"> </span><span class="s2">"arn:aws:s3:::YOUR_BUCKET_NAME/*"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>After the policy is saved, the bucket will be marked as <code class="highlighter-rouge">Public</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_5_policy_added.gif" alt="05" /></p>
<p>Next, you should enable public website hosting for this bucket.</p>
<p>Open bucket, go to <code class="highlighter-rouge">Properties</code> tab, and then open <code class="highlighter-rouge">Static website hosting</code> section.
Check <code class="highlighter-rouge">Use this bucket to host a website</code> and enter <code class="highlighter-rouge">Index document</code>. Save the changes.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_6_website.gif" alt="06" /></p>
<p>Now the bucket is created, public access to it is allowed and website hosting for it is enabled.
So you can upload some static assests to the newly created bucket, like sample index.html page. By doing this, you can check that it’s publically accessible via endpoint (you can see it on the public website properties above).</p>
<p>Next step is to create second bucket for the naked domain, in my example <code class="highlighter-rouge">adragunov.com</code> (without www).</p>
<p>Please follow exactly the same steps as before for the previous bucket, except for the last one when enabling website hosting.</p>
<p>Instead configure the bucket to redirect requests to <code class="highlighter-rouge">www.adragunov.com</code> and use <code class="highlighter-rouge">https</code> as protocol.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/s3_7_redirect.gif" alt="07" /></p>
<p>Also as this bucket redirects all requests to the other bucket, you should not upload any content to this naked bucket.</p>
<h3 id="step-3-create-cloudfront-ditributions">Step 3: Create CloudFront ditributions</h3>
<p>Next create two CloudFront distributions for these two buckets using https certificate created before.
Go to AWS Console and open <code class="highlighter-rouge">CloudFront</code>.</p>
<p>Create first distribution for the fist bucket, in my case for the <code class="highlighter-rouge">www.adragunov.com</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_0_create.gif" alt="00" /></p>
<blockquote>
<p>IMPORTANT: As <code class="highlighter-rouge">Origin Domain Name</code> paste URL for the public website for the S3 bucket that was created (do not choose anything from dropdown!). URL should look like <code class="highlighter-rouge">BUCKET-NAME.s3-website.REGION.amazonaws.com</code>.</p>
</blockquote>
<p>For viewer protocol policy choose <code class="highlighter-rouge">Redirect HTTP to HTTPS</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_1.gif" alt="01" /></p>
<p>Enter CNAME of the domain.
Choose <code class="highlighter-rouge">Custom SSL certificate</code> and select certificate from dropdown (the one that was created in the beginning).</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_2.gif" alt="02" /></p>
<p>Enter default root object (in my case the start page is index.html).</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_3.gif" alt="03" /></p>
<p>Next create new distribution for the naked domain, in my case for the <code class="highlighter-rouge">adragunov.com</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_4.gif" alt="04" /></p>
<p>The difference is that you do not need to enter default root object as this bucket is already configured to redirect all requests to your <code class="highlighter-rouge">www</code> bucket.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/cloudfront_5.gif" alt="05" /></p>
<h3 id="step-4-configure-route-53">Step 4: Configure Route 53</h3>
<p>The last step is to configure DNS entries in Route 53 to point to the newly created CloudFront distrubutions.</p>
<p>Go to AWS Console and open <code class="highlighter-rouge">Route 53</code>.
Open Hosted zone for your domain and click <code class="highlighter-rouge">Create Record Set</code>.</p>
<p><img src="/images/configuring-https-and-protocol-redirects/route53_1_hosted_zone.gif" alt="01" /></p>
<ul>
<li>Enter name <code class="highlighter-rouge">www</code>.</li>
<li>Choose <code class="highlighter-rouge">A</code> as type.</li>
<li>Check Alias as <code class="highlighter-rouge">Yes</code>.</li>
<li>Choose CloudFront distribution for your <code class="highlighter-rouge">www</code> domain from the list.</li>
</ul>
<p><img src="/images/configuring-https-and-protocol-redirects/route53_2_recordset.gif" alt="02" /></p>
<p>Next create one more Record Set for the naked domain (leave name empty and choose CloudFront distribution for the naked domain, in my case to the <code class="highlighter-rouge">adragunov.com</code>).</p>
<p>So at the end the final configuration will look like this:</p>
<p><img src="/images/configuring-https-and-protocol-redirects/architecture.gif" alt="Final design" /></p>
<h3 id="that-is-it">That is it!</h3>
<p>If you are hosting Single Page Application (SPA) and need to make client side routing working, please refer to <a href="/static-website-hosting-and-client-side-routing">Static website hosting and client side routing</a>.</p>Alexander DragunovIn this post I will describe how I configured static website hosting using Amazon S3 with custom domain, secured website using https, and also configured redirects from naked domain to www and protocol redirects from http to https.Static website hosting and client side routing2019-03-31T00:00:00+01:002019-03-31T00:00:00+01:00https://blog.adragunov.com/static-website-hosting-and-client-side-routing<p>My photo portfolio is implemented as SPA (Single Page Application) using React, so all routing is happening on the client. And it worked fine, until I did hard refresh of the
page or wanted to share direct link to one of the pages (for example <a href="https://www.adragunov.com/ethiopia">https://www.adragunov.com/ethiopia</a>). In this case users saw 404 error page produced by Amazon S3 as it tried to find object with key <b>ethiopia</b> in the bucket, which obviously did not exist as it only existed as client route.</p>
<p><img src="/images/static-website-hosting-and-client-side-routing/1_404_error.gif" alt="01" /></p>
<p>My first solution was to simply set index.html as error page under S3 bucket static website hosting configuration.
It worked fine from end user perspective, the page was displayed correctly.
But when I checked network, actually the page content was returned with 404 Not Found status code, not with 200 OK.
This means that this solution was not good for indexing and crawlers.</p>
<p><img src="/images/static-website-hosting-and-client-side-routing/2_error_document.gif" alt="02" /></p>
<p>The other solution that I found was to create Custom Error Response in Amazon CloudFront distribution. As long as I already used CloudFront for content delivery using https, this was exactly what I needed.</p>
<p><img src="/images/static-website-hosting-and-client-side-routing/3_cloudfront.gif" alt="03" /></p>
<p><img src="/images/static-website-hosting-and-client-side-routing/4_custom_error_response.gif" alt="04" /></p>
<p>And now client side routing works perfectly with 200 OK status code. Simple and elegant.</p>Alexander DragunovMy photo portfolio is implemented as SPA (Single Page Application) using React, so all routing is happening on the client. And it worked fine, until I did hard refresh of the page or wanted to share direct link to one of the pages (for example https://www.adragunov.com/ethiopia). In this case users saw 404 error page produced by Amazon S3 as it tried to find object with key ethiopia in the bucket, which obviously did not exist as it only existed as client route.Moving domain from GoDaddy to AWS2019-03-29T00:00:00+01:002019-03-29T00:00:00+01:00https://blog.adragunov.com/moving-domain-from-godaddy-to-aws<p>I’ve used GoDaddy for the hosting of my personal photo web site since 2012, and every time I logged in into the GoDaddy portal I felt lost by the amount of different ads, partner services and security packages. Also the price for the same hosting plan has raised from 80$/year to over 130$/year during past few years.</p>
<p>So being developer I’ve decided to move both my web site and domain to AWS to keep everything in one single developer-friendly place.</p>
<p>This is part one of the series of blog posts on how I set up my personal web sites in AWS so that my developer nature is happy.</p>
<h3 id="lets-get-started">Let’s get started!</h3>
<p>First of all check that your top level domain is supported by Route 53: <a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/registrar-tld-list.html">Domains That You Can Register with Amazon Route 53</a></p>
<p>In order for domain to be transfered, it should not be locked. Go to GoDaddy portal to list of your domains and click <code class="highlighter-rouge">Manage</code>.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_1_manage.gif" alt="01" /></p>
<p>Scroll down to the <code class="highlighter-rouge">Additional Settings</code> and unlock your domain. It could take few minutes for the status to be changed.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_2_lock.gif" alt="02" /></p>
<p>Once your domain is unlocked, you should request Authorization code.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_3_unlocked.gif" alt="03" /></p>
<p>Few minutes later you should get two emails from GoDaddy: one notifying that status is changed to Unlocked and the second one with your Authorization code.
You will need the code from this email later when requesting tranfer to Route 53.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_4_auth_email.gif" alt="04" /></p>
<p>Next you should switch to AWS Management Console and open <code class="highlighter-rouge">Amazon Route 53</code> console.</p>
<p>Go to <code class="highlighter-rouge">Hosted zones</code> left menu and click <code class="highlighter-rouge">Create Hosted Zone</code> button and enter your domain name.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_5_hosted_zone.gif" alt="05" /></p>
<p>As a result Hosted zone will be created with name servers entries pointing to AWS DNS.</p>
<blockquote>
<p>IMPORTANT: If you are currently using your domain, you have to create/copy all your needed record sets from GoDaddy DNS records. In my case it was only one CNAME record pointing to my Azuze CDN and one TXT record for the Google domain verification.</p>
</blockquote>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_6_hosted_zone.gif" alt="06" /></p>
<p>Next go to <code class="highlighter-rouge">Registered domains</code> menu and click <code class="highlighter-rouge">Transfer Domain</code> button. Enter your domain name and click <code class="highlighter-rouge">Check</code>. As you already unlocked your domain at GoDaddy portal,
you should see green confirmation message that your domain can be transferred to Route 53.</p>
<p>Also I hope you have already created/copied all your records for the hosted zone.</p>
<p>Note, that domain transfer is not free, you will have to pay for 1-year registration extension of domain, 12$ is case of .com domain. So click <code class="highlighter-rouge">Add to Cart</code>.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_7_transfer_check.gif" alt="07" /></p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_8_shopping_cart.gif" alt="08" /></p>
<p>Next enter Authorization code that you have received in the email from GoDaddy. Also under <code class="highlighter-rouge">Name server options</code> choose to import name servers from Route 53 hosted zone
(as hosted zone is already created and configured before).</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_9_auth_code.gif" alt="09" /></p>
<p>Next you will see your domain is listed under <code class="highlighter-rouge">Pending requests</code>.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_10_transfer_in_progress.gif" alt="10" /></p>
<p>Few minutes later you will get email from GoDaddy that domain is about to be transferred. Click the small link (not big button!) to procees to GoDaddy portal.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_11_email.gif" alt="11" /></p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_12_transfer.gif" alt="12" /></p>
<p>In the GoDaddy portal open list of your domains and click <code class="highlighter-rouge">Manage</code>. You will see <code class="highlighter-rouge">Pending transfer out</code> notification. Click <code class="highlighter-rouge">View Details</code> link and accept transfer.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_13_confirm.gif" alt="13" /></p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_14_accept.gif" alt="14" /></p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_15_accept.gif" alt="15" /></p>
<p>After transfer is accepted, you will receive few more emails from GoDaddy that transfer is complete and they are sorry that you left.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_16_sorry.gif" alt="16" /></p>
<p>Next you will receive email from Amazon Registrator that you must confirm you email address that you entered in your domain details. Open email and click link to confirm your email address.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_17_verify_email.gif" alt="17" /></p>
<p>Once you confirmed email, your transfer is complete.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_18_success.gif" alt="18" /></p>
<p>So you can verify that everything is fine by checking that your domain is listed under Route 53 <code class="highlighter-rouge">Registered domains</code> section.</p>
<p><img src="/images/moving_domain_from_godaddy_to_aws/godaddy_19_registered.gif" alt="19" /></p>
<h3 id="that-is-it">That is it!</h3>
<p>In the <a href="/static-website-hosting-with-custom-domain-and-https">next post</a> I will go through the process of setting up static web site using Amazon S3 storage, getting https certificate via AWS Certificate Manager, setting up Amazon CloudFront distribution and connecting all the pieces together.</p>Alexander DragunovI’ve used GoDaddy for the hosting of my personal photo web site since 2012, and every time I logged in into the GoDaddy portal I felt lost by the amount of different ads, partner services and security packages. Also the price for the same hosting plan has raised from 80$/year to over 130$/year during past few years.