[{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/attention/","section":"Tags","summary":"","title":"Attention","type":"tags"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/blog/","section":"Blogs","summary":"","title":"Blogs","type":"blog"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/digital-wellbeing/","section":"Tags","summary":"","title":"Digital Wellbeing","type":"tags"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/focus/","section":"Tags","summary":"","title":"Focus","type":"tags"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/","section":"HOW INTERESTING...","summary":"","title":"HOW INTERESTING...","type":"page"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/productivity/","section":"Tags","summary":"","title":"Productivity","type":"tags"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/series/reclaiming-your-attention/","section":"Series","summary":"","title":"Reclaiming Your Attention","type":"series"},{"content":" Introduction # I\u0026rsquo;ve always liked mobile phones. I was immediately captivated by having a little communications device in my pocket that could be instantly used to contact my friends, play some games or perform the occasional prank. I was one of the first in my whole school to get my own mobile phone, at a time when teachers and other adults wondered why on earth I would ever need one. Mobiles used to be exclusively for business people, engineers, diplomats, bankers and the like, not for calling your mates or texting your girlfriend. But as with most new consumer tech, it begins to take off and becomes cheaper and more accessible.\nMy first mobile was some already obsolete analogue device, sold as the first cheap pay-as-you-go tariff by Vodafone. It just did calls; texts weren\u0026rsquo;t a thing yet. Back then, you had to be 18 to own one, but I convinced my mum to sign up on my behalf, and I won a gold number for being the X\u0026rsquo;th customer of that particular shop. As more friends got phones too, they soon became a regular topic of conversation, with various new models and features by dozens of manufacturers and networks who have since all been consigned to history.\nWhen I went to university I dutifully lived well outside of my means, and the constant pull of having the latest device faded with my bank balance. I stuck with my Sony Ericsson w800i for much longer than I care to remember.\nOnce I got a proper job as an NOC Engineer, the company was going through some restructuring, and as a result, a bunch of EoL smart phones were being retired and recycled (binned) by the IT Service Desk. I called in a favour and obtained my first personal smart phone: an HTC Touch Pro2 running Windows Mobile 6.1. It was fairly goofy, with the iPhone 3GS out at the same time and nowhere near the flexibility. My business was rolling iPhones out to the people who \u0026ldquo;needed\u0026rdquo; them (sales and marketing people, mainly), but us lowly engineers had to make do and share a HTC Snap for on-call duties. The batteries were poor and wouldn\u0026rsquo;t last anywhere near a day, but the Snap was actually a decent BlackBerry clone with a loud ringtone that did a great job of alerting you when the website was down.\nOnce the iPhone wave began, the tech and mobile phone industries shifted with it. There were already some pretty big, addictive websites buried into our lives by then, but they were mainly consigned to laptop or desktop environments. There was a physical gap between Big Tech and people which was about to be closed forever.\nThe app culture that Apple kicked off between 2007 and 2009 was ripping up the rulebooks and allowing access to web services like never before. Suddenly you could check your Facebook from anywhere, just as some ex-Yahoo dudes decided to create a data-based messaging service (WhatsApp) to replace expensive SMS with even cheaper text messages, as long as you were on the WiFi at least. Soon enough, everyone started building apps too. My company included; we subsequently occupied a top-10 downloaded app in the UK marketplace for several years. Our website, like lots of addictive websites, started to focus on keeping you on its app, something that would change the course of human behaviour.\nIt sounds like some tale of yore, but before 2007, most people did not stare at their mobile phone for hours at a time. Hard to believe these days.\nPhones and laptops were created to make our lives easier, yet most of us feel more distracted than ever. Between notifications, doom-scrolling and the pressure to stay constantly available, it can be tough if not impossible to switch off or focus properly any more.\nA long time ago now, maybe 9 or 10 years ago, I had a realisation that I was spending too much time on my mobile phone. Perhaps because I\u0026rsquo;d done it for many years at this point I was getting bored of it. Perhaps I just started to get irritated by friends and family staring into their phones instead of actually interacting with me. I don\u0026rsquo;t know for sure, but as usual with things like this I began to ask: wait, am I like that? Am I part of the problem?\nAnd of course the answer was 100% yes. I was a hypocrite. I was finally annoyed with a behaviour that I myself had been fully guilty of committing. I was addicted to my mobile phone, and as we all know these days, the first step to beating any kind of addiction is acceptance. Not acceptance in the sense that I was happy about it, or that it was going to be an easy fix, but I\u0026rsquo;d finally accepted that it was a problem, and I was keen to see it for what it is.\nI knew it wasn\u0026rsquo;t just me that this affected, and even back then I was wondering how I could regain control of my mobile and share what I\u0026rsquo;d done for anyone else who felt the same. It\u0026rsquo;s admittedly taken me a long time to finally turn this draft into a proper article, but in the time that it\u0026rsquo;s collected dust, lots of other bloggers, tech writers, journalists, professionals and doctors from all over the place have started to have the same realisations and published their own articles suggesting how you, too, can reclaim your attention from your mobile phone.\nDespite How Interesting being a more technically focussed blog, I decided to place a foot into digital wellbeing for a change and share some ways I\u0026rsquo;ve been able to reclaim control of my attention. I figured that some of this stuff may be useful to others, and the results are this two-part essay.\nHere in Part I, we explore how our devices hijack attention and what that constant noise does to our brains. Over in Part II, there are some practical ways to take control again, from simple boundaries to a more mindful and deliberate use of your technology. For those who want to continue reading, I\u0026rsquo;ll include some of the other articles I read over the years too.\nThe Constant Ping # 🔔 You unlock your phone to check the weather.\n🔔 Thirty seconds later you have read a message, skimmed a meme, noticed a calendar alert and almost forgotten why you reached for it.\n\u0026ldquo;It is fine, you tell yourself, just noise\u0026hellip;\u0026rdquo;\n🔔 Then another ping\u0026hellip;\nPhoto by Artem Balashevsky on Unsplash Most of us are now well within the territory where our devices talk more than we do. Every app, widget and smart thing wants a piece of our attention. Only a bit, but it\u0026rsquo;s all of them.\nThe result is what The Verge called Notification Hell: a world where even system menus try to sell you some garbage, and \u0026ldquo;helpful\u0026rdquo; assistants keep interrupting you with guesses about what you might want to do next. How many times have you opened an app and it immediately asked for a review before you\u0026rsquo;d even used it? As a tiny and perhaps juvenile protest, these cheerily get 1/5 stars from me every time.\nOne of the first things an app will do when you install it is ask for permission to send notifications. Many of these apps don\u0026rsquo;t accept no for an answer, so you have to go back into settings to disable them again. Some badger you each time you open them to re-enable the notifications you\u0026rsquo;ve already turned off (*glares at Snapchat, Reddit etc*).\nWe can end up living inside a never-ending game of whack-a-mole, with alerts arriving from every direction while we try to swat them away. Some are useful, such as your parcel arriving; most are not, such as someone liking a photo from your Corfu \u0026lsquo;06 holiday album. Either way, the cost of switching attention adds up far faster than we realise.\nAccording to researcher Sophie Leroy, even small interruptions break the mental thread we rely on to stay focused. A quick glance at a message forces the brain to rebuild context afterwards. Do this tens of times per day and it is no surprise that we feel busy without actually achieving anything. For a deeper dive into this switching cost, see The Guardian on notifications and concentration.\nIf this all sounds uncomfortably familiar, you are in good company. From healthcare workers drowning in Microsoft Teams alerts, to anyone who has ever muted a busy WhatsApp group only for the app to light up with another one minutes later, we are living through the same experiment inside tiny pieces of fragmented attention. The question isn\u0026rsquo;t whether we\u0026rsquo;re distracted, but how much control we are willing to take back.\nIn order to tackle any problem, one must first try to understand it. Learning to spot the patterns offers the opportunity to act before the habits become too engrained.\nLet\u0026rsquo;s dig into what is happening in our heads when we just check one more notification, and why it is so hard to stop\u0026hellip;\nThe Science of Distraction # It\u0026rsquo;s easy to blame ourselves for being glued to little screens, but distraction is baked into how our brains and devices interact. Every ping, pop-up and badge is engineered to trigger a tiny burst of dopamine, the brain\u0026rsquo;s reward signal that says something new just happened. Novelty feels good, even if it\u0026rsquo;s meaningless.\nScientists and researchers call this the variable-reward effect. Like a slot machine, our phones occasionally deliver a genuine reward such as a message from a friend, a delivery update, or an interesting post. Our brains quickly learn to keep checking in case the next refresh brings another hit. Even the little red numbers that appear on app icons are engineered to be irresistible. You can blame Steve Jobs for that one, and it\u0026rsquo;s only a tiny part of the game.\nThe real drag is the context-switching cost. Each diversion leaves a trace of the previous task behind, and your mind has to grind back up to speed when you return. Multiply that by hundreds of micro-interruptions a day and it becomes clear why it is harder than ever to concentrate for long stretches. Psychologists sometimes refer to the lingering effect that follows an interruption; whatever you call it, the result is the same: more friction, less focus.\nSelf-control helps, but it is a finite resource. The more often we resist, the more mentally tired we become, until it is easier to give in and check again. None of this means we are weak or lazy. It means the game is stacked. Teams of behavioural scientists optimise products to keep us engaged, while the tools designed to help us work, socialise and relax are also tuned to capture every spare second of our attention.\nIt\u0026rsquo;s also worth knowing that a lot of what you\u0026rsquo;re scrolling past isn\u0026rsquo;t even being posted by humans. TechRadar\u0026rsquo;s Matt Evans wrote a sobering piece after watching a viral video of an industrial-scale social media bot farm: racks of screenless phones, pumping out fake engagement at scale. Knowing that the outrage you\u0026rsquo;re reacting to may well have been manufactured by a server room somewhere doesn\u0026rsquo;t really make it less infuriating, but it does help to keep things in perspective.\nSo if you have ever found yourself unlocking your phone without realising you picked it up, you are not alone. Your brain is simply doing what it has been trained to do.\nNext, let\u0026rsquo;s zoom out from the science to the bigger picture: how the background noise of modern tech has changed the way we see work, relationships and even the passage of time.\nThe Bigger Picture # It is tempting to frame distraction as a personal failing. Perhaps we just need to be more disciplined, or find the right productivity app. The truth is that this is a cultural shift on a scale we have not faced before.\nIn a piece by Tom on Another Angry Voice, he describes how years of social media use rewired his attention, mood, and even his sense of connection to the real world. It is a feeling many of us recognise, even if we can\u0026rsquo;t quite describe it. The modern world runs on constant data input, and silence can feel strange or even uncomfortable to some.\nSean Morley\u0026rsquo;s Who Remembers Attention Spans? in Now Then Magazine puts it well too: a lot of what we frame as a personal attention problem is really a symptom of an information environment that has been deliberately engineered to be exhausting. We didn\u0026rsquo;t choose this; it was built around us, slowly, while we were busy looking at it.\nWe have seen big leaps in how people consume information before. The printing press put knowledge in everyone\u0026rsquo;s hands. Radio and television reshaped daily life and culture. The difference here is that those changes unfolded across generations, while social media reached a far greater scale within just a few years.\nThat speed is key. The faster something spreads, the less time there is for people to adapt. Children now learn to swipe before they can read. Many adults rely on algorithmic feeds for news, social contact, and sometimes even a sense of identity. These tools have made information accessible to everyone, but at the cost of scattering attention in every direction all at once.\nThere is also a social cost. When everyone is permanently half-present, conversations fragment and downtime diminishes. Work stretches into personal hours, and even into our beds. Rest feels less like a pause and more like a window to catch up. Do you ever sit down for 10 minutes and then immediately feel guilty that you could be doing something productive?\nIt adds up to the sense that life is happening in short bursts rather than clear moments. More than once I have felt like I\u0026rsquo;ve got a lot done in a morning, just to realise all I\u0026rsquo;ve really done is clear some emails and notifications. Worthless time-sapping garbage.\nAs one summary of notification overload put it, we are switching between different worlds and never fully in the moment. When you are never quite present, you stop properly listening, stop properly laughing, and the moments that are actually worth having slip past while you were half-checking something else.\nThe good news is that awareness is growing. From schools and gigs introducing phone-free policies to individuals experimenting with digital detoxes, people are questioning the cost of constant connection.\nChildren, schools and the next generation # If any of the above lands uncomfortably for adults, it\u0026rsquo;s worth pausing on what this looks like for the people who\u0026rsquo;ve never known a world without it.\nPlenty of schools, parents and governments are now openly questioning whether the deal we\u0026rsquo;ve struck with the smartphone is one we\u0026rsquo;d want our children to inherit. The Guardian has argued the case for banning smartphones from schools entirely, and a growing number of schools across the UK and elsewhere are doing exactly that. The early reports are striking: classrooms quieter, breaktimes louder, kids actually talking to each other again.\nThere\u0026rsquo;s a knock-on effect at home, too. The BBC has written about phubbing, the slightly ungainly term for snubbing the person in front of you in favour of your phone. Most of us have done it; quite a lot of us have had it done to us. Children pick it up faster than anyone, because they learn what attention looks like by watching us. If we model \u0026ldquo;half-present, half-scrolling\u0026rdquo; at the dinner table, they\u0026rsquo;ll do it straight back.\nNone of this is a moral lecture. I\u0026rsquo;m not naturally drawn to the position that kids today have it worse than we did, because every generation says some version of that and most of them turn out to be wrong. But the specific tool has changed, and the rate at which it\u0026rsquo;s changing is unprecedented. That\u0026rsquo;s worth taking seriously, especially if you\u0026rsquo;re around younger people.\nSigns You Are Losing the Balance # Photo by Nathan Dumlao on Unsplash Most of us like to think we use our devices sensibly and acceptably. We tell ourselves we could stop whenever we want, and that we are in control. Yet small signs will give the game away.\nYou pick up your phone to reply to a message and forget why you picked it up. You check the time, then realise you have checked three other apps before putting it down. You take a photo of something nice, then spend longer editing and posting it than you did enjoying the moment. You flip between home screens for no reason. These lapses don\u0026rsquo;t mean you have a problem, or that you\u0026rsquo;re to blame. They show how good technology has become at stealing focus. Your focus has become a gold rush to technology companies, and they\u0026rsquo;re digging hard. Over time, even the smallest interruptions start to feel normal. Great news for them. Not so much for you.\nOther signs that your digital habits might be taking over more than you would like:\nPhantom notifications: feeling your phone buzz when it has not. Split attention: half-listening in meetings, conversations or films while doom-scrolling something unrelated. Sleep issues: checking messages and emails just before bed, or reaching for the phone the moment you wake. Restless downtime: finding it hard to do nothing, or to sit quietly without a screen nearby. Reduced patience: struggling with tasks that do not give instant feedback or reward. None of these on their own is a crisis, but together they paint a familiar picture. You are not bored, you are overstimulated. The brain gets so used to short bursts of novelty that calm starts to feel uncomfortable. When calm feels wrong, the cycle continues.\nIf you suspect you might have wandered a little further down this road than you\u0026rsquo;d like, Internet \u0026amp; Technology Addicts Anonymous has a short self-assessment questionnaire on phone addiction which is worth a calm five minutes. Nobody\u0026rsquo;s going to grade you on it; it\u0026rsquo;s just useful data.\nBut don\u0026rsquo;t panic! # Awareness is the first step back to balance. In Part II we shift from root cause to fix: practical ways to take control of digital life without going completely off-grid.\n📷 Cover photo by John Lockwood on Unsplash under the Unsplash licence. All references and further reading for the whole essay are collected at the end of Part II.\n","date":"31 May 2026","externalUrl":null,"permalink":"/blog/2026-05-31-reclaiming-your-attention-part-i/","section":"Blogs","summary":"","title":"Reclaiming Your Attention – Part I: How Our Devices Hijacked Our Focus","type":"blog"},{"content":" Drawing a line in the sand # If Part I struck a nerve, that\u0026rsquo;s the whole point. Once you start noticing what your phone is doing to your time, you can\u0026rsquo;t really un-notice it. The next step is important: deciding where to draw the line.\nDisclaimer first: there\u0026rsquo;s no single magic fix here. None of this is groundbreaking stuff either; most of it is just things I\u0026rsquo;ve actually tried over the years and stuck with because they worked for me. Some bits I pinched from articles I\u0026rsquo;ve read; some I figured out the hard way. Take what\u0026rsquo;s useful, ignore the rest, and don\u0026rsquo;t beat yourself up if you slip back into old habits. That\u0026rsquo;s pretty much the default state.\nOne thing I will say up front is that willpower is a terrible long-term strategy. If you have to fight your phone every time you pick it up, you\u0026rsquo;ll lose more often than you win. Catherine Price, author of How to Break Up With Your Phone, makes a similar point: the trick is to make the temptation harder to reach in the first place, so you\u0026rsquo;re not constantly arm-wrestling yourself. The rest of this article is basically a bunch of practical ways to do exactly that.\nQuick wins for today # Before we get into the why and how, here\u0026rsquo;s the very short version. If you only do one or two things from this whole article, do these:\nBuy a separate alarm clock and stop using your phone as one. Turn off notifications for every app that isn\u0026rsquo;t a real human or a real diary appointment. Use Focus modes - schedule Bedtime Mode on iOS (or Wind Down on Android) and let your phone go quiet and grey at night. Pick a single time of day, every day (the morning cup of tea, the school run, dinner, whatever), and make it phone-free. No exceptions. Delete one app you don\u0026rsquo;t really use any more. Then another next week. Offload apps - as an alternative to fully deleting, offloading applications was originally designed to help with managing storage, but it has two more practical uses we can use too - prevent an app from accessing too much data when you are not using it, and also to prevent you using an app so much. Offloading keeps your data but offloads the app to prevent it from running (and sending notifications etc). The rest of this article digs into the why behind each of these, plus a load of other practical bits. Take what\u0026rsquo;s useful.\nStart with your mornings # The single biggest change I made was this: stop reaching for the phone the second I wake up.\nPhoto by Ahmed Nishaath on Unsplash For years, my morning routine went: alarm, dismiss alarm, \u0026ldquo;just a quick check\u0026rdquo;, twenty-five minutes of emails, news, WhatsApp, and a vague sense of dread before my feet had even touched the floor. By the time I was in the shower I was already irritated, behind, and mentally responding to three different conversations I hadn\u0026rsquo;t actually had yet.\nIt turns out this is a properly bad habit. Filling your brain with other people\u0026rsquo;s priorities before you\u0026rsquo;ve even had a coffee trains you to spend the whole day in reaction mode, bouncing from notification to notification rather than actually choosing what to think about. The article makes the point quite well - you basically hand over control of your mental state before you\u0026rsquo;ve even got your socks on.\nA few things that helped me early on:\nBuy a separate alarm clock. This might sound daft or inconvenient, but it\u0026rsquo;s still pretty effective. Once your phone isn\u0026rsquo;t the alarm, you\u0026rsquo;ve got no reason to touch it within the first hour. Mine lives on a shelf the other side of the room, which has the bonus effect of forcing me out of bed to switch it off. I\u0026rsquo;ve since been able to switch back to using my phone as an alarm again because my smart watch wakes me up now on behalf of the phone. I no longer need to reach for my phone to dismiss my alarm. It was a game-changer for me. Charge the phone outside the bedroom. Or at least, not on the bedside table. Out of reach equals out of habit. I charge my phone at my desk at work, or in another room when I get home from the office. If you work in an office, you\u0026rsquo;re sat there most of the day, why wouldn\u0026rsquo;t you just shift the charge time to when you\u0026rsquo;re captive anyway? Give yourself a buffer window before you check anything. Mine is roughly the time it takes to make and drink the first cup of coffee. We\u0026rsquo;re not talking meditation-app territory, just a quiet fifteen minutes where the world\u0026rsquo;s noise stays muted for your brain to boot up. It feels weird for a couple of days, and then you\u0026rsquo;ll wonder how you ever did it the other way.\nWind down at night, too # The other end of the day is just as important, and the fix is much the same in reverse.\nBedtime mode on the iPhone has been super helpful for me. You set a time, and the phone basically goes into wind-down mode: dimmed screen, silenced notifications, a tinted lock screen that just says go to sleep. Android has its own equivalent in the Digital Wellbeing settings, and Chris Hall over at TechRadar has written nicely about using greyscale mode at bedtime. When Instagram looks like a black-and-white textbook, the urge to scroll evaporates almost immediately. It\u0026rsquo;s a clever trick, and one you can do manually on iOS via a Shortcut.\nWhat this stuff does, more than anything, is create a hard stop. Without one, the evening just dribbles on until you begin to nod-off mid-scroll with the lights still on. With one, your brain learns that 10pm means that\u0026rsquo;s enough now, and, crucially, you stop going to bed wound up about whatever you were doom-scrolling five minutes earlier.\nSleeping has measurably improved for me since I stopped using the phone as a nightcap. Of course, this is all anecdotal but almost everyone could probably benefit from installing similar boundaries.\nDeclare war on notifications # A friend's phone — notification overload: every app competing for attention at once. My phone with notifications strictly managed: only what actually matters gets through. I can\u0026rsquo;t stress how important this is.\nMost app notifications are not for your benefit.\nThey exist to drag you back into the app so somebody can sell ads against your eyeballs. Treat them accordingly; with suspicion and contempt.\nMy rules of thumb, roughly:\nDefault position: off. Notifications go on only if I have a specific reason: messages from actual humans, calendar reminders, stuff like front-door camera for deliveries. Almost nothing else qualifies. Apps that beg you to turn notifications back on every time you open them get punished. Snapchat, Reddit, X, Facebook: I\u0026rsquo;ve called them out before and I\u0026rsquo;ll do it again. Some of them give you a manipulative little dialog every single launch. No. Turn off the red badges, too. Those little numbers were literally engineered to be irresistible. They hijack the same novelty circuit that everything else exploits. Switch them off and you\u0026rsquo;ll be amazed how little you miss them. De-Facebooking (the app, the notifications, the lot) was the single biggest single-app win for me. I went from checking it dozens of times a day to barely opening it once a month, and I have lost precisely nothing of value in the process. I\u0026rsquo;ve not had Facebook on my device for years now and don\u0026rsquo;t miss it one bit. I had a transitional period of accessing it through the browser instead (which is actually better for your privacy than having the app anyway) and that barrier of it being less smooth is one of the ways I was able to take back a bit more control. I still haven\u0026rsquo;t deleted the account, but I\u0026rsquo;m getting close now. Something I thought impossible 10 years ago. I was hooked - and now I am free. Meta has been talking about moving to paid subscriptions for a while now (something they promised to \u0026ldquo;never\u0026rdquo; do) and they\u0026rsquo;re finally implementing just that in 2026. This will probably be the last straw for me.\nWhile you\u0026rsquo;re at it: delete the apps you don\u0026rsquo;t actually use. The iOS Offload App feature is excellent for the in-between case. It removes the app to save space but keeps your data, so if you ever do want it back, you\u0026rsquo;re not starting over. This usually maintains your login cookies too. A pruned home screen is a calmer home screen. And a more private one.\nUse what\u0026rsquo;s already in your pocket # Before you go installing another app to fix your app problem, have a good look at what your phone can do already. Both iOS and Android have spent years quietly building in tools to help you use them less. Whether anyone\u0026rsquo;s allowed to make money from that is another question, but the features are there.\nTechRadar\u0026rsquo;s Josephine Watson wrote a great piece about three native iOS features that nearly halved her screen time. Worth a read, but in short:\nDo Not Disturb and Focus Modes. Schedule them, set exceptions for people who actually matter, dim the lock screen, hide badges. The Apple Intelligence version that picks priority notifications for you is genuinely useful too. Screen Time limits. Set a hard cap on the worst offenders. Instagram and TikTok deserve no more than half an hour of your life a day; tell your phone to enforce it. Screen Distance. This one was new to me. It nags you when you hold the phone too close to your face, which is exactly the position you adopt when you\u0026rsquo;re in bed at midnight doomscrolling. It\u0026rsquo;s annoying by design, and that\u0026rsquo;s exactly the point. Android has very similar bits and pieces under Digital Wellbeing, plus the greyscale trick mentioned earlier on. None of these tools are a magic bullet, but activated together they add real friction in the right places, and friction here is your friend.\nBlock the rest with apps # When the built-in tools aren\u0026rsquo;t enough (usually for me that means deep-focus work on the laptop rather than the phone), bring in the heavy artillery.\nThere\u0026rsquo;s a whole little industry of blocker apps built precisely for this:\nFreedom: blocks distracting sites and apps across all your devices on a schedule. Founder Fred Stutzman built it because he couldn\u0026rsquo;t write his dissertation with Facebook open; human rights lawyer Susie Alegre used it while writing her book Freedom to Think. Cold Turkey: desktop-focused, brutal, and very effective. Has a \u0026ldquo;Frozen Turkey\u0026rdquo; mode that locks you out of your computer entirely if you really need it. FocusMe: similar idea, cross-platform, lots of granular control. Forest: a gentler approach where you grow a little tree while you don\u0026rsquo;t touch your phone. Sounds twee, but it works on people who respond well to gamification and sustainability practices. Duolingo Focus mode: blocks your social media until you finish your lessons. My partner swears by this one, and as a result, her Spanish is coming along very nicely, at the expense of her Instagram addiction. Most of these have a locked mode so you can\u0026rsquo;t undo the block mid-session. Ruthless, but exactly what you want when the urge to \u0026ldquo;just quickly check\u0026rdquo; hits.\nThis is roughly the principle behind the whole Monk Mode trend the BBC wrote about a few years back: pick a finite block of time, kill every distraction you can, and only do the one thing that actually matters. You don\u0026rsquo;t need an app or a hashtag for it, mind; you just need to commit to one task at a time for an hour or two and see what happens. Spoiler: quite a lot, actually.\nSplit work from the rest of your life # Once you start working from home (or just doing both on the same phone), the line between work and life gets dangerously fuzzy. The fix is to put that line back, by force if necessary.\nPhoto by Haberdoedas on Unsplash A few things that have worked for me:\nSeparate profiles on the browser. Firefox now properly supports multiple profiles via the Profile Manager and containerised tabs too, so I can have a Work window with the work bookmarks, logins and tabs, and a totally separate Personal window for everything else. Same browser, same machine, two entirely different mental spaces. Chromium-based browsers have similar things too. App-level profiles where they exist. Signal has rolled out separate notification profiles, which is brilliant for muting work groups outside of working hours without going fully silent. More apps need to follow suit. A work-only Focus or Do Not Disturb schedule. My phone has no idea what Slack or Teams are after 6pm; they\u0026rsquo;re routed straight into the bin until the next morning. Nobody has ever died as a result. The bigger workplace problem is cultural, of course. Wellbeing coach John Pearson writes about this well: the expectation of instant responses is the real killer. A message sent at 4pm doesn\u0026rsquo;t need an answer by 4:01. If your team behaves as though it does, that\u0026rsquo;s a conversation worth having, because the alternative is everyone permanently half-working, half-stressed, and never actually offline.\nThe nuclear option is to use a completely separate device for business and personal time. Instead of recycling your old mobile at upgrade time, turn it into a work phone and have a completely separate set of apps and settings. Combine this with the focus modes too, and one goes quiet while the other wakes up. The work phone goes into my work bag at the end of the day and it comes out again on my way back into the office the next working day.\nI hear a lot of people challenge me on this point, but it really is a game-changer not only with attention, but work-life balance. The best barriers between your workself and your personal self are the physical ones. Everything else falls into place. Try it.\nTry going cold turkey for a bit # You don\u0026rsquo;t have to do anything as dramatic as ditching your smartphone entirely, but for some people, that turns out to be exactly the cure. The BBC ran a piece about Jess Farnham, a 24-year-old in Manchester who swapped her smartphone for a 2000s flip-phone for a week. She said the first 24 hours were grim, the next six days felt amazing, and her sleep, mood and productivity all improved.\nA similar story comes from Tom over at Another Angry Voice, who took a proper break from social media after years of feeling chewed up by the negativity. He came back lighter, calmer, and with more time for actual life. Same story, over and over, from everyone who tries it.\nYou can scale it however you like. Things worth trying:\nA 24-hour offline day. Tell anyone who needs to know, then put the phone in a drawer. See what happens. A weekend with the WiFi off. Brutal, brilliant. Uninstall (not just log out of) the worst offending apps for a week. If you can\u0026rsquo;t bring yourself to delete them, at least bury them deep on the last home screen. Walk somewhere with no music or podcast. Just walk, with your own thoughts for company. Genuinely uncomfortable at first; genuinely worth it. If even thinking about being unreachable for a day makes you twitchy, that itself is data. It usually means the leash is shorter than you realised.\nThe bots are watching too # Photo by Waldemar Brandt on Unsplash Worth a quick mention here, because it changed how I look at all social media feeds. TechRadar\u0026rsquo;s Matt Evans deleted his 13-year-old Reddit account after seeing a viral video of an industrial-scale bot farm: racks and racks of screenless phones, pumping out fake engagement on every site you can name.\nOnce you\u0026rsquo;ve seen something like that, you can\u0026rsquo;t really argue with comment threads in the same way again. A huge chunk of what you\u0026rsquo;re getting wound up by online is either generated by, or amplified by, accounts that are not actually people. Sean Morley\u0026rsquo;s lovely piece in Now Then Magazine makes a related point, more eloquently than I will: a lot of what we frame as a personal attention problem is really a symptom of an information environment that has been deliberately engineered to be exhausting.\nThe takeaway, for me at least: be picky. Stick to apps, sites and communities where the owner isn\u0026rsquo;t just there to get your cash and your data. Only pay for the ones that earn it. Walk away from the ones that don\u0026rsquo;t. Your attention is very valuable - spend it like it is.\nKeeping it up # There is no final battle with this stuff. Habits creep back, especially the digital ones. The apps update, the notifications quietly turn themselves back on, a new shiny thing appears. Maintenance is part of the deal unfortunately.\nWhat works for me is a kind of low-effort weekly or monthly check-in. A quick glance at the Screen Time or Digital Wellbeing report, and an honest answer to one question. Did I spend that time on things I actually wanted to spend it on? If the answer\u0026rsquo;s no, change one small thing for the next week. Not ten things; one. Move an app. Kill a notification. Add an extra hour to bedtime mode. Small changes, compounded.\nA useful gut-check, if any of this is starting to feel less like a habit and more like a problem: Internet \u0026amp; Technology Addicts Anonymous has a short, blunt questionnaire on phone addiction that\u0026rsquo;s worth running through. If you tick several of them, no shame in seeking some proper support. This stuff is genuinely engineered to be addictive, and you wouldn\u0026rsquo;t be the first.\nThe point is not to become a tech-hating hermit or luddite. None of this is about rejecting technology. I work in it, I love it, I write a whole blog about it. The point is to use it with intent: when, where, and how you choose, rather than letting it choose for you.\nTake a second after you put this article down. That quiet? That\u0026rsquo;s your attention coming home. Don\u0026rsquo;t lend it out again unless you really want to. Another thing that helped me with this stuff - whenever you pick up your phone, ask yourself \u0026ldquo;Am I using my phone, or is my phone using me?\u0026rdquo;\nWrap up # If any of this essay has been useful, pick one thing, just one, and try it for a week. A different alarm clock. A new home screen. Bedtime mode. Killing Facebook\u0026rsquo;s notifications. Whatever feels easiest. You don\u0026rsquo;t have to do everything at once, and you definitely don\u0026rsquo;t have to be perfect at any of it. I am an all or nothing type of person, so I went as hard in as possible. While I did see immediate benefits, I also missed some important stuff too:- but I learned as I went, tweaked and adjusted and now I can honestly say I am using my phone, it is not using me\u0026hellip;. well, mostly.\nI\u0026rsquo;ll probably revisit this in a year or two to see how it\u0026rsquo;s all aged, and to see what new flavours of digital quicksand have appeared in the meantime. As ever, feel free to share your own tricks, war stories or hot takes in the comments.\nFurther reading # A grab-bag of the articles I\u0026rsquo;ve read while putting this essay together. Some of them inspired specific sections; others are just well worth your time on the broader topic. This list covers both articles in the series.\nThe Guardian: Distraction disaster! Notifications are ruining our concentration The Verge: We live in notification hell The Guardian: Banning smartphones from school? What a brilliant idea Another Angry Voice: Too much doom scrolling BBC News: The people going \u0026lsquo;monk mode\u0026rsquo; to limit social media use BBC News: Susie Alegre on using Freedom to think clearly Now Then Magazine: Who Remembers Attention Spans? BBC News: Why I got rid of my smartphone for a \u0026lsquo;digital detox\u0026rsquo; BBC News: Is phubbing ruining your relationship? Silicon Canals: People who check their phone within five minutes of waking up are training their brain to start every day in reaction mode TechRadar: Three native iOS features that almost halved my screen time TechRadar: I used greyscale on my Android phone to reduce my screen time TechRadar: What a social media bot farm looks like Internet \u0026amp; Technology Addicts Anonymous: Phone addiction self-assessment Catherine Price: How to Break Up With Your Phone Psychology Today: The variable-reward effect Apple Support: How to use Focus on iPhone Apple Magazine: How to offload apps on iPhone Economic Times: Meta moves to paid subscriptions Medium: Duolingo Focus Mode Wellside: The Expectation of Immediate Responses in the Digital Age 📷 Cover photo by Oxana Melis on Unsplash under the Unsplash licence. If you or someone you know is struggling with a serious mobile or internet addiction, you don\u0026rsquo;t have to deal with it alone. Internet \u0026amp; Technology Addicts Anonymous offers a self-assessment, peer support groups, and a welcoming community. There is no shame in asking for help - these products were deliberately engineered to hook us, and professional support exists precisely because willpower alone is rarely enough. ","date":"31 May 2026","externalUrl":null,"permalink":"/blog/2026-05-31-reclaiming-your-attention-part-ii/","section":"Blogs","summary":"","title":"Reclaiming Your Attention – Part II: Taking Back Control of Your Digital Life","type":"blog"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/screen-time/","section":"Tags","summary":"","title":"Screen Time","type":"tags"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open Source","type":"tags"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/os/","section":"Tags","summary":"","title":"Os","type":"tags"},{"content":"Knowing how to quickly spin up a Linux server with desktop environment can be super useful. Whether the use-case is for development, testing/experimenting, or general tasks, this article will describe how do just that, complete with two distinct web browsers; Firefox and Chromium.\nWe\u0026rsquo;ll build two different flavours of Linux to provide a variety of choice and preparation method. For the Ubuntu box, I will demonstrate the use of a pre-built Digital Ocean image, and the Fedora box with a choice of bootstrap script or manual steps. This should give plenty of scope to experiment yourself further with, depending on your specific use-case or preferences.\nWe\u0026rsquo;ll begin with the simplest method (Ubuntu, using an image), moving on to the more manual (Fedora, using a script or by manually running commands). Finally we\u0026rsquo;ll take a look at connecting to the desktop of the new box from your local machine, be it Windows or Mac based.\nIntroducing Digital Ocean # I use Digital Ocean for this sort of task, because it\u0026rsquo;s a great platform for getting up and running quickly with no existing cloud environment. While I feel that the platform is a bit more user-friendly than others, getting started can still rely on some DevOps or Sysadmin experience (hence this article). While I\u0026rsquo;ll be using Digital Ocean for demonstration purposes, the script and manual steps later will remain useful and somewhat transferable for other cloud platforms too.\nA note on Terminology # There are many words used to describe servers, such as server, box, or instance to name a few. At Digital Ocean, they refer to them as Droplets.\nA note on Billing # While running small servers for a number of hours or even days will only cost you pennies, it\u0026rsquo;s important to destroy them when you\u0026rsquo;re finished with them to avoid any unexpected bills. It\u0026rsquo;s important to understand the costs before spinning up the machines before proceeding as they can quickly sprawl out of control if you\u0026rsquo;re not careful. As a rough guide, I spun up around 10 servers when writing this article over two days and the total bill was under $2 (USD).\nA note about Machine Type # While there are other cheaper machine types available on Digital Ocean, I\u0026rsquo;ve used the 4 GB / 2 CPUs option for a couple of reasons:\n2 CPUs and 4 GB of RAM should provide acceptable performance for the desktop while supporting KDE/GNOME, XRDP/VNC and a web browser with a couple of tabs open simultaneously. The basic plan ensures a good balance between cost and functionality, making it ideal for personal or lightweight tasks. Feel free to experiment with this choice, but you will discover that if you choose a machine type that\u0026rsquo;s too underpowered, installation and use of the desktop systems can become a long and drawn out affair; whereas overpowered machines will cost more while not necessarily offering better performance.\nIf you don\u0026rsquo;t yet have an account, sign up at DigitalOcean. To spin up servers, you\u0026rsquo;ll probably have to add a valid payment method first. To be clear, I\u0026rsquo;m not affiliated or connected to Digital Ocean in any way.\nCreating an Ubuntu Desktop (GNOME) Server with a Prebuilt Image # This is the easiest and fastest method of getting a server online with a remote-desktop capability I\u0026rsquo;ve found so far. You can be connected to a remote desktop via VNC within 3 minutes from creating an account if you know what you\u0026rsquo;re doing.\nOnce you\u0026rsquo;re signed up and logged in, at the top of the screen, click Create \u0026gt; Droplets\nOn the Create a Droplet page, pick a location to build your server. The best network performance is achieved from the closest location to you. Leave the data centre and VPC options as default.\nOn Choose an image, select Market Place\nSearch for GNOME and select Ubuntu Desktop (GNOME)\nSelect the following options and leave the rest as defaults:\nDroplet Type: Basic CPU Options:\n- Regular SSD\n- 4 GB / 2 CPUs SSH Key: New SSH Key\n(Paste in one of your existing public keys, or proceed to follow the on-screen instructions to create a new keypair) Your screen will look something like this by now:\nSelect Create Droplet at the bottom of the screen. It will take 30 seconds or so to provision and launch and should be ready when the IP address is shown.\nSSH to the new machine from your computer. The machine may still be finishing up its build, and once the logs finish printing on screen, a VNC username (user) and a unique password will be revealed there. This will be used for the remote-desktop connection, so make a note of these credentials.\nThis build of Ubuntu comes with Firefox already, so we just need to install Chromium. Do so with:\napt install chromium-browser Now you\u0026rsquo;re ready to connect to the desktop!\nCreating a Fedora Desktop (KDE Plasma) Server - Using a bootstrap script # I\u0026rsquo;ve written a bootstrap script to automate the manual steps of creating this Fedora desktop machine. It\u0026rsquo;s hosted on GitHub and I\u0026rsquo;d always strongly recommend checking scripts before running them on your machines to make sure they\u0026rsquo;re not doing anything nasty.\nThis script will handle everything, including setting up the new non-root remote-desktop user \u0026amp; password. The final step of the script will reboot the machine. Just before the server reboots, the username and password used to connect to the desktop will be printed on-screen, so remember to job them down in case you close the terminal window.\nOnce you\u0026rsquo;re signed up and logged in, at the top of the screen,\nclick Create \u0026gt; Droplets.\nOn the Create a Droplet page, pick a location to build your server. The best network performance is achieved from the closest location to you. Leave the data centre and VPC options as default.\nOn Choose an image, select OS.\nSelect Fedora (latest version).\nSelect the following options and leave the rest as defaults:\nDroplet Type: Basic CPU Options:\n- Regular SSD\n- 4 GB / 2 CPUs SSH Key: New SSH Key\n(Paste in one of your existing public keys, or proceed to follow the on-screen instructions to create a new keypair) Your screen will look something like this by now:\nSelect Create Droplet at the bottom of the screen. It will take 30 seconds or so to provision and launch and should be ready when the IP address is shown.\nSSH to the new machine from your computer.\nssh -i ~/.ssh/\u0026lt;path/to/your/private-keyname\u0026gt; root@\u0026lt;droplet ip address\u0026gt; Run the bootstrap script:\ncurl -s https://gist.githubusercontent.com/chris-gillatt/bfccc00cb938134879b428d8ee2e6e8c/raw/setup_fedora_kde_xrdp.sh | bash The machine will print out the XRDP username and password to access the remote desktop and reboot.\nNow you\u0026rsquo;re ready to connect to the desktop!\nCreating a Fedora Desktop (KDE Plasma) Server - Manually from Scratch # If you\u0026rsquo;d rather perform the steps manually or wish to make some customisations of your own along the way, you can do so by following along the provided step-by-step breakdown.\nUpdate all installed packages to their latest versions\ndnf update -y -q Create a user named user, add them to the wheel group, and set a password\nuseradd -m -G wheel user passwd user Install the KDE desktop environment, XRDP server, and web browsers\ndnf install -y -q @kde-desktop-environment xrdp firefox chromium Ensure all necessary KDE components are installed\ndnf install -y plasma-workspace-x11 Start and enable the XRDP service to allow incoming RDP connections\nsystemctl enable xrdp --now Obtain your local Public IP address\nYou can obtain your public IP address on your local machine either from the terminal:\ncurl ifconfig.me or visit a site like https://ifconfig.me in your web browser.\nOptional - Add a Firewall Rule for Your IP Address only Before opening the RDP port (3389), it’s highly recommended to restrict access to your specific source IP address for enhanced security. This prevents unauthorised users from attempting to connect.\nReplace \u0026lt;your ip\u0026gt; (no chevrons) with your actual external IP address:\nfirewall-cmd --permanent --add-rich-rule=\u0026#34;rule family=\u0026#39;ipv4\u0026#39; source address=\u0026#39;\u0026lt;your ip\u0026gt;\u0026#39; port protocol=\u0026#39;tcp\u0026#39; port=\u0026#39;3389\u0026#39; accept\u0026#34; firewall-cmd --reload Alternatively - allow All Connections to the RDP Port (Less Secure)\nIf your network setup makes restricting access difficult or you frequently switch between networks, you can open the RDP port for all connections:\nfirewall-cmd --permanent --add-port=3389/tcp firewall-cmd --reload ⚠️ Warning: This option is less secure and should only be used temporarily or in environments with additional layers of protection.\nReboot the server to apply all changes\nreboot Now you\u0026rsquo;re ready to connect to the desktop!\nConnecting via RDP on macOS or Windows # macOS: Using the Windows App # To connect to your Fedora server from macOS, you can use the Windows App (formerly known as Microsoft Remote Desktop) available on the Mac App Store:\nDownload the Windows App.\nInstall the Windows App from the link above. Launch the app and click Add PC. Enter your droplet\u0026rsquo;s public IP address. For the user account, choose \u0026ldquo;Ask me every time\u0026rdquo; or provide the credentials (the user username and its password obtained in the SSH session). Click Connect, and in the next screen, choose the Xorg session. If you see certificate warnings, click continue. Windows: Using the Built-in Remote Desktop App # If you’re on Windows, you can use the built-in Remote Desktop Connection app:\nPress the windows key, and search for Remote Desktop and hit enter. Enter your droplet\u0026rsquo;s public IP address in the Computer field. Click Connect, and dismiss the certificate warnings A new log-in screen will appear. Continue to log in (using the user username and its password obtained in the SSH session). Wrap Up # In this article, we\u0026rsquo;ve explored how to quickly get started with a Fedora Desktop machine in the cloud, ready to connect to with RDP. Whether you chose to use the automated script or followed the manual steps, your server is now equipped for graphical remote access.\nJust One more thing - remember to destroy your machine when you\u0026rsquo;ve finished with it to avoid any unexpected charges!\nIf you encounter any issues or have suggestions for improving the script, feel free to share your feedback in the comments section below.\n📷 Cover photo by AllGo - An App For Plus Size People on Unsplash under the Unsplash license.\nModified by Chris Gillatt. ","date":"19 Nov 2024","externalUrl":null,"permalink":"/blog/2024-11-19-quickly-spin-up-a-linux-desktop-box-with-remote-access/","section":"Blogs","summary":"","title":"Quickly spin up cloud-based machines with a desktop frontend","type":"blog"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/remote-access/","section":"Tags","summary":"","title":"Remote Access","type":"tags"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"19 Nov 2024","externalUrl":null,"permalink":"/tags/workflow/","section":"Tags","summary":"","title":"Workflow","type":"tags"},{"content":"","date":"7 Nov 2024","externalUrl":null,"permalink":"/tags/pi/","section":"Tags","summary":"","title":"Pi","type":"tags"},{"content":"","date":"7 Nov 2024","externalUrl":null,"permalink":"/tags/raspberry-pi/","section":"Tags","summary":"","title":"Raspberry Pi","type":"tags"},{"content":"While Docker has been my go-to for isolated experimentation without affecting my laptop’s setup for a while now, today I needed a device with its own browser to test both on and off the local network. I realised I still had a Raspberry Pi tucked away in a cupboard — a perfect candidate for the job, though likely very outdated.\nSure enough, it was online and running Raspbian OS Stretch from 2017, which lost support in early 2024. The pre-installed Chromium browser was so old that some sites even blocked it\u0026hellip; no problem, I thought — I’d just install the latest Firefox. But soon, apt threw errors about incorrect entries in sources.list preventing package upgrades and installs, and I found myself down a rabbit hole. I couldn’t immediately find a coherent guide for upgrading from Stretch, so I decided to document my journey here for anyone else facing the same issue.\nThankfully in my case, this thing was not internet facing, but it was on the local network and could have provided a useful entry for someone with a certain set of skills.\nWait, why not just perform a fresh install? # If you’re ready to jump straight to Bookworm, the best approach is to perform a clean install. This avoids potential complications from upgrading across multiple OS versions and ensures your system is running as smoothly and efficiently as possible.\nHowever, the Raspberry Pi was designed for experimentation, modding, tinkering and tweaking. Chances are, there\u0026rsquo;s bits and pieces all over the place that are probably not worth the effort of finding and backing up one at a time, but might worth keeping. If you don\u0026rsquo;t care about this stuff, you can just leap ahead and install from fresh in a fraction of the time it takes to manually upgrade one major version at a time. While this is the cleanest and most straight-forward option to get your device up to date, it might not suit everyone; especially if you\u0026rsquo;ve spent a long time on a specific configuration or setup.\nTo install a fresh version and wipe the slate clean # Download the Latest OS Image: Head over to the Raspberry Pi website and download the Raspberry Pi OS Bookworm image. Flash the Image: Use an imaging tool like Raspberry Pi Imager or Balena Etcher to write the OS image to your SD card. Boot from SD Card: Insert the SD card into your Pi and power it on to boot into your new OS. The remainder of this article explains the process on how to manually upgrade Raspberry OS to the latest version.\nChecking Hardware Compatibility # My first thought for upgrading the OS to latest for such an old machine would be to check if the hardware can support it. It\u0026rsquo;s possible to find the model of the Raspberry Pi by using the following command:\ncat /sys/firmware/devicetree/base/model \u0026amp;\u0026amp; echo Fortunately though, this ended up being totally moot, because Raspberry Pi OS remains to be compatible with all Raspberry Pi models.\u0026hellip;Nice!\nMay long this continue!\nHow to Upgrade from Raspberry Pi OS Stretch to Bookworm # Raspberry Pi OS Stretch has been around since 2017, and it’s understandably showing its age a little bit. Over the years, several major versions of Raspberry Pi OS have been released, offering security improvements, features, and optimisations that make upgrading well worth doing.\nHere’s a table summarising the release dates and support windows for recent Raspberry Pi OS versions:\nRaspberry Pi OS Version Release Date Support End Date Stretch August 2017 January 2024 (EOL) Buster June 2019 June 2025 Bullseye November 2021 June 2026 Bookworm October 2023 Currently supported Staying up-to-date is essential for optimising performance and longevity of the Pi — particularly if you’re using it for projects that need security, like home automation, remote access, or advert blocking with Pi-hole etc.\nRaspberry Pi OS doesn’t support direct upgrades from Stretch to Bookworm, so we need to perform incremental upgrades through each intermediate version: Stretch to Buster -\u0026gt; Buster to Bullseye -\u0026gt; Bullseye to Bookworm. I\u0026rsquo;m not sure it\u0026rsquo;s even possible without instead performing a fresh install, but skipping versions would most likely cause compatibility issues with packages and dependencies. Each OS iteration will bring changes to the kernel, system libraries, and software repositories that must be applied step-by-step.\nToy Story: A naming convention # While writing this article, a quirky detail about Raspberry Pi OS names suddenly hit me: they’re all named after characters from the Toy Story films. For instance, Stretch was the purple octopus from Toy Story 3, Buster is Andy’s dachshund, Bullseye is Woody’s loyal steed, and Bookworm is the spectacled book lover also seen in Toy Story 3. Perhaps everyone knows this, but it was certainly news to me. Anyway - let\u0026rsquo;s get to work!\nBefore You Begin: Make a Full Backup # As always with things like this - it’s absolutely crucial to create a backup of your data. This includes not only your important files (sometimes easier said than done) but a full backup of the whole SD card. If something goes wrong during the upgrade, having an SD card backup means you can restore your system to where we started. Tools like Raspberry Pi Imager, Win32DiskImager, or Balena Etcher work well for creating a full SD card image, allowing you to preserve all your data and system configurations.\nImportant Note: This Process Takes Time # Upgrading the OS in the manor as follows takes a fair amount of time — often a couple of hours per version hop. If you’re connected over SSH from your laptop or any other device that could potentially go to sleep, consider using the screen utility on the Raspberry Pi. This allows you to run the upgrade commands in a detachable session, allowing you get on with other things; Watching a gazillion lines of logs for hours probably isn’t the best use of your time.\nTo install and use screen:\nsudo apt install screen screen You can detach from a session with Ctrl + A and then D. To reconnect, use:\nscreen -r I strongly recommend experimenting with screen before using it in anger; specifically with detaching and reattaching. It can come across a bit fiddly to new users, but once you get the hang of it, it\u0026rsquo;s a super useful tool for system administration. See screen\u0026rsquo;s man page or view the manual here.\nIn-Place Upgrade from Stretch to Bookworm # For those looking to keep their current setup and files intact, here’s a guide to performing an in-place upgrade from Stretch to Bookworm. Again, be aware that this method carries some risk, so it’s strongly recommended to have a recent backup.\n1. Prepare for Upgrade # Fully update your current OS packages before starting the upgrade:\nsudo apt update sudo apt full-upgrade 2. Upgrade Stretch to Buster # 2.1. Edit Sources Files\nUpdate the following files by changing stretch to buster:\n/etc/apt/sources.list /etc/apt/sources.list.d/raspi.list For example, in /etc/apt/sources.list:\ndeb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi And in /etc/apt/sources.list.d/raspi.list\ndeb http://archive.raspberrypi.org/debian/ buster main Tip \u0026#x1f680; - Use sed to update your list files # To change the release name in both files, you can use sed to replace stretch with buster in a single command:\nsudo sed -i \u0026#39;s/stretch/buster/g\u0026#39; /etc/apt/sources.list /etc/apt/sources.list.d/raspi.list Obviously you can rinse and repeat with the other versions in upcoming steps.\nHeads up: I hit this issue at this stage.\n2.2. Run the upgrade\nsudo apt update sudo apt full-upgrade -y Warning: The -y flag automatically accepts all prompts during the upgrade process, which is convenient for most users. However, if you prefer to review and confirm each change, run sudo apt full-upgrade without -y to make those choices manually.\n2.3. Reboot\nsudo reboot 3. Upgrade Buster to Bullseye # 3.1. Update the sources files again, replacing buster with bullseye\n/etc/apt/sources.list\ndeb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi /etc/apt/sources.list.d/raspi.list\ndeb http://archive.raspberrypi.org/debian/ bullseye main To quickly update both files:\nsudo sed -i \u0026#39;s/buster/bullseye/g\u0026#39; /etc/apt/sources.list /etc/apt/sources.list.d/raspi.list 3.2. Run the upgrade\nsudo apt update sudo apt full-upgrade -y Heads up: I hit this issue at this stage.\n3.3. Reboot again:\nsudo reboot 4. Upgrade Bullseye to Bookworm # 4.1. Update the sources files, now replacing bullseye with bookworm\n/etc/apt/sources.list\ndeb http://raspbian.raspberrypi.org/raspbian/ bookworm main contrib non-free rpi /etc/apt/sources.list.d/raspi.list\ndeb http://archive.raspberrypi.org/debian/ bookworm main Quickly update both files:\nsudo sed -i \u0026#39;s/bullseye/bookworm/g\u0026#39; /etc/apt/sources.list /etc/apt/sources.list.d/raspi.list 4.2. Run the upgrade\nsudo apt update sudo apt full-upgrade -y 4.3. Reboot:\nsudo reboot 5. Final System Check # After the upgrade, remove any obsolete or deprecated packages to keep your system clean and optimised:\nsudo apt autoremove sudo apt autoclean Troubleshooting # Deprecated Components: The ui Warning # When upgrading from older versions like Stretch, you may see a warning related to a deprecated ui component in your sources list. The ui component was initially part of earlier Raspberry Pi OS repositories, providing packages related to the user interface, but it’s been deprecated and removed in recent versions (like Bullseye and Bookworm). If ui remains in your sources list, you may see warnings similar to the following during apt update:\nW: Skipping acquire of configured file \u0026#39;ui/binary-armhf/Packages\u0026#39; as repository \u0026#39;http://archive.raspberrypi.org/debian bullseye InRelease\u0026#39; doesn\u0026#39;t have the component \u0026#39;ui\u0026#39; (component misspelt in sources.list?) To resolve this, simply remove ui from /etc/apt/sources.list.d/raspi.list.\nOpen /etc/apt/sources.list.d/raspi.list:\nsudo vi /etc/apt/sources.list.d/raspi.list Remove ui from any lines that include it, such as:\ndeb http://archive.raspberrypi.org/debian bullseye main ui Change it to:\ndeb http://archive.raspberrypi.org/debian bullseye main Save the file and run sudo apt update again to confirm the warning is gone.\nRemoving this deprecated component will allow the upgrade to proceed without warnings and prevent potential conflicts with newer package sources.\n\u0026lsquo;No space left on device\u0026rsquo; error # As part of this journey, a lot of packages will get cached and you might even run out of space in the root disk. If this happens, you\u0026rsquo;ll need to clear up some junk files and re-run the command that failed. Be sure to take a look at my article on this topic Reclaiming space on Linux Machines if you need any guidance in this area. There\u0026rsquo;s a bunch of tips and tricks about reclaiming space on your linux devices.\nHeld Packages # There may be cases of incompatible versions of essential packages (like libc6-dev and libgcc-8-dev) during an upgrade. This typically happens because of \u0026ldquo;held\u0026rdquo; packages, where some packages are \u0026ldquo;pinned\u0026rdquo; to an older version, preventing dependencies from properly resolving.\nIf you run into these issues;\n1. Check for Held Packages # Check for packages that are currently held:\nsudo apt-mark showhold If there are any packages listed, un-hold them so they can be upgraded like so:\nsudo apt-mark unhold \u0026lt;package_name\u0026gt; For example:\nsudo apt-mark unhold libc6-dev libgcc-8-dev 2. Update and Try the Upgrade Again # Run the following commands to make sure all package information is up-to-date and then try upgrading again:\nsudo apt update sudo apt upgrade --fix-broken sudo apt full-upgrade -y 3. Manually Install Dependencies # If the issue persists, you may need to manually install the required versions of the dependencies:\nsudo apt install libc6-dev libgcc-8-dev -y 4. Clean Up Package Cache # If there are still issues, clearing the package cache can help ensure no outdated packages are causing conflicts:\nsudo apt clean sudo apt autoclean sudo apt autoremove Then, try updating and upgrading again:\nsudo apt update sudo apt full-upgrade -y 5. Use dist-upgrade as a Last Resort # If the issue remains, try using dist-upgrade, which may resolve complex dependencies:\nsudo apt dist-upgrade -y 6. If you\u0026rsquo;re still seeing issues\u0026hellip; # Uninstalling problematic packages may be the only way forward. Start with the least critical, one at a time, whilst retrying the full-upgrade. Be careful with core packages as uninstalling them (such as libc6-dev) could brick your machine. If you\u0026rsquo;ve taken a backup you can always go back anyway, but you have been warned!\nAfter resolving the dependency issues, proceed with the usual upgrade steps and reboot as necessary as seen earlier in this article.\nWrap Up # Upgrading your Raspberry Pi OS over several major versions is no small task. By following this guide, you\u0026rsquo;ve taken your Pi from an older, unsupported OS through several major upgrades, making it up-to-date and secure for future projects.\nKeeping your Pi updated maximises its performance, security, and compatibility, which is especially valuable if you’re running long-term projects or experimenting with new applications. Whether you chose the clean install route or tackled the in-place upgrade, you’ve set yourself up for a more powerful and future-ready Pi.\nIf you have any questions or thoughts, feel free to drop a comment below!\n📷 Cover photo by Louis Reed on Unsplash under the Unsplash license. ","date":"7 Nov 2024","externalUrl":null,"permalink":"/blog/2024-11-07-updating-raspberry-pi-os-from-stretch-to-bookworm/","section":"Blogs","summary":"","title":"Updating Raspberry Pi OS from Stretch to Bookworm","type":"blog"},{"content":"","date":"7 Nov 2024","externalUrl":null,"permalink":"/tags/upgrade/","section":"Tags","summary":"","title":"Upgrade","type":"tags"},{"content":"","date":"15 May 2024","externalUrl":null,"permalink":"/tags/brew/","section":"Tags","summary":"","title":"Brew","type":"tags"},{"content":"","date":"15 May 2024","externalUrl":null,"permalink":"/series/distributing-tools/","section":"Series","summary":"","title":"Distributing Tools","type":"series"},{"content":"In Part I of this two-part article, we\u0026rsquo;ll take a look at an easy method of sharing tools/apps/utilities using Brew between Apple Macs. It\u0026rsquo;s a convenient way to share home-grown tools to friends, coworkers, and random people on the internet quickly and easily. In Part II , we\u0026rsquo;ll look at how to automate away some of the chore of creating releases ourselves, by leveraging the power of popular CI/CD tool, GitHub Actions.\nPrerequisites / Disclaimer # I\u0026rsquo;ll assume you\u0026rsquo;ve already got Brew installed and have a basic understanding of its purpose as a package manager and are comfortable with it managing your packages.\nIf this doesn\u0026rsquo;t sound like you yet, I strongly recommend that you take a look at https://brew.sh before proceeding with any of the below. While we won\u0026rsquo;t be doing anything intentionally destructive, we will be installing/upgrading some unix packages that could override currently installed native versions. For most people this won\u0026rsquo;t matter (and could even improve things), but if you\u0026rsquo;re a developer or software engineer this may cause some unexpected or undesired effects.\nBasic knowledge of Ruby (I\u0026rsquo;ll provide examples anyway).\nBasic knowledge of Git and GitHub (there\u0026rsquo;ll be screenshots and examples for GitHub).\nDistributing tools with Brew # You may already have your own app or tool that\u0026rsquo;s ready to share using Brew. For demonstration purposes for this article, I\u0026rsquo;ve thrown together a command-line tool named joke, because I wanted to demonstrate how to specify dependencies, and most hello world stuff I could find doesn\u0026rsquo;t have any. joke prints a random joke on the command-line from the icanhazdadjoke.com API, in various amusing formats.\nSetting things up # Brew has a couple of its own prerequisites, such as your binary (or binaries) in a tarball, a shasum of that tarball, and a ruby formula to give Brew the info it needs to manage the install of the tool. All this combined forms the package - or formula - that Brew will manage.\nWe will be using GitHub throughout this article, so first of all, publish your project on GitHub. Later on, we\u0026rsquo;ll learn later how to use GitHub Actions to automate some of the chore related to the Brew package creation. Note the GitHub repository URL as we will need that shortly.\nIMPORTANT - Your new repository MUST be named with a prefix of \u0026ldquo;homebrew-\u0026rdquo; to allow the short-hand (opposed to having to supply the full URL to the repository when issuing brew commands such as brew install). Your app can be called whatever you like, but the repository must be named like so. So for my example joke tool, the repository is named homebrew-joke, but the tool remains simply joke. There\u0026rsquo;s some Brew magic that lets us refer to the shorter name, which I\u0026rsquo;ll touch on later.\nCreate a directory within your project/repository to contain the tarballs. In the following examples I\u0026rsquo;ll be using the directory named dist.\n$ mkdir dist Create a tar containing the tool\u0026rsquo;s files. In my example, there\u0026rsquo;s only one, named joke. It\u0026rsquo;s worth mentioning here that it\u0026rsquo;s important to include a version number. This enables us to release new versions and for anyone who uses this tool, to upgrade it to those new versions. This is the first version of this particular one, so we\u0026rsquo;ll start with 0.0.1 using Semantic Versioning pattern. $ tar -cvf dist/joke-0.0.1.tar.gz joke Get a shasum for the tar (needed for the Formula file next). $ shasum -a 256 dist/joke-0.0.1.tar.gz | awk \u0026#39;{printf $1}\u0026#39; Create a formula in the root of the repo so Brew knows what to install, which dependencies it needs, versions and file locations for the app. Below you\u0026rsquo;ll find an example for the joke app. It\u0026rsquo;s a ruby file because Brew is written in Ruby. Filename: joke.rb class Joke \u0026lt; Formula desc \u0026#34;Prints a random joke on the command-line\u0026#34; homepage \u0026#34;https://github.com/chris-gillatt/homebrew-joke\u0026#34; url \u0026#34;https://github.com/chris-gillatt/homebrew-joke/releases/download/v0.0.1/joke-0.0.1.tar.gz\u0026#34; sha256 \u0026#34;8c47f8c3cd9137b0fa476c0e6ae084ee29cde94d613250a8532bb333351b6080\u0026#34; version \u0026#34;0.0.1\u0026#34; depends_on \u0026#34;curl\u0026#34; depends_on \u0026#34;figlet\u0026#34; depends_on \u0026#34;cowsay\u0026#34; depends_on \u0026#34;lolcat\u0026#34; depends_on \u0026#34;coreutils\u0026#34; def install bin.install \u0026#34;joke\u0026#34; end end Click to expand for a drill-down of this file In the formula file for joke above, we can see various metadata required for the distribution to function. Let\u0026rsquo;s dig into what this file represents.\nline number(s) Description 1 The class name should begin with a capital letter (This is a Brew rule). This should match the name of the tool. 2 A short purpose statement for the tool. 3 The URL of the repository that contains the homebrew app. 4 The URL of the release asset files. 5 Contains the sha256 sum we generated earlier in step 3 above. 6 Version number of our app 8-12 Dependencies for our app to function. These will be attempted to be installed with our app if they are not yet present 14-17 What is installed when a \u0026quot;Brew install...\u0026quot; command is issued Finally, before you commit and push those changes to the repository, make sure you use a .gitignore file to prevent committing of the tarball or dist directory. We don\u0026rsquo;t need to commit them as we\u0026rsquo;ll use GitHub Release Assets instead. This keeps your repositories lean and quick to clone down. **/dist *.tar.gz Now we can commit and push those changes. Your repository will look something like this: Manually Creating a release on GitHub # Now we have all the required files, next we need to package things up so that Brew can find them. We can create a release manually directly using curl commands, or by using a script, or better still, we can use the new GitHub CLI.\nDepending on your use-case, one may be preferable to the other, but I\u0026rsquo;m all about the GitHub CLI these days; it makes lots of things way simpler. Creating a release is no exception.\nYou can use Brew to install the GitHub CLI. $ brew install gh Now authenticate by following the prompts so that we can push our changes to GitHub. $ gh auth login ? What account do you want to log into? GitHub.com ? What is your preferred protocol for Git operations on this host? HTTPS ? Authenticate Git with your GitHub credentials? Yes ? How would you like to authenticate GitHub CLI? Login with a web browser ! First copy your one-time code: xxxx-xxxx Press Enter to open github.com in your browser... ✓ Authentication complete. - gh config set -h github.com git_protocol https ✓ Configured git protocol ✓ Logged in as chris-gillatt Push our new release to GitHub. $ gh release create v0.0.1 ./dist/joke-0.0.1.tar.gz --title \u0026#34;0.0.1\u0026#34; --generate-notes Brew Tapping # In Brew, tapping is the process of informing the package manager client where a homebrew application resides; i.e, the repository URL.\nLet\u0026rsquo;s tap that app!\n$ brew tap chris-gillatt/joke NOTE - we can choose to omit the \u0026ldquo;homebrew-\u0026rdquo; prefix when tapping. Brew is smart enough to be able to find the repository because it\u0026rsquo;s automatically looking for the \u0026ldquo;homebrew-\u0026rdquo; prefix.\nInstalling using Brew 🍺 # Function command Install the app brew install joke Uninstall the app brew remove joke Show app info brew info joke $ brew install joke ==\u0026gt; Downloading https://formulae.brew.sh/api/formula.jws.json ########################################################################################################################################################################## 100.0% ==\u0026gt; Downloading https://formulae.brew.sh/api/cask.jws.json ########################################################################################################################################################################## 100.0% ==\u0026gt; Fetching chris-gillatt/joke/joke ==\u0026gt; Downloading https://github.com/chris-gillatt/homebrew-joke/releases/download/v0.0.1/joke-0.0.1.tar.gz ==\u0026gt; Downloading from https://objects.githubusercontent.com/github-production-release-asset-2e65be/800356494/dd71e6a3-6c91-488d-92dc-0d07e788d0a8?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026amp;X-Amz-Credential=releaseassetprodu ########################################################################################################################################################################## 100.0% ==\u0026gt; Installing joke from chris-gillatt/joke 🍺 /opt/homebrew/Cellar/joke/0.0.1: 3 files, 7KB, built in 1 second ==\u0026gt; Running `brew cleanup joke`... And now we can test that it installed correctly\u0026hellip;\n$ joke I used to work for an origami company but they folded. \u0026hellip;and we can see that the tool appears to be installed and functions as intended.\nSo far so good.\nUpdates # Updates work for your homebrew tools in the exact same way as they do for well-known core apps like curl or gh. To get updates, we must first update Brew\u0026rsquo;s local state. Updates through tapped apps behave in the same way.\nTo update the state:\n$ brew update Then we can update to the latest available version, just like any other app distributed with Brew:\n$ brew upgrade joke ==\u0026gt; Upgrading 1 outdated package: chris-gillatt/joke/joke 0.0.1 -\u0026gt; 0.0.2 ==\u0026gt; Fetching chris-gillatt/joke/joke ==\u0026gt; Downloading https://github.com/chris-gillatt/homebrew-joke/releases/download/v0.0.2/joke-0.0.2.tar.gz ==\u0026gt; Downloading from https://objects.githubusercontent.com/github-production-release-asset-2e65be/800356494/309c2626-66d6-45cf-b6b2-29fc10a41e9c?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026amp;X-Amz-Credential=releaseassetprodu ########################################################################################################################################################################## 100.0% ==\u0026gt; Upgrading chris-gillatt/joke/joke 0.0.1 -\u0026gt; 0.0.2 🍺 /opt/homebrew/Cellar/joke/0.0.2: 4 files, 27.9KB, built in 1 second ==\u0026gt; Running `brew cleanup joke`... Uninstall the app and its dependencies with:\n$ brew remove joke ✗ brew remove joke Uninstalling /opt/homebrew/Cellar/joke/0.0.2... (4 files, 27.9KB) ==\u0026gt; Autoremoving 3 unneeded formulae: cowsay figlet lolcat Uninstalling /opt/homebrew/Cellar/cowsay/3.04_1... (63 files, 82.8KB) Uninstalling /opt/homebrew/Cellar/lolcat/100.0.1... (262 files, 598.4KB) Uninstalling /opt/homebrew/Cellar/figlet/2.2.5... (677 files, 9.5MB) Next up\u0026hellip; # 🚀 Cool right? But wait, there\u0026rsquo;s more\u0026hellip;\nThe thing is, each time we update our code and push it to GitHub so that others can receive these updates, we have a list of chores to do to create a new release:\nGenerate a new tarball. Obtain the new sha256 sum of our tarball. Update our formula file with the new version and shasum. Push the changes. Create a new release. Wouldn\u0026rsquo;t it be great if we could automate some of this away?\nWell, we can do just that!\nCheck out Distributing tools with Brew and GitHub Actions - Part II to find out how!\n📷 Cover photo by Jon Tyson on Unsplash under the Unsplash license. ","date":"15 May 2024","externalUrl":null,"permalink":"/blog/2024-05-15-distributing-tools-with-brew-and-github-actions-part-i/","section":"Blogs","summary":"","title":"Distributing tools with Brew \u0026 GitHub Actions - Part I","type":"blog"},{"content":"Over in Part I of this two-part article, we investigated sharing tools/apps/utilities using Brew. Now in Part II, we\u0026rsquo;ll complete the solution by automating away the chore of creating releases ourselves with GitHub Actions.\nAutomate releases with GitHub Actions # GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform. It allows developers to automate the build, test, and deployment pipeline for their applications directly from their GitHub repositories. We can use GitHub Actions to automate some of the chore, so that we can better spend our time on developing our tools instead.\nFortunately, GitHub Runners come pre-installed with the GitHub CLI and Ruby.\nBrew Formula File Template # To automatically create our Brew formula file, we need to convert it to a Ruby Template that we can call as part of the workflow. Below you will find an example for the joke app.\nFilename: joke.erb\nclass Joke \u0026lt; Formula desc \u0026#34;Prints a random joke on the command-line\u0026#34; homepage \u0026#34;https://github.com/chris-gillatt/homebrew-joke\u0026#34; url \u0026#34;https://github.com/chris-gillatt/homebrew-joke/releases/download/v0.0.\u0026lt;%= ENV[\u0026#34;GITHUB_RUN_NUMBER\u0026#34;] %\u0026gt;/joke-0.0.\u0026lt;%= ENV[\u0026#34;GITHUB_RUN_NUMBER\u0026#34;] %\u0026gt;.tar.gz\u0026#34; sha256 \u0026#34;\u0026lt;%= `sha256sum dist/joke-0.0.#{ENV[\u0026#34;GITHUB_RUN_NUMBER\u0026#34;]}.tar.gz | awk \u0026#39;{printf $1}\u0026#39;` %\u0026gt;\u0026#34; version \u0026#34;0.0.\u0026lt;%= ENV[\u0026#34;GITHUB_RUN_NUMBER\u0026#34;] %\u0026gt;\u0026#34; depends_on \u0026#34;curl\u0026#34; depends_on \u0026#34;figlet\u0026#34; depends_on \u0026#34;cowsay\u0026#34; depends_on \u0026#34;lolcat\u0026#34; depends_on \u0026#34;coreutils\u0026#34; def install bin.install \u0026#34;joke\u0026#34; end end As you can see, most of the file is the same as before, with a few key differences:\nThe file extension is now erb rather than .rb. On lines 4-6, we\u0026rsquo;re extracting the built-in GitHub Runner variable GITHUB_RUN_NUMBER and using the Ruby template file to substitute in their values. This handles the automatic incremental versioning with each push to our repository. NOTE - There is a gotcha here. If you\u0026rsquo;ve been following this guide throughout, you will already have version 0.0.1 of your app published as a release in GitHub. The value of GITHUB_RUN_NUMBER starts at 1 so the first run of the workflow will fail. You can either run the workflow again until GITHUB_RUN_NUMBER becomes higher than your latest version number of your app, or increment the minor version of the app in the template, such as 0.1.1. You could also write a bit of bash that performs some maths to ensure that the version number is where it needs to be and place it in the workflow.\nIdentity and Access Management (IAM) # Not so long ago I would have recommended creating a GitHub Personal Access Token (PAT) and placing it into a secret to be read by the CI/CD system of choice. However, I\u0026rsquo;ve discovered a more elegant solution in the form of simply granting write permissions on our repository to the workflow via the GitHub Runner (the term for a worker agent of GitHub Actions).\nThis conveniently avoids the need to create and manage a PAT or SSH key to allow the committing of new files back to our repository. GitHub hosted runners are ephemeral only shared with other members of the same organisation. They\u0026rsquo;re created for the job they are allocated for and are destroyed on completion, so they should be more than secure enough for our personal projects. For the purposes of organisational use, you can always deploy your own self-hosted GitHub Runners and manage them internally, as the runners themselves are Open Source!\nGranting Permissions # To grant permissions to the GitHub Runner, we need to change Workflow Settings\nIn GitHub, navigate to: Settings \u0026gt; Actions / General \u0026gt; Actions permissions / Workflow Permissions\nUnder Workflow Permissions, ensure the Read and write permissions is selected, and click Save.\nThat\u0026rsquo;s it, unless you wish to further fine-tune this permission within the workflow file itself.\nGit Config # When working manually, our Git config is set up for our personal user that appears in the git logs. This as a minimum requires a name and email address to identify us. When shifting this responsibility to the GitHub Runner, we could choose instead to have it identify itself so it\u0026rsquo;s less confusing when looking back at git commits and the git log. This will make things easier to debug too if something goes wrong at a later date.\nThere\u0026rsquo;s a special user and email address that\u0026rsquo;s been created specifically for this purpose. We\u0026rsquo;ll use this in the workflow shortly.\n\u0026#34;github-actions[bot]\u0026#34; \u0026#34;41898282+github-actions[bot]@users.noreply.github.com\u0026#34; Creating a Workflow # A workflow in GitHub Actions terms is just a manifest file in yaml format that describes a set of actions. If you\u0026rsquo;re familiar with CI/CD principles (especially if you\u0026rsquo;ve used CI/CD platforms like Ansible) you\u0026rsquo;ll be right at home here. Within this file we tell GitHub Actions where to find our files and what to do with them to produce a result.\nWorkflows exist within the .github/workflows path, relative to your GitHub repository. You can learn more specifically about GitHub Actions, workflows etc via the official documentation.\nHere\u0026rsquo;s an example workflow file for joke:\nFilename/path: .github/workflows/ci.yaml\nname: ci # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ main ] pull_request: branches: [ main ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called \u0026#34;build\u0026#34; build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 # Runs a set of commands using the runners shell - name: Create Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Use the GitHub Bot user for Git and GitHub IAM. git config user.name \u0026#34;github-actions[bot]\u0026#34; git config user.email \u0026#34;41898282+github-actions[bot]@users.noreply.github.com\u0026#34; # Specify name of app for packaging \u0026amp; distribution purposes; Compress to a tar.gz. export APP=\u0026#34;joke\u0026#34; mkdir dist tar cf dist/\u0026#34;${APP}-0.0.${GITHUB_RUN_NUMBER}.tar.gz\u0026#34; \u0026#34;$APP\u0026#34; # Generate Brew formula file using the template file. erb \u0026#34;${APP}.erb\u0026#34; \u0026gt; \u0026#34;${APP}.rb\u0026#34; # Commit the new complete formula file back to the repository. git add \u0026#34;${APP}.rb\u0026#34; # Commit and push file to repository. git commit -m \u0026#34;$APP release 0.0.${GITHUB_RUN_NUMBER}\u0026#34; git push # Create and publish release to repository. gh release create v0.0.${GITHUB_RUN_NUMBER} ./dist/*.tar.gz --title \u0026#34;0.0.${GITHUB_RUN_NUMBER}\u0026#34; --generate-notes As can be seen above, I\u0026rsquo;ve annotated the workflow and embedded script to explain what\u0026rsquo;s going on. As the script is only a few lines, I\u0026rsquo;ve chosen to write it directly in the workflow for repository simplicity. Should there be more work to do, I would place the script into a file of its own and call it separately as part of the run command.\nNOTE - We already gave permission to the workflow (via the GitHub Runner) to be able to commit back to the repo as part of Identity and Access Management (IAM) above. However, this does not grant permission to the gh (GitHub CLI) app. Therefore, we can use the existing permission by reusing its credentials as can be seen on lines 28-29 (highlighted). A GitHub runner has its credential stored automatically inside variable GITHUB_TOKEN, and GitHub CLI uses one named GH_TOKEN. Because we already granted elevated permissions, we can use them again.\nOne last thing\u0026hellip; # The last thing to do is to commit and push the workflow file and the Ruby template file. Doing so will automatically kick off the workflow, and if you\u0026rsquo;ve done everything correctly, a new release will appear.\nYou will notice the GitHub Bot user now appears as a contributor now. This is because it created the new Brew formula file and automatically pushed it back to your repo!\n🚀 Nice work\nTroubleshooting # Click to expand for Troubleshooting Workflow reports error 403\nThis usually means you\u0026rsquo;ve forgotten to click save when granting workflow permissions. Check Granting Permissions above.\nWorkflow reports exit code 1: a release with the same tag name already exists\nIf you\u0026rsquo;ve followed along from beginning to end, you will have already published a release containing v0.0.1 and the variable we\u0026rsquo;re using to automatically increment the version number (GITHUB_RUN_NUMBER) starts at 1. You can just run the workflow again as the second run will become 2. For more information, check the note on Brew Formula File Template.\nWrap Up # Over the course of this two-part series, we\u0026rsquo;ve covered a whole lot, so well done if you\u0026rsquo;ve made it this far.\nIn Part I, we learned how to package a tool with a formula file in Ruby for Brew distribution and publish those changes on GitHub. In Part II, we automated packaging and releases with GitHub Actions. This is just the tip of the iceberg for both Brew and GitHub Actions, which are incredibly cool and powerful tools. For me, it\u0026rsquo;s been enjoyable and rewarding to experiment with them both, and I highly recommend doing so for yourself.\nI hope you enjoyed reading, and have fun playing around with your own projects! As ever, feel free to drop any comments below.\n📷 Cover photo by Ionela Mat on Unsplash under the Unsplash license. ","date":"15 May 2024","externalUrl":null,"permalink":"/blog/2024-05-15-distributing-tools-with-brew-and-github-actions-part-ii/","section":"Blogs","summary":"","title":"Distributing tools with Brew \u0026 GitHub Actions - Part II","type":"blog"},{"content":"","date":"15 May 2024","externalUrl":null,"permalink":"/tags/homebrew/","section":"Tags","summary":"","title":"Homebrew","type":"tags"},{"content":"","date":"15 May 2024","externalUrl":null,"permalink":"/tags/macos/","section":"Tags","summary":"","title":"Macos","type":"tags"},{"content":"","date":"15 May 2024","externalUrl":null,"permalink":"/tags/scripts/","section":"Tags","summary":"","title":"Scripts","type":"tags"},{"content":"","date":"27 Oct 2023","externalUrl":null,"permalink":"/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"27 Oct 2023","externalUrl":null,"permalink":"/tags/docker-images/","section":"Tags","summary":"","title":"Docker Images","type":"tags"},{"content":"In this article we\u0026rsquo;ll explore several techniques on optimising Dockerfiles to reduce the size of the final image and increase build efficiency.\nFirst, if you\u0026rsquo;re interested in learning more about the relationship between Dockerfiles and Docker images, take a look at my previous article on the subject.\nHolistically thinking # First of all, it\u0026rsquo;s important to consider that every layer in a Dockerfile adds to the size of the final image. A layer is any line which starts with Docker syntax, such as RUN or COPY. Fortunately, there\u0026rsquo;s a built-in docker command to help us understand where the data is; docker history.\nFor instance:\n$ docker history test-image | head -n 15 Which results in something like the following (Note, you may need to scroll to see the SIZE column on this page):\nIMAGE CREATED CREATED BY SIZE COMMENT 132df553de45 2 months ago CMD [\u0026#34;/ops/bin/uvicorn\u0026#34; \u0026#34;ma… 0B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago COPY main.py logging.yaml ./ # buildkit 982B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago RUN /bin/sh -c poetry run pip3 install -r $A… 480MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago COPY /atcloud/artifacts/* /usr/local/applica… 24.2MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago ENV AT_ML_MODEL_PATH=/ops/a… 0B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago RUN /bin/sh -c poetry install --no-interacti… 978MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago COPY pyproject.toml poetry.lock snyk-ignore.… 199kB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago ENTRYPOINT [\u0026#34;/ops/bin/pytho… 0B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago WORKDIR /ops/app 0B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago RUN |4 PYTHON_VERSION_MINOR=8 PYTHON_VERSION… 8.63MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago RUN |4 PYTHON_VERSION_MINOR=8 PYTHON_VERSION… 13.5MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago COPY ./scripts /ops/scripts… 636B buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago RUN |4 PYTHON_VERSION_MINOR=8 PYTHON_VERSION… 82MB buildkit.dockerfile.v0 \u0026lt;missing\u0026gt; 2 months ago COPY install-build-tools.sh /usr/local/appli… 220B buildkit.dockerfile.v0 It’s important to understand that your image will be the sum of these layers, not just the size of the final layer. So how can we reduce the sizes of our images?\nOptimising Dockerfiles # There\u0026rsquo;s a number of things we can do to make our Dockerfile and the image that it produces as optimal as possible, not just in size, but efficiency too. The following tips will help you can achieve the most optimal Dockerfile possible.\nUse a Supported Minimal/Slim Base Image # Start with a well trusted and up-to-date base image, such as Rocky Linux \u0026lsquo;minimal\u0026rsquo; (around 130mb), Debian \u0026lsquo;slim\u0026rsquo; (around 100mb), or for one of the smallest around - Alpine (~8mb!). There\u0026rsquo;s a trade-off when selecting a base image here concerning the amount of dependencies you\u0026rsquo;ll require. Sometimes it\u0026rsquo;ll be more work maintaining those dependencies manually than it\u0026rsquo;s worth, so choose wisely. I\u0026rsquo;d suggest experimenting with the a tiny image like Alpine and see how you get on, especially if you\u0026rsquo;re working on something that you know to have a small number of dependencies. An added bonus to using these slender images is their reduced attack surface, increasing security somewhat. Less stuff installed is less stuft to attack.\nCombining Commands # Minimise the number of layers by combining multiple commands into a single RUN command. This reduces the number of intermediate layers created during the build process. This also allows you to remove any junk which comes along with commands by adding a clean-up operation at the end. Remember, once the layer is successfully created, the filesystem in that layer becomes immutable, along with any files it created along the way.\nGood example:\nRUN dnf update \u0026amp;\u0026amp; \\ dnf install -y -q package1 package2 \u0026amp;\u0026amp; \\ dnf clean all Notice the use of the logical AND operator \u0026amp;\u0026amp;. Using this technique, we\u0026rsquo;re able to string together multiple commands into one Docker command! The \\ character is a method to allow us to use multiple lines and just allows us to keep Dockerfiles easily readable.\nBad example: This will result in a larger image than necessary:\nRUN dnf update \u0026amp;\u0026amp; \\ dnf install -y -q package1 package2 RUN dnf clean all In this bad example, the dnf clean all command runs after the previous layer became immutable. The files are already written at this point, and size savings are no longer possible for that layer.\nMake good use of layer caching # Intelligent use of layering isn’t just to have a smaller images. It\u0026rsquo;s necessary to holistically consider what happens when your application builds too. Using nodejs as an example, if you rm -rf node_modules in your Dockerfile, this means that whilst your Docker image will indeed be smaller, the next time your CI/CD pipeline builds, it’s going to have to run npm install again. The pattern for build dependencies should be to install dependencies that don’t change frequently as one layer, and then copy code as another.\nAgain taking nodejs as an example:\nGood: This will cache the npm install unless your package json ever changes. Whilst your build image will be slightly larger as a result, the trade off is a cached npm install, which is worth it.\nCOPY .npmrc package.json $APP_DIR/ RUN npm install COPY . $APP_DIR/ RUN npm run build Bad: This will cause an npm install every time any code in your app changes:\nCOPY . $APP_DIR/ RUN npm install \u0026amp;\u0026amp; \\ npm run build \u0026amp;\u0026amp; \\ rm -rf node_modules Use Multi-Stage Builds # If your application requires extra build tools, libraries, or dependencies that are not needed in the final image, use multi-stage builds to create a smaller final image. This involves building in one container and copying only the necessary artefacts to the final container.\n# Build stage FROM alpine:3.14 AS build WORKDIR /usr/local/bin/build COPY package*.json ./ RUN npm install COPY . . RUN npm run build # Final stage FROM alpine:3.14 COPY --from=build /some/path/build-output /usr/local/bin/app Multistage builds in Docker offer several advantages, such as:\nSmaller and more lightweight final images Reduced attack surface and security vulnerabilities of your production container Build tool isolation prevents build processes affecting the final runtime environment Minimal production runtime images The Docker build cache is used more effectively (Only the stages that have changes since the last build will be rebuilt) Clean Up Unnecessary Files # Remove unnecessary or temporary files, such as package caches, build artefacts, and log files, in the same RUN command to keep the layer size small. If you delete these temporary files in a different RUN command, Docker will still keep them in an intermediate layer which bloats the size of the image.\nGood:\nRUN npm run lint:styles \u0026amp;\u0026amp; \\ npm run lint:all \u0026amp;\u0026amp; \\ npm run test:all \u0026amp;\u0026amp; \\ npm run pact:all \u0026amp;\u0026amp; \\ rm -rf .angular \u0026amp;\u0026amp; \\ rm -rf node_modules/.cache \u0026amp;\u0026amp; \\ rm -rf ~/.npm Bad:\nRUN npm run lint:styles \u0026amp;\u0026amp; \\ npm run lint:all \u0026amp;\u0026amp; \\ npm run test:all \u0026amp;\u0026amp; \\ npm run pact:all RUN rm -rf .angular \u0026amp;\u0026amp; \\ rm -rf node_modules/.cache \u0026amp;\u0026amp; \\ rm -rf ~/.npm To reiterate the point again, the layer creating the .angular node_modules/.cache ~/.npm files and directories is immutible by now, and this clean-up will have no effect on the image layer or final image size.\nUse .dockerignore # Create a .dockerignore file to exclude unnecessary files and directories from being added to the image. This prevents adding large files, build artefacts, and unneeded data to the image.\nExample .dockerignore file:\n.git node_modules .vscode *.log Utilise Layer Caching by Ordering Commands Logically # Arrange your Dockerfile commands/layers to ensure that frequently changing parts of your application are placed towards the end. This way, changes in these layers don\u0026rsquo;t trigger a rebuild of the entire image. Instead, they use cached layers from previous builds.\nUse COPY/ADD Wisely # Use caution when using COPY or ADD commands. Include only necessary files and directories, as this can quickly increase the layer/image size. It\u0026rsquo;s easy to fall into the trap of running a COPY . . to get all files into the current working directory. However, it\u0026rsquo;s well worth figuring out the exact files required and copying only those, to keep layer and image sizes optimum.\nLayer Squashing # Docker layer squashing refers to the process of reducing the number of layers in a Docker image. Combining multiple layers into a single layer may help conserve space and offer better performance during operations such as pulling, pushing and running containers.\nIn this article and the last, we\u0026rsquo;ve already covered when building a Docker image, each command in the Dockerfile creates a new layer. While this layering system has advantages, such as caching and reusability, it can also result in larger image sizes due to the accumulation of those layers. You\u0026rsquo;ll notice that when you pull a well-known base image such as Rockylinux or Debian, there only appears to be one layer. This is because the image has been squashed.\nVarious tools and techniques can be used to squash Docker layers. You\u0026rsquo;re can pass the argument of --squash to the Docker build command in order to produce a squashed image. You can read more about that in the official documentation.\nAdditionally, some build tools or CI/CD pipelines have built-in features or options for automatic layer squashing. There\u0026rsquo;s also, external tools like docker-squash that can be used to manually squash layers.\nIt\u0026rsquo;s worth knowing however that squashing does come at a cost. You lose the layer sharing ability of Docker which can actually increase build times of multiple images.\nWrap Up # By following these best practices, you can significantly reduce the size of your Docker image while still maintaining all the required dependencies and components for your application to run properly and successfully. We\u0026rsquo;ve covered lots in this article, so hopefully one or two of these methods can help. Please let me know in the comments if you\u0026rsquo;ve discovered any other techniques of your own!\n📷 Cover photo by Bernd 📷 Dittrich on Unsplash under the Unsplash license. ","date":"27 Oct 2023","externalUrl":null,"permalink":"/blog/2023-10-27-optimising-dockerfiles/","section":"Blogs","summary":"","title":"Optimising Dockerfiles","type":"blog"},{"content":"Container technologies have fundamentally transformed the way we package and ship applications. The team behind Docker, were one of the pioneers of the container movement, and also one of the first to provide a standardised and portable environment through its Docker images.\nIn this article, we\u0026rsquo;ll explore the relationship between the Dockerfile and the Docker image, investigating how each instruction/command in the Dockerfile contributes to the creation of Docker image layers.\nThe Dockerfile # Some like to think of a Dockerfile as a sort of shell script, but it\u0026rsquo;s more than that; it\u0026rsquo;s a blueprint that builds-up a step-by-step construction of a Docker image. Let\u0026rsquo;s take a closer look into the key elements that build up a Dockerfile, and investigate some of the key reasons Docker has become a key piece of software for many organisations today.\nBase Images # The Dockerfile begins with a base image, setting up the operating system and/or runtime environment. This choice significantly influences the characteristics and capabilities of the final Docker image. This is unless of course, you\u0026rsquo;re creating a multi-stage build, where your build-time container is using a different base image to your runtime container. You can read about some of the advantages of multi-stage builds in my other article Optimising Dockerfiles.\nInstructions # Each line that begins in Docker syntax in the Dockerfile represents an instruction, which is akin to a command. These instructions include installing dependencies, copying files, setting environment variables, defining runtime configurations and so on.\nFor example, consider this simple Dockerfile:\nFROM ubuntu:22.04 COPY . /app RUN make /app CMD python /app/app.py Notice that each line begins with a Docker command, then continues with what looks like a shell command. In some cases, it is a shell command, but Docker must first know what to do with that command, and this is why we have Docker syntax.\nAlthough Docker commands are case-insensitive, it\u0026rsquo;s a widely used convention to have them in uppercase, so they\u0026rsquo;re easy to distinguish between them and your commands which appear as arguments to the Docker commands. If you\u0026rsquo;re familiar with bash -c, Docker is essentially replicating the same behaviour with its Docker syntax: \u0026ldquo;run the following as a script\u0026rdquo;.\nFor example, let\u0026rsquo;s break down what\u0026rsquo;s going on:\nDocker Syntax Your Command (arguments) What's happening FROM ubuntu:22.04 Creates a layer from the ubuntu:22.04 Docker image from the default registry (docker hub) COPY . /app Adds files from your Docker client\u0026rsquo;s current directory . to the directory /app RUN make /app Builds your application using the make utility CMD python /app/app.py Specifies what to do to run the container 🔖 You can view a complete list of Dockerfile syntax commands in the official documentation.\nLayered Construction # So Docker images are built-up in a layered fashion. Every instruction in the Dockerfile results in the creation of an intermediate layer, forming a layered filesystem.\nLayering enables efficient caching and incremental builds. If a change occurs, only the affected layers and subsequent layers need to be rebuilt, significantly speeding up development work-cycles.\nAnother perspective # Consider another simple Dockerfile, and this time think of each line as a layer, rather than a command:\nFROM ubuntu:20.04 RUN apt-get update RUN apt-get install -y nginx COPY . /app The FROM instruction initializes the image with a base layer of Ubuntu 20.04. Subsequent instructions add layers by updating the package list, installing Nginx, and copying local files into the image. This layered approach enables a granular understanding of the image\u0026rsquo;s composition, and it\u0026rsquo;s easier to diagnose issues along the way.\nDocker Images # A Docker image is the end result of executing the instructions listed within a Dockerfile. It serves as a standalone, executable package, which contains app code, runtime, libraries, and dependencies. This makes them portable \u0026amp; lightweight.\nHere\u0026rsquo;s a diagram on how the Docker image relates to the Dockerfile:\nWhen an image layer is successfully written (because the command in the Dockerfile was successful) the layer becomes immutable. If a layer is not successfully written (because the command resulted in a non-zero exit status) the layer is not written and the build fails and no image is produced.\nWhen running an instance of the final image, (such as when using the docker run command) a new read-write layer is appended so that the image can run as a container; processes can run, volumes are able to be mounted, and so on. This read-write layer is also known as the container layer.\nLayered like a Cake 🍰 # This layered structure ensures efficiency in terms of storage, caching, and incremental builds, emphasising the modularity of the Docker image. This makes debugging of builds easier, as it\u0026rsquo;s possible to identify the exact location - or layer - of a problem in a build and experiment from there instead of building the whole thing repeatedly.\nFor example, say you\u0026rsquo;re investigating a Docker build failure on layer 6 which was previously successfully building. One possible way you could begin your investigation, would be to temporarily remove the problem layer and all subsequent layers from the Dockerfile and run the build again. The build should be nice and fast because of layer caching more on caching in the next article and you should be able to use the docker exec command to execute into the container to have a poke around. Now you could manually run the command which fails to see if you\u0026rsquo;re able to replicate the issue and resolve it. Once you have your solution, you can modify the Dockerfile with your fix and readd the subsequent commands back in again.\nThis can help shorten your development cycle and allows you experiment incrementally, and is especially useful in long, complex builds.\nConsistency \u0026amp; Portability # Dockerfiles ensure consistent reproducibility by defining the environment and dependencies that an app or process requires. This guarantees that an environment can be recreated on totally different physical systems and a standardised development and deployment process. You can also share and store them in Infrastructure as Code platforms, as they\u0026rsquo;re just text files.\nThe layered structure of Docker images, combined with compression technologies, contributes to their compact size and ease of distribution. When an image is sent or received from an image registry, such as Docker Hub or Google Artifact Registry etc, the layers of the Dockerfile and Docker image come back in to play once again. You\u0026rsquo;ll see this when you\u0026rsquo;re pulling an image down from a registry. Notice that Docker doesn\u0026rsquo;t download the image in one piece, but it downloads the layers of the image and extracts them one by one, recreating the image on your local machine.\nDocker uses a technology called a Union File System to compress the layers of Docker images. The Union File System is a way of combining multiple file systems into a single view, allowing files and directories from different file systems to be overlaid on top of each other. This technology is crucial for Docker\u0026rsquo;s layered image approach. The Union File System is a bit out of scope for this article, but if you\u0026rsquo;re interested in learning more about the topic, take a look at this great blog article how-docker-images-work-union-file-systems by Eli Uriegos.\nWrap Up # Understanding the link between a Dockerfile and a Docker image is extremely useful to Engineers when creating efficient container builds. Dockerfiles provide a clear recipe for constructing images, ensuring reproducibility, modularity, and portability.\nIn the next article, we\u0026rsquo;ll take a look at how we can use this knowledge to optimise our Dockerfiles and Docker images, and make the best use of layer caching while keeping the image sizes as small as possible.\n📷 Cover photo by Dominik Lückmann on Unsplash under the Unsplash license. ","date":"26 Oct 2023","externalUrl":null,"permalink":"/blog/2023-10-26-dockerfiles-and-docker-images-explained/","section":"Blogs","summary":"Container technologies have fundamentally transformed the way we package and ship applications. The team behind Docker, were one of the pioneers of the container movement, and also one of the first to provide a standardised and portable environment through its Docker images.\nIn this article, we’ll explore the relationship between the Dockerfile and the Docker image, investigating how each instruction/command in the Dockerfile contributes to the creation of Docker image layers.\n","title":"Dockerfiles and Docker Images explained","type":"blog"},{"content":"","date":"21 Sep 2022","externalUrl":null,"permalink":"/tags/blog/","section":"Tags","summary":"","title":"Blog","type":"tags"},{"content":"","date":"21 Sep 2022","externalUrl":null,"permalink":"/tags/cloudflare/","section":"Tags","summary":"","title":"Cloudflare","type":"tags"},{"content":"","date":"21 Sep 2022","externalUrl":null,"permalink":"/tags/github/","section":"Tags","summary":"","title":"Github","type":"tags"},{"content":"","date":"21 Sep 2022","externalUrl":null,"permalink":"/tags/hugo/","section":"Tags","summary":"","title":"Hugo","type":"tags"},{"content":"In this post, I\u0026rsquo;ll describe the current stack of this very blog. Not only that, but it\u0026rsquo;s almost free to do. The only cost I face for is the domain, and I can even help with getting that for the lowest possible price too. If you don\u0026rsquo;t need a custom domain, the entire stack can be completely free!\nBlog for cheap (or even free!) # Before diving straight in, it\u0026rsquo;s a good idea to think about the features you are going to need for your site or blog. I\u0026rsquo;ve used a few different blog platforms over the years, each with their own pros, cons and feature-sets. However, this current stack consisting of Cloudflare, Netlify, GitHub and Hugo is by far the most feature rich and flexible that I\u0026rsquo;ve encountered so far. Once set up, the whole thing is just nice to use.\nIf you\u0026rsquo;re a super casual blogger and you\u0026rsquo;re not interested in too much customisation, Google's Blogger is simple, free and secure. Be sure to check out my previous post on the subject.\nIf you\u0026rsquo;re into powerful plugins, full drag-and-drop widget interface support, require a database and don\u0026rsquo;t mind proactively keeping on top of security hardening, Wordpress could be for you.\nIf you\u0026rsquo;re like me and prefer blogging using markdown syntax and prioritise security, version control and don\u0026rsquo;t want a monthly webspace bill, then read on\u0026hellip;\n1. Static Site Generation # Blogs of old ranged from hosted gif-fodder and somewhat vulnerable options such as Geocities and Myspace, to full-fat host-it-yourself webservers which come with a host of management and cost overheads such as upgrades and webspace rental. A modern option is to use a static site generator. A static site generator takes your content and your chosen framework, and generates series of flat HTML documents which you can serve directly from your chosen platform, such as Google Cloud or Amazon s3 storage \u0026ldquo;buckets\u0026rdquo;. There\u0026rsquo;s a great article how you can do this over at karlstoney.com if you\u0026rsquo;re interested in avoiding CI/CD tools such as Netlify or wish to take a more bispoke route.\n1a. Hugo # There are many static site generators these days, such as Ghost, Jeykll and Hugo and hundreds more written in a plethora of different languages. After playing around with a few, I quickly found Hugo to be the right mix of ease-of-use and feature support for me. I was also inspired by some of the availible themes, and some of their out-of-the-box features. More on themes shortly.\nHugo claims to be the worlds fastest static site generator. It\u0026rsquo;s written in Golang and comes complete with reusable blocks of code - called short-codes - to speed up and simplify page and/or theme construction. It supports the use of HTML where markdown is not enough, but it can also fully generate a site with little to no additional code from you. It supports emojis, math typesets, embedded videos, and twitter posts out of the box to name just a few features. Once your content is ready, Hugo then converts your content into static HTML files which you can then serve as you wish. Hugo is free and open source \u0026#x1f389;\nSimilarly to its main competitors, Hugo makes local development easy, by allowing you to spin up a local copy of your site to view and test your changes. It has a server mode, which allows you to get live feedback on your edits and changes as you work.\nAll you need to get started with Hugo is to install it, and install a theme.\n1b. Hugo Themes # Take a look @ https://themes.gohugo.io to browse hundreds of available themes. Some themes require slightly different configuration and build commands, but the all follow the same basic steps:\nCreate and change into a new directory Do a hugo init command to spin up the framework Add your chosen theme as a submodule to the themes directory Run hugo server from the root directory All going well you should have a running copy of your new site running on your local machine in no time.\nIf you\u0026rsquo;re new to Hugo, it\u0026rsquo;s worth taking a read through the Hugo quick-start guide. Be sure to pay close attention to your chosen theme\u0026rsquo;s Readme for any setup instructions as they can vary. It\u0026rsquo;s also wise to take note of any commands you may need to run build your production site in CI/CD too. While a simple hugo server is all that\u0026rsquo;s required to quickly spin up a local copy and run it through the hugo webserver, you may need to run an npm install or set an environment variable your \u0026ldquo;production\u0026rdquo; build by your CI/CD platform. More on CI/CD shortly.\n2. Source Code # I\u0026rsquo;ve chosen GitHub to host my blog mainly due to convenience, but you can use alternatives such as BitBucket, GitLab or other source code control systems which support private repositories. Using a private repository while not a strict requirement, is recommended to prevent anyone easily stealing your work and claiming it as their own. I can\u0026rsquo;t think of a reason why you would need your site\u0026rsquo;s files to be public, unless you intend to open source it intentionally, such as if you\u0026rsquo;re creating your own theme or framework. That said, it\u0026rsquo;s up to you if you want to make your blog\u0026rsquo;s source code public or not.\nOnce you have your code committed to your chosen source control platform, you can them go about automating your deployment, and getting your site live on the internet.\n2a. Change Automation (Optional Bonus) # There may be some changes which you wish to automate, and fortunately these days you get 2,000 minutes free GitHub Actions on the GitHub Free plan. The task I wanted to automate is to update the copyright notice date in the footer each year. Setting up a GitHub Actions automation is reasonably straight forward, and we can complete this given task using some unix tooling, in this case, I used git and sed.\nUsing GitHub Actions to update a copyright date # In GitHub, navigate Actions \u0026gt; New workflow \u0026gt; Simple Workflow \u0026gt; Configure\nOnce in the workflow, I edited the yaml file to contain the following pipeline configuration:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 name: update-copyright-date on: schedule: # Run on the 1st of January, at midnight - cron: \u0026#39;0 0 1 1 *\u0026#39; # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called \u0026#34;build\u0026#34; build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks out your repo so that you can do things with it - uses: actions/checkout@v3 # Creates a step, which we\u0026#39;ll shell out to bash and update the date string - name: Happy new year run: | export DATE=$(date +%Y) sed -i -r \u0026#34;s/Copyright © [0-9]*/Copyright © $DATE/g\u0026#34; \u0026#34;config.toml\u0026#34; # Finally we\u0026#39;ll commit our changes back to the repo - name: Update Repo run: | git config --global user.name \u0026#34;Chris Gillatt\u0026#34; git config --global user.email \u0026#34;chris.gillatt@users.noreply.github.com\u0026#34; git add -A git commit -m \u0026#34;Happy new year; copyright date updated\u0026#34; git push If you\u0026rsquo;re used to CI/CD systems such as Ansible etc, you\u0026rsquo;ll be right at home with GitHub actions. If not, here\u0026rsquo;s a breakdown on what\u0026rsquo;s going on. This GitHub Action will run on the 1st of January each year, and use the sed utility to find and replace the year from the main Hugo config file, config.toml. It then proceeds to commit the changes back to the GitHub repository with some standard git commands while placing a date in the commit message. It doesn\u0026rsquo;t need any secrets because it\u0026rsquo;s acting on its own repo \u0026#x1f604;\nCustom Domains (Optional) # This is another optional section, as services such as Netlify and Github Pages come with a free subdomain, which is perfectly suitible to use with your site or blog. Personally I perfer a custom top-level domain to give that little extra neatness to the site. This is the only section which incurres a cost, so if you\u0026rsquo;re aiming to keep costs to an absolute minimum, you can confidently skip this section.\nI recommend registering your domain through Cloudflare for several reasons. Not only do Cloudflare offer enterprise-class edge-network security products, they\u0026rsquo;re also great value for personal users too. Cloudflare do not add markup to their domain prices meaning you get them at the cost price.\nThis in turn means you can avoid having to move your domain regularly to get the best deal once your honeymoon discount runs out like with other registrars. The howinteresting.co.uk domain costs under $5 per year through Cloudflare, whereas it was around £9 with Fasthosts.co.uk. If you transfer your domain from your old registrar to Cloudflare, you often get an additional year for free (as they round up the difference).\nCloudflare is a US company, so prices are in USD With your cloudflare domain, you get DDoS protection for free, as well as a bunch of free tools and automatic caching to make your blog even more performant. It\u0026rsquo;s a no-brainer. Check them out @ https://www.cloudflare.com/en-gb/products/registrar.\nI\u0026rsquo;d recommend enabling the following settings to get started:\nAutomatic HTTPS Rewrites: ON\nAlways use HTTPS: ON\nAuto Minify: JS, CSS, HTML\nBrotli: ON\nRocket Loader™: ON\nCI/CD \u0026amp; Site Hosting # It\u0026rsquo;s possible to automate Continuous Integration / Continuous Deployment (CI/CD) for free too. It\u0026rsquo;s just one less thing do have to do when you make write a new article or make changes. There\u0026rsquo;s plenty of competition in this space, so to the curious I\u0026rsquo;d recommend checking a few out and seeing which is your best fit. I went with Netlify, so I\u0026rsquo;ll focus on Netlify here. It\u0026rsquo;s got a nice clean UI, it\u0026rsquo;s super simple to use and supports custom domains and private GitHub repos.\nOn the free plan, you get 100GB of bandwith and 300 build minutes per month, which is more than enough for a personal blog. All you\u0026rsquo;ll need to do is to link your GitHub repo to Netlify (you\u0026rsquo;ll need to authorise access to it if you made it private) and enter your build command. Remember, the build command may be different from the simple hugo serve command you use locally. Check your themes\u0026rsquo; readme to see if there are any special arguments or additional commands.\nTip \u0026#x1f680; # Chances are that you\u0026rsquo;re working locally with the latest version of Hugo. Be sure to instruct Netlify which version of Hugo to use when building your site, so that your local development environment is the same as the CI/CD environment. You can specify the version of Hugo in the Environment variables section of the build settings. This ensures that you\u0026rsquo;re not caught out with any changes which could have occurred between versions.\nTo avoid any surprises or inconsistent results, sync your Hugo Version Once you\u0026rsquo;re set up, you can get your new posts and changes live in a matter of seconds. Simply by committing to GitHub, Netlify will detect your changes and will begin a new build run. Your static files are generated, and on success, Netlify serves your static content immediately. If you choose to use the default subdomain, you can configure this in the Netlify GUI. You can even pick your own if it\u0026rsquo;s not yet been taken by another user.\nIf you\u0026rsquo;ve bought a custom domain, you can configure that in the GUI. It really is that simple.\nRemember to configure your domain with a flattened CNAME as can be seen in the image below if you don\u0026rsquo;t want to use a subdomain such as www.domain.com or blog.domain.com:\nUse the special @ character in the Name field to \"flatten\" your CNAME Wrap up # We\u0026rsquo;ve covered a lot in this blog, so well done for making it this far \u0026#x1f605;\nTo sum up:\nWe\u0026rsquo;ve used Hugo as a static site generator with a custom theme We\u0026rsquo;ve placed your blogs\u0026rsquo; code into a source control system such as Github We\u0026rsquo;ve automated changes to the source code using GitHub actions Netlify has provided hosting and CI/CD functionality Finally we\u0026rsquo;ve covered fronting your site with a custom domain through Cloudflare, with performance and security options As ever if you\u0026rsquo;ve got any thoughts or suggestions, I\u0026rsquo;d love to hear them in the comments below \u0026#x1f447;\n📷 Cover photo by Jason Tharsiman on Unsplash under the Unsplash license. Modified by Chris Gillatt. ","date":"21 Sep 2022","externalUrl":null,"permalink":"/blog/2022-09-21-hugo-blog-stack/","section":"Blogs","summary":"In this post, I’ll describe the current stack of this very blog. Not only that, but it’s almost free to do. The only cost I face for is the domain, and I can even help with getting that for the lowest possible price too. If you don’t need a custom domain, the entire stack can be completely free!\n","title":"Hugo Blog Stack","type":"blog"},{"content":"","date":"21 Sep 2022","externalUrl":null,"permalink":"/tags/netlify/","section":"Tags","summary":"","title":"Netlify","type":"tags"},{"content":"","date":"3 Sep 2022","externalUrl":null,"permalink":"/tags/comments/","section":"Tags","summary":"","title":"Comments","type":"tags"},{"content":"","date":"3 Sep 2022","externalUrl":null,"permalink":"/series/github-based-blog-comments/","section":"Series","summary":"","title":"Github-Based Blog Comments","type":"series"},{"content":"Wait, what happened to Utterances? # In my previous post, I described how to add a GitHub-based comments system to your blog using Utterances. In all the excitement of a free and open source comments platform for my blog, I forgot to check to see if it was still maintained, and it appears to have recently been mothballed. Utterances still works fine - for now, but it\u0026rsquo;s best practice to implement maintained dependencies.\nThe folk at Giscus have taken the idea of Utterances, expanded upon it and made it even better. Like Utterances, Giscus is written in typescript, uses the GitHub API, is free and open source and relies on an app to perform the writes to a public repo which you own; however there are some key differences. With Giscus, they use Discussions instead of issues. It\u0026rsquo;s more expandable and configurable and has some powerful new features, like lazy loading comments and the ability to place the input box at the top of the comments. It\u0026rsquo;s also slightly simpler to install, with relaxed repository requirements.\nGiscus # Giscus uses the discussions API by GitHub in order to facilitate the comments window which you can subsequently supply in your blog\u0026rsquo;s code. Like Utterances, this means no adverts, no tracking and no irritating 3rd party to deal with. You can provide a comments box to each page you wish. Simply find a suitable place in your blogs\u0026rsquo; code and bob\u0026rsquo;s your uncle. Lets take a look at getting set up.\nLike Utterances, you even get a neat sign-in button It\u0026rsquo;s worth knowing that commenters will need a GitHub account to make a comment or react with an emoji.\nGetting set up # First of all create yourself a new GitHub repository and set it to public. It needs to be public because that\u0026rsquo;s how your commenters will be able to comment. Unlike Utterances, you don\u0026rsquo;t need to create your repository under the github.io domain. Giscus works with the standard github.com domain \u0026#x1f680;\nInstall the Giscus app to your new public GitHub repository.\nGenerate your Giscus code. You can generate your own code and customisations here: https://giscus.app\n\u0026hellip;or you can use the below template edit to taste. Remember to enter the name of your new public repo with the Giscus app enabled on line 3:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026lt;!-- Add in Giscus (https://giscus.app) Github Comments --\u0026gt; \u0026lt;script src=\u0026#34;https://giscus.app/client.js\u0026#34; data-repo=\u0026#34;\u0026lt;github username\u0026gt;/\u0026lt;repository name\u0026gt;\u0026#34; data-repo-id=\u0026#34;xxxxxxxxxxxxx\u0026#34; data-category=\u0026#34;Announcements\u0026#34; data-category-id=\u0026#34;xxxxxxxxxxx\u0026#34; data-mapping=\u0026#34;pathname\u0026#34; data-strict=\u0026#34;0\u0026#34; data-reactions-enabled=\u0026#34;1\u0026#34; data-emit-metadata=\u0026#34;0\u0026#34; data-input-position=\u0026#34;top\u0026#34; data-theme=\u0026#34;transparent_dark\u0026#34; data-lang=\u0026#34;en\u0026#34; data-loading=\u0026#34;lazy\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34; async\u0026gt; \u0026lt;/script\u0026gt; Tip \u0026#x1f680; # There\u0026rsquo;s a bunch of colour themes you can use for your new comments box, but if you\u0026rsquo;d rather not bother and just assume the colour of the existing CSS, use the transparent themes such as transparent_dark (seen in the comments section below). Check out https://giscus.app/ for all of the possible customisations.\nNow you have your code, you can now cut and paste it into your site where you want the comments to appear. This blog is currently using Hugo, and the theme I\u0026rsquo;m running contains a partial for blog pages. For me, this was the perfect place for blog article comments and it was on the following path: layouts/_default/single.html You can see on this article where this ends up being when the site renders at the footer of the page. Here\u0026rsquo;s the file with some extra context:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 {{ .Content }} \u0026lt;!-- Add in Giscus (https://giscus.app) Github Comments --\u0026gt; \u0026lt;script src=\u0026#34;https://giscus.app/client.js\u0026#34; data-repo=\u0026#34;\u0026lt;github username\u0026gt;/\u0026lt;repository name\u0026gt;\u0026#34; data-repo-id=\u0026#34;xxxxxxxxxxxxx\u0026#34; data-category=\u0026#34;Announcements\u0026#34; data-category-id=\u0026#34;xxxxxxxxxxx\u0026#34; data-mapping=\u0026#34;pathname\u0026#34; data-strict=\u0026#34;0\u0026#34; data-reactions-enabled=\u0026#34;1\u0026#34; data-emit-metadata=\u0026#34;0\u0026#34; data-input-position=\u0026#34;top\u0026#34; data-theme=\u0026#34;transparent_dark\u0026#34; data-lang=\u0026#34;en\u0026#34; data-loading=\u0026#34;lazy\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34; async\u0026gt; \u0026lt;/script\u0026gt; \u0026lt;/article\u0026gt; {{- partial \u0026#34;social.html\u0026#34; . -}} This shows that the comments will appear as part of each blog post article, and before the \u0026ldquo;socials\u0026rdquo; which is what delivers the Twitter, LinkedIn and Stack Overflow etc links at the footer of the page.\nDeleting Comments # Occasionally you\u0026rsquo;ll want to delete comments, such as when someone posts something which violates your policies, or to tidy up tests etc. Fortunately you can manage comments in the exact same way as your GitHub comments on discussions. Simply delete the comment in the relevant discussion in your GitHub repository. This works for users too (as long as they made the comments in the first place).\nWrap up # Whichever you decide to use, Utterances or Giscus, they\u0026rsquo;re both a nice and elegant way of providing an interaction interface with your readers, and well worth a look.\nFeel free to give the comments a whirl below \u0026#x1f447; # ","date":"3 Sep 2022","externalUrl":null,"permalink":"/blog/2022-09-03-setting-up-github-comments-on-your-blog-with-giscus/","section":"Blogs","summary":"Wait, what happened to Utterances? # In my previous post, I described how to add a GitHub-based comments system to your blog using Utterances. In all the excitement of a free and open source comments platform for my blog, I forgot to check to see if it was still maintained, and it appears to have recently been mothballed. Utterances still works fine - for now, but it’s best practice to implement maintained dependencies.\n","title":"Setting up Github comments on your blog with Giscus","type":"blog"},{"content":"I\u0026rsquo;ve been steadily migrating articles over from my old blogs over the past couple of weeks. It\u0026rsquo;s been a great excuse to look at some new (at least new to me) blog technologies and techniques. This one I like so much I thought I would share it with you all, and it\u0026rsquo;s a nice break from the older content I\u0026rsquo;ve been sifting through. This blog article is about how to use GitHub\u0026rsquo;s technology on your very own blog or website!\nUtterances # The folks at Utterances have figured out that you can use GitHub\u0026rsquo;s APIs to create a comment platform for your own blog or website. It all works on GitHub issues, which means you get to benefit from some of the built-in features of GitHub without using an untrusted 3rd party or having to tolerate ads. Each page of your blog or website gets its own GitHub Issue as people comment on them, and subsequent comments are added in the same way as replies to GitHub issues.\nYou even get a neat sign in-button Commenters will need to have a GitHub account, but for tech blogs like this, I\u0026rsquo;d hazard a guess that 99% of its readers will already have one. I flirted with the idea of implementing Disqus (I actually did implement Disqus, and immediately removed it because of its tracking cookies and adverts) but this feels like a much more elegant solution. It\u0026rsquo;s open source too which is awesome.\nGetting set up # First of all create yourself a new GitHub repository and leave it public. It needs to remain public because that\u0026rsquo;s how your commenters will be able to comment. Utterances only works with repositories on the github.io domain, and to get one of those you\u0026rsquo;ll need to create it as if you\u0026rsquo;re using GitHub Pages.\n1a. Name the new repository like so \u0026lt;repository name\u0026gt;.github.io. If you\u0026rsquo;ve not done this it\u0026rsquo;s a bit strange looking at first. If you\u0026rsquo;re still not sure, you can see the one for this blog here.\n1b. Once you\u0026rsquo;ve created your repository in this way, you should now see your page published under a github.io address. If it\u0026rsquo;s not yet published, publish it. If you click Visit site you\u0026rsquo;ll be taken to your new page. This is the URL you\u0026rsquo;ll use with Utterances.\nInstall the Utterances app to GitHub.\nYou only need to grant access to your new repository, so just select that, unless you\u0026rsquo;re going to enabled it on multiple websites.\nReplace the value of the repository variable below (line 2) with your new github.io address.\n1 2 3 4 5 6 7 8 \u0026lt;script src=\u0026#34;https://utteranc.es/client.js\u0026#34; repo=\u0026#34;\u0026lt;your github username\u0026gt;/\u0026lt;repository name\u0026gt;.github.io\u0026#34; issue-term=\u0026#34;pathname\u0026#34; label=\u0026#34;\u0026lt;your-custom-label\u0026gt;\u0026#34; theme=\u0026#34;dark-blue\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34; async\u0026gt; \u0026lt;/script\u0026gt; Tip \u0026#x1f680; # Don\u0026rsquo;t include http/https in the repository address or you\u0026rsquo;ll get a repo invalid error.\nColour themes # You can choose from the following colour themes:\ngithub-light github-dark preferred-color-scheme github-dark-orange icy-dark dark-blue gruvbox-dark photon-dark boxy-light You can further configure your experience on the Utterances read-me, and even make a test comment there\nNext, you can now cut and paste the code into your site where you want the comments block to appear. This blog is currently using Hugo, and the theme I\u0026rsquo;m running contains a partial for blog pages. For me, this was the perfect place for blog article comments and it was on the following path: layouts/_default/single.html You can see on this article where this ends up being when the site renders at the footer of the page. Here\u0026rsquo;s the file with some extra context:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 {{ .Content }} \u0026lt;/article\u0026gt; \u0026lt;script src=\u0026#34;https://utteranc.es/client.js\u0026#34; repo=\u0026#34;\u0026lt;your github username\u0026gt;/\u0026lt;repository name\u0026gt;.github.io\u0026#34; issue-term=\u0026#34;pathname\u0026#34; label=\u0026#34;\u0026lt;your-custom-label\u0026gt;\u0026#34; theme=\u0026#34;dark-blue\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34; async\u0026gt; \u0026lt;/script\u0026gt; {{- partial \u0026#34;social.html\u0026#34; . -}} Deleting Comments # Occasionally you\u0026rsquo;ll want to delete comments, such as when someone posts something which violates your policies, or to tidy up tests. Fortunately you can manage comments in the exact same way as your GitHub issues. Simply delete the comment in your GitHub repository.\nSorted! :thumbs_up:\n","date":"28 Aug 2022","externalUrl":null,"permalink":"/blog/2022-08-28-setting-up-github-comments-on-your-blog-with-utterances/","section":"Blogs","summary":"I’ve been steadily migrating articles over from my old blogs over the past couple of weeks. It’s been a great excuse to look at some new (at least new to me) blog technologies and techniques. This one I like so much I thought I would share it with you all, and it’s a nice break from the older content I’ve been sifting through. This blog article is about how to use GitHub’s technology on your very own blog or website!\n","title":"Setting up Github comments on your blog with Utterances","type":"blog"},{"content":"","date":"21 Jul 2022","externalUrl":null,"permalink":"/tags/devops/","section":"Tags","summary":"","title":"DevOps","type":"tags"},{"content":"","date":"21 Jul 2022","externalUrl":null,"permalink":"/tags/google-cloud/","section":"Tags","summary":"","title":"Google Cloud","type":"tags"},{"content":"","date":"21 Jul 2022","externalUrl":null,"permalink":"/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes","type":"tags"},{"content":"","date":"21 Jul 2022","externalUrl":null,"permalink":"/tags/platform-engineering/","section":"Tags","summary":"","title":"Platform Engineering","type":"tags"},{"content":"","date":"27 Nov 2021","externalUrl":null,"permalink":"/tags/cd/","section":"Tags","summary":"","title":"Cd","type":"tags"},{"content":"CDeX appears to be dead these days, so how does one rip a CD on Windows? With all the ID tags and artwork?!\nThe answer is EAC: Extract Audio Copy. EAC does not come with its own compression technology, citing some laws prohibiting them from bundling it in some countries. You’ll need the LAME encoder. Download the bundle and put the .exe somewhere on your local windows file system. You’ll have to point EAC to it, to compress the generated WAV files into MP3’s like in the good ole\u0026rsquo; days.\nHere we go \u0026#x1f3b5;\nThe Chemical Brothers # Getting Set Up # Download EAC and install it Download LAME and extract / copy / paste LAME.exe to somewhere sensible. I put it in the EAC install directory C:\\Program Files (x86)\\Exact Audio Copy\\LAME.EXE. Open up EAC and run the Wizard if it does not appear on its own on first run. Click next up the point where it wants to do a test of the CD Drive Click next a again a couple of times until it does its Automatic Search of the LAME.exe. Cancel it out and do it manually as it likes to take all day. This is where I placed mine earlier: C:\\Program Files (x86)\\Exact Audio Copy\\LAME.EXE Click next to the CBBD section which looks up track names etc. Feel free to use a made-up email address. Choose your preferred naming conventions on the next page or so and complete the Wizard. Select MusicBrainz as the lookup agent as it works well: Using EAC # EAC works in a two-stage process, it will rip a WAV from your CD and then run a separate process to take that WAV and via the LAME encoder, compress it to the compressed MP3 format.\nIt’s confusing as when you press the CMP button to create yourself a compressed file it creates files first. Let it do its thing - it will proceed to delete the WAV files automatically following compression.\nOnce you’ve selected MusicBrainz as seen above, click it. It will then perform a lookup and hopefully populate the CD text meta data for you to save typing.\nYou will then be prompted to search for cover art, which you can do it you want to. I’d suggest only looking for small or medium images.\nPick your image art and click the Transfer Selected cover to EAC, and EAC will attach the image to the files. Neat.\nNow all\u0026rsquo;s that’s left to do is to click the CMP button and away you go! It takes much longer than CDeX used to, unfortunately. Notice the .wav file it’ll create before encoding to MP3:\nThat\u0026rsquo;s it - job done. All you\u0026rsquo;re left to do is copy your MP3 files on to whatever digital media device you like..\ndone, done, on to the next one \u0026#x1f3b5;\nThe Foo Fighters # ","date":"27 Nov 2021","externalUrl":null,"permalink":"/blog/2021-11-27-cd-ripping-in-2021-like-it-s-1999/","section":"Blogs","summary":"","title":"CD Ripping in 2021 like it's 1999","type":"blog"},{"content":"","date":"27 Nov 2021","externalUrl":null,"permalink":"/tags/cdex/","section":"Tags","summary":"","title":"Cdex","type":"tags"},{"content":"","date":"27 Nov 2021","externalUrl":null,"permalink":"/tags/eac/","section":"Tags","summary":"","title":"Eac","type":"tags"},{"content":"","date":"27 Nov 2021","externalUrl":null,"permalink":"/tags/mp3/","section":"Tags","summary":"","title":"Mp3","type":"tags"},{"content":"","date":"26 Jul 2021","externalUrl":null,"permalink":"/tags/https/","section":"Tags","summary":"","title":"Https","type":"tags"},{"content":"","date":"26 Jul 2021","externalUrl":null,"permalink":"/tags/nas/","section":"Tags","summary":"","title":"Nas","type":"tags"},{"content":"","date":"26 Jul 2021","externalUrl":null,"permalink":"/tags/qnap/","section":"Tags","summary":"","title":"Qnap","type":"tags"},{"content":"This article shows you how to front your QNAP’s public DDNS with Cloudflare; an enterprise-class edge network service. Using Cloudflare - even on the free tier comes with a ton of benefits including:\nDistributed Denial-of-Service (DDoS) protection by default Origin Server privacy \u0026amp; our CNAME to our myqnapcloud Dynamic DNS address (DDNS) Web Application Firewall (WAF) to allow us to configure access Basic analytics Delivery optimisation techniques to speed up your access (Auto minify, Brotli etc) Yey another feature we\u0026rsquo;ll use is to offload our responsibility of SSL certificate renewals to Cloudflare. If you\u0026rsquo;ve set up Let\u0026rsquo;s Encrypt such as in my previous post you\u0026rsquo;ll already know you need to manually renew this certificate every three months. Sure it\u0026rsquo;s just a click of a button, but it\u0026rsquo;s annoyingly not automatable directly from the QNAP\u0026rsquo;s user interface. Cloudflare are their own certificate authority, which means we can replace this old process with one which automatically renews \u0026#x1f680;\nIntroduction # When this article was originally written, DNS Flattening, which allows you to host a canonical name (CNAME) at the root of a domain was not yet available. Therefore I used a subdomain, which is a more traditional way of supporting a CNAME. Both ways should work and it\u0026rsquo;s up to you if you want your QNAP on a subdomain or at the root.\nBefore you begin # Before you start making changes, it’s worth knowing a few things.\nUsing Cloudflare in this way will only offer its benefits on your vanity domain - not on your DDNS myqnapcloud domain. If someone were to learn that address they could access it directly and skip Cloudflare. You could additionally set up some firewall rules to QuFirewall which only allow access from Cloudflare\u0026rsquo;s network, but those connections would still be received by the NAS, meaning DDoS attacks would still be possible. If I find a way to solve this problem, I\u0026rsquo;ll write a future post on how.\nIf you use your domain for multiple services # The following changes will affect all services or endpoints which you host on your custom vanity domain. For instance, if you have a vanity domain such as example.com and you currently host your QNAP on qnap.example.com but you also have a website on a subdomain such as blog.example.com, both will be affected. Once you configure Cloudflare, any existing SSL certificates will be overruled and become irrelevant. If you only intend to host your QNAP on your vanity domain, this warning is safe to ignore.\nThe process takes time # This process can take several hours to complete. DNS propagation takes time and you might end up debugging ghosts if you\u0026rsquo;re not careful. You will have limited and sometimes no access to your vanity domain until everything is finished. If you get something wrong you’ll have to resort to accessing your QNAP via your local IP address within your network until you resolve the issues, so it\u0026rsquo;s worth performing this work when you\u0026rsquo;re within the same network as your QNAP.\nYou may also need access to your domain registrar to make changes.\nPreparing the NAS # Add Cloudflare access to QuFirewall # You may need to add Cloudflare to your firewall if you have one active, even with if you only have basic protection selected. This is because Cloudflare is an North American company and your GeoIP blocking will prevent any access unless you\u0026rsquo;re in North America. We\u0026rsquo;ll continue to use QuFirewall as your DDNS domain will not be directly protected.\nCloudflare’s IP ranges can be found here:\nhttps://www.cloudflare.com/en-gb/ips/\nWe will need to add them all to the the firewall\u0026rsquo;s allow list.\nEditing your QuFirewall Profile # Edit the active profile Click Add Rule and enter the fist IP4 address to the list as an IP Range. Select the correct Subnet Mask via the drop-down like so: Click Apply and rinse and repeat for all IP4 addresses in the list\nOnce all of the IP4 Addresses have been added, ensure they sit above the deny all rule in the list. You can drag and drop to modify ordering Make sure you apply the changes\nSetting Up Cloudflare # Create a Cloudflare account here if you do not have one already and sign in: https://dash.cloudflare.com/sign-up\nAdd your custom vanity domain you use for your QNAP using the Add a Site button. Don\u0026rsquo;t add your DDNS (qnap.myqnapcloud.com) here: Select the Free Account Let Cloudflare scan and add your existing DNS records. Once it’s populated them, click Add Record Fill out the following details:\nType: select CNAME from the drop down menu\nName: enter your subdomain here, eg qnap if you want to access your QNAP at qnap.yourdomain.com. If you just want to host your QNAP at the root of the domain, simply enter an @ symbol. What this does is \u0026ldquo;flatten\u0026rdquo; your domain to allow you to use a CNAME to your DDNS.\nTarget: enter your QNAP DDNS domain here in full. Do this even if you\u0026rsquo;re using DNS flattening. The end result will be something like so:\nA CNAME (canonical name) is an alias of another domain. This domain can be either another CNAME record, or different domain, such as qnap.example.com. You can read more about CNAMEs here\nChange your nameservers as instructed by the next page. You\u0026rsquo;ll need to visit your Domain Registrar and update the name server records to point to the ones Cloudflare assign you. Here\u0026rsquo;s the ones I have assigned for this blog: This bit can take a while as the DNS changes need to be propagated around the world.\nI recommend setting up security with the following settings to get you started. Cloudflare are adding new features all the time, so it\u0026rsquo;s a good idea to take a look around and experimenting to see what works best for you.\nAutomatic HTTPS Rewrites: ON\nAlways use HTTPS: ON\nAuto Minify: JS, CSS, HTML\nBrotli: ON\nCheck back in 24 hours. You may lose access to your QNAP if you have a Firewall running such as QFirewall etc. This will be because you have not yet added in access to and from Cloudflare.\nThat\u0026rsquo;s it. All going well you should now have some of the added benefits of fronting your QNAP with Cloudflare.\n","date":"26 Jul 2021","externalUrl":null,"permalink":"/blog/2021-07-26-qnap-front-your-internet-facing-nas-with-cloudflare/","section":"Blogs","summary":"","title":"QNAP - front your internet facing NAS with Cloudflare","type":"blog"},{"content":"","date":"26 Jul 2021","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"There\u0026rsquo;s a reasonable debate about whether you should expose your QNAP - or any NAS for that matter - to the outside internet directly. Anything on the internet is an attack surface, and nothing is completely un-hackable. Sure we can harden security with SSL/TLS, Web Application Firewalls, DDoS protection and Bot scoring, but any device which is publicly available will always provide an element of risk. This article attempts to describe one method for hardening security for your NAS, cheaply (well, free).\nApply a Let\u0026rsquo;s Encrypt Certificate # A Let\u0026rsquo;s Encrypt certificate can be configured to support both your free DDNS domain myqnap.myqnapcloud.com and your personal vanity domain too, such as qnap.howinteresting.co.uk.\nThere’s a couple of ways of getting an SSL certificate for the QNAP, and as to be expected, the easiest method costs you money: The paid QNAP cert. I suggest you ignore that. I\u0026rsquo;m with Let\u0026rsquo;s Encrypt in believing that security should be standard for all, and it\u0026rsquo;s something we all benefit from. Let\u0026rsquo;s Encrypt are a non-profit Certificate Authority with a long standing record of providing free certificates to hundreds of millions of websites around the world. You can read more about the project here.\nLet’s Encrypt certificate through QNAP Security Config # If you have the QuFirewall running (recommended) with some strict access rules (also recommended) such as UK only for example, you’ll need to prevent the ACME challenge from being rejected. Easiest way to do this is to either stop the app or switch the Firewall off while this work is performed, otherwise you’ll see an error with the challenge and the certificate issue process will fail.\nNavigate Control Panel \u0026gt; Security \u0026gt; Certificate \u0026amp; Private Key Click on Replace or Create Certificate (depending on if there’s one there already or not)\nEnter the following details in the prompt:\nin the first box enter your Custom Domain enter the email you wish to associate the certificate with under the third box entitled “Alternate Addresses”, enter your myqnapcloud.com address, such as myqnap.myqnapcloud.com Click save and that should be all you need to do Tip \u0026#x1f680; # If you’re running into issues, see the troubleshooting section below \u0026#x2b07;\u0026#xfe0f;\nCertificate Renewal # You may be able to renew the certificate with a click of a button when you’re near or past the expiry date.\nRemember to first switch off the firewall or the ACME challenge will fail and you only get 5 attempts before a one hour ban.\nLet’s Encrypt certificate through myQNAPcloud # This supports myqnapcloud.com domains only. For custom domains, see above \u0026#x2b06;\u0026#xfe0f;\nEnsure you’ve installed the myQNAPcloud app through the App Centre :thumbs_up:\nSelect the SSL certificate menu on the left-hand side of the window\nSelect Let’s Encrypt \u0026gt; Download and install\nYou’ll then be required to input a valid email address which Let\u0026rsquo;s Encrypt will associate the certificate issue with. The address will not be written to the certificate don’t worry\nMake sure you tick the option to auto-renew as this saves a bit of time manually renewing it every three months\nClick confirm and all should be done Troubleshooting # Let\u0026rsquo;s Encrypt only allow 5 failed certificate issues per hour. If you reach this point you’ll have to wait for an hour before trying again.\nIf for some reason the certificates are failing to issue, ensure that port 80 is open on the router and is port-forwarded to the QNAP correctly Check firewall logs to see if the challenge is being blocked Check any router-level advert blockers are not blocking the ACME challenge by accident by viewing the dnsmasq logs If you ended up with a Bitdefender free certificate # To ensure that your new certificate is showing correctly to new devices, you’ll want to make sure that you clear any Bitdefender free certs which your machine has cached to allow access to your https domain (if it expired or if you’re setting this up after a restore / new NAS)\nYou need to delete these certs in two different places;\nFirefox # Options \u0026gt; Privacy \u0026amp; Security \u0026gt; Security \u0026gt; View Certificates\nWindows 10 # Start \u0026gt; Manage Computer Certificates \u0026gt; Action \u0026gt; Find Certificates\nDelete the Bitdefender Personal CA.avfree000000 certificates you find and restart the browser\nVerify the certificate # Once you’ve removed those items above, you should able to verify that your new Let’s Encrypt certificate is showing through Firefox:\nClick Padlock then the right chevron \u0026gt; Notice that Verified by should now show Let’s Encrypt rather than the Bitdefender Unknown verifier one\nClick More Information Click Security and you can now see your new certificate in Firefox It’s the same principle for the other browsers, I\u0026rsquo;ve just not had time to check the exact steps\n","date":"24 Jun 2021","externalUrl":null,"permalink":"/blog/2021-06-24-qnap-add-a-let-s-encrypt-ssl-certificate-for-https/","section":"Blogs","summary":"","title":"QNAP - Add a Let's Encrypt SSL Certificate for HTTPS","type":"blog"},{"content":"","date":"4 Mar 2021","externalUrl":null,"permalink":"/tags/adblocking/","section":"Tags","summary":"","title":"Adblocking","type":"tags"},{"content":"","date":"4 Mar 2021","externalUrl":null,"permalink":"/tags/cookies/","section":"Tags","summary":"","title":"Cookies","type":"tags"},{"content":"","date":"4 Mar 2021","externalUrl":null,"permalink":"/tags/firefox/","section":"Tags","summary":"","title":"Firefox","type":"tags"},{"content":"","date":"4 Mar 2021","externalUrl":null,"permalink":"/tags/privacy/","section":"Tags","summary":"","title":"Privacy","type":"tags"},{"content":"Reader Mode? What is it and why is it useful? This article covers what it is, does, and how it can help minimise distractions and clean up your internet browsing experience.\nWhat is Reader View? # Reader View is a is an accessibility feature that\u0026rsquo;s usually built-in to most modern browsers with no extensions required. It loads websites into a simplified, fresh, concise appearance with fewer unnecessary distractions, such as:\nCookie confirmation dialogues Adverts! Scripts Extraneous images Popups Notifications You can even customise and configure the view, and set it to open by default too. The name of this special mode differs between browsers, but they essentially all share the same characteristics. I\u0026rsquo;ll share the official links for the browsers and what they call Reader View at the bottom of this page for you to take a look at.\nAccessing Reader View # Accessing Reader View differs between browsers. Generally you can find it under the icon that looks like a piece of paper with lines of text.\nFirefox on iOS # Mozilla have made accessing Reader View really easy in Firefox. Just open up the browser, navigate to a page and if the page is supported, the icon will be right there in the address bar:\nTo activate Reader View, tap the Reader View button highlighted below: See Reader View spring into view and immediately kill the cookie nag. You can customise your Reader View to taste. Tap the Aa button and change the font size and colours. To disable Reader View, simply tap the icon again to return to standard view. Safari on iOS # If you\u0026rsquo;re on Safari on iOS, the Reader View icon is hidden behind the Aa button:\nAs shown in the screenshot above, in Safari, look for the Aa button. Tapping the Aa button reveals the Reader View icon. Reader Mode in Safari takes on a familiar form. Similarly to Firefox, you can opt to customise your experience to taste too. Firefox Desktop on Mac / Windows # On Firefox for Desktop, it\u0026rsquo;s right there again in the address bar. The difference between standard view and Reader View is even more profound on Desktop: Reader View Official Documentation # As mentioned earlier, Reader View goes by different titles depending on which browser you are using. It\u0026rsquo;s no wonder that Google hide it away in Chrome under a bizarre dual-view where you get both standard view and a reader view-like experience. It\u0026rsquo;s easy to speculate that this decision was made due to Google not wanting to neuter their advert-based revenue stream by offering an ad-free view. However Reader View does appear, but just in a reduced form.\nI\u0026rsquo;ve collected the links to official documentation for some of the most popular browsers below, and by now you hopefully know what to look for if your browser is not listed. Please let me know in the comments if you find an official document for one not yet listed and I\u0026rsquo;ll add it.\nBrowser Feature Name Links Firefox Reader View [Desktop] [iOS] [Android] Chrome Reader Mode [Desktop] [Android] Safari Reader View [Mac] [iOS] Edge Immersive Reader [Desktop] Android Browser Simplified View [Android] Wrap up # So there you have it, a hidden built-in browser feature can help remove common website annoyances and you may have never even noticed it was there. I find it super useful for news sites where they\u0026rsquo;re often overwhelmingly baked with intrusive adverts, pop-ups and other garbage.\n📷 Cover photo by Giorgio Trovato on Unsplash under the Unsplash license. ","date":"4 Mar 2021","externalUrl":null,"permalink":"/blog/2021-03-04-remove-website-ads-annoyances-with-reader-view/","section":"Blogs","summary":"","title":"Remove website ads \u0026 annoyances with Reader View","type":"blog"},{"content":"","date":"21 Jun 2020","externalUrl":null,"permalink":"/tags/network-drive/","section":"Tags","summary":"","title":"Network Drive","type":"tags"},{"content":"","date":"21 Jun 2020","externalUrl":null,"permalink":"/tags/powershell/","section":"Tags","summary":"","title":"Powershell","type":"tags"},{"content":"","date":"21 Jun 2020","externalUrl":null,"permalink":"/tags/windows/","section":"Tags","summary":"","title":"Windows","type":"tags"},{"content":"This post describes a work around to automatically connect network drives instead of showing the silly red X through them in explorer on Windows startup. It’s been a bug in Windows for about 15 years, and I believe it\u0026rsquo;s because of a longstanding race condition when the OS loads its services. In this blog article, we\u0026rsquo;ll do a little bit of powershell.\nSymptoms # In Windows Explorer, a red X appears over mapped network drives Mapped network drives are displayed as Unavailable when you run the net use command at a command prompt In the notification area, a notification displays the following message: Could not reconnect all network drives Workaround # The following files should be executed on the regular command prompt - opposed to an elevated permissions command prompt to ensure they run with the same privilege as Windows Explorer.\nCreate a script file named MapDrives.cmd Paste the following code into the new file:\nPowerShell -Command \u0026#34;Set-ExecutionPolicy -Scope CurrentUser Unrestricted\u0026#34; \u0026gt;\u0026gt; \u0026#34;%TEMP%\\StartupLog.txt\u0026#34; 2\u0026gt;\u0026amp;1 PowerShell -File \u0026#34;%SystemDrive%\\Scripts\\MapDrives.ps1\u0026#34; \u0026gt;\u0026gt; \u0026#34;%TEMP%\\StartupLog.txt\u0026#34; 2\u0026gt;\u0026amp;1 Create a script file named MapDrives.ps1 Paste the following code into the new file:\n$i=3 while($True){ $error.clear() $MappedDrives = Get-SmbMapping |where -property Status -Value Unavailable -EQ | select LocalPath,RemotePath foreach( $MappedDrive in $MappedDrives) { try { New-SmbMapping -LocalPath $MappedDrive.LocalPath -RemotePath $MappedDrive.RemotePath -Persistent $True } catch { Write-Host \u0026#34;There was an error mapping $MappedDrive.RemotePath to $MappedDrive.LocalPath\u0026#34; } } $i = $i - 1 if($error.Count -eq 0 -Or $i -eq 0) {break} Start-Sleep -Seconds 30 } Create a startup item This workaround works only for devices that are already on the network at the time of log-on. If the device has not yet established a network connection by the time of logon, the startup script won\u0026rsquo;t automatically reconnect network drives. This script does not run continually in the background as that would take up computer resources unnecessarily.\nCopy the script file MapDrives.cmd to the following location: %ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp Copy the script file (MapDrives.ps1) to the following location: %SystemDrive%\\Scripts\\ Tip \u0026#x1f680; # You can quickly get to the above locations by opening up explorer and copy/pasting the above paths into the navigation bar.\nLogs # A log file (StartupLog.txt) will be created in the %TEMP% folder.\nFinally, log off then back on again and you should correctly observe correctly mapped and accessible drives.\n","date":"21 Jun 2020","externalUrl":null,"permalink":"/blog/2020-06-21-workaround-for-network-drive-not-connected-bug-in-windows/","section":"Blogs","summary":"","title":"Workaround for \"Network Drive Not connected\" bug in Windows","type":"blog"},{"content":"","date":"5 Jul 2019","externalUrl":null,"permalink":"/tags/mac/","section":"Tags","summary":"","title":"Mac","type":"tags"},{"content":"","date":"5 Jul 2019","externalUrl":null,"permalink":"/tags/multitasking/","section":"Tags","summary":"","title":"Multitasking","type":"tags"},{"content":"I\u0026rsquo;ve been a big fan of the Firefox browser for a long time now. It\u0026rsquo;s fast, open source, secure and feature rich. However, one feature still eludes it - being able to run multiple instances simultaneously with differrent profiles. Chrome has long had the feature, which can be conveniently accessed through the profile switcher. As can be seen below, this too is possible with Firefox but Mozilla don\u0026rsquo;t make make it so easy.\nYou could be forgiven for wondering why this somewhat niche feature is required. Firstly it\u0026rsquo;s a good idea to keep your work and personal browsing separate. It can be fairly annoying (and in some cases anxiety inducing) to see adverts relating to work appearing in your downtime which can impact on your work-life balance and ability to disconnect. Similarly, personal browsing habits may lead to distractions at work. Secondly you\u0026rsquo;ll almost certainly need different browser addons. Work and personal life often requires very different feature-sets from your browser, and too many installed addons can severely impact on your browsers\u0026rsquo; performance. It\u0026rsquo;s a good idea to split them out, and the way you do this is with different profiles. Another reason is website logins - there may be some sites which you have a personal and work account for, and to save you logging in and out as you start or finish work for the day can be somewhat laborious if there\u0026rsquo;s several.\nIn this article, we will explore how to create a new profile, and also how to run the default and new profile simultaneously on the same Apple Mac.\nCreating an additional profile # The default Firefox profile is simply named \u0026ldquo;default\u0026rdquo;. If you only have one profile this is the one which starts when you start the browser. You can observe and create profiles through Profile Manager within the browser itself.\nIn Firefox, type about:profiles in the address bar Click continue to dismiss the introduction and you\u0026rsquo;ll be able to set a name for your new profile. Notice here the location of the profile on the Mac\u0026rsquo;s filesystem.\nClick done and your profile is created. You can now switch to this profile and customise it to taste by clicking the \u0026ldquo;Launch Profile in new browser\u0026rdquo; button in the Profile Manager.\nIf you\u0026rsquo;re happy with starting and switching profiles through the GUI, you\u0026rsquo;re done. Personally, I\u0026rsquo;d rather launch it through the terminal.\nLaunching through the terminal # If you prefer launching your profiles through the terminal, you can do that too.\nObtain the path to the profile you wish to launch from the Profile Manager in about:profiles It\u0026rsquo;ll look similar to this: /Users/chris.gillatt/Library/Application Support/Firefox/Profiles/54qewttc.Chris\nConstruct an expression like so, replacing my profile for your own: nohup /Applications/Firefox.app/Contents/MacOS/firefox -no-remote -profile /Users/chris.gillatt/Library/Application Support/Firefox/Profiles/54qewttc.Chris \u0026amp;\u0026gt;/dev/null \u0026amp;!\nExplanation # Argument Description nohup prevent hangup (end process) when you close your terminal window -no-remote ignore the existing Firefox process if there is one -profile specifies your new profile other than the default one \u0026amp;\u0026gt;/dev/null forward errors and logs to nowhere \u0026amp;! Send the process to the background and disown it, so that it continues to run Creating an alias # You can then place this into your .zshrc or .bashrc for convenience:\n# Profile 1\nfirefox_profile_1='nohup /Applications/Firefox.app/Contents/MacOS/firefox -no-remote -profile /Users/chris.gillatt/Library/Application Support/Firefox/Profiles/54qewttc.Chris_work \u0026amp;\u0026gt;/dev/null \u0026amp;!'\n# Profile 2\nfirefox_profile_2='nohup /Applications/Firefox.app/Contents/MacOS/firefox -no-remote -profile /Users/chris.gillatt/Library/Application Support/Firefox/Profiles/54qewttc.Chris_personal \u0026amp;\u0026gt;/dev/null \u0026amp;!'\nLaunching the profile using the alias # Once the alias is created, you\u0026rsquo;ll be able to launch your profiles from your terminal like any other commandline utility, without needing to type all of the arguments manually like so:\nfirefox_profile_1 If your alias is not working, open up a new terminal window to load in your changes to your *rc file.\n","date":"5 Jul 2019","externalUrl":null,"permalink":"/blog/2019-07-05-running-multiple-firefox-profiles-simultaneously-on-a-mac/","section":"Blogs","summary":"I’ve been a big fan of the Firefox browser for a long time now. It’s fast, open source, secure and feature rich. However, one feature still eludes it - being able to run multiple instances simultaneously with differrent profiles. Chrome has long had the feature, which can be conveniently accessed through the profile switcher. As can be seen below, this too is possible with Firefox but Mozilla don’t make make it so easy.\nYou could be forgiven for wondering why this somewhat niche feature is required. Firstly it’s a good idea to keep your work and personal browsing separate. It can be fairly annoying (and in some cases anxiety inducing) to see adverts relating to work appearing in your downtime which can impact on your work-life balance and ability to disconnect. Similarly, personal browsing habits may lead to distractions at work. Secondly you’ll almost certainly need different browser addons. Work and personal life often requires very different feature-sets from your browser, and too many installed addons can severely impact on your browsers’ performance. It’s a good idea to split them out, and the way you do this is with different profiles. Another reason is website logins - there may be some sites which you have a personal and work account for, and to save you logging in and out as you start or finish work for the day can be somewhat laborious if there’s several.\nIn this article, we will explore how to create a new profile, and also how to run the default and new profile simultaneously on the same Apple Mac.\n","title":"Running multiple Firefox profiles simultaneously on a Mac","type":"blog"},{"content":"","date":"5 Jan 2019","externalUrl":null,"permalink":"/tags/ink/","section":"Tags","summary":"","title":"Ink","type":"tags"},{"content":"My Epson XP 312 gets snarky when I sporadically, then suddenly I need to print out a boarding past for an airline who still operates like it\u0026rsquo;s 1999, or some venue insists on physical tickets etc. When I finally want to use the printer, the cheap replacement ink I loaded it with all those months ago is now a dried mess all over the print head, clogging it right up - Every. Damn. Time. Cue the frantic hour or so running the head-clean program and spending a litre of ink, or at worst a new printer because it really isn\u0026rsquo;t worth the time over the £30-£50 for a replacement. Perhaps this is punishment for buying non-official (and overpriced) ink direct from the manufacturer.. 🤔\nIn my experience, the best way to keep the printer healthy - even with the knock-off ink from down the market - is to keep it in use rather than in semi-permanent stasis. Anyway I had a brainwave - could it be possible to automate a test page print-job? It certainly sounds plausible, and it\u0026rsquo;s the sort of thing Raspberry Pi's are made for.\nThe thing with Raspbian, the OS which comes with Raspberry Pi\u0026rsquo;s as standard, as great as it is for portability, you have to start pretty much from scratch every time you want to do even the most basic of tasks, and therefore something which would take me all of 5 minutes on fuller distros like Ubuntu or Windows images or whatever to script, the Pi takes a couple more steps. This is great for learning about the OS and great exposure to similar minimal distros such as Alpine however, so it\u0026rsquo;s important not to moan too much \u0026#x1f603;.\nThis post will show what I did to set this automated test-page cron going.\nHere\u0026rsquo;s what I started with:\nEpson XP312 Raspberry Pi 3 with git installed CUPS # Cups are great. I had two cups of tea as I figured all this out. Also, CUPS stands for Common UNIX Printing System which will get us up and printing. If you\u0026rsquo;ve not updated your Pi recently it could be worth the obligatory update first:\n$ sudo apt-get update $ sudo apt-get install cups Add your user (default is pi) to the correct group for permissions:\n$ sudo usermod -a -G lpadmin pi lp is the actual application which will allow you to print - more on lp later.\nOnce cups is installed, we\u0026rsquo;ll need to configure it to work beyond the default of localhost.\nEdit the following file:\n$ sudo vi /etc/cups/cupsd.conf Replace this line\nListen localhost:631\nWith this line\nPort 631\n\u0026hellip;and modify your config to look like the below. Some of this will already exist, so ensure you don\u0026rsquo;t repeat any lines:\n1 2 3 4 5 \u0026lt; Location / \u0026gt; # Restrict access to the server... Order allow,deny Allow @local\u0026lt; /Location \u0026gt; \u0026lt; Location /admin \u0026gt; # Restrict access to the admin pages... Order allow,deny Allow @local\u0026lt; /Location \u0026gt; \u0026lt; Location /admin/conf \u0026gt; AuthType Default Require user @SYSTEM # Restrict access to the configuration files... Order allow,deny Allow @local\u0026lt; /Location \u0026gt; Save the file then restart cups to apply your changes:\n$ sudo /etc/init.d/cups restart Now you should be able to get to the CUPS GUI by hitting your Raspberry Pi\u0026rsquo;s IP address on port 631 which we configured above. My Pi is on 192.168.1.247, so my access was http://192.168.1.247:631\nYou\u0026rsquo;ll get a screen like this all going well:\nNavigate to the Administration Tab and then \u0026ldquo;Add Printer\u0026rdquo;\nExpect a couple of things to happen:\nIt may ask you to sign in - the credentials you\u0026rsquo;ll need to use are the same ones you use to log into the Pi (either SSH or VNC) CUPS will say you need to \u0026ldquo;Upgrade\u0026rdquo; to https addresses. If you\u0026rsquo;re using a modern browser, you\u0026rsquo;ll get some warning about the page being insecure - it\u0026rsquo;s safe to ignore this warning and proceed. Everything is fine, it\u0026rsquo;s just you\u0026rsquo;ve probably not set up a SSL certificate on your Pi. Once that\u0026rsquo;s done, proceed to add your printer, which will hopefully appear on the discovered devices:\nFor some reason, mine was listed here twice, I just selected the top one. If your printer isn\u0026rsquo;t showing up here, ensure it\u0026rsquo;s switched on and connected to the network. Then try refreshing the page.\nOnce you\u0026rsquo;ve been able to select your printer, click continue.\nNext CUPS wants you to confirm the printer name (which you\u0026rsquo;ll use shortly on the Pi itself). I just left it as the default. The sharing option here is if you wanted to share the printer through the Pi. This isn\u0026rsquo;t necessary as the printer is already a network printer.\nClick Continue again.\nNext CUPS wants you to select the driver for your printer. If the name of your printer is clearly listed here then go ahead and select it.\nDrivers # My driver wasn\u0026rsquo;t listed, so I found a Github repository which contained the driver and used that. Here\u0026rsquo;s what I did. You\u0026rsquo;ll need to find the correct driver for your printer, but the process should hopefully be somewhat similar:\nClone the Github repository $ git clone https://github.com/liberodark/Print-PPD Decompress the Zip using Gunzip $ gunzip Print-PPD/Epson/Epson-XP-312_313_315_Series-epson-driver.ppd.gz Select the file in the CUPS interface manually Environment Variable # Next we need to set the default printer variable on the Raspberry Pi so it knows where to send your print jobs. This is especially important if you want to set up multiple printers.\nSSH back onto the Pi and add the following to your bashrc file. You\u0026rsquo;ll need the name of the printer you specified in the CUPS GUI earlier.\n$ sudo vi ~/.bashrc and add\nexport PRINTER=\u0026#34;EPSON_EPSON_XP-312_313_315_Series\u0026#34; Replace \u0026ldquo;EPSON_EPSON_XP-312_313_315_Series\u0026rdquo; with your printer\u0026rsquo;s name from CUPS.\nTime to send a test print job! # Create yourself a file if you don\u0026rsquo;t already have one, and use lp which came a part of the CUPS install to send it to the printer like so:\n$ lp \u0026lt;filename\u0026gt; e.g.\n$ lp ~/Desktop/test-print-file.txt All going well you should now see your printer spring into action and print the contents of your specified file.\nAutomate the print job # Finally, use cron to automate the print job \u0026#x1f5a8;\u0026#xfe0f;\n$ crontab -e Don\u0026rsquo;t forget the -e flag if you already have other crons, or you\u0026rsquo;ll delete them.\nAdd something like the following line:\n0 15 * * 3 lp ~/Desktop/test-print-file.txt This cron runs every Wednesday at 3pm and prints out my test-print-file.txt file. It\u0026rsquo;ll need to contain all four colours to keep the printer head clean and healthy.\nTip \u0026#x1f680; # Each time you notice the print has occurred, you can just re-use the same piece of paper over and again so save paper and the environment \u0026#x1f334;\n","date":"5 Jan 2019","externalUrl":null,"permalink":"/blog/2019-01-05-keep-your-printer-healthy-with-an-automated-print-job-via-raspberry-pi/","section":"Blogs","summary":"","title":"Keep your printer healthy with an automated print-job via Raspberry Pi","type":"blog"},{"content":"","date":"5 Jan 2019","externalUrl":null,"permalink":"/tags/printer/","section":"Tags","summary":"","title":"Printer","type":"tags"},{"content":"","date":"23 Dec 2018","externalUrl":null,"permalink":"/tags/ext/","section":"Tags","summary":"","title":"Ext","type":"tags"},{"content":"","date":"23 Dec 2018","externalUrl":null,"permalink":"/tags/format/","section":"Tags","summary":"","title":"Format","type":"tags"},{"content":"Horses for courses. Formats for file systems.\nFor many reasons including if you use a WRT-based Router, there may come a time where you need to format a USB Stick to EXT2/3/4.\nYou can do this with mkfs.ext2 / mkfs.ext3 / mkfs.ext4\nSSH to your Router and simply run mkfs.ext2\n$ mkfs.ext2 Alternatively you can do it using your Mac using e2fsprogs\nyou can install e2fsprogs using brew $ brew install e2fsprogs Find the name of your target partition or disk $ diskutil list Run something like the following $ sudo $(brew --prefix e2fsprogs)/sbin/mkfs.ext2 /dev/disk2s1 Tip \u0026#x1f680; # You may need to change the drive from disk2s1 to whatever your target disk / partition is.\n","date":"23 Dec 2018","externalUrl":null,"permalink":"/blog/2018-12-23-format-a-usb-stick-to-extx-using-a-mac-or-wrt-based-router/","section":"Blogs","summary":"Horses for courses. Formats for file systems.\n","title":"Format a USB Stick to EXTx using a Mac or WRT-based router","type":"blog"},{"content":"","date":"23 Dec 2018","externalUrl":null,"permalink":"/tags/usb/","section":"Tags","summary":"","title":"Usb","type":"tags"},{"content":"","date":"6 Aug 2018","externalUrl":null,"permalink":"/tags/pki/","section":"Tags","summary":"","title":"Pki","type":"tags"},{"content":"This article shows how to set up an SSH key-pair to allow you to log into servers in a quick, simple, and secure way from your Mac. It\u0026rsquo;s certainly worth doing if you log onto remote servers regularly.\nWhat is an SSH Key-pair? # An SSH key pair consists of a public key and a private key. The public key is like a lock that you install on your server, and the private key is the key you keep securely on your computer. Together, they ensure only you can access the server securely - a bit like the lock on your front door and the key you have in your pocket.\nThe public key can safely be shared with the server (and even others, if needed), while the private key must remain protected and known only to you.\nWhy Use SSH Key-pairs Instead of Passwords? # Key-pairs are more secure than passwords because:\nThey are far more resistant to brute-force attacks. The private key is never transmitted to the server, so it cannot be intercepted. They simplify access to servers by eliminating the need to type a password each time. Generating and Using a Public/Private Key Pair on Your Mac # Open the Terminal and run:\nssh-keygen When prompted, you may accept the default location (~/.ssh/id_rsa) by pressing the Enter key, or by specifying a new name and location. If you already an existing key, you will probably want to pick a new name to avoid overwriting the existing one.\nYou can optionally create a passphrase for your private key, which adds an extra layer of security. If you do, you\u0026rsquo;ll need to enter it whenever the private key is used.\nInstall the Public Key on the Remote Server\nssh-copy-id -i ~/.ssh/id_rsa.pub your_username@your_server Replace your_username and your_server with the appropriate values for your remote host.\nThis copies your public key and transmits it to the server.\nTip 🚀 # If ssh-copy-id is not installed on macOS, you can install it using Homebrew:\nbrew install ssh-copy-id Alternatively, manually copy the contents of the public key to the server:\ncat ~/.ssh/id_rsa.pub | ssh your_username@your_server \u0026#39;cat \u0026gt;\u0026gt; ~/.ssh/authorized_keys\u0026#39; Configure macOS to Use the SSH Key\nTo avoid entering the passphrase repeatedly, store the private key in your macOS keychain. Run:\nssh-add -K ~/.ssh/id_rsa Enter your passphrase when prompted. The keychain will now remember it.\nConfigure SSH for Convenience\nCreate or edit your SSH configuration file (~/.ssh/config):\nnano ~/.ssh/config Add the following configuration:\nHost * UseKeychain yes AddKeysToAgent yes IdentityFile ~/.ssh/id_rsa This tells SSH to automatically use your private key from the keychain.\nFor specific servers, you can define individual entries:\nHost your_server HostName your_server User your_username IdentityFile ~/.ssh/id_rsa Test the SSH Connection\nTry logging into the server:\nssh your_server If everything is set up correctly, you should be logged in without being asked for a password or username.\nTips for Managing SSH Keys # Permissions # Ensure your private key has the correct permissions to avoid warnings:\nchmod 600 ~/.ssh/id_rsa Troubleshooting # If you encounter issues, use verbose mode to debug:\nssh -v your_server Treat your Private Keys like.. um.. your keys # Your private key allows access to your server with your permissions, just like your house keys allow the person holding them to enter your house. Therefore treat them in a similar way.\nStore your private keys in secure locations. Generally, don\u0026rsquo;t share your private keys. Use a passphrase for added security, especially if you’re storing your private key on shared devices. Conclusion # Using SSH key-pairs simplifies and secures access to remote servers. Once set up, you\u0026rsquo;ll save time and improve security for all your remote connections. This method is widely supported, so you can use similar steps on Linux or Windows with tools like PuTTY or WSL. Start using SSH key-pairs today for a more seamless and secure workflow!\n","date":"6 Aug 2018","externalUrl":null,"permalink":"/blog/2018-08-06-using-ssh-key-pairs-to-better-secure-connections-to-remote-servers-mac/","section":"Blogs","summary":"","title":"Using SSH Key-pairs to Better Secure Connections to Remote Servers - Mac","type":"blog"},{"content":"","date":"17 Jul 2017","externalUrl":null,"permalink":"/tags/blogger/","section":"Tags","summary":"","title":"Blogger","type":"tags"},{"content":"Why would you even want to do such a thing? Well I will tell you.\nSometimes the simplest platforms are the most frustrating. Enter Blogger.\nThis next post is going to contain all the customisations I used to make this very blog. Mainly to remind myself, just in case I forget. I\u0026rsquo;ll probably forget. I will definitely forget. But there\u0026rsquo;s a couple of ways to make your blog a little less tacky, and it\u0026rsquo;s not that hard to do either.\nThis blog is run from Google's Blogger platform, and they like for you to advertise their platform in the URL and footer etc. Forced advertisement annoys me and so I choose to hide it. The reason I originally chose blogger over WordPress (the most popular blogging software in the world) is that Word Press suffers some huge security issues and it requires some manual maintenance or experience with some appropriate plugins to automate. If you\u0026rsquo;re a casual blogger and just don\u0026rsquo;t want the overhead, Blogger offers a secure but very basic option.\nCreating an account # Of cause Google want you to use your Google account for Blogger. This attaches it to your Google + account, and instantly links it to that. I\u0026rsquo;m not a fan of someone being able to see my random rants on the internet and get my holiday photos in a few clicks. Even if you know what you\u0026rsquo;re doing with the permissions, Google has made it a little bit hard to see who exactly can see what. At least facebook somewhat solved this issue with the View As.. functionality. However, what I can suggest to those who wish to maintain anonymity, is create a totally separate Blogger account just for the blog. This might be useful to some people, especially if you\u0026rsquo;re discussing controversial topics.\nTo create an account not attached to your google account # Sign up to your email provider of choice. Pick yourself a name and date of birth you can remember. You might need to recover the account at some point. This account will be an additional account to your \u0026lsquo;usual\u0026rsquo; account. On some accounts eg Microsoft Outlook, you can create aliases which we will cover in a separate blog post. This means you can have multiple email addresses and one inbox.. very useful for maintaining anonymity. Now you\u0026rsquo;re ready to create your blogger account. Make sure you click the \u0026ldquo;I would like to use my current email address\u0026rdquo; button. Or click this link. Sign up with the email address or alias you created. When you finally get to the stage where you create your blogger blog, just make sure you choose the Blogger account and NOT the google plus one. This just means you don\u0026rsquo;t get the Google+ account. You don\u0026rsquo;t need it. Nobody needs it.\nChoose the name you picked earlier again for sanity and make sure you save all those details in your favourite password manager.\nEmail account details (email, password, DOB) Google Account (password, the other details same as above) Finally create your Blog\nPicking a template # Personally I like to pick something I\u0026rsquo;ve not seen (much) before, something striking, hence why this blog is in highlighter-pen green and black currently. My advise to you is play around with the templates and get something which sets it off from the rest. It doesn\u0026rsquo;t have to be groundbreaking web design, it just needs to be interesting. I mean I broke one of the first rules of WebDev by having a dark background and light text.. so what as long as you\u0026rsquo;re not posting novels. There are too many blogs which look like they belong to a high-school geography teacher. Avoid anything you\u0026rsquo;ve seen a million times before.\nChop and change around with the various themes and colours until you get something you like. Blogger is quite limited with it\u0026rsquo;s basic Themes, but they\u0026rsquo;re pretty solid and scale well for mobile devices, which is another plus for Blogger.\nCustom Domains # Your blogger blog URL will looks something like https://www.mynewblog.blogspot.com. This is fine, but you might like to get rid of the \u0026ldquo;.blogspot.com\u0026rdquo; bit to make it a bit more unique and/or professional. Domains can cost as little as £2 per year and just look a whole lot better. I\u0026rsquo;ve used a fair few domain registrars over the years and some are better than others. Just do a google around and see who\u0026rsquo;s decent at the moment. Bigger names tend to offer some better services, but not always. I\u0026rsquo;ve used fasthosts.co.uk extensively over the years, as I like their straight-forward portal and the prices are competitive too.\nYou can either buy yourself a domain from the likes of Fasthosts or get one through Google. Here\u0026rsquo;s Google's instructions on how to apply the custom domain to your site. If you bought your domain from an external registrar such as Fasthosts, you\u0026rsquo;ll need to follow the Connect to your non-Google domain from Blogger section of the above page.\nRemove the \u0026ldquo;Powered by Blogger\u0026rdquo; attribution # Forced advertising just deserves to be removed. At the bottom of your blog you will see a little advert telling everyone where your blog is hosted. Not a fan, personally.\nYou can remove it via a couple of methods, but the method I choose, is by via good old fashioned HTML:\nNavigate to Dashboard -\u0026gt; Template -\u0026gt; edit HTML of your blog Click into the code - anywhere will do - press the ctrl/command + F button, and search for: ]]\u0026gt;\u0026lt;/b:skin\u0026gt; It\u0026rsquo;s important that you use the built-in blogger search functionality (obtained by clicking the code before you ctrl/command + F), opposed to the one which exists in your browser, because in this mode, blogger lazy loads the HTML. This means your browser will only \u0026lsquo;see\u0026rsquo; the HTML on screen and your search will not turn up anything otherwise.\nCreate a new line above the line you\u0026rsquo;re taken to, and add: #Attribution1 {display: none;} Your code will now look something like so:\nbody.collapsed-header.item-view .centered-top-container .blog-name{ margin-left:40px } } #Attribution1 {display: none;} ]]\u0026gt;\u0026lt;/b:skin\u0026gt; \u0026lt;b:template-skin\u0026gt; \u0026lt;![CDATA[ body#layout .hidden, body#layout .invisible { display: inherit; } Click the save icon and \u0026ldquo;Powered by Blogger\u0026rdquo; should be gone! Favicon # The humble Favourite Icon, or favicon for short, started to gain some proper popularity back when Firefox was king, as it was a nice way to keep your bookmarks\u0026rsquo; descriptions small (or entirely absent). This was especially true when the bookmarks bar was introduced, and then further so when browser tabs came about. As you can see in this Blog, I have a green and black one to match the current theme, with the initials of the site \u0026ldquo;HI\u0026rdquo;.\nCreate a Favicon # First of all you need a favicon. There are many favicon generators these days and unless you\u0026rsquo;re really intent on getting all Photoshoppy on it to make a masterpiece, I suggest you use one of those. I prefer simplicity when it comes to these as you really don\u0026rsquo;t have much space to play with, although I have seen some very clever use of animation and transparencies if you have the time to be creative. Thankfully, some Favicon Generators support the uploading of your own images, transparencies and animation. Just remember that your images are going to get shrunk to 16x16 pixels, so the more complex your image, the poorer it will look as a favicon. Simplicity is key, unless you\u0026rsquo;re great with transparencies.\nThe Favicon Generator I used for this site is http://www.favicon.cc. It\u0026rsquo;s a very simple, click-the-colour-you-want and click-the-block-you-want-that-colour simplicity. Once you\u0026rsquo;re done, click download and it\u0026rsquo;ll helpfully be in the correct .ico format automatically.\nInstall the Favicon # Now you have your favicon, you can proceed to install it. You\u0026rsquo;ll need to make sure it\u0026rsquo;s **under 100K in size to use it on blogger.\nGo to Blogger \u0026gt; Settings \u0026gt; Basic \u0026gt; Favicon Upload \u0026amp; save your new icon When you visit your site for the first time after you change your favicon, you might have to do a forced refresh of you browser to see it. To do this, press CTRL+F5 on windows, or Command+R on a Mac. It should now appear in all it\u0026rsquo;s tiny glory.\nGo you! \u0026#x1f389;\n","date":"17 Jul 2017","externalUrl":null,"permalink":"/blog/2017-07-17-blogging-on-a-better-blog-on-blogger-probably/","section":"Blogs","summary":"Why would you even want to do such a thing? Well I will tell you.\n","title":"Blogging on a better blog on blogger, probably","type":"blog"},{"content":"","date":"17 Jul 2017","externalUrl":null,"permalink":"/tags/google/","section":"Tags","summary":"","title":"Google","type":"tags"},{"content":"","date":"11 Jul 2017","externalUrl":null,"permalink":"/tags/adblock/","section":"Tags","summary":"","title":"Adblock","type":"tags"},{"content":"Who enjoys seeing adverts? Anyone? Didn\u0026rsquo;t think so. Lets block them.\nSo I figured that I would start this blog with a post about how to block those annoying adverts on literally every website in the world these days. Especially when you\u0026rsquo;ve made the mistake of looking for something on Amazon and the stalker-cookies from hell are now bent on making you part with your hard earned cash on that stupid toaster your mother made you look for that time.\nNot the mention the obnoxious Facebook ads masquerading as news-feed content but are little more than thinly veiled junkverts based on the information you\u0026rsquo;ve been encouraged to put on your profile. Yeah about that. It\u0026rsquo;s advert targeting fodder. Did you really believe the trope about Facebook being \u0026lsquo;free forever\u0026rsquo; did you? Well it ain\u0026rsquo;t. Never was a truer word said than:\nYou’re Not the Customer; You’re the Product\nAnyway, there are options to block some of the above. It all depends on how much time you have at your disposal, and effort you\u0026rsquo;re willing to put in to it. Anyway, we\u0026rsquo;ll start with the easiest platform, method and target. Desktop, Adblock and Banner ads. We\u0026rsquo;ll look at mobile devices, router-level blocking and hostfile blocking in another post.\nBrowser Advert blockers # Most people have used a browser-based advert blocker at some point. Many use one every day, and there\u0026rsquo;s a collection to choose from these days. Personally I recommend uBlock Origin these days, as it honest and requires no set-up from install. The likes of Adblock Plus have generated a fair amount of critics in recent years, working with advertisers to intentionally allow some adverts through, making them somewhat accomplices of advertisers rather than defenders against them. You can switch off this functionality, but it just makes me wonder what else they\u0026rsquo;re up to. Browser extensions can have access to anything you look at on the internet, so you should take a reasonable amount of caution when installing them. If you notice any alarm bells of strange behaviour from the addons themselves or their authors, I\u0026rsquo;d suggest airing on the side of caution and binning them off.\nAddon Links # Browser Addon Link Chrome https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en Firefox https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/ You can pick up your safari addons via the browser directly from the app if you\u0026rsquo;re on a Mac. Go Safari \u0026gt; Safari Extensions and it\u0026rsquo;ll launch an addon window.\nIf you prefer Adblock Plus for whatever reason, you\u0026rsquo;re probably going to want to unsubscribe from the \u0026lsquo;acceptable adverts programme\u0026rsquo; to block the greatest amount of adverts possible.\nAdvert blockers don\u0026rsquo;t block many facebook adverts # ..but if you use Adblock Plus, there are sometimes ways and means. One good thing about Microsoft\u0026rsquo;s new Edge Browser is that it cleverly automatically BLOCKS Facebook adverts, so if you\u0026rsquo;re an Edge user, you might be wondering what this blog post is about. Fistbump to Microsoft. Something I thought I\u0026rsquo;d never see myself type.\nFor users of Chrome, Firefox or Safari:\nClick the AdBlock button and select Options, then click the CUSTOMIZE tab Click Edit to open the custom filters box Paste the filters below exactly as given Click Save Reload the page you\u0026rsquo;re trying to view Copy these three filters: facebook.com###pagelet_ego_pane .uiHeader.uiHeaderTopBorder.mbs.uiSideHeader facebook.com##.ego_unit facebook.com###pagelet_ego_pane .ego_unit This will take care of the SIDEBAR ADS ONLY.\nTo get rid of those in-news-feed ads:\nInstall Tampermonkey (or the equivalent for your browser) and enable it. Chrome, and other chromium-based browsers: Tampermonkey Firefox and other gecko-based browsers: Greasemonkey Safari: Tampermonkey Edge: Tampermonkey Visit the Facebook unsponsored page and click the green Install this script button Refresh your Facebook page You should now be considerably lighter on adverts! \u0026#x1f389;\nHowever, there is a better way to block ads within your home network\u0026hellip; # There are better ways of blocking adverts in your home network / desktop and even mobile which I will talk about in another blog article soon.\nCheerio for now.\n","date":"11 Jul 2017","externalUrl":null,"permalink":"/blog/2017-07-11-blocking-adverts-on-the-web-part-one/","section":"Blogs","summary":"Who enjoys seeing adverts? Anyone? Didn’t think so. Lets block them.\n","title":"Blocking adverts on the web - part one","type":"blog"},{"content":"","date":"11 Jul 2017","externalUrl":null,"permalink":"/tags/dns/","section":"Tags","summary":"","title":"Dns","type":"tags"},{"content":"","date":"11 Jul 2017","externalUrl":null,"permalink":"/tags/facebook/","section":"Tags","summary":"","title":"Facebook","type":"tags"},{"content":"","date":"11 Jul 2017","externalUrl":null,"permalink":"/tags/favicon/","section":"Tags","summary":"","title":"Favicon","type":"tags"},{"content":"","date":"15 Jul 2016","externalUrl":null,"permalink":"/tags/emoji/","section":"Tags","summary":"","title":"Emoji","type":"tags"},{"content":"Emoji can be enabled in a Hugo site in a couple of different of ways.\nThe emojify function can be called directly in templates or Inline Shortcodes.\nTo enable emoji globally, set enableEmoji to true in your site\u0026rsquo;s configuration\nIn this blog\u0026rsquo;s theme, the following line is simply added to the config.toml:\nenableEmoji = true Then you can type emoji shorthand codes directly in content files; e.g.\n🙈 :see_no_evil: 🙉 :hear_no_evil: 🙊 :speak_no_evil:\nTip \u0026#x1f680; # The Emoji cheat sheet hosted at https://www.webfx.com/tools/emoji-cheat-sheet is a great reference for emoji shortcodes:\nN.B. The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.\n.emoji { font-family: Apple Color Emoji, Segoe UI Emoji, NotoColorEmoji, Segoe UI Symbol, Android Emoji, EmojiSymbols; } ","date":"15 Jul 2016","externalUrl":null,"permalink":"/blog/2016-07-15-emoji-support-in-hugo/","section":"Blogs","summary":"Emoji can be enabled in a Hugo site in a couple of different of ways.\n","title":"Emoji Support in Hugo","type":"blog"},{"content":"","date":"15 Jul 2016","externalUrl":null,"permalink":"/series/hugo-configuration/","section":"Series","summary":"","title":"Hugo Configuration","type":"series"},{"content":"Hugo ships with several Built-in Shortcodes for rich content, along with a Privacy Config and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds. Here\u0026rsquo;s a couple of examples to get you started.\nYouTube Privacy Enhanced Shortcode # Shortcode: # {{\u0026lt; youtube ZJthWmvUzzc \u0026gt;}}\nResult: # Shortcode: # {{\u0026lt; x user=\u0026ldquo;KawaaiMayumi\u0026rdquo; id=\u0026ldquo;1557658979018440705\u0026rdquo; \u0026gt;}}\nResult: # Stay hydrated#CatsOfTwitter #CatsOnTwitter #Cats #Thursday #Life #Funny pic.twitter.com/1sSbisGyL8\n\u0026mdash; mayumi kawaai (@KawaaiMayumi) August 11, 2022 Vimeo Simple Shortcode # Shortcode: # {{\u0026lt; vimeo_simple 48912912 \u0026gt;}}\nResult: # ","date":"13 Jul 2016","externalUrl":null,"permalink":"/blog/2016-07-13-rich-content/","section":"Blogs","summary":"Hugo ships with several Built-in Shortcodes for rich content, along with a Privacy Config and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds. Here’s a couple of examples to get you started.\n","title":"Rich Content","type":"blog"},{"content":"","date":"13 Jul 2016","externalUrl":null,"permalink":"/tags/shortcodes/","section":"Tags","summary":"","title":"Shortcodes","type":"tags"},{"content":"","date":"11 Apr 2014","externalUrl":null,"permalink":"/tags/pc/","section":"Tags","summary":"","title":"Pc","type":"tags"},{"content":"This article shows how to set up a SSH key pair to allow you to log into servers in a quick, simple and secure way from your Windows Laptop or PC. It\u0026rsquo;s certainly worth doing if you log onto remote servers regularly.\nWhat is an SSH key-pair? # I get asked this question a lot at work, and the concept is a little bit strange if you\u0026rsquo;re new to it. A key-pair is a pair of keys which are generated at the same time by a cryptographic algorithm. They only work with each other and each key-pair is unique. A Public Key is useless without the Private Key, and this goes on your remote host, and is perfectly secure to do so.\nKeys and Locks # You could think of the Public Key as a physical padlock on a door, where everyone is able to see the lock, but nobody can unlock it. Your unique private key - that you keep safe in your pocket - is the only key able to unlock the padlock. The lock is useless to anyone without the correct key.\nOnce your key is used with the lock, the lock becomes open and you\u0026rsquo;re able to gain access.\nThe process # What happens is when your client sends a connection request to the server that contains the Public Key, the server responds with an encrypted challenge request using the shared Public Key information. Your client decrypts the challenge message and responds back to the server. The secure connection is then established if the response matches the Public Key.\nKey-pairs are more secure than passwords as they\u0026rsquo;re much much harder to attack via brute force. The Private Key is never transmitted to the remote host, so it can never be compromised. They\u0026rsquo;re also more convenient, as Public Keys can be saved upon your remote hosts for reuse, removing the need to manually authenticate.\nGenerating and using a Public/Private Key Pair on your PC # Prerequisites # Download and install Putty.\nPutty PuttyGen (Included with a standard Putty installation) Tip \u0026#x1f680; # PuttyGen is located in C:\\Program Files (x86)\\PuTTY\\puttygen.exe by default. Usually a shortcut to PuttyGen will not have been created on installation.\nGenerating a Public/Private Key Pair # Run PuttyGen (location shown above)\nClick Generate and follow the on screen instruction to move the mouse around in the blank box. What this is doing is building a new strong unique key-pair based on the movements of your mouse. Your key will now appear in the Key field. Don\u0026rsquo;t close the window.\nCopy the script below and paste into notepad\n1 2 3 4 5 PUBLIC_KEY=\u0026#34;ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAxwKhgtc86xumFtEBCyQa7kRo718BFeRMwSSRuoGMTXq8D8yMbgx7NcJJCS04gdLTbFAVhj1KX+zCIli9LOVnR5q0BgjOYfTC4lk97tA2puxJ7MMw3yf6MbuP4QIB4qKLf/GfU08Gj2oukZgN/PP8DTYxVIozYi08tae2D+qlT2+3GiwKY23VkAZ3LebKc+hvbubN7BD6BK1qGS+ctBZTdtqOAi8ZyM65GmoWqxiUqi7ZvkvcOsINFARpL406ZZbRzZONitINVU7qTfi2BxIIV14TM9FgoSUathAxa6XGrOz2wOjvjZcfI9n63HXBU/fEnovEn4Z1WZX/KDtRyTEEaQ== rsa-key-20140411\u0026#34; if [[ ! -d \u0026#34;$HOME/.ssh\u0026#34; ]]; then mkdir \u0026#34;$HOME/.ssh\u0026#34;; fi \u0026amp;\u0026amp; \\ echo \u0026#34;$PUBLIC_KEY\u0026#34; \u0026gt;\u0026gt; \u0026#34;$HOME/.ssh/authorized_keys\u0026#34; \u0026amp;\u0026amp; \\ chmod 600 \u0026#34;$HOME/.ssh/authorized_keys\u0026#34; \u0026amp;\u0026amp; \\ chmod 700 \u0026#34;$HOME/.ssh/\u0026#34; What does the script do? # Line 1: First of all it sets a variable containing your Public Key\nLine 2: A check is performed to see if there\u0026rsquo;s an .ssh directory and creates it if there isn\u0026rsquo;t one already\nLine 3: The Public Key is placed into the remote hosts\u0026rsquo; authorized_keys file\nLine 4 \u0026amp; 5: Finally, secure permissions are applied to the files and directories\nBe sure to replace the contents of the PUBLIC_KEY variable with the contents of your Public Key\nCopy your script to your clipboard\nLog on to a server with your password, and paste your script into the terminal\nGoing back to your PuttyGen window, now save your Private Key. Name and save your Private Key carefully. You should not share this key with anyone else, or they will be able to act as you and log onto your remote hosts!\nUsing Public and Private Keys with Putty # If you want to automate logging into servers, you can use your new keys to allow instant access - without having to type in your username and password every time. In regards to security, this can have benefits and drawbacks. The main drawback is that anyone with access to your laptop will be able to log into servers as you. This means locking your machine when you are away from it becomes even more important. It does however mean that obtaining your server password is very difficult for malware or other methods.\nOpen up your standard Putty window\nNavigate to Connection \u0026gt; SSH \u0026gt; Auth\nOn this tab, enter the location of your Private Key under Private Key file for authentication: Navigate to Connection \u0026gt; Data\nOn this tab, enter your Linux username under Login Details Navigate back to Session, type in a name for your new settings under Saved Sessions, and click Save Once this has been completed, you should be able to simply type in an IP or hostname and click Open to automatically log you in! without entering a username or password!\n","date":"11 Apr 2014","externalUrl":null,"permalink":"/blog/2014-04-11-using-ssh-key-pairs-to-better-secure-connections-to-remote-servers-windows/","section":"Blogs","summary":"","title":"Using SSH Key-pairs to better secure connections to remote servers - Windows","type":"blog"},{"content":"","date":"16 Jan 2012","externalUrl":null,"permalink":"/tags/centos/","section":"Tags","summary":"","title":"Centos","type":"tags"},{"content":"If you’ve ever managed a Linux server, whether it’s a virtual machine, a physical server, or a router with Debian or Red Hat roots, you’ll know that reclaiming disk space is an ongoing battle. Over time, logs accumulate, redundant files pile up, and unused packages sit around taking up space. In this article, we\u0026rsquo;ll dive into some helpful tips and tricks to help you identify and reclaim space on your Linux server.\nWhat\u0026rsquo;s Eating Your Space? # df and du are your friends. These two powerful utilities, are a good port of call when investigating space use. But it\u0026rsquo;s important to keep in mind that they work quite differently:\ndf: Reads the superblock (filesystem metadata) to show total usage at a high level. Think of it as a broad overview. du: Goes through each directory and file individually to tally up usage, giving a more granular report. To get started, here are a few useful commands:\nSummary of Current Directory # du -smch * -s: Summarises the disk usage for each specified argument. -m: Shows the output in megabytes for easier readability. -c: Displays a grand total at the end. -h: Outputs the sizes in human-readable format. This command gives a readable breakdown of usage in the current directory. Here\u0026rsquo;s an example output of that command:\n$ sudo du -smch * 4.9M\tbackups 1.5G\tcache 161M\tlib 4.0K\tlocal 0\tlock 3.9M\tlog 20K\tmail 4.0K\topt 0\trun 124K\tspool 100M\tswap 44K\ttmp 1.7G\ttotal Now it should be straight forward enough to see where your space is being utilised. You can cd into the directory with the most used space in it, and run the exact same command until you find where your problem is. Then it\u0026rsquo;s just a case of removing any unwanted garbage.\nIncluding Hidden Files # du -sch .* * .* *: Includes both hidden (.*) and visible (*) files. -s, -c, -h: Same as above. Useful when dealing with hidden files that might be taking up significant space.\nSorted Output, Excluding Unix \u0026ldquo;Dotfiles\u0026rdquo; # du -sch .[!.]* * | sort -h .[!.]*: Matches hidden files excluding . and .. (common dotfiles). | sort -h: Sorts the output in ascending order by human-readable size. This one excludes Unix-specific dotfiles like . and .. while showing other hidden files.\nUsing find and du Together to Track Down Large Files and Directories # Long-lived systems tend to accumulate “forgotten” files. For instance, large log files, old backups, or misconfigured apps might silently hoard space. Here’s how to find them:\nListing Large Files in /var # find /var -type f -size +10000k -exec ls -lh {} \\; | awk \u0026#39;{ print $9 \u0026#34;: \u0026#34; $5 }\u0026#39; /var: Target directory to search in. -type f: Finds only files (ignores directories). -size +10000k: Lists files larger than 10 MB. -exec ls -lh {} \\;: Executes ls -lh on each matching file, showing detailed size in human-readable format. | awk '{ print $9 \u0026quot;: \u0026quot; $5 }': Outputs the filename and file size. This command searches for files over 10 MB in /var, a typical directory for log files and caches.\nTop 10 Largest Files # find /var -type f -print0 | xargs -0 du | sort -n | tail -10 | cut -f2 | xargs -I{} du -sh {} -print0: Outputs file paths separated by null characters (avoids issues with special characters). xargs -0 du: Feeds the null-separated paths into du for detailed sizes. sort -n: Sorts output numerically by file size. tail -10: Retrieves the last 10 entries, representing the largest files. cut -f2: Extracts just the filenames. xargs -I{} du -sh {}: Re-runs du to show sizes in human-readable format. Great for pinpointing the space hogs on your system. Adjust the directory path if needed.\nTop 10 Largest Directories (Handling \u0026ldquo;Permission Denied\u0026rdquo; Errors) # find /var -type d -print0 2\u0026gt;/dev/null | xargs -0 du 2\u0026gt;/dev/null | sort -n | tail -10 | cut -f2 | xargs -I{} du -sh {} 2\u0026gt;/dev/null -type d: Finds directories only. 2\u0026gt;/dev/null: Redirects permission-denied errors to /dev/null to avoid cluttering output. | xargs -0 du: Feeds null-separated directories into du to calculate sizes. sort -n | tail -10 | cut -f2: Same as the previous command, used for listing the largest directories. This finds the biggest directories while bypassing common permission errors. Just replace /var with the directory you’re interested in.\nCleaning Up # Once you’ve identified the space hogs, it’s time to clean up. But be careful—deleting the wrong file can have serious consequences. Here’s a safe way to start:\nDeleting Files Older Than 10 Days # sudo /usr/bin/find . -mtime +10 -type f -exec rm {} \\; . -mtime +10: Searches for files older than 10 days in the current directory. -type f: Targets files only. -exec rm {} \\;: Executes rm to delete each matching file. This will remove files older than 10 days in the current directory—perfect for clearing out old logs. Adjust +10 to the age limit you’re comfortable with.\nAdditional Tools for Disk Space Management on Debian and RHEL # Both RHEL-based systems (e.g., CentOS, Rocky) and Debian-based systems (e.g., Ubuntu, Debian itself) have their unique methods when it comes to package management and maintenance.\nRHEL-based Systems (RedHat Enterprise Linux/CentOS/RockyLinux) # yum clean all This clears out cached packages and headers, freeing up space used by old packages.\nLogrotate\nBy default, RHEL systems use logrotate to manage log sizes. Ensure it\u0026rsquo;s configured to archive or delete logs appropriately. Configurations can be checked or updated in /etc/logrotate.conf.\nDebian-based Systems (Debian / Raspberry Pi OS / loads more) # apt clean This removes local copies of retrieved packages, freeing up space.\njournalctl --vacuum-size=100M This limits systemd’s journal logs to a maximum of 100 MB, useful on Debian-based systems where journal logs grow quickly.\nKeeping Your System Lean and Healthy with automation # Setting up a cron job for periodic clean-up is an effective way to keep your system from running out of space unexpectedly. Here’s how you can set up a cron job to automatically delete files older than 10 days in a specified directory.\nExample Cron Job to Delete Old Files # Edit the cron file: Open the crontab editor by running: crontab -e Important - don\u0026rsquo;t forget the -e! If you don\u0026rsquo;t include this flag, you will overwrite the crontab, potentially losing any existing crons in there!\nAdd the cron job: Insert the following line to delete files older than 10 days from /path/to/directory every week:\n0 2 * * 0 find /path/to/directory -type f -mtime +10 -exec rm {} \\; 0 2 * * 0: Runs the job every Sunday at 2:00 AM. find /path/to/directory -type f -mtime +10 -exec rm {} \\;: Deletes files older than 10 days from the specified directory. Save and exit: After adding the line, save and close the editor.\nTesting the Cron Job # To test the job without waiting, you can copy and paste the command directly in the terminal:\nfind /path/to/directory -type f -mtime +10 -exec rm {} \\; Checking Cron Logs # To confirm the cron job is running, you can check the cron logs:\ngrep CRON /var/log/syslog On some systems, the cron logs may be located in /var/log/cron.log.\nWith cron, automated monitoring tools like Nagios or Prometheus can also alert you to spikes in disk usage before they become critical.\nHere’s the troubleshooting section with the inode scenario:\nTroubleshooting Disk Space Issues # du Shows 100% Usage, but you can\u0026rsquo;t find the files! # If you’ve used du to check your disk usage and it reports 100% usage, but you can’t locate any large files consuming the space, the issue could be with inodes rather than the actual disk space.\nWhat Is an Inode? # An inode (index node) is a data structure in Linux that stores information about a file, like its owner, permissions, and location on the disk. Every file and directory on a filesystem has an associated inode. While the disk might still have free space, if your filesystem has used up all its inodes, you won\u0026rsquo;t be able to create new files. Essentially this means that lots of small files that don\u0026rsquo;t even cumulatively fill up the volume\u0026rsquo;s free space, they can still prevent new files from being written.\nTo check inode usage, you can use the df command with the -i flag:\ndf -i If you see 100% inode usage on a particular filesystem, this is likely the cause of your \u0026ldquo;full disk\u0026rdquo; issue. Now, you should be able to effectively ascertain the location of the heavy inode use and resume your clear down task using the methods shown earlier. I\u0026rsquo;ve seen this issue catch out even the most senior of engineers in the past and it\u0026rsquo;s easy to forget about.\n","date":"16 Jan 2012","externalUrl":null,"permalink":"/blog/2012-01-16-reclaiming-space-on-linux-machines/","section":"Blogs","summary":"","title":"Reclaiming space on Linux Machines","type":"blog"},{"content":"","date":"16 Jan 2012","externalUrl":null,"permalink":"/tags/rhel/","section":"Tags","summary":"","title":"Rhel","type":"tags"},{"content":"","date":"16 Jan 2012","externalUrl":null,"permalink":"/tags/space/","section":"Tags","summary":"","title":"Space","type":"tags"},{"content":" Well, hello there\u0026hellip; # My name is Chris. I\u0026rsquo;m a Systems \u0026amp; Cloud Engineer with a background in IT spanning well over a decade, and this is where I write about the things I find interesting.\nI started the blog partly to give something back to the tech community from whom I\u0026rsquo;ve learned so much over the years, and partly because writing things down is one of the best ways I know to actually understand them. The articles here range from personal projects and practical how-to guides to the occasional opinion piece: whatever catches my attention and refuses to let go.\nI trained at Manchester Metropolitan University and have spent most of my career at companies that actively encourage experimentation with new technology. One of the bigger shifts I\u0026rsquo;ve witnessed along the way has been the industry\u0026rsquo;s move from long-lived, multi-purpose virtual machines (the \u0026ldquo;pets\u0026rdquo; of the old world) to single-purpose ephemeral containers (the \u0026ldquo;cattle\u0026rdquo; of the new one). It\u0026rsquo;s a simplification, but it captures something real about how the discipline has changed.\nIf you\u0026rsquo;re curious about my work outside this blog, a few years ago I wrote an article for Auto Trader\u0026rsquo;s engineering blog about how my team and I built a process for non-disruptive, in-place Kubernetes cluster upgrades across multiple production environments.\nSide project: The Joke Bot # I also run The Joke Bot, a little side project that posts jokes to Bluesky. You can check out the code on GitHub or follow the account at thejokebot.bsky.social.\nGetting in touch # There are comments sections powered by Giscus under each article, so please reach out if you have any comments. It\u0026rsquo;d be great to see what you think! Alternatively, feel free to reach out via my social links.\nBlowfish Hugo theme # This blog is currently running the Blowfish theme for Hugo, created by Nuno Coração, with a custom homepage layout that I\u0026rsquo;ve designed myself.\nIf you\u0026rsquo;re interested in beginning your own blog and need some pointers on where to start, be sure to check out my Hugo Blog Stack article on this very subject.\n","externalUrl":null,"permalink":"/page/about/","section":"Pages","summary":"","title":"About","type":"about"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"Change access permissions with ease. Adjust the numeric and symbolic values to see the corresponding permissions.\nPermissions (Octal): Symbolic Representation: Owner Group Other Read Write Execute ","externalUrl":null,"permalink":"/page/tools/chmod-calculator/","section":"Pages","summary":"","title":"Chmod Calculator","type":"about"},{"content":"Standard Client information for the current session.\nUser Agent: Loading... Copy to Clipboard IP Address: Loading... Copy to Clipboard ISP: Loading... Copy to Clipboard Location: Loading... Copy to Clipboard Map: Copy All to Clipboard ","externalUrl":null,"permalink":"/page/tools/visitor-info/","section":"Pages","summary":"","title":"Client Info","type":"about"},{"content":"Enter an Epoch Time or a Human-Readable Date and click the corresponding button to convert between formats.\nEnter Epoch Time: Convert to Date Human-Readable Date: Enter Human-Readable Date: Convert to Epoch Epoch Time: Clear All Fields ","externalUrl":null,"permalink":"/page/tools/epoch-converter/","section":"Pages","summary":"","title":"Epoch Converter","type":"about"},{"content":" James McNee - jamesmcnee.com # Writes about: Internet security, databases, Kubernetes\nKarl Stoney - karlstoney.com # Writes about: Kubernetes, Istio, Security, Observability, Docker, Nginx\nNick Ebbitt - nickebbitt.com # Writes about: Java, Manchester Java Community, Tracing, Web Services\nTom Riley - thomasriley.co.uk # Writes about: Kubernetes, Cloud Native Community, Monitoring, Observability\n📷 Cover photo by Florian Klauer on Unsplash under the Unsplash license.\nModified by Chris Gillatt. ","externalUrl":null,"permalink":"/page/friends/","section":"Pages","summary":"","title":"Interesting Friends","type":"about"},{"content":"Query the high-level / approximate location of an IPv4 address.\nEnter IP Address: Query Location Clear Location: Loading current location... Map: ","externalUrl":null,"permalink":"/page/tools/ip-location-query/","section":"Pages","summary":"","title":"IP Geo-location Query","type":"about"},{"content":"Enter an IP Address (e.g., 192.168.1.1) and choose either Subnet Mask (e.g., 255.255.255.0) or CIDR Notation (e.g., /24) to perform calculations.\nIP Address: Subnet Mask: CIDR: Calculate Network Address: Broadcast Address: First Host: Last Host: Total Hosts: Clear All Fields ","externalUrl":null,"permalink":"/page/tools/ip-subnet-calculator/","section":"Pages","summary":"","title":"IP Subnet Calculator","type":"about"},{"content":"","externalUrl":null,"permalink":"/page/","section":"Pages","summary":"","title":"Pages","type":"page"},{"content":"Create yourself some strong passwords. They\u0026rsquo;re generated on-the-fly and not stored.\nTotal Password Length: Min Special Characters: Min Uppercase: Min Lowercase: Min Numbers: Exclude Characters: Generate Password Copy to Clipboard Password copied!\n","externalUrl":null,"permalink":"/page/tools/password-generator/","section":"Pages","summary":"","title":"Password Generator","type":"about"}]