I recently decided to put together a personal website. I've previously used
github pages for any blogging or writing I felt like doing and that worked well enough
but I've been on a self-hosting kick so I figured I would try setting up my own. I've
done plenty of web development work how hard could it be right? Since I'm making this
for myself and my own needs I get to set it up exactly how I want.
Requirements #
- Display static content
Text, images, videos, links and code. I want to be able to easily write up any technical
or other stuff I'm working on and include images, links and code.
- Pretty Code Blocks
I do a lot of programming and I hate trying to read unformatted code. I'm spoiled by nice
editors and need my syntax highlighting.
- Basic Analytics
I'd like to know how many visits I'm getting on anything I write. That's about all I want. There's a lot of advanced
analytics tools available that are massive overkill for my needs.
- Quality of Life
Be easy to look at and navigate. I'm no designer but for me this means a dark theme and an obvious visual separation
between elements with different purposes (headings/text/links/etc.). There's also some small nice tweaks I like.
- Versioning
Basic version control for anything I'm writing.
Tech Stack #
Handling Static Content
A Website or if we want to get specific this is a
set of static html pages served by an nginx webserver on a cheap vps running debian. I handwrote
some css markup
stolen loosely inspired by a hugo theme. I've included some javascript
but it's only necessary for code formatting. The blog will display fine without it. I'm also serving
the js libs from the site itself so there are zero external dependencies. If an external cdn goes
down for some reason we don't care. Server includes on nginx add some templating and reusable components
to our plain html files which makes it a little easier for me to work on.
This runs very very fast by modern web standards. We're using a big chunk of js to help with code
formatting and this takes a bit to load the first time but will be cached for any subsequent requests.
I also do not include the js library or it's associated css file when I'm not using it. Same for any
images. So our pages get initial load times of 20-30 ms best case and maybe 100ms or so on the first
load with any images or scripts.
With caching on our big assets a page reload is a consistent 20ms. Nginx can handle very large
numbers of requests and is very well optimized for serving static content like this. Even on a
little potato vps like this we can comfortably handle a metric shitton of simultaneous connections.
We also crank through those requests very quickly because each user only needs max 100ms to finish
the whole exchange and does not need to keep any open tcp connections. Have I mentioned websites are great?
It's also trivial to handle more traffic, just slap a cdn in front of this bad boy and we can entirely
offload the traffic to the cdn. The whole site is a static file that can be cached, no complicated state management.
Server Side Includes are Cool
NGINX SSI
Boilerplate with straight html can get kind of crazy and there's not any built in method to handle
code reuse or make it more modular. This in my opinion is one of the few good reasons to reach for
a static site generator or js framework instead of slogging through html. But check this out.
<!--# include file="/si/header.html" -->
<div class="content">
<h2>Posts</h2>
<!--# include file="/si/blogsummaries.html" -->
</div>
</body>
That's the blog index page for this site. Where's all the boilerplate for the header and stuff?
Nice and modular in a separate file so we don't have to repeat the code and it's easy to update.
server {
server_name bunnylab.net www.bunnylab.net
access_log /var/log/nginx/tracking.access.log;
root /var/www/tp;
location / {
ssi on;
}
}
All we have to do is set ssi on in the nginx location block for our site to on and this works. As far
as I can tell there's no real noticeable performance cost for using server side includes for simple static
html pages. I'm going to use these everywhere now, wish I'd known about them earlier.
Pretty Code Blocks #
Need javascript for this. You can do some basic styling but as far as I know there's no way to get
syntax highlighting without doing a real parse of the code. So I'm using a nice js library
Prism JS for syntax highlighting and code formatting. Works well
and has support for most languages. This also degrades nicely if js is disabled or unusable you
still get the formatted code blocks it just loses the nice syntax highlights.
Basic Analytics #
Most people I've talked to reach for google analytics for this but its complete overkill in my
opinion. For this blog I'm running a small script on a cron job that parses the nginx access
logs and outputs the view counts to a file. I'll write up how I did this elsewhere in case
anyone is interested. I'm really only interested in a simple view count on different pages
and there's zero need for it to be live updated. A view count that updates every few minutes
on a cron job is more than sufficient for me.
Keeping it sekrit
I originally just ssh'd into the server or grabbed the views file via scp, but this was kind
of a pain in the ass. So I made the file available on the web with nginx and protected it
with
NGINX Basic Authentication.
location /admin {
auth_basic "Admin Area";
auth_basic_user_file /etc/apache2/.htpasswd;
}
This is pretty easy to set up. Just set the file for basic user auth which contains user/password hash
pairs. I'll also set a rate limit on it to prevent any brute forcing of the passwords.
Basic Auth Security
You might be wondering hey basic auth is pretty ancient is that
really secure?
Basic Auth Problems
- Password Security
For a website admin area you're generally using a username/password combination or some sort of sso. Passwords
can be quite weak but it's just me using this so I will simply not use a weak password. Turns out there is nothing
stopping you from having a 256 character random string as a password in basic auth.
- Unencrypted Credential Transmission
Credentials are sent in base64 so we need to use https or its trivial to get the credentials with
a man in the middle attack. This isn't any different than a standard web login form in my opinion.
We just use https.
- CSRF
Basic auth just sends a saved authentication header with any request for the domain. Notably it does not
have any limits on the request origin so if another site embeds a request for our admin panel the browser
will not stop it and will happily pass the request to the server and include any saved authorization headers.
This is a big problem if we're using basic auth to do state changes on the site: send money, change passwords,
etc. I'm just using it to restrict the ability to view certain static content so it's not a problem.
- No Logout Button
This is a little stupid. There seems to be no consistently working method to have the browser clear basic
auth credentials for a site. There are a couple workarounds but all require browser specific behavior or
changing the default server responses. The workaround is to just always open the admin panel in a new
private window/container and then close it to 'logout'. This is a pita though, browser devs please just
implement a js api to clear the basic auth credentials for a site.
So there's a few problems with basic authentication but for something like this where we just want a quick
and dirty way to require authorization on some static content? I think it's great.
Quality of Life #
There's a few things here that are not too hard to do and I think make the website a lot more usable.
Color Code Elements with Different Purposes
I don't know why this makes such a big difference but slightly lighter color for headings and
a noticeably different color for links really helps my brain parse things quickly.
Relative Units for Different Screen Sizes
Using
REM instead of px goes a long
way to making the layout work on phone/desktop etc.
Image Zoom
img {
transition: -webkit-transform 0.25s ease;
transition: transform 0.25s ease;
}
img:active {
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
Neat css trick. Makes all images scale on hold. Useful for zooming in on image details when you want
without having them take up too much space in the normal layout.
Section Links
<h2 id="sitestyle">Don't Hurt My Eyes <href="#sitestyle">#</a></h2>
Adds a link for each main heading section. Nice quality of life thing where you can click on the heading and the page will scroll to the right spot.
Always Open External Links in New Tabs
<a href="external link" target="_blank" rel="noopener noreferrer">link</a>
I personally like external links to open in new tabs so I don't have to lose my place in whatever I'm reading. The
html for having links
do this isn't really obvious in my opnion but here it is.
Version Control #
I put all the site files into a git repository locally. Done.
Deployment
SSH into the server and pull or copy over the latest version of the site. I also just edit in prod half the time. Since this is just my personal site
I don't care if anyone can see my half finished thoughts.
After Action Report #
Took me a bit to tweak my css for spacing, font sizes and coloring the way I wanted but as someone fairly experienced working with
web stuff the basic site setup and NGINX config was not difficult. I also didn't find writing straight html substantially harder
than writing markup. I discovered nginx basic auth and server side includes while writing this up both of which were a big help.
Highly reccomend server side includes if you're developing a larger static html site. I did find writing some sets of html tags by hand got repetitive.
<pre><code class="language-markup">html stuff</code></pre>
Doing this over and over for every code block is annoying. I know writing in markdown could solve this but that seems like overkill. I wonder if
there's a way to configure my editor to write the whole block for me via some sort of shortcut or tag?
Good Enough
I might tweak or do some more fixes in the future but this handles what I want fairly cleanly. Since we're using very standard html/css/js
there shouldn't be any issues to worry about with switching hosting or browser updates in the future. I can leave the site and focus on
writing and other projects. In general I think programmers and web developers in particular are too used to working with extremely complex
web application frameworks and really underestimate how far you can get with a static site plus a little js. Please join me and write
websites like its 1999, it's fun I promise!
Top Home