Index

joshstock.in / 8d865bc

Source for serving and static templating/compiling of https://joshstock.in.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
2831 Dec 2019 14:25efe86e3Update site styling and metadataJosh Stockin110N

Blob @ joshstock.in / resources / articles / website-creation.html

text/html8894 bytesdownload raw
1<p>I've always wanted a little website I could use as a general portfolio and showcase for my hobby projects. Granted it's not a lot of stuff at the moment, there still are things I'd like to take the time to explain in a more orderly fashion. This website isn't anything special; it's just something I can use to organize my thoughts, projects, and files.</p>
2<p>This article serves a few purposes. Namely, it documents my process of creating this website (and the method of using <a href="https://github.com/JoshuaS3/joshstock.in" target="_blank">my compiler for it</a>) and provides step-by-step details for anyone who would like to follow suit. It also helps populates my blog page as I currently don't have anything else to publish.</p>
3$sections
4<h2>Design</h2>
5<p>There are a few things I wanted from the start in a website:</p>
6<ul>
7 <li>A simple landing page and blog system</li>
8 <li>Statically hosted/no backend</li>
9 <li>A way to push to production from Git</li>
10 <li>An easy way to compile multiple separate pages with shared components</li>
11 <li>An easy way to add new pages/articles</li>
12</ul>
13<p>Most of these technical requirements are for ease of use on my end. As it currently stands, I'm able to make changes on my machine, test them by compiling and using nginx on localhost, and finally use Git to push to my box and compile the repository into production assets. In general, I believed it easier and faster to create and implement each of these mechanics on my own than rely on a framework like <a href="https://gohugo.io/" target="_blank">Hugo</a> and take the time to learn another framework.</p>
14<p>Sending each request to a backend for processing is unnecessary in the case of a small blog like this. While I'd love to use something like WordPress, it's overkill for what I'm trying to do here. Serving pages statically is also safer; the lack of a backend for REST requests eliminates almost any opportunity to hack or exploit the site. At the moment, the only ways to hack the site are to either take over the box entirely or to attempt to exploit the nginx configuration, both being nearly impossible.</p>
15<h2>Creating Site Templates</h2>
16<img class="blog-img-right" src="/static/site-assets.png" />
17<p>I first began drafting some simple asset templates I knew would be reused across the website. I wrote a basic outline for the blog article and blog archive pages, the shared CSS style for them, and the HTML for individual article listings on the archive page. These were created as templates the compiler script could splice data into. I settled on the <code>$</code> character to indicate template keys. You can see this in the templates for article listings and their place in the blog archive:</p>
18<script src="https://gist.github.com/JoshuaS3/be6d66aca08f986f3f98074d56dc5168.js"></script>
19<p>Other pages employ similar techniques for other trivial variables. For example, the footer is represented by the <code>&#36;copyright</code> key. Wherever redundant information is repeated, there's probably a template key for it.</p>
20<h2>Writing the Compiler</h2>
21<p>(All website resources and compiler code and configuration can be found in the <a href="https://github.com/JoshuaS3/joshstock.in" target="_blank">GitHub repository</a>.)</p>
22<p>I decided to write the compiler script in Python because it's nearly universal and comes equipped with multiple modules for filesystem manipulation. It also handles strings with ease.</p>
23<p>To record metadata alternative to hardcoding it into the compiler, I first created a JSON configuration file and populated it with some variables. In the end there's no "correct" way to do this and it ultimately relies on whatever the developer believes to be most efficient or convenient schema. Here's the compiler configuration for this website at the time of writing this article:</p>
24<script src="https://gist.github.com/JoshuaS3/7191765aff7c36244092c7aa40aa58d1.js"></script>
25<p>Everything here appears to be self explanatory. The <code>static</code> key points to the location of the <code>resources/static</code> folder. Key-value pairs of the <code>templates</code> dictionary provide names to the file paths of file templates. The <code>articles</code> list contains dictionaries of metadata for each blog article.</p>
26<p>Because each template key is indicated clearly and uniquely in each file, the compiler can simply read the template file, replace the template keys with their respective values, and write the final output. See the following snippet:</p>
27<script src="https://gist.github.com/JoshuaS3/1f6b93ac5a8a4652b3346ece1c79f7f7.js"></script>
28<p>There are a few things happening here. First, the working (production) directory is cleared of files using a separate utility function. Next, the configuration file is read and parsed into the <code>config</code> variable. After that, the <code>static/</code> folder is copied to the working directory, and the landing and privacy policy pages are created.</p>
29<p>When the privacy page is created, the builtin <code>str.replace</code> function is used to replace the template key with its corresponding value. Nothing fancy here. This continues for the rest of the script, substituting text and writing output files.</p>
30<p>For blog articles, I iterate through the list in the configuration file and use the blog article template to create new <code>blog-*.html</code> files in the working directory. As such, this page can also be indexed using <code><a href="/blog-creating-my-website-stack.html">/blog-creating-my-website-stack.html</a></code>. Internal redirection will be covered in the nginx configuration file.</p>
31<p>(For search engine optimization, I pass each route through a <code>routemap</code> function which generates the sitemap.xml containing each location and its priority.)</p>
32<p>Running the full file generates the site contents and dispenses them in the indicated directory.</p>
33<img class="blog-img-full" src="/static/site-compile.png"/>
34<img class="blog-img-full" src="/static/site-compiled.png"/>
35<h2>Serving Webpages</h2>
36<p>Before I made this site, I'd never used nginx or Apache—or really any "real" webserver apart from express.js—so this was a learning experience for me. I followed some tutorials found online on the installation and configuration of nginx. After many hours trying to configure it, I got this server configuration to work the best (heavily commented for convenience):</p>
37<script src="https://gist.github.com/JoshuaS3/14742cc812d69be428bd6baf3239895d.js"></script>
38<p>This server is configured to redirect all <code>http</code> requests (port 80) to <code>https</code> (port 443) and any requests to the <code>www</code> subdomain to the non-www root domain, where requests are fulfilled. Of course, while this works for my website, it won't work for everything. If there are more or less or different pages to serve than I have, the <code>location</code> blocks should be changed accordingly. If the server doesn't have a TLS certificate to use for HTTPS connections, it should only <code>listen</code> on port 80 without the <code>ssl</code> and <code>http2</code> directives.</p>
39<h2>Automatic Deployment into Production</h2>
40<p>I currently do all site development on my own machine and push to my box which acts as a production server. This was done by initiating a bare Git repository on my server and adding it as a remote ("<code>production</code>") on my local. From my local, I can run <code>git push production master</code> to push my code to the server. In the Git repository on my server, I have a custom <code>post-receive</code> hook that checks out the <code>master</code> branch into a different directory and runs <code>compile.py</code> on <code>/var/www/html</code> (the nginx server's static files folder).</p>
41<img class="blog-img-full" src="/static/site-push.png"/>
42<p>There's a great tutorial on GitHub Gist that explains the process in detail: <a href="https://gist.github.com/noelboss/3fe13927025b89757f8fb12e9066f2fa" target="_blank">Simple automated GIT Deployment using GIT Hooks</a></p>
43<h2>Publishing the Website</h2>
44<p>After using Git to push to the server and running the compile script, the server will begin serving static web pages as long as nginx is running. From this point, new pages or articles can be created and the compile script modified at any time. The hook in the server's Git repository automatically compiles the static pages into production.</p>
45<p>Beyond here, everything is just frontend development.</p>
46<p>In the future, I'll continue writing blog articles detailing my projects and pursuits. I might create a separate directory of pages showcasing my projects as part of a portfolio. I also plan on creating a subdomain with dynamic file hosting. Until then, <a href="https://github.com/JoshuaS3" target="_blank">I have other projects to work on</a>.</p>
47