What is this site?
This site is a collection of experiments and exercises meant to act as my own creative canvas, as a learning & brushing-up experience, as a springboard for my next projects, and as a personal site that solves personal problems. Do I want a Web page resume? Well, here it is. Do I want some easy metrics on my browsing devices to help me develop for them? Well, I just go to my homepage with the device info tab open. Do I want to jot down what I'm making so I don't lose track of the next steps I want to take? That's what I made the WIP page for.
I don't plan for it all to be so utilitarian at the end of the day, because I do have an affection for independent & retro Web design. However, I am creating this development log to help me document my process & see what I was thinking when I made things. If anyone else ever reads this, I hope you can learn from my experiences.
How I made this site
I'm writing the rest of this in the form of a guide. It's been in my plan to document how I made this site, so I'll be able to just come back to this page if I want do it again in the future or adapt parts of my process for something else.
Putting this website live on the Web required my use of an account on Amazon Web Services (AWS). As a completely optional preference of mine, I also made the site code automatically update upon pushing to a code repository on GitHub.
What exactly this guide covers can be inferred from the titles of the sections below.
USING AMAZON WEB SERVICES REQUIRES A MONTHLY PAYMENT AFTER THE FIRST YEAR. FOR A SIMPLE STATIC SITE LIKE THIS ONE, THE PAYMENT WILL BE ON THE ORDER OF $2-$15 USD PER MONTH IN ADDITION TO THE INITIAL AND YEARLY RENEWAL PAYMENT MADE FOR THE WEBSITE NAME REGISTRATION. IF THIS PAYMENT CAN'T BE MADE, THE SITE MAY BE CREATED BUT MAY WANT TO BE TAKEN DOWN OR MOVED AFTERWARD.
Creating the local website files
To make the barebones files required for a Web page, I:
- created a folder on my computer with a descriptive name (like "example.com")
- entered that folder and created a file in the folder called "index.html"
- right-clicked that file and selected "open with..." before selecting a text editor (like Notepad or Sublime Text or Visual Studio Code)
- entered the following into the file:
<!DOCTYPE html> <html> <head> <link rel="shortcut icon" type="image/x-icon" href="./img/icon.png" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" /> <title>Main Page</title> <!-- Opengraph properties, for giving a site preview if the link is posted anywhere. Makes the link look less sketchy. --> <meta property="og:title" content="The Main Page" /> <meta property="og:description" content="This is my website" /> <meta property="og:type" content="website" /> <meta property="og:image" content="https://example.com/img/example-image.png" /> <meta property="og:image:alt" content="my website image" /> <meta property="og:url" content="https://example.com/" /> <meta property="og:site_name" content="My website name" /> <!-- Style properties --> <style> body { margin: 0; min-height: 100dvh; } body > *:first-child { margin-top: 0; } </style> </head> <body> <h1> My Website </h1> </body> </html>
After saving the file with these contents, I created a subfolder called "img" and put a 32x32 image in the folder called "icon.png". After this, I'm done with the most basic setup of the site's files. I should be able to open index.html (with a Web browser this time) and see something like the following:
This is what will show up on the Web page whenever it's live on the Web. To add content, there are many tutorials online, from brief to in-depth, with which HTML, CSS, and potentially JavaScript. can be learned. For now, the page justs look like this, and this document focuses on how I put the site live on the Web.
Signing in to the AWS Management Console
Go to AWS using using the "Sign In to the Console" button at the upper right of the AWS management console page:
On this page, it gives the option to create a new AWS account, if needed. To sign on to my existing account, then instead of filling out the login details right away, I hit the "Sign in using root user email" button:
I select "Root user" from the following screen and follow the login process. MFA may need to be set up for this, which should be doable from this page, after entering login details. I use the mobile "Authenticator" app from Microsoft.
Once logged in, I can go to the top right and select a default region. I select the region closest to me.
Registering the website name / domain name with AWS
THIS SECTION IS NECESSARY TO CHECK IF A WEBSITE NAME IS AVAILABLE BEFORE ASSIGNING OTHER AWS RESOURCES TO IT. HOWEVER, HAVING MY OWN WEBSITE NAME REQUIRES A MONETARY PAYMENT. IF I DO NOT WANT THE SITE TO BE ACCESSED ON THE WEB BY OTHER PEOPLE OR IF I DON'T HAVE A PAYMENT ON THE ORDER OF AROUND $15 USD TO PAY TO AWS, I MAY COMPLETE EVERYTHING IN THIS SECTION THAT COMES BEFORE HITTING THE "Proceed to checkout" BUTTON.
Logged into the AWS Management Console, I go to the search bar in the top left and enter "Route 53" before hitting the favorite star on it and clicking into it:
I then do to the "Dashboard" option under the top-left hamburger menu icon.
In the "Register domain" box, I enter a website name to check if it's available. For instance, "example.com" won't be available, but at the time of writing, "example-999.com" will be available:
If the original name I planned for wasn't available, I can simply change the name of the folder I created in my local system in the above steps.
Once I select the domain name, I hit "Proceed to checkout," "Next," and enter my information. This information is required for the domain name registrar but is then anonymized as long as I keep the "Privacy protection" checkbox at the bottom selected. I can just fill out the "Registrant contact" section and select "Same as registrant contact" for all the others. After this, it's a regular checkout process that'll take the payment.
After paying for the domain name, the registration will take some minutes to complete. During this time, the next steps can be pursued.
Setting up AWS static website hosting
In the AWS management console, I go to the same search bar that was used to find Route 53 and instead type "S3" and favorite & enter that service:
From here, I make sure the hamburger menu icon in the top left is selected so I can see the menu that has "General purpose buckets" as one of its first menu items:
After clicking the "General purpose buckets" link, there's a button saying "Create bucket," which I click:
I create my bucket with these options:
- Bucket name: the name of my website (like "example.com"); IF I COULD NOT PURCHASE A WEBSITE NAME, I SHOULD NOT GIVE MY BUCKET THE NAME OF A WEBSITE, AS THIS MAY CAUSE PROBLEMS LATER
- Region (if available): some place close to me
- Uncheck all boxes under "Block Public Access..." to allow the bucket to be used to host a website. Also check the box acknowledging that the bucket may become public.
- Under Default encryption > Bucket Key, choose "Enable"
- Everything else can be default.
I repeat the above steps, but with the bucket name beginning with "www." (as in "www.example.com"), to enable the site to be accessed with or without the "www." in its name.
The page displays the buckets in a list, so I then:
- click into the bucket WITHOUT "www." in its name ("example.com")
- go to the "Properties" tab
- scroll to the "Static website hosting" section and hit its corresponding "Edit" button
- hit "Enable"
- choose "Host a static website"
- enter "index.html" into the "Index document" box; this box and the optional "Error document" box both are case sensitive (creating an error document is left as an exercise, details outlined here)
- save changes
- go to the "Permissions" tab
- scroll to the "Bucket policy" section and hit its corresponding "Edit" button
-
Enter the following into the Bucket policy editor:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example.com/*" } ] }
- replace "example.com" above with the actual name of the website
- save changes
Putting the website files on AWS
After all of the above setup, I went into the "Objects" tab of my root domain bucket ("example.com") and simply dragged the website files from my local system's folder (also named "example.com") onto that Web page. Once this is done, the screen should look something like the below:
I hit the "Upload" button at the bottom right. After this, I hit the "Close" button at the top right of the following page.
I go to the "Properties" tab, scroll down to the "Static website hosting" section, and click the link that's under the "Bucket website endpoint" text. This takes me to the web page:
Notice the address bar. In order to use the Web address of my choosing, I need to use a website name I own. Website name ownership can be accomplished through the above section on registering a website name.
Assigning the website name ("http://example.com/")
Assuming I purchased the domain name in the above sections, I head back to Route 53, which should now be available in a clickable shortcut on the top left if I favorited it:
The domain should be registered by now. I follow these steps:
- choose "Hosted zones" in the left-hand menu under the top-left hamburger menu icon
- choose the name that matches the website
- hit "Create record"
- under "Record name," leave the subdomain text box empty
- make sure "A" is selected under the "Record type" field; this will be referred to as an "A Record" or "Alias Record" in other places
- make sure the "Alias" switch is selected
- under "Route traffic to," choose the endpoint "Alias to S3 website endpoint" along with the region selected for by bucket
- click the "Enter S3 endpoint" text box that appears to select the bucket corresponding to the website
- "Routing policy" is Simple routing
- "Evaluate target health" is "No"
- hit "Create records"
After 60 seconds, the website should be available under its given name with HTTP requests (http://example.com). If the site is not available, try clearing the browser cache (a quick method to try could be ctrl+F5, but also try the long way to see if that works).
CLICK FOR TROUBLESHOOTING IF CACHE CLEARING DOESN'T WORK
If cache clearing doesn't work, try going into the website's hosted zone entry in Route 53, opening the "Hosted zone details" drop-down arrow near the top of the entry, and comparing the "Name servers" entries, on the right, against the 4 entries that are in the "Records" table on the same record, under the "Value/Route traffic to" column. If there is no such record, a record of type "NS" must be created with values matching the name servers of the hosted zone, plus a period at the end of each (i.e., name server entry "ns-123.awsdns-99.net" means an NS record value "ns-123.awsdns-99.net."). If there IS such an entry but if those entries (besides the last period) don't match the "Name servers" entries in the hosted zone details section, select that record (type should be "NS") using the check box next to the record, hit "Edit record," and correct the values. If this doesn't work, the hosted zone may need to be deleted and re-created.
Using HTTPS is not available yet and will be set up in another step. Additionally, using www.example.com is not yet valid, either. This is a subdomain and will be handled in the next step.
Setting up the "www." subdomain ("http://www.example.com/")
I return to S3 and select the website bucket beginning with "www." that I created earlier.
- Go to the "Properties" tab
- Scroll down to "Static website hosting" and hit its "Edit" button
- Hit "Enable"
- Under "Hosting type," select "Redirect requests for an object"
- In the "Host name" box, use the root domain name of the website (like "example.com")
- under "Protocol," choose "http"
- Save changes
- Check for correctness by scrolling back down to the "Static website hosting" section and clicking the link under the "Bucket website endpoint" text
If clicking the link from the last statement above leads to the website ("http://example.com"), the next step is to set up an A record for this bucket in Route 53. I go to Route 53 under Hosted zones and do the following:
- select the hosted zone with my website name
- hit "Create record"
- in the "Record name" text box, enter "www"
- make sure "A" is selected under the "Record type" field
- make sure the "Alias" switch is selected
- under "Route traffic to," select "Alias to another record in this hosted zone"
- in the "Choose record" text box that appears, select the A record of the root domain ("example.com.")
- "Routing policy" is Simple routing
- "Evaluate target health" is "No"
- hit "Create records"
After 60 seconds, the website should be available under its subdomain name with HTTP requests (http://www.example.com will automatically direct to http://example.com). Using HTTPS is not available yet, but setup for it may begin now.
Getting an SSL certificate for HTTPS
Find "Certificate Manager" in the search bar, hit favorite, and follow these steps:
- Hit the Request button
- Select "Request a public certificate," hit "Next"
- In the text box under "Domain names," enter the root domain name ("example.com")
- Hit "Add another name to this certificate," and enter "*." before the root domain to include all subdomains ("*.example.com")
- Under "Validation method," select "DNS validation - recommended"
- "Key algorithm" is fine using RSA 2048
- hit "Request"
- now with the request created, hit "Create records in Route 53," make sure every entry is selected, and hit "Create records"
The certificate will be in the "Pending validation" state for a while after this. For now, basic logging will be set up for the website.
Setting up S3 site logging
Go back to S3, in the same region where the website buckets are.
- Create bucket
- Under "Bucket name," choose a name that describes that it will hold logs for the site; this does NOT need a website name, it can be "example-com-logs" for instance.
- Everything else can be default before hitting "Create bucket"
- In the "Objects" tab of the bucket, select "Create folder" and give it a descriptive name; I chose the folder naming scheme "example-com-s3-logs"
- Go back up to the buckets list
Now that the logs bucket is set up to receive entries, go into the root-domain bucket ("example.com" / NOT the logs bucket) and follow these steps:
- go the the "Properties" tab
- scroll down to the "Server access logging" section, and hit its "Edit" button
- enable
- next to the "Destination" text box, hit "Browse S3"
- click INTO the logs bucket, select the circle next to the logs folder created above ("example-com-s3-logs"), and hit "Choose destination"
- under "Log object key format," I choose the second option
- under "Source of date used in log object key format," I choose "S3 event time"
- hit "Save changes"
Logs won't appear immediately, even upon accessing the site. Now, the SSL certificate in Certificate Manager may be in "Issued" status, allowing the next step for HTTPS to occur.
Setting up CloudFront for HTTPS
Go to Certificate Manager and ensure that the certificate with the domain name has moved from "Pending validation" to "Issued" status. If it hasn't, wait a few minutes. If it hasn't moved in an hour, try the TROUBLESHOOTING dropdown under the "Assigning the website name ("http://example.com/")" section above, then try dealing with the certificate again.
Once the SSL certificate is issued, find "CloudFront" in the search bar, hit favorite, and follow these steps:
- Create a distribution
- "Origin domain" is the root-domain bucket address ("example.com.[...].amazonaws.com")
- If a warning recommends to use the website endpoint, accept it by clicking "Use website endpoint," or if there's no warning, ensure that the origin is the correct root-domain bucket (NOT www or logs) and that the address is of the scheme "example.com.s3-website-[...].amazonaws.com" with the "s3-website-" portion present
- Under "Default cache behavior" > "Viewer" > "Viewer protocol policy," select "Redirect HTTP to HTTPS"
- Web Application Firewall (WAF) can be disabled for a fresh site due to its cost, but may want to enable later in the CloudFront's Security tab.
- Under "Settings" > "Price class," select "Use only North America and Europe"
- Under "Alternate domain name (CNAME) - optional," add the root domain AND the subdomain (example.com AND www.example.com)
- Ensure "Custom SSL certificate - optional" is populated
- Enter "index.html" into the "Default root object" text box
- Standard logging is optional at the beginning, can be set now or later; I used S3 (Legacy) initially
- Hit "Create distribution"
The distribution will initially be in "Deploying" status. While that completes, version control for the website's source code can be set up through Git.
Setting up Git version control (GitHub)
Sign in to Git, on the GitHub website and locally. Local sign-in procedures will vary depending on operating system & Git software used; more information can be found online.
Create a repo on the GitHub website. The name can be anything, but I just give it the name of the website domain or subdomain being held by that repo ("example.com")
For personal projects, I prefer the copyleft GNU General Public License v3.0; commercial derivative projects are allowed, but all derivative projects must be open source and include the same license.
I clone the repo into my local system, then inside that cloned repo folder, I place a subfolder, which can be named anything, but for this example, I name it the "public" the folder. I put the website files in the public folder, then outside the public folder, in the root folder of the repo, I make a ".github" folder. In that folder, I put a "workflows" subfolder. In that "workflows" subfolder, I put a file called "main.yml" that will call on a Github action to connect to AWS S3 and update the files on push. The content of main.yml is as follows:
on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v1 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: [THE AWS REGION] - name: [CI JOB NAME] run: aws s3 sync ./public/ s3://example.com --delete
The text "[THE AWS REGION]" must be replaced with the AWS region name (like "us-east-1") of the website S3 bucket, and "example.com" must be replaced with the actual root domain name of the S3 bucket. The text "[CI JOB NAME]" can be changed to whatever is preferred.
Add the changes to git, commit it to the repo, and push it to the origin. This will need to be connected to AWS through an IAM user and custom security policy. For now, Cloudfront deployment should be complete.
Directing Route 53 to HTTPS
("https://www.example.com/")
Go to Route 53 in the AWS Management Console, go to hosted zones, then go into the zone with the name of the website.
- Check the box next to the A record, which will be the record with "A" in the "Type" column and the root domain (like "example.com") in the "Record name" column
- In the "Record details" panel that populates to the right, hit "Edit record"
- Under "Route traffic to," change the first selection box to "Alias to CloudFront distribution"
- In the "Choose distribution" text box, clicking it should give the option to fill the newly deployed CloudFront distribution into the box; select it
- Hit "Save"
After 60 seconds, the HTTPS site should be available. Try visiting the HTTPS site and its subdomain (i.e., https://example.com and https://www.example.com). Now, the site should be completely live.
Lastly, Git setup will be completed.
Creating an AWS IAM user for Git
In search, look up "IAM" and then favorite & enter the result. Choose users, either by selecting it on the left panel that appears when the top left hamburger menu icon is pressed or by clicking the number under the "Users" entry under "IAM resources."
- Hit "Create user"
- Give it a descriptive name; I use the schema "example.com-git-ci-user"
- Hit "Next"
- Choose "Attach policies directly"
- In the "Permissions policies" box, hit the button in the top right of its box that says "Create policy"
-
In the new tab that opened under "Select a
service," choose S3, then in the dropdowns that
appear, select:
- List > ListBucket
- Write > PutObject
- Write > DeleteObject
- Scroll down to the "Resources" dropdown, and select "Specific"
- Next to "bucket," hit "Add ARNs" and input the root domain name, which is also the name of the S3 bucket that it targets, into the "Resource bucket name" box; hit "Add ARNs"
- Next to "object," hit "Add ARNs," input the root domain name into the "Resource bucket name" box, select "Any object name" for the "Resource object name," and hit "Add ARNs"
- Hit "Next"
- In "Policy name," I just reuse the name from before; "example.com-git-ci-user"
- Standard description: "Git CI hook used to edit the code for the example.com site, using Git version control.
- Scroll down and hit "Create policy"
- On the original tab, where permissions were being set, hit the refresh button next to the "Create policy" button that opened the other tab; the new policy should appear in the search here if refreshed after about a minute.
- Find the new policy through search, and check the checkbox next to it
- Hit "Next"
- Hit "Create user"
After this, an IAM user for Git actions on the S3 bucket will be created, and Git will be hooked up to this IAM user in the next & final section.
Connecting Git to AWS S3
In IAM, under Users, go to the user created to connect to S3.
- In the middle on the right side of the "Summary" box, click the "Create access key" link
- Select "Command Line Interface (CLI)" and check the box at the bottom before hitting "Next"
- Can enter a description or just hit the "Create access key" button
- After the access key is created, KEEP THAT PAGE OPEN IN THE TAB when also opening up Github
- In Github, in the website repo, go to the "Settings" tab at the top of the repository
- Go to "Secrets and variables" > "Actions," and hit the "New repository secret" button
- The first key name is "AWS_ACCESS_KEY_ID" like in the yml file above, and the "Secret" is the text in the still-open AWS console under the "Access key" section in the "Access key" column
- Hit "Add secret," then hit "New repository secret" again
- The next secret will have the name "AWS_SECRET_ACCESS_KEY" and will have the value from the AWS console that's under the "Access key" section in the right-side "Secret key" column; copy & paste it into GitHub before hitting "Add secret" again
- Push any update to the Git repository's "main" branch to run the pipeline from the repo into AWS
All of that composes how I built and am building this site, aside from the contents of the HTML, CSS, and JavaScript. I'll reflect on my use of those frontend technologies in other journal entries, dedicating this entry to the setup above.
Post-script / reflection
For me, the site's infrastructure is the hard part of putting it online, and the code is the easy part. For the code & design of the site, I plan to write about it by creating a journal entry for each page I've put onto this site.
The next development logs may be about patterns in how I'm building things, improvements to my process, things I'm moving toward, and parts of my projects' creation that wind up having unexpected depth. Devlogs do sometimes highlight how people solved problems they encountered, and the problem I had was setting up all the infrastructure & automation to put this site up in first place.
Additionally, in the course of writing this guide, much of the information didn't come from me reviewing documentation, but rather it came from me going back through the settings & configurations for everything, to reverse engineer how I did it. For instance, I didn't find which permissions to grant to an IAM user for this specific purpose anywhere on the Web, so I initially had to figure the permissions out through experimentation. Then, for this guide, I had to retrieve these permissions from my IAM policy setup rather than through any documentation or guides. To my knowledge, this guide is the only one on the open Web that composes all of the information covered.
Re-tracing all my steps and documenting this all after the fact, it was at least as grueling as figuring a lot of it out, but hopefully, the step-by-step is gonna save me some headaches in the future. It could even save headaches for someone else, too!
That's all for now.
Sources: