blog.iankulin.com

Web-Dev

Certbot - removing a domain

After I moved a domain to a new host, the original certbot certificate on the old host still included it, causing renewal errors. I explain that domains can’t be deleted from a certificate directly; instead you renew the certificate specifying only the domains you want to keep, and certbot warns about the ones being dropped. I include the commands for listing certificates and their domains, and for renewing with a reduced domain set...

Quick & Dirty auth with nginx & Node

I walk through protecting a Node/Express app with nginx basic auth, aimed at simple utilities on public servers: firewall off the app’s port so only nginx can reach it, configure nginx to proxy requests and require htpasswd credentials, and pass the authenticated username to the app via a request header. I also cover the approach’s limitations, such as plaintext passwords without SSL, no logout mechanism, and no brute-force protection...

Beginning Node App Security

I cover simple steps to secure a Node.js web app exposed to the public internet on a VPS, including putting it behind an Nginx reverse proxy with basic auth, enforcing HTTPS, and using Fail2ban to automatically ban brute-force attempts. I also cover restricting ports via a cloud firewall, disabling root SSH login, using SSH keys, keeping the system updated, and basic monitoring with Uptime Kuma...

User Sessions & Cookies in Node

In this tutorial, I build a user login and session management system from scratch in Node and Express, starting with a simple cookie-based session counter and progressively adding file-based persistence, user accounts, logout, and password authentication using bcrypt. I also cover input sanitisation, secure cookies, and enforcing HTTPS behind an NGINX proxy. The tutorial is aimed at readers with basic familiarity with Node and Express...

Web Development Overview

In this short post, I link to Brad Traversy’s Web Development In 2024 – A Practical Guide YouTube video, describing it as a comprehensive, beginner-friendly overview of web development that he publishes each year...

Fly.io, Uptime Kuma & scraping a status page

Because my Uptime Kuma monitoring instance runs on a home network sharing the same flaky 4G connection as the VPS sites it watches, I consider Uptime Robot before deploying a second instance on Fly.io’s free tier. Setting it up as a Docker container proves simple, and to fold the remote status back into my local instance I discover Uptime Kuma already exposes an SVG status badge usable with keyword monitoring, avoiding a custom scraping endpoint...

How to Have Cooler File Icons in VS Code

A short walkthrough of fixing the default VS Code file icons in the explorer view. I explain how to find the File Icon Theme option via the command palette, why a vanilla install requires installing additional themes from the marketplace, and how I settled on the popular VS Code Icons theme...

Getting Your Vite React App to Work on Github Pages

I walk through deploying a Vite/React app on GitHub Pages using the branch-based setup. I cover pointing Pages at a /docs directory, setting Vite’s base path to the repo name, building and copying the output to /docs, and an optional vite.config change to build directly into it...

React Expense Tracker App

This is a write-up of an exercise from Mosh’s React 18 course: building a small expense-tracking app in React and TypeScript, with Zod used for form validation. I cover component breakdown decisions, persisting expenses to local storage, tradeoffs in TypeScript type definitions, and refactoring repeated table markup into reusable components...

What's unfinished in your Udemy?

A rundown of the tech courses and tutorials I started but never finished, including Udemy purchases, 100 Days of SwiftUI, MIT’s Missing Semester lectures, and Stanford’s CS193p, with brief notes on why each was abandoned. I argue that quitting a course in favor of building real projects is usually a good trade, since courses are mainly valuable for discovering tools and concepts you didn’t know you needed...

Copying Objects in JS

I take a look at copying objects in JavaScript for React state updates, covering why simple assignment fails, how the spread operator creates copies, and how to selectively replace properties during a copy. I also show why shallow copies fall short with nested data, demonstrating how to manually spread nested arrays for add and remove operations, and end by noting how the approach gets messy at deeper nesting levels...

CSS for React Components

I compare approaches to styling React components, including global stylesheets, inline style objects, CSS and component libraries, per-component CSS files, CSS modules, and styled-components. I demonstrate each on a simple card component, noting trade-offs such as name clashes, hover effects, and unused CSS accumulating over time. I find styled-components the most elegant but lean toward per-component CSS files to avoid extra dependencies...

React - a To Do Example

My To Do app gets rebuilt in React, continuing a series that has already covered vanilla JavaScript and htmx versions backed by the same REST API. I cover React’s core ideas—components, declarative UI, and the virtual DOM—along with Vite build tooling, and walk through the app’s components, useState-based state management, and passing data via props. React’s tooling complexity and 150K of shipped JavaScript make it overkill at this scale, but I plan further React work, possibly with TypeScript...

htmx - A To Do Example

An introduction to htmx and the hypermedia and HATEOAS concepts behind it, followed by a conversion of a simple todo app from a Node/Express setup that serves JSON and renders client-side in JavaScript to an htmx version where the server returns HTML fragments instead. I compare the two implementations and discuss when htmx makes sense, particularly for server-side developers who want to avoid writing frontend JavaScript...

Testing Node.js apps - Mocha, Chai, and Supertest

I walk through testing a Node/Express API with mocha, chai, and supertest, using a simple maths-endpoint app as the example. I cover installing the tools as dev dependencies, exporting the app so tests can control it, writing test suites and cases, running tests via an npm script, and the role each tool plays. I had been using Bruno for lightweight endpoint checks and found the full setup trivial to configure...

Simple SQLite in Express

In this walkthrough, I build a minimal Node/Express REST API backed by SQLite as a learning exercise for migrating an app away from Mongoose. I cover query strings versus request bodies, CRUD endpoints for a users table, and rewriting string-interpolated SQL as parameterized queries to prevent injection. I close with a table of REST conventions for HTTP methods and a link to the finished project on GitHub...

Gogs, Gitea, Forgejo

A security vulnerability announced for Forgejo, which also affects Gitea and Gogs, prompted me to look into the fork history behind my self-hosted Gogs setup: Gitea split from Gogs in 2016 over project management disagreements, and Forgejo forked from Gitea in 2022 after its trademarks moved to a company. Impressed by Forgejo’s handling of the issue and only lightly invested in Gogs, I’m considering a switch. The takeaway is that project governance matters alongside features, and security announcements for the tools you rely on are worth following...

Concurrency and channels in Go

I offer a beginner-oriented walkthrough of Go’s concurrency basics, built around a small demo program with a worker function that sleeps and reports. I introduce goroutines, then channels for passing values between the worker and the main program, explain why plain channel reads block, and show how a select statement with a default case enables non-blocking checks, finishing with closing the channel to release resources. The sample code is available on GitHub...

Date formatting in Go is quirky

I ask ChatGPT for a Go date-formatting example and assume its answer of Format(“02012006”) is a hallucination, until discovering it was actually correct: Go bases its date format strings on the reference time 1/2 3:04:05 2006, with each number mapping to month, day, hour, minute, second, and year...

Adding Front Matter To mdserver

The mdserver project needed page titles defined as YAML front matter inside markdown files, in the style of Jekyll and Hugo, instead of being generated from the file name. Rather than writing custom extraction code, I use Showdown’s built-in metadata support, enabled with a converter flag, and confirm the front matter leaves the HTML output unchanged...