Commit bfa5b12e22

bfa5b12e2266a39944f2a270527021d78bb867b6

parent: 25fa00e18c

Unsigned

cmc <hello@cleberg.net> · 2024-04-29 19:18 UTC

format line wrapping and fix escaped characters

Layout: unified · split

README.md +9 −8
@@ -28,12 +28,13 @@ Use `zola build` and deploy to whichever deployment target you prefer.
28 28
29## Tasks 29## Tasks
30 30
31- [ ] Format all blog posts 31- [x] Format all blog posts
32 - [ ] 2018 32 - [x] 2018
33 - [ ] 2019 33 - [x] 2019
34 - [ ] 2020 34 - [x] 2020
35 - [ ] 2021 35 - [x] 2021
36 - [ ] 2022 36 - [x] 2022
37 - [ ] 2023 37 - [x] 2023
38 - [ ] 2024 38 - [x] 2024
39- [ ] Add descriptions to blog posts
39- [ ] Figure out how to get file tags to show up 40- [ ] Figure out how to get file tags to show up
content/blog/2018-11-28-aes-encryption.md +89 −95
@@ -7,119 +7,113 @@ draft = false
7 7
8# Basic AES 8# Basic AES
9 9
10If you\'re not familiar with encryption techniques, 10If you're not familiar with encryption techniques,
11[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) is the 11[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) is the
12**Advanced Encryption Standard**. This specification was established by 12**Advanced Encryption Standard**. This specification was established by the
13the National Institute of Standards and Technology, sub-selected from 13National Institute of Standards and Technology, sub-selected from the Rijndael
14the Rijndael family of ciphers (128, 192, and 256 bits) in 2001. 14family of ciphers (128, 192, and 256 bits) in 2001. Furthering its popularity
15Furthering its popularity and status, the US government chose AES as 15and status, the US government chose AES as their default encryption method for
16their default encryption method for top-secret data, removing the 16top-secret data, removing the previous standard which had been in place since
17previous standard which had been in place since 1977. 171977.
18 18
19AES has proven to be an extremely safe encryption method, with 7-round 19AES has proven to be an extremely safe encryption method, with 7-round and
20and 8-round attacks making no material improvements since the release of 208-round attacks making no material improvements since the release of this
21this encryption standard almost two decades ago. 21encryption standard almost two decades ago.
22 22
23> Though many papers have been published on the cryptanalysis of AES, 23> Though many papers have been published on the cryptanalysis of AES, the
24> the fastest single-key attacks on round-reduced AES variants \[20, 24> fastest single-key attacks on round-reduced AES variants [20, 33] so far are
25> 33\] so far are only slightly more powerful than those proposed 10 25> only slightly more powerful than those proposed 10 years ago [23,24].
26> years ago \[23,24\].
27> 26>
28> - [Bogdonav, et 27> - [Bogdonav, et
29> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf) 28> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf)
30 29
31# How Secure is AES? 30# How Secure is AES?
32 31
33In theory, AES-256 is non-crackable due to the massive number of 32In theory, AES-256 is non-crackable due to the massive number of combinations
34combinations that can be produced. However, AES-128 is no longer 33that can be produced. However, AES-128 is no longer recommended as a viable
35recommended as a viable implementation to protect important data. 34implementation to protect important data.
36 35
37A semi-short [comic 36A semi-short [comic
38strip](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html) 37strip](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html)
39from Moserware quickly explains AES for the public to understand. 38from Moserware quickly explains AES for the public to understand. Basically AES
40Basically AES encrypts the data by obscuring the relationship between 39encrypts the data by obscuring the relationship between the data and the
41the data and the encrypted data. Additionally, this method spreads the 40encrypted data. Additionally, this method spreads the message out. Lastly, the
42message out. Lastly, the key produced by AES is the secret to decrypting 41key produced by AES is the secret to decrypting it. Someone may know the method
43it. Someone may know the method of AES, but without the key, they are 42of AES, but without the key, they are powerless.
44powerless. 43
45 44To obscure and spread the data out, AES creates a substitution-permutation
46To obscure and spread the data out, AES creates a 45network. Wikipedia has a wonderful [example of an SP
47substitution-permutation network. Wikipedia has a wonderful [example of
48an SP
49network](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/SubstitutionPermutationNetwork2.png/468px-SubstitutionPermutationNetwork2.png) 46network](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/SubstitutionPermutationNetwork2.png/468px-SubstitutionPermutationNetwork2.png)
50available. This network sends the data through a set of S boxes (using 47available. This network sends the data through a set of S boxes (using the
51the unique key) to substitute the bits with another block of bits. Then, 48unique key) to substitute the bits with another block of bits. Then, a P box
52a P box will permutate, or rearrange, the bits. This is done over and 49will permutate, or rearrange, the bits. This is done over and over, with the key
53over, with the key being derived from the last round. For AES, the key 50being derived from the last round. For AES, the key size specifies the number of
54size specifies the number of transformation rounds: 10, 12, and 14 51transformation rounds: 10, 12, and 14 rounds for 128-bit, 192-bit, and 256-bit
55rounds for 128-bit, 192-bit, and 256-bit keys, respectively. 52keys, respectively.
56 53
57# The Process 54# The Process
58 55
591. \*KeyExpansion=: Using [Rijndael\'s key 561. **KeyExpansion**: Using [Rijndael's key
60 schedule](https://en.m.wikipedia.org/wiki/Advanced_Encryption_Standard), 57 schedule](https://en.m.wikipedia.org/wiki/Advanced_Encryption_Standard), the
61 the keys are dynamically generated. 58 keys are dynamically generated.
622. **AddRoundKey**: Each byte of the data is combined with this key 592. **AddRoundKey**: Each byte of the data is combined with this key using
63 using bitwise xor. 60 bitwise xor.
643. **SubBytes**: This is followed by the substitution of each byte of 613. **SubBytes**: This is followed by the substitution of each byte of data.
65 data. 624. **ShiftRows**: Then, the final three rows are shifted a certain number of
664. **ShiftRows**: Then, the final three rows are shifted a certain 63 steps, dictated by the cipher.
67 number of steps, dictated by the cipher. 645. **MixColumns**: After the rows have been shifted, the columns are mixed and
685. **MixColumns**: After the rows have been shifted, the columns are 65 combined.
69 mixed and combined. 66
70 67This process does not necessarily stop after one full round. Steps 2 through 5
71This process does not necessarily stop after one full round. Steps 2 68will repeat for the number of rounds specified by the key. However, the final
72through 5 will repeat for the number of rounds specified by the key. 69round excludes the MixColumns step. As you can see, this is a fairly complex
73However, the final round excludes the MixColumns step. As you can see, 70process. One must have a solid understanding of general mathematic principles to
74this is a fairly complex process. One must have a solid understanding of 71fully understand how the sequence works (and to even attempt to find a
75general mathematic principles to fully understand how the sequence works 72weakness).
76(and to even attempt to find a weakness). 73
77 74According to research done by Bogdanov et al., it would take billions of years
78According to research done by Bogdanov et al., it would take billions of 75to brute force a 126-bit key with current hardware. Additionally, this brute
79years to brute force a 126-bit key with current hardware. Additionally, 76force attack would require storing 2^88^ bits of data! However, there are a few
80this brute force attack would require storing 2^88^ bits of data! 77different attacks that have been used to show vulnerabilities with the use of
81However, there are a few different attacks that have been used to show 78this technology. Side-channel attacks use inadvertent leaks of data from the
82vulnerabilities with the use of this technology. Side-channel attacks 79hardware or software, which can allow attackers to obtain the key or run
83use inadvertent leaks of data from the hardware or software, which can 80programs on a user's hardware.
84allow attackers to obtain the key or run programs on a user\'s hardware. 81
85 82Please note that this is not something you should run out and try to implement
86Please note that this is not something you should run out and try to 83in your `Hello, World!` app after only a few hours of research. While AES
87implement in your `Hello, World!` app after only a few hours 84(basically all encryption methods) is extremely efficient in what it does, it
88of research. While AES (basically all encryption methods) is extremely 85takes a lot of time and patience to understand. If you're looking for something
89efficient in what it does, it takes a lot of time and patience to 86which currently implements AES, check out the [Legion of the Bouncy
90understand. If you\'re looking for something which currently implements
91AES, check out the [Legion of the Bouncy
92Castle](https://www.bouncycastle.org/documentation.html) for Java 87Castle](https://www.bouncycastle.org/documentation.html) for Java
93implementations of cryptographic algorithms. 88implementations of cryptographic algorithms.
94 89
95# Why Does Encryption Matter? 90# Why Does Encryption Matter?
96 91
97There are limitless reasons to enable encryption at-rest or in-transit 92There are limitless reasons to enable encryption at-rest or in-transit for
98for various aspects of your digital life. You can research specific 93various aspects of your digital life. You can research specific examples, such
99examples, such as [Australia passes new law to thwart strong 94as [Australia passes new law to thwart strong
100encryption](https://arstechnica.com/tech-policy/2018/12/australia-passes-new-law-to-thwart-strong-encryption/). 95encryption](https://arstechnica.com/tech-policy/2018/12/australia-passes-new-law-to-thwart-strong-encryption/).
101However, I will simply list a few basic reasons to always enable 96However, I will simply list a few basic reasons to always enable encryption,
102encryption, where feasible: 97where feasible:
103 98
1041. Privacy is a human right and is recognized as a national right in 991. Privacy is a human right and is recognized as a national right in some
105 some countries (e.g., [US Fourth 100 countries (e.g., [US Fourth
106 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)). 101 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)).
1072. \"Why not?\" Encryption rarely affects performance or speed, so 1022. "Why not?" Encryption rarely affects performance or speed, so there's
108 there\'s usually not a reason to avoid it in the first place. 103 usually not a reason to avoid it in the first place.
1093. Your digital identity and activity (texts, emails, phone calls, 1043. Your digital identity and activity (texts, emails, phone calls, online
110 online accounts, etc.) are extremely valuable and can result in 105 accounts, etc.) are extremely valuable and can result in terrible
111 terrible consequences, such as identity theft, if leaked to other 106 consequences, such as identity theft, if leaked to other parties. Encrypting
112 parties. Encrypting this data prevents such leaks from ruining 107 this data prevents such leaks from ruining lives.
113 lives. 1084. Wiping or factory-resetting does not actually wipe all data from the storage
1144. Wiping or factory-resetting does not actually wipe all data from the 109 device. There are methods to read data from the physical disks/boards inside
115 storage device. There are methods to read data from the physical 110 devices.
116 disks/boards inside devices. 1115. Corporations, governments, and other nefarious groups/individuals are
1175. Corporations, governments, and other nefarious groups/individuals 112 actively looking for ways to collect personal information about anyone they
118 are actively looking for ways to collect personal information about 113 can. If someone's data is unencrypted, that person may become a target due
119 anyone they can. If someone\'s data is unencrypted, that person may 114 to the ease of data collection.
120 become a target due to the ease of data collection.
121 115
122​**Read More:** 116​**Read More:**
123 117
124- [Federal Information Processing Standards Publication 118- [Federal Information Processing Standards Publication
125 197](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf) 119 197](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf)
content/blog/2018-11-28-cpp-compiler.md +48 −52
@@ -7,14 +7,14 @@ draft = false
7 7
8# A Brief Introduction 8# A Brief Introduction
9 9
10[C++](https://en.wikipedia.org/wiki/C%2B%2B) is a general-purpose 10[C++](https://en.wikipedia.org/wiki/C%2B%2B) is a general-purpose programming
11programming language with object-oriented, generic, and functional 11language with object-oriented, generic, and functional features in addition to
12features in addition to facilities for low-level memory manipulation. 12facilities for low-level memory manipulation.
13 13
14The source code, shown in the snippet below, must be compiled before it 14The source code, shown in the snippet below, must be compiled before it can be
15can be executed. There are many steps and intricacies to the compilation 15executed. There are many steps and intricacies to the compilation process, and
16process, and this post was a personal exercise to learn and remember as 16this post was a personal exercise to learn and remember as much information as I
17much information as I can. 17can.
18 18
19``` cpp 19``` cpp
20#include <iostream> 20#include <iostream>
@@ -29,56 +29,52 @@ int main()
29 29
30### An Overview 30### An Overview
31 31
32Compiling C++ projects is a frustrating task most days. Seemingly 32Compiling C++ projects is a frustrating task most days. Seemingly nonexistent
33nonexistent errors keeping your program from successfully compiling can 33errors keeping your program from successfully compiling can be annoying
34be annoying (especially since you know you wrote it perfectly the first 34(especially since you know you wrote it perfectly the first time, right?).
35time, right?).
36 35
37I\'m learning more and more about C++ these days and decided to write 36I'm learning more and more about C++ these days and decided to write this
38this concept down so that I can cement it even further in my own head. 37concept down so that I can cement it even further in my own head. However, C++
39However, C++ is not the only compiled language. Check out [the Wikipedia 38is not the only compiled language. Check out [the Wikipedia entry for compiled
40entry for compiled 39languages](https://en.wikipedia.org/wiki/Compiled_language) for more examples of
41languages](https://en.wikipedia.org/wiki/Compiled_language) for more 40compiled languages.
42examples of compiled languages.
43 41
44I\'ll start with a wonderful, graphical way to conceptualize the C++ 42I'll start with a wonderful, graphical way to conceptualize the C++ compiler.
45compiler. View [The C++ Compilation 43View [The C++ Compilation
46Process](https://web.archive.org/web/20190419035048/http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html) 44Process](https://web.archive.org/web/20190419035048/http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html)
47by Kurt MacMahon, an NIU professor, to see the graphic and an 45by Kurt MacMahon, an NIU professor, to see the graphic and an explanation. The
48explanation. The goal of the compilation process is to take the C++ code 46goal of the compilation process is to take the C++ code and produce a shared
49and produce a shared library, dynamic library, or an executable file. 47library, dynamic library, or an executable file.
50 48
51## Compilation Phases 49## Compilation Phases
52 50
53Let\'s break down the compilation process. There are four major steps to 51Let's break down the compilation process. There are four major steps to
54compiling C++ code. 52compiling C++ code.
55 53
56### Step 1 54### Step 1
57 55
58The first step is to expand the source code file to meet all 56The first step is to expand the source code file to meet all dependencies. The
59dependencies. The C++ preprocessor includes the code from all the header 57C++ preprocessor includes the code from all the header files, such as `#include
60files, such as `#include 58<iostream>`. Now, what does that mean? The previous example includes the
61<iostream>`. Now, what does that mean? The previous example 59`iostream` header. This tells the computer that you want to use the `iostream`
62includes the `iostream` header. This tells the computer that 60standard library, which contains classes and functions written in the core
63you want to use the `iostream` standard library, which 61language. This specific header allows you to manipulate input/output streams.
64contains classes and functions written in the core language. This 62After all this, you'll end up which a temporary file that contains the expanded
65specific header allows you to manipulate input/output streams. After all
66this, you\'ll end up which a temporary file that contains the expanded
67source code. 63source code.
68 64
69In the example of the C++ code above, the `iostream` class 65In the example of the C++ code above, the `iostream` class would be included in
70would be included in the expanded code. 66the expanded code.
71 67
72### Step 2 68### Step 2
73 69
74After the code is expanded, the compiler comes into play. The compiler 70After the code is expanded, the compiler comes into play. The compiler takes the
75takes the C++ code and converts this code into the assembly language, 71C++ code and converts this code into the assembly language, understood by the
76understood by the platform. You can see this in action if you head over 72platform. You can see this in action if you head over to the [GodBolt Compiler
77to the [GodBolt Compiler Explorer](https://godbolt.org), which shows C++ 73Explorer](https://godbolt.org), which shows C++ being converted into assembly
78being converted into assembly dynamically. 74dynamically.
79 75
80For example, the `Hello, world!` code snippet above compiles 76For example, the `Hello, world!` code snippet above compiles into the following
81into the following assembly code: 77assembly code:
82 78
83``` asm 79``` asm
84.LC0: 80.LC0:
@@ -124,17 +120,17 @@ _GLOBAL__sub_I_main:
124 120
125### Step 3 121### Step 3
126 122
127Third, the assembly code generated by the compiler is assembled into the 123Third, the assembly code generated by the compiler is assembled into the object
128object code for the platform. Essentially, this is when the compiler 124code for the platform. Essentially, this is when the compiler takes the assembly
129takes the assembly code and assembles it into machine code in a binary 125code and assembles it into machine code in a binary format. After researching
130format. After researching this online, I figured out that a lot of 126this online, I figured out that a lot of compilers will allow you to stop
131compilers will allow you to stop compilation at this step. This would be 127compilation at this step. This would be useful for compiling each source code
132useful for compiling each source code file separately. This saves time 128file separately. This saves time later if a single file changes; only that file
133later if a single file changes; only that file needs to be recompiled. 129needs to be recompiled.
134 130
135### Step 4 131### Step 4
136 132
137Finally, the object code file generated by the assembler is linked 133Finally, the object code file generated by the assembler is linked together with
138together with the object code files for any library functions used to 134the object code files for any library functions used to produce a shared
139produce a shared library, dynamic library, or an executable file. It 135library, dynamic library, or an executable file. It replaces all references to
140replaces all references to undefined symbols with the correct addresses. 136undefined symbols with the correct addresses.
content/blog/2019-01-07-useful-css.md +54 −64
@@ -7,36 +7,32 @@ draft = false
7 7
8# Introduction to CSS 8# Introduction to CSS
9 9
10[CSS](https://en.wikipedia.org/wiki/CSS), the language used to markup 10[CSS](https://en.wikipedia.org/wiki/CSS), the language used to markup HTML code
11HTML code and make it \"pretty\", is one of the most effective ways to 11and make it "pretty", is one of the most effective ways to increase the
12increase the attractiveness of a website. It can also lead to increased 12attractiveness of a website. It can also lead to increased user engagement,
13user engagement, retention, and satisfaction. In fact, there are whole 13retention, and satisfaction. In fact, there are whole career fields are
14career fields are dedicated to the improvement of user experiences, 14dedicated to the improvement of user experiences, known as UI design and UX
15known as UI design and UX design. 15design.
16 16
17Some web developers are used to the common CSS properties, such as 17Some web developers are used to the common CSS properties, such as element
18element sizing, fonts, colors, etc., but are not as well versed in 18sizing, fonts, colors, etc., but are not as well versed in less-used properties
19less-used properties and values such as `flexbox`, 19and values such as `flexbox`, `clip-path`, and `transform`. This article will
20`clip-path`, and `transform`. This article will
21provide some insight into the less-used and unique CSS properties. 20provide some insight into the less-used and unique CSS properties.
22 21
23# CSS Variables 22# CSS Variables
24 23
25The first topic today is CSS variables. Variables are not often used by 24The first topic today is CSS variables. Variables are not often used by smaller
26smaller developers. CSS variables allow you to give your website a 25developers. CSS variables allow you to give your website a well-defined
27well-defined structure, where you can easily reuse CSS properties 26structure, where you can easily reuse CSS properties throughout the project.
28throughout the project.
29 27
30You can use variables to define things, such as color palettes. Then, 28You can use variables to define things, such as color palettes. Then, you can
31you can use these colors for backgrounds anywhere else in the HTML. This 29use these colors for backgrounds anywhere else in the HTML. This could be
32could be extended, where extra variables could be defined for 30extended, where extra variables could be defined for `primary-text`,
33`primary-text`, `quoted-text`, etc. Variables can 31`quoted-text`, etc. Variables can also be used to define spacing (e.g. `32px` or
34also be used to define spacing (e.g. `32px` or 32`2rem`), which can then be applied to margins, padding, font sizes, and more.
35`2rem`), which can then be applied to margins, padding, font
36sizes, and more.
37 33
38For example, here are some variables defined at the root of the website, 34For example, here are some variables defined at the root of the website, which
39which allows for any subsequent CSS rules to use those variables: 35allows for any subsequent CSS rules to use those variables:
40 36
41``` css 37``` css
42:root { 38:root {
@@ -52,23 +48,22 @@ body {
52 48
53# CSS Box Shadows 49# CSS Box Shadows
54 50
55Box shadows were once my mortal enemy. No matter how hard I tried, I 51Box shadows were once my mortal enemy. No matter how hard I tried, I just
56just couldn\'t get them to work how I wanted. Because of this, my 52couldn't get them to work how I wanted. Because of this, my favorite discovery
57favorite discovery has been CSSMatic\'s [box shadow 53has been CSSMatic's [box shadow
58generator](https://www.cssmatic.com/box-shadow). It provides an 54generator](https://www.cssmatic.com/box-shadow). It provides an excellent tool
59excellent tool to generate box shadows using their simple sliders. 55to generate box shadows using their simple sliders. Surprisingly, this is the
60Surprisingly, this is the reason I learned how box shadows work! You can 56reason I learned how box shadows work! You can use the sliders and watch how the
61use the sliders and watch how the CSS code changes in the image that is 57CSS code changes in the image that is displayed. Through this, you should
62displayed. Through this, you should understand that the basic structure 58understand that the basic structure for box shadows is:
63for box shadows is:
64 59
65``` css 60``` css
66box-shadow: inset horizontal vertical blur spread color; 61box-shadow: inset horizontal vertical blur spread color;
67``` 62```
68 63
69Now, let\'s look at some basic examples! You can copy and paste the 64Now, let's look at some basic examples! You can copy and paste the following
70following code into a site like CodePen or your own HTML files. Feel 65code into a site like CodePen or your own HTML files. Feel free to play around
71free to play around with the code, experiment, and learn. 66with the code, experiment, and learn.
72 67
73**Box Shadow #1** 68**Box Shadow #1**
74 69
@@ -124,22 +119,20 @@ free to play around with the code, experiment, and learn.
124} 119}
125``` 120```
126 121
127Try these box shadows out on your own and see how changing each shadow 122Try these box shadows out on your own and see how changing each shadow value
128value works. 123works.
129 124
130# CSS Flexbox 125# CSS Flexbox
131 126
132Now, let\'s move on to the best part of this article: flexbox. The 127Now, let's move on to the best part of this article: flexbox. The flexbox is by
133flexbox is by far my favorite new toy. I originally stumbled across this 128far my favorite new toy. I originally stumbled across this solution after
134solution after looking for more efficient ways of centering content 129looking for more efficient ways of centering content horizontally AND
135horizontally AND vertically. I had used a few hack-ish methods before, 130vertically. I had used a few hack-ish methods before, but flexbox throws those
136but flexbox throws those out the window. The best part of it all is that 131out the window. The best part of it all is that flexbox is *dead simple*.
137flexbox is *dead simple*.
138 132
139Flexbox pertains to the parent div of any element. You want the parent 133Flexbox pertains to the parent div of any element. You want the parent to be the
140to be the flexbox in which items are arranged to use the flex methods. 134flexbox in which items are arranged to use the flex methods. It's easier to see
141It\'s easier to see this in action that explained, so let\'s see an 135this in action that explained, so let's see an example.
142example.
143 136
144**Flexbox** 137**Flexbox**
145 138
@@ -174,27 +167,24 @@ example.
174} 167}
175``` 168```
176 169
177You may notice that we no longer need to use the `top` 170You may notice that we no longer need to use the `top` property for the `h3`
178property for the `h3` elements in our code. This is because 171elements in our code. This is because we set the display box to be a flex
179we set the display box to be a flex container for the small boxes, AND 172container for the small boxes, AND we made the small boxes flex containers for
180we made the small boxes flex containers for their elements (the h3 173their elements (the h3 tags). Flex boxes can be nested like this to center
181tags). Flex boxes can be nested like this to center content that is 174content that is inside centered content.
182inside centered content.
183 175
184For the example above, we designated the `justify-content` 176For the example above, we designated the `justify-content` property to be
185property to be `flex-start` so that the boxes stack from the 177`flex-start` so that the boxes stack from the left side of the screen. This
186left side of the screen. This property can be changed to 178property can be changed to `center` to make the boxes appear in the center of
187`center` to make the boxes appear in the center of the 179the screen.
188screen.
189 180
190For an interactive example, [check out this 181For an interactive example, [check out this
191CodePen](https://codepen.io/LandonSchropp/pen/KpzzGo) from 182CodePen](https://codepen.io/LandonSchropp/pen/KpzzGo) from
192[LandonScropp](https://codepen.io/LandonSchropp/). Resize the window 183[LandonScropp](https://codepen.io/LandonSchropp/). Resize the window with dice
193with dice to see how they collapse and re-align. 184to see how they collapse and re-align.
194 185
195# Even More CSS 186# Even More CSS
196 187
197For more inspiration, you can visit [CodePen](https://www.codepen.io), 188For more inspiration, you can visit [CodePen](https://www.codepen.io),
198[Dribbble](https://dribbble.com), or [UI 189[Dribbble](https://dribbble.com), or [UI Movement](https://uimovement.com) to
199Movement](https://uimovement.com) to browse the collections of many 190browse the collections of many amazing web designers.
200amazing web designers.
content/blog/2019-09-09-audit-analytics.md +154 −172
@@ -7,150 +7,139 @@ draft = false
7 7
8# What Are Data Analytics? 8# What Are Data Analytics?
9 9
10A quick aside before I dive into this post: `data analytics` 10A quick aside before I dive into this post: `data analytics` is a vague term
11is a vague term that has become popular in recent years. Think of a 11that has become popular in recent years. Think of a `data analytic` as the
12`data analytic` as the output of any data analysis you 12output of any data analysis you perform. For example, a pivot table or a pie
13perform. For example, a pivot table or a pie chart could be a data 13chart could be a data analytic.
14analytic. 14
15 15[Data analysis](https://en.wikipedia.org/wiki/Data_analysis) is a process that
16[Data analysis](https://en.wikipedia.org/wiki/Data_analysis) is a 16utilizes statistics and other mathematical methods to discover useful
17process that utilizes statistics and other mathematical methods to 17information within datasets. This involves examining, cleaning, transforming,
18discover useful information within datasets. This involves examining, 18and modeling data so that you can use the data to support an opinion, create
19cleaning, transforming, and modeling data so that you can use the data 19more useful viewpoints, and gain knowledge to implement into audit planning or
20to support an opinion, create more useful viewpoints, and gain knowledge 20risk assessments.
21to implement into audit planning or risk assessments. 21
22 22One of the common mistakes that managers (and anyone new to the process) make is
23One of the common mistakes that managers (and anyone new to the process) 23assuming that everything involved with this process is "data analytics". In
24make is assuming that everything involved with this process is \"data 24fact, data analytics are only a small part of the process.
25analytics\". In fact, data analytics are only a small part of the 25
26process. 26See **Figure 1** for a more accurate representation of where data analysis
27 27sits within the full process. This means that data analysis does not include
28See **Figure 1\*** for a more accurate representation of where data 28querying or extracting data, selecting samples, or performing audit tests. These
29analysis sits within the full process. This means that data analysis 29steps can be necessary for an audit (and may even be performed by the same
30does not include querying or extracting data, selecting samples, or 30associates), but they are not data analytics.
31performing audit tests. These steps can be necessary for an audit (and
32may even be performed by the same associates), but they are not data
33analytics.
34 31
35![The Intelligence 32![The Intelligence
36Cycle](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/intelligence_cycle-min.png) 33Cycle](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/intelligence_cycle-min.png)
37 34
38# Current Use of Analytics in Auditing 35# Current Use of Analytics in Auditing
39 36
40While data analysis has been an integral part of most businesses and 37While data analysis has been an integral part of most businesses and departments
41departments for the better part of the last century, only recently have 38for the better part of the last century, only recently have internal audit
42internal audit functions been adopting this practice. The internal audit 39functions been adopting this practice. The internal audit function works
43function works exclusively to provide assurance and consulting services 40exclusively to provide assurance and consulting services to the business areas
44to the business areas within the firm (except for internal auditing 41within the firm (except for internal auditing firms who are hired by different
45firms who are hired by different companies to perform their roles). 42companies to perform their roles).
46 43
47> Internal Auditing helps an organization accomplish its objectives by 44> Internal Auditing helps an organization accomplish its objectives by bringing
48> bringing a systematic, disciplined approach to evaluate and improve 45> a systematic, disciplined approach to evaluate and improve the effectiveness
49> the effectiveness of risk management, control and governance 46> of risk management, control and governance processes.
50> processes.
51> 47>
52> - The IIA\'s Definition of Internal Audit 48> - The IIA's Definition of Internal Audit
53 49
54Part of the blame for the slow adoption of data analysis can be 50Part of the blame for the slow adoption of data analysis can be attributed to
55attributed to the fact that internal auditing is strongly based on 51the fact that internal auditing is strongly based on tradition and following the
56tradition and following the precedents set by previous auditors. 52precedents set by previous auditors. However, there can be no progress without
57However, there can be no progress without auditors who are willing to 53auditors who are willing to break the mold and test new audit techniques. In
58break the mold and test new audit techniques. In fact, as of 2018, [only 54fact, as of 2018, [only 63% of internal audit departments currently utilize data
5963% of internal audit departments currently utilize data
60analytics](https://www.cpapracticeadvisor.com/accounting-audit/news/12404086/internal-audit-groups-are-lagging-in-data-analytics) 55analytics](https://www.cpapracticeadvisor.com/accounting-audit/news/12404086/internal-audit-groups-are-lagging-in-data-analytics)
61in North America. This number should be as close as possible to 100%. I 56in North America. This number should be as close as possible to 100%. I have
62have never been part of an audit that would not have benefited from data 57never been part of an audit that would not have benefited from data analytics.
63analytics.
64 58
65So, how do internal audit functions remedy this situation? It\'s 59So, how do internal audit functions remedy this situation? It's definitely not
66definitely not as easy as walking into work on Monday and telling your 60as easy as walking into work on Monday and telling your Chief Audit Executive
67Chief Audit Executive that you\'re going to start implementing analytics 61that you're going to start implementing analytics in the next audit. You need a
68in the next audit. You need a plan and a system to make the analysis 62plan and a system to make the analysis process as effective as possible.
69process as effective as possible.
70 63
71# The DELTA Model 64# The DELTA Model
72 65
73One of the easiest ways to experiment with data analytics and gain an 66One of the easiest ways to experiment with data analytics and gain an
74understanding of the processes is to implement them within your own 67understanding of the processes is to implement them within your own department.
75department. But how do we do this if we\'ve never worked with analysis 68But how do we do this if we've never worked with analysis before? One of the
76before? One of the most common places to start is to research some data 69most common places to start is to research some data analysis models currently
77analysis models currently available. For this post, we\'ll take a look 70available. For this post, we'll take a look at the DELTA model. You can take a
78at the DELTA model. You can take a look at **\*\*\*Figure 2\*\*\*\*** 71look at **Figure 2** for a quick overview of the model.
79for a quick overview of the model. 72
80 73The DELTA model sets a few guidelines for areas wanting to implement data
81The DELTA model sets a few guidelines for areas wanting to implement 74analytics so that the results can be as comprehensive as possible:
82data analytics so that the results can be as comprehensive as possible: 75
83 76- **Data**: Must be clean, accessible, and (usually) unique.
84- **Data**: Must be clean, accessible, and (usually) unique. 77- **Enterprise-Wide Focus**: Key data systems and analytical resources must be
85- **Enterprise-Wide Focus**: Key data systems and analytical resources 78 available for use (by the Internal Audit Function).
86 must be available for use (by the Internal Audit Function). 79- **Leaders**: Must promote a data analytics approach and show the value of
87- **Leaders**: Must promote a data analytics approach and show the 80 analytical results.
88 value of analytical results. 81- **Targets**: Must be set for key areas and risks that the analytics can be
89- **Targets**: Must be set for key areas and risks that the analytics 82 compared against (KPIs).
90 can be compared against (KPIs). 83- **Analysts**: There must be auditors willing and able to perform data
91- **Analysts**: There must be auditors willing and able to perform 84 analytics or else the system cannot be sustained.
92 data analytics or else the system cannot be sustained.
93 85
94![The Delta 86![The Delta
95Model](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/delta-min.png) 87Model](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/delta-min.png)
96 88
97# Finding the Proper KPIs 89# Finding the Proper KPIs
98 90
99Once the Internal Audit Function has decided that they want to start 91Once the Internal Audit Function has decided that they want to start using data
100using data analytics internally and have ensured they\'re properly set 92analytics internally and have ensured they're properly set up to do so, they
101up to do so, they need to figure out what they will be testing against. 93need to figure out what they will be testing against. Key Performance Indicators
102Key Performance Indicators (KPIs) are qualitative or quantitative 94(KPIs) are qualitative or quantitative factors that can be evaluated and
103factors that can be evaluated and assessed to determine if the 95assessed to determine if the department is performing well, usually compared to
104department is performing well, usually compared to historical or 96historical or industry benchmarks. Once KPIs have been agreed upon and set,
105industry benchmarks. Once KPIs have been agreed upon and set, auditors 97auditors can use data analytics to assess and report on these KPIs. This allows
106can use data analytics to assess and report on these KPIs. This allows 98the person performing the analytics the freedom to express opinions on the
107the person performing the analytics the freedom to express opinions on 99results, whereas the results are ambiguous if no KPIs exist.
108the results, whereas the results are ambiguous if no KPIs exist. 100
109 101It should be noted that tracking KPIs in the department can help ensure you have
110It should be noted that tracking KPIs in the department can help ensure 102a rigorous Quality Assurance and Improvement Program (QAIP) in accordance with
111you have a rigorous Quality Assurance and Improvement Program (QAIP) in 103some applicable standards, such as IPPF Standard 1300.
112accordance with some applicable standards, such as IPPF Standard 1300. 104
113 105> The chief audit executive must develop and maintain a quality assurance and
114> The chief audit executive must develop and maintain a quality 106> improvement program that covers all aspects of the internal audit activity.
115> assurance and improvement program that covers all aspects of the
116> internal audit activity.
117> 107>
118> - IPPF Standard 1300 108> - IPPF Standard 1300
119 109
120Additionally, IPPF Standard 2060 discusses reporting: 110Additionally, IPPF Standard 2060 discusses reporting:
121 111
122> The chief audit executive must report periodically to senior 112> The chief audit executive must report periodically to senior management and
123> management and the board on the internal audit activity\'s purpose, 113> the board on the internal audit activity's purpose, authority,
124> authority, responsibility, and performance relative to its plan and on 114> responsibility, and performance relative to its plan and on its conformance
125> its conformance with the Code of Ethics and the Standards. Reporting 115> with the Code of Ethics and the Standards. Reporting must also include
126> must also include significant risk and control issues, including fraud 116> significant risk and control issues, including fraud risks, governance issues,
127> risks, governance issues, and other matters that require the attention 117> and other matters that require the attention of senior management and/or the
128> of senior management and/or the board. 118> board.
129> 119>
130> - IPPF Standard 2060 120> - IPPF Standard 2060
131 121
132The hardest part of finding KPIs is to determine which KPIs are 122The hardest part of finding KPIs is to determine which KPIs are appropriate for
133appropriate for your department. Since every department is different and 123your department. Since every department is different and has different goals,
134has different goals, KPIs will vary drastically between companies. To 124KPIs will vary drastically between companies. To give you an idea of where to
135give you an idea of where to look, here are some ideas I came up with 125look, here are some ideas I came up with when discussing the topic with a few
136when discussing the topic with a few colleagues. 126colleagues.
137 127
138- Efficiency/Budgeting: 128- Efficiency/Budgeting:
139 - Audit hours to staff utilization ratio (annual hours divided by 129 - Audit hours to staff utilization ratio (annual hours divided by total
140 total annual work hours). 130 annual work hours).
141 - Audit hours compared to the number of audits completed. 131 - Audit hours compared to the number of audits completed.
142 - Time between audit steps or to complete the whole audit. E.g., 132 - Time between audit steps or to complete the whole audit. E.g., time from
143 time from fieldwork completion to audit report issuance. 133 fieldwork completion to audit report issuance.
144- Reputation: 134- Reputation:
145 - The frequency that management has requested the services of the 135 - The frequency that management has requested the services of the IAF.
146 IAF. 136 - Management, audit committee, or external audit satisfaction survey
147 - Management, audit committee, or external audit satisfaction 137 results.
148 survey results. 138 - Education, experience, certifications, tenure, and training of the
149 - Education, experience, certifications, tenure, and training of 139 auditors on staff.
150 the auditors on staff.
151- Quality: 140- Quality:
152 - Number and frequency of audit findings. Assign monetary or 141 - Number and frequency of audit findings. Assign monetary or numerical
153 numerical values, if possible. 142 values, if possible.
154 - Percentage of recommendations issued and implemented. 143 - Percentage of recommendations issued and implemented.
155- Planning: 144- Planning:
156 - Percentage or number of key risks audited per year or per audit. 145 - Percentage or number of key risks audited per year or per audit.
@@ -158,65 +147,59 @@ when discussing the topic with a few colleagues.
158 147
159# Data Analysis Tools 148# Data Analysis Tools
160 149
161Finally, to be able to analyze and report on the data analysis, auditors 150Finally, to be able to analyze and report on the data analysis, auditors need to
162need to evaluate the tools at their disposal. There are many options 151evaluate the tools at their disposal. There are many options available, but a
163available, but a few of the most common ones can easily get the job 152few of the most common ones can easily get the job done. For example, almost
164done. For example, almost every auditor already has access to Microsoft 153every auditor already has access to Microsoft Excel. Excel is more powerful than
165Excel. Excel is more powerful than most people give it credit for and 154most people give it credit for and can accomplish a lot of basic statistics
166can accomplish a lot of basic statistics without much work. If you 155without much work. If you don't know a lot about statistics but still want to
167don\'t know a lot about statistics but still want to see some of the 156see some of the more basic results, Excel is a great option.
168more basic results, Excel is a great option. 157
169 158To perform more in-depth statistical analysis or to explore large datasets that
170To perform more in-depth statistical analysis or to explore large 159Excel cannot handle, auditors will need to explore other options. The big three
171datasets that Excel cannot handle, auditors will need to explore other 160that have had a lot of success in recent years are Python, R, and ACL. ACL can
172options. The big three that have had a lot of success in recent years 161be used as either a graphical tool (point and click) or as a scripting tool,
173are Python, R, and ACL. ACL can be used as either a graphical tool 162where the auditor must write the scripts manually. Python and the R-language are
174(point and click) or as a scripting tool, where the auditor must write 163solely scripting languages.
175the scripts manually. Python and the R-language are solely scripting 164
176languages. 165The general trend in the data analytics environment is that if the tool allows
177 166you to do everything by clicking buttons or dragging elements, you won't be
178The general trend in the data analytics environment is that if the tool 167able to fully utilize the analytics you need. The most robust solutions are
179allows you to do everything by clicking buttons or dragging elements, 168created by those who understand how to write the scripts manually. It should be
180you won\'t be able to fully utilize the analytics you need. The most 169noted that as the utility of a tool increases, it usually means that the
181robust solutions are created by those who understand how to write the 170learning curve for that tool will also be higher. It will take auditors longer
182scripts manually. It should be noted that as the utility of a tool 171to learn how to utilize Python, R, or ACL versus learning how to utilize Excel.
183increases, it usually means that the learning curve for that tool will
184also be higher. It will take auditors longer to learn how to utilize
185Python, R, or ACL versus learning how to utilize Excel.
186 172
187# Visualization 173# Visualization
188 174
189Once an auditor has finally found the right data, KPIs, and tools, they 175Once an auditor has finally found the right data, KPIs, and tools, they must
190must report these results so that actions can be taken. Performing 176report these results so that actions can be taken. Performing in-depth data
191in-depth data analysis is only useful if the results are understood by 177analysis is only useful if the results are understood by the audiences of the
192the audiences of the data. The best way to create this understanding is 178data. The best way to create this understanding is to visualize the results of
193to visualize the results of the data. Let\'s take a look at some of the 179the data. Let's take a look at some of the best options to visualize and report
194best options to visualize and report the results you\'ve found. 180the results you've found.
195 181
196Some of the most popular commercial tools for visualization are 182Some of the most popular commercial tools for visualization are Microsoft
197Microsoft PowerBI and Tableau Desktop. However, other tools exist such 183PowerBI and Tableau Desktop. However, other tools exist such as JMP, Plotly,
198as JMP, Plotly, Qlikview, Alteryx, or D3. Some require commercial 184Qlikview, Alteryx, or D3. Some require commercial licenses while others are
199licenses while others are simply free to use. For corporate data, you 185simply free to use. For corporate data, you may want to make sure that the tool
200may want to make sure that the tool does not communicate any of the data 186does not communicate any of the data outside the company (such as cloud
201outside the company (such as cloud storage). I won\'t be going into 187storage). I won't be going into depth on any of these tools since visualization
202depth on any of these tools since visualization is largely a subjective 188is largely a subjective and creative experience, but remember to constantly
203and creative experience, but remember to constantly explore new options 189explore new options as you repeat the process.
204as you repeat the process. 190
205 191Lastly, let's take a look at an example of data visualization. This example
206Lastly, let\'s take a look at an example of data visualization. This 192comes from a [blog post written by Kushal
207example comes from a [blog post written by Kushal
208Chakrabarti](https://talent.works/2018/03/28/the-science-of-the-job-search-part-iii-61-of-entry-level-jobs-require-3-years-of-experience/) 193Chakrabarti](https://talent.works/2018/03/28/the-science-of-the-job-search-part-iii-61-of-entry-level-jobs-require-3-years-of-experience/)
209in 2018 about the percent of entry-level US jobs that require 194in 2018 about the percent of entry-level US jobs that require experience.
210experience. **Figure 3\*** shows us an easy-to-digest picture of the 195**Figure 3** shows us an easy-to-digest picture of the data. We can quickly
211data. We can quickly tell that only about 12.5% of entry-level jobs 196tell that only about 12.5% of entry-level jobs don't require experience.
212don\'t require experience. 197
213 198This is the kind of result that easily describes the data for you. However, make
214This is the kind of result that easily describes the data for you. 199sure to include an explanation of what the results mean. Don't let the reader
215However, make sure to include an explanation of what the results mean. 200assume what the data means, especially if it relates to a complex subject. *Tell
216Don\'t let the reader assume what the data means, especially if it 201a story* about the data and why the results matter. For example, **Figure 4**
217relates to a complex subject. *Tell a story* about the data and why the 202shows a part of the explanation the author gives to illustrate his point.
218results matter. For example, **Figure 4\*** shows a part of the
219explanation the author gives to illustrate his point.
220 203
221![Entry-Level 204![Entry-Level
222Visualization](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/vis_example-min.png) 205Visualization](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/vis_example-min.png)
@@ -226,8 +209,7 @@ Explanation](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/vis
226 209
227# Wrap-Up 210# Wrap-Up
228 211
229While this is not an all-encompassing program that you can just adopt 212While this is not an all-encompassing program that you can just adopt into your
230into your department, it should be enough to get anyone started on the 213department, it should be enough to get anyone started on the process of
231process of understanding and implementing data analytics. Always 214understanding and implementing data analytics. Always remember to continue
232remember to continue learning and exploring new options as your 215learning and exploring new options as your processes grow and evolve.
233processes grow and evolve.
content/blog/2019-12-03-the-ansoff-matrix.md +87 −96
@@ -7,38 +7,35 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10As the world of business evolves, managers must approach business 10As the world of business evolves, managers must approach business planning and
11planning and strategy with a contemporary mindset. According to Dess, 11strategy with a contemporary mindset. According to Dess, McNamara, Eisner, and
12McNamara, Eisner, and Lee, managers must be willing to adapt to the 12Lee, managers must be willing to adapt to the modern business environment by
13modern business environment by going beyond \"\'incremental 13going beyond "'incremental management', whereby they view their job as making
14management\', whereby they view their job as making a series of small, 14a series of small, minor changes to improve the efficiency of the firm's
15minor changes to improve the efficiency of the firm\'s 15operations"(2019).
16operations\"(2019). 16
17 17One reason that strategic management is crucial is because most businesses that
18One reason that strategic management is crucial is because most 18fail in the United States each year fail due to a lack of strategic focus or
19businesses that fail in the United States each year fail due to a lack 19direction(2019). The rate of failure for businesses with poor strategies shows
20of strategic focus or direction(2019). The rate of failure for 20that strategic planning and management are crucial to a business's strength and
21businesses with poor strategies shows that strategic planning and 21longevity, injecting the critical factors of growth and direction into a
22management are crucial to a business\'s strength and longevity, 22company's business plan.
23injecting the critical factors of growth and direction into a company\'s 23
24business plan. 24One of the most significant strategic planning and management frameworks that
25 25companies can use is the [Ansoff
26One of the most significant strategic planning and management frameworks 26Matrix](https://en.wikipedia.org/wiki/Ansoff_matrix). While this framework has
27that companies can use is the [Ansoff 27unique purposes and use-cases, it can effectively help an organization grow and
28Matrix](https://en.wikipedia.org/wiki/Ansoff_matrix). While this 28compete. Specifically, the Ansoff matrix is one of the most effective frameworks
29framework has unique purposes and use-cases, it can effectively help an 29for companies who want to focus on increasing sales revenue or
30organization grow and compete. Specifically, the Ansoff matrix is one of 30profitability(2019).
31the most effective frameworks for companies who want to focus on 31
32increasing sales revenue or profitability(2019). 32This framework uses a two-by-two figure to show the four strategic options for
33 33companies to use in this framework: market penetration, market development,
34This framework uses a two-by-two figure to show the four strategic 34product development, and diversification (see **Figure 1**). The x-axis of the
35options for companies to use in this framework: market penetration, 35matrix focuses on the firm's markets and also determines if the firm is looking
36market development, product development, and diversification (see 36to enter new markets or innovate in its current markets. The y-axis of the
37**Figure 1**). The x-axis of the matrix focuses on the firm\'s markets 37matrix focuses on the firm's products and determines if the firm wants to
38and also determines if the firm is looking to enter new markets or 38pursue strategies around their existing products or explore new products.
39innovate in its current markets. The y-axis of the matrix focuses on the
40firm\'s products and determines if the firm wants to pursue strategies
41around their existing products or explore new products.
42 39
43![The Ansoff Matrix by JaisonAbeySabu, Own work, CC BY-SA 40![The Ansoff Matrix by JaisonAbeySabu, Own work, CC BY-SA
443.0](https://img.cleberg.net/blog/20191203-the-ansoff-matrix/ansoff_matrix-min.png) 413.0](https://img.cleberg.net/blog/20191203-the-ansoff-matrix/ansoff_matrix-min.png)
@@ -47,82 +44,76 @@ around their existing products or explore new products.
47 44
48## Market Penetration 45## Market Penetration
49 46
50The most straightforward strategy in the Ansoff matrix is to focus on 47The most straightforward strategy in the Ansoff matrix is to focus on existing
51existing products in existing markets, also known as market 48products in existing markets, also known as market penetration(2019). Companies
52penetration(2019). Companies such as Coca-Cola have used market 49such as Coca-Cola have used market penetration successfully by investing a lot
53penetration successfully by investing a lot of money to get further 50of money to get further value out of their current markets. Coca-Cola does this
54value out of their current markets. Coca-Cola does this by introducing 51by introducing new features such as Christmas-themed bottles, personal names on
55new features such as Christmas-themed bottles, personal names on the 52the bottles, and other marketing schemes.
56bottles, and other marketing schemes.
57 53
58## Market Development 54## Market Development
59 55
60Market development extends existing products into new markets in an 56Market development extends existing products into new markets in an attempt to
61attempt to increase the number of buyers. One interesting way that 57increase the number of buyers. One interesting way that Coca-Cola used this
62Coca-Cola used this strategy comes from the stigma that Diet Coke is a 58strategy comes from the stigma that Diet Coke is a woman's drink(2019).
63woman\'s drink(2019). Coca-Cola introduced Coca-Cola Zero, which 59Coca-Cola introduced Coca-Cola Zero, which contained the same nutritional
64contained the same nutritional content as Diet Coke, but was packaged in 60content as Diet Coke, but was packaged in a dark black can to appear more
65a dark black can to appear more \"manly\"(2019). 61"manly"(2019).
66 62
67## Product Development 63## Product Development
68 64
69Product development uses existing markets to introduce new products so 65Product development uses existing markets to introduce new products so that the
70that the firm can better meet customer needs(2019). The extreme end of 66firm can better meet customer needs(2019). The extreme end of diversification is
71diversification is home to companies such as Johnson & Johnson, a 67home to companies such as Johnson & Johnson, a healthcare company that has
72healthcare company that has developed a business portfolio of more than 68developed a business portfolio of more than 60,000 different products(2019).
7360,000 different products(2019). Johnson & Johnson\'s dedication to 69Johnson & Johnson's dedication to continuous diversification has led them to a
74continuous diversification has led them to a balance sheet rating of 70balance sheet rating of "AAA", industry recognition for diversification, and
75\"AAA\", industry recognition for diversification, and increases in 71increases in their investor dividends for 57 consecutive years(2019).
76their investor dividends for 57 consecutive years(2019).
77 72
78## Related Diversification 73## Related Diversification
79 74
80Diversification, the final strategy of the Ansoff Matrix, is more 75Diversification, the final strategy of the Ansoff Matrix, is more difficult than
81difficult than the others since it involves exploring both new markets 76the others since it involves exploring both new markets and new products.
82and new products. Related diversification is a diversification strategy 77Related diversification is a diversification strategy that closely relates to
83that closely relates to the firm\'s core business. Coca-Cola\'s best 78the firm's core business. Coca-Cola's best example of related diversification
84example of related diversification is its acquisition of Glaceau and 79is its acquisition of Glaceau and Vitamin Water, which expanded their drinking
85Vitamin Water, which expanded their drinking lines of business(2019). 80lines of business(2019).
86 81
87## Unrelated Diversification 82## Unrelated Diversification
88 83
89Unrelated diversification is a diversification strategy that does not 84Unrelated diversification is a diversification strategy that does not really
90really relate to the firm\'s core business but still diversifies their 85relate to the firm's core business but still diversifies their business
91business portfolio. A good example of this would be a coffee company who 86portfolio. A good example of this would be a coffee company who has decided to
92has decided to enter the market for bicycle sales. The main purpose of 87enter the market for bicycle sales. The main purpose of this strategy is to an
93this strategy is to an extremely diverse company that will not go 88extremely diverse company that will not go bankrupt if one market goes through
94bankrupt if one market goes through difficult times. However, this 89difficult times. However, this requires a lot of independent skills and heavy
95requires a lot of independent skills and heavy investments since the 90investments since the company most likely cannot easily transfer knowledge
96company most likely cannot easily transfer knowledge between the markets 91between the markets they compete in.
97they compete in.
98 92
99# Requirements for Success 93# Requirements for Success
100 94
101To use the Ansoff Matrix framework, managers need to formulate corporate 95To use the Ansoff Matrix framework, managers need to formulate corporate goals
102goals and objectives. Without goals and direction, management frameworks 96and objectives. Without goals and direction, management frameworks do not
103do not present much practical utility. Further, the Ansoff Matrix 97present much practical utility. Further, the Ansoff Matrix requires the managers
104requires the managers involved to make tactical decisions and create a 98involved to make tactical decisions and create a path for the company to take
105path for the company to take toward their goals. Lastly, both the Ansoff 99toward their goals. Lastly, both the Ansoff Matrix needs to consider both
106Matrix needs to consider both internal and external perspectives 100internal and external perspectives throughout the strategy formulation process.
107throughout the strategy formulation process. 101
108 102One interesting probability is that companies will be using multiple strategic
109One interesting probability is that companies will be using multiple 103planning and management frameworks at the same time. While this may sound like
110strategic planning and management frameworks at the same time. While 104it could crowd the management process, there are numerous reasons to do so. For
111this may sound like it could crowd the management process, there are 105example, the Ansoff Matrix and the Balanced Scorecard are relatively popular,
112numerous reasons to do so. For example, the Ansoff Matrix and the 106and they cover entirely different parts of a company's strategy. Using the
113Balanced Scorecard are relatively popular, and they cover entirely 107results from the Balanced Scorecard could inform a company of the potential
114different parts of a company\'s strategy. Using the results from the 108product and market demands, such as from customer or supplier survey results, to
115Balanced Scorecard could inform a company of the potential product and 109help the company determine which Ansoff Matrix strategy to pursue. However, a
116market demands, such as from customer or supplier survey results, to 110combined approach at this level would require mature frameworks and focused
117help the company determine which Ansoff Matrix strategy to pursue. 111managers who are able to strategize at a high level.
118However, a combined approach at this level would require mature 112
119frameworks and focused managers who are able to strategize at a high 113Lastly, it should be noted that the author of the Ansoff matrix, Igor Ansoff,
120level. 114often used the term [paralysis by
121 115analysis](https://en.wikipedia.org/wiki/Analysis_paralysis) to explain the
122Lastly, it should be noted that the author of the Ansoff matrix, Igor 116mistake of companies who overuse analysis and spend too much time planning.
123Ansoff, often used the term [paralysis by 117Companies need to understand the utility of a strategic management framework
124analysis](https://en.wikipedia.org/wiki/Analysis_paralysis) to explain 118while ensuring that the company is poised to execute as efficiently as they have
125the mistake of companies who overuse analysis and spend too much time 119planned.
126planning. Companies need to understand the utility of a strategic
127management framework while ensuring that the company is poised to
128execute as efficiently as they have planned.
content/blog/2019-12-16-password-security.md +85 −95
@@ -9,119 +9,109 @@ draft = false
9 9
10## Why Does It Matter? 10## Why Does It Matter?
11 11
12Information security, including passwords and identities, has become one 12Information security, including passwords and identities, has become one of the
13of the most important digital highlights of the last decade. With 13most important digital highlights of the last decade. With [billions of people
14[billions of people affected by data breaches each 14affected by data breaches each
15year](https://www.usatoday.com/story/money/2018/12/28/data-breaches-2018-billions-hit-growing-number-cyberattacks/2413411002/), 15year](https://www.usatoday.com/story/money/2018/12/28/data-breaches-2018-billions-hit-growing-number-cyberattacks/2413411002/),
16there\'s a greater need to introduce strong information security 16there's a greater need to introduce strong information security systems. If you
17systems. If you think you\'ve been part of a breach, or you want to 17think you've been part of a breach, or you want to check and see, you can use
18check and see, you can use [Have I Been 18[Have I Been Pwned](https://haveibeenpwned.com/) to see if your email has been
19Pwned](https://haveibeenpwned.com/) to see if your email has been 19involved in any public breaches. Remember that there's a possibility that a
20involved in any public breaches. Remember that there\'s a possibility 20company experienced a breach and did not report it to anyone.
21that a company experienced a breach and did not report it to anyone.
22 21
23## How Do I Protect Myself? 22## How Do I Protect Myself?
24 23
25The first place to start with any personal security check-up is to 24The first place to start with any personal security check-up is to gather a list
26gather a list of all the different websites, apps, or programs that 25of all the different websites, apps, or programs that require you to have login
27require you to have login credentials. Optionally, once you know where 26credentials. Optionally, once you know where your information is being stored,
28your information is being stored, you can sort the list from the 27you can sort the list from the most-important items such as banks or government
29most-important items such as banks or government logins to less 28logins to less important items such as your favorite meme site. You will want to
30important items such as your favorite meme site. You will want to ensure 29ensure that your critical logins are secure before getting to the others.
31that your critical logins are secure before getting to the others.
32 30
33Once you think you have a good idea of all your different authentication 31Once you think you have a good idea of all your different authentication
34methods, I recommend using a password manager such as 32methods, I recommend using a password manager such as
35[Bitwarden](https://bitwarden.com/). Using a password manager allows you 33[Bitwarden](https://bitwarden.com/). Using a password manager allows you to
36to automatically save your logins, create randomized passwords, and 34automatically save your logins, create randomized passwords, and transfer
37transfer passwords across devices. However, you\'ll need to memorize 35passwords across devices. However, you'll need to memorize your "vault
38your \"vault password\" that allows you to open the password manager. 36password" that allows you to open the password manager. It's important to make
39It\'s important to make this something hard to guess since it would 37this something hard to guess since it would allow anyone who has it to access
40allow anyone who has it to access every password you\'ve stored in 38every password you've stored in there.
41there.
42 39
43Personally, I recommend using a 40Personally, I recommend using a
44[passphrase](https://en.wikipedia.org/wiki/Passphrase) instead of a 41[passphrase](https://en.wikipedia.org/wiki/Passphrase) instead of a
45[password](https://en.wikipedia.org/wiki/Password) for your vault 42[password](https://en.wikipedia.org/wiki/Password) for your vault password.
46password. Instead of using a string of characters (whether random or 43Instead of using a string of characters (whether random or simple), use a phrase
47simple), use a phrase and add in symbols and a number. For example, your 44and add in symbols and a number. For example, your vault password could be
48vault password could be `Racing-Alphabet-Gourd-Parrot3`. Swap 45`Racing-Alphabet-Gourd-Parrot3`. Swap the symbols out for whichever symbol you
49the symbols out for whichever symbol you want, move the number around, 46want, move the number around, and fine-tune the passphrase until you are
50and fine-tune the passphrase until you are confident that you can 47confident that you can remember it whenever necessary.
51remember it whenever necessary. 48
52 49Once you've stored your passwords, make sure you continually check up on your
53Once you\'ve stored your passwords, make sure you continually check up 50account and make sure you aren't following bad password practices. Krebs on
54on your account and make sure you aren\'t following bad password 51Security has a great [blog post on password
55practices. Krebs on Security has a great [blog post on password 52recommendations](https://krebsonsecurity.com/password-dos-and-donts/). Any time
56recommendations](https://krebsonsecurity.com/password-dos-and-donts/). 53that a data breach happens, make sure you check to see if you were included, and
57Any time that a data breach happens, make sure you check to see if you 54if you need to reset any account passwords.
58were included, and if you need to reset any account passwords.
59 55
60# Developers 56# Developers
61 57
62## What Are the Basic Requirements? 58## What Are the Basic Requirements?
63 59
64When developing any password-protected application, there are a few 60When developing any password-protected application, there are a few basic rules
65basic rules that anyone should follow even if they do not follow any 61that anyone should follow even if they do not follow any official guidelines
66official guidelines such as NIST. The foremost practice is to require 62such as NIST. The foremost practice is to require users to use passwords that
67users to use passwords that are at least 8 characters and cannot easily 63are at least 8 characters and cannot easily be guessed. This sounds extremely
68be guessed. This sounds extremely simple, but it requires quite a few 64simple, but it requires quite a few different strategies. First, the application
69different strategies. First, the application should check the potential 65should check the potential passwords against a dictionary of insecure passwords
70passwords against a dictionary of insecure passwords such 66such `password`, `1234abc`, or `application_name`.
71`password`, `1234abc`, or 67
72`application_name`. 68Next, the application should offer guidance on the strength of passwords being
73 69entered during enrollment. Further, NIST officially recommends **not**
74Next, the application should offer guidance on the strength of passwords 70implementing any composition rules that make passwords hard to remember (e.g.
75being entered during enrollment. Further, NIST officially recommends 71passwords with letters, numbers, and special characters) and instead encouraging
76**not\*** implementing any composition rules that make passwords hard to 72the use of long pass phrases which can include spaces. It should be noted that
77remember (e.g. passwords with letters, numbers, and special characters) 73to be able to keep spaces within passwords, all unicode characters should be
78and instead encouraging the use of long pass phrases which can include 74supported, and passwords should not be truncated.
79spaces. It should be noted that to be able to keep spaces within
80passwords, all unicode characters should be supported, and passwords
81should not be truncated.
82 75
83## What Does NIST Recommend? 76## What Does NIST Recommend?
84 77
85The National Institute of Standards and Technology 78The National Institute of Standards and Technology
86([NIST](https://www.nist.gov)) in the US Department of Commerce 79([NIST](https://www.nist.gov)) in the US Department of Commerce regularly
87regularly publishes information around information security and digital 80publishes information around information security and digital identity
88identity guidelines. Recently, NIST published [Special Publication 81guidelines. Recently, NIST published [Special Publication
89800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html): Digital 82800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html): Digital Identity
90Identity Guidelines and Authentication and Lifecycle Management. 83Guidelines and Authentication and Lifecycle Management.
91 84
92> A Memorized Secret authenticator - commonly referred to as a password 85> A Memorized Secret authenticator - commonly referred to as a password or, if
93> or, if numeric, a PIN - is a secret value intended to be chosen and 86> numeric, a PIN - is a secret value intended to be chosen and memorized by the
94> memorized by the user. Memorized secrets need to be of sufficient 87> user. Memorized secrets need to be of sufficient complexity and secrecy that
95> complexity and secrecy that it would be impractical for an attacker to 88> it would be impractical for an attacker to guess or otherwise discover the
96> guess or otherwise discover the correct secret value. A memorized 89> correct secret value. A memorized secret is something you know.
97> secret is something you know.
98> 90>
99> - NIST Special Publication 800-63B 91> - NIST Special Publication 800-63B
100 92
101NIST offers a lot of guidance on passwords, but I\'m going to highlight 93NIST offers a lot of guidance on passwords, but I'm going to highlight just a
102just a few of the important factors: 94few of the important factors:
103 95
104- Require passwords to be a minimum of 8 characters (6 characters if 96- Require passwords to be a minimum of 8 characters (6 characters if randomly
105 randomly generated and be generated using an approved random bit 97 generated and be generated using an approved random bit generator).
106 generator). 98- Compare potential passwords against a list that contains values known to be
107- Compare potential passwords against a list that contains values 99 commonly-used, expected, or compromised.
108 known to be commonly-used, expected, or compromised. 100- Offer guidance on password strength, such as a strength meter.
109- Offer guidance on password strength, such as a strength meter. 101- Implement a rate-limiting mechanism to limit the number of failed
110- Implement a rate-limiting mechanism to limit the number of failed 102 authentication attempts for each user account.
111 authentication attempts for each user account. 103- Do not require composition rules for passwords and do not require passwords to
112- Do not require composition rules for passwords and do not require 104 be changed periodically (unless compromised).
113 passwords to be changed periodically (unless compromised). 105- Allow pasting of user identification and passwords to facilitate the use of
114- Allow pasting of user identification and passwords to facilitate the 106 password managers.
115 use of password managers. 107- Allow users to view the password as it is being entered.
116- Allow users to view the password as it is being entered. 108- Use secure forms of communication and storage, including salting and hashing
117- Use secure forms of communication and storage, including salting and 109 passwords using a one-way key derivation function.
118 hashing passwords using a one-way key derivation function. 110
119 111NIST offers further guidance on other devices that require specific security
120NIST offers further guidance on other devices that require specific 112policies, querying for passwords, and more. All the information discussed so far
121security policies, querying for passwords, and more. All the information 113comes from [NIST SP800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html) but
122discussed so far comes from [NIST 114NIST offers a lot of information on digital identities, enrollment, identity
123SP800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html) but NIST 115proofing, authentication, lifecycle management, federation, and assertions in
124offers a lot of information on digital identities, enrollment, identity 116the total [NIST SP800-63 Digital Identity
125proofing, authentication, lifecycle management, federation, and
126assertions in the total [NIST SP800-63 Digital Identity
127Guidelines](https://pages.nist.gov/800-63-3/). 117Guidelines](https://pages.nist.gov/800-63-3/).
content/blog/2020-01-25-linux-software.md +72 −87
@@ -12,32 +12,31 @@ draft = false
12![Etcher 12![Etcher
13Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/etcher.png) 13Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/etcher.png)
14 14
15[Etcher](https://www.balena.io/etcher/) is a quick and easy way to burn 15[Etcher](https://www.balena.io/etcher/) is a quick and easy way to burn ISO
16ISO images to CDs and USB devices. There are two different ways you can 16images to CDs and USB devices. There are two different ways you can install this
17install this program. First, you can navigate to the [official 17program. First, you can navigate to the [official
18website](https://www.balena.io/etcher/) and download the AppImage file, 18website](https://www.balena.io/etcher/) and download the AppImage file, which
19which can run without installation. 19can run without installation.
20 20
21However, AppImage files are not executable by default, so you\'ll either 21However, AppImage files are not executable by default, so you'll either need to
22need to right-click to open the properties of the file and click the 22right-click to open the properties of the file and click the "Allow executing
23\"Allow executing file as program\" box in the Permissions tab or use 23file as program" box in the Permissions tab or use the following command:
24the following command:
25 24
26```sh 25```sh
27chmod u+x FILE_NAME 26chmod u+x FILE_NAME
28``` 27```
29 28
30If you don\'t like AppImage files or just prefer repositories, you can 29If you don't like AppImage files or just prefer repositories, you can use the
31use the following commands to add the author\'s repository and install 30following commands to add the author's repository and install it through the
32it through the command-line only. 31command-line only.
33 32
34First, you\'ll have to echo the repo and write it to a list file: 33First, you'll have to echo the repo and write it to a list file:
35 34
36```sh 35```sh
37echo "deb https://deb.etcher.io stable etcher" | sudo tee /etc/apt/sources.list.d/balena-etcher.list 36echo "deb https://deb.etcher.io stable etcher" | sudo tee /etc/apt/sources.list.d/balena-etcher.list
38``` 37```
39 38
40Next, add the application keys to Ubuntu\'s keyring: 39Next, add the application keys to Ubuntu's keyring:
41 40
42```sh 41```sh
43sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61 42sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61
@@ -49,8 +48,7 @@ Finally, update the repositories and install the app.
49sudo apt update && sudo apt install balena-etcher-electron 48sudo apt update && sudo apt install balena-etcher-electron
50``` 49```
51 50
52Using Arch, Manjaro, or another distro using the AUR? Use this command 51Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
53instead:
54 52
55```sh 53```sh
56sudo pacman -S etcher 54sudo pacman -S etcher
@@ -61,12 +59,11 @@ sudo pacman -S etcher
61![Atom 59![Atom
62Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/atom.png) 60Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/atom.png)
63 61
64[Atom](https://atom.io) is the self-proclaimed \"hackable text editor 62[Atom](https://atom.io) is the self-proclaimed "hackable text editor for the
65for the 21st century\". This text editor is made by GitHub, [now owned 6321st century". This text editor is made by GitHub, [now owned by
66by
67Microsoft](https://news.microsoft.com/2018/06/04/microsoft-to-acquire-github-for-7-5-billion/), 64Microsoft](https://news.microsoft.com/2018/06/04/microsoft-to-acquire-github-for-7-5-billion/),
68and has some of the best add-ons available to customize the layout and 65and has some of the best add-ons available to customize the layout and abilities
69abilities of the app. 66of the app.
70 67
71First, add the Atom repository to your sources. 68First, add the Atom repository to your sources.
72 69
@@ -80,25 +77,24 @@ Next, update your package listings and install atom.
80sudo apt update && sudo apt install atom 77sudo apt update && sudo apt install atom
81``` 78```
82 79
83If you have issues updating your packages with the Atom repository, 80If you have issues updating your packages with the Atom repository, you'll need
84you\'ll need to use the snap package described below instead of the 81to use the snap package described below instead of the repository. To remove the
85repository. To remove the repository we just added, use this command: 82repository we just added, use this command:
86 83
87```sh 84```sh
88sudo add-apt-repository -r ppa:webupd8team/atom 85sudo add-apt-repository -r ppa:webupd8team/atom
89``` 86```
90 87
91You can also install Atom as a snap package, but it must be installed 88You can also install Atom as a snap package, but it must be installed with the
92with the `--classic` flag. A [full explanation is 89`--classic` flag. A [full explanation is
93available](https://language-bash.com/blog/how-to-snap-introducing-classic-confinement) 90available](https://language-bash.com/blog/how-to-snap-introducing-classic-confinement)
94if you\'d like to read more about why you need the classic flag. 91if you'd like to read more about why you need the classic flag.
95 92
96```sh 93```sh
97snap install atom --classic 94snap install atom --classic
98``` 95```
99 96
100Using Arch, Manjaro, or another distro using the AUR? Use this command 97Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
101instead:
102 98
103```sh 99```sh
104sudo pacman -S atom 100sudo pacman -S atom
@@ -109,28 +105,25 @@ sudo pacman -S atom
109![Visual Studio Code 105![Visual Studio Code
110Code](https://img.cleberg.net/blog/20200125-the-best-linux-software/vscode.png) 106Code](https://img.cleberg.net/blog/20200125-the-best-linux-software/vscode.png)
111 107
112[Visual Studio Code](https://code.visualstudio.com) is yet another 108[Visual Studio Code](https://code.visualstudio.com) is yet another fantastic
113fantastic choice for programming on Linux, especially if you need those 109choice for programming on Linux, especially if you need those extra add-ons to
114extra add-ons to spice up your late-night coding sessions. The theme 110spice up your late-night coding sessions. The theme used in the screenshot is
115used in the screenshot is 111[Mars](https://marketplace.visualstudio.com/items?itemName=EliverLara.mars) by
116[Mars](https://marketplace.visualstudio.com/items?itemName=EliverLara.mars) 112theme creator [Eliver Lara](https://github.com/EliverLara), who makes a ton of
117by theme creator [Eliver Lara](https://github.com/EliverLara), who makes 113great themes for VS Code, Atom, and various Linux desktop environments.
118a ton of great themes for VS Code, Atom, and various Linux desktop 114
119environments. 115To install VS Code, you'll need to download the `.deb` file from the official
120 116website. Once you've downloaded the file, either double-click it to install
121To install VS Code, you\'ll need to download the `.deb` file 117through the Software Center or run the following command:
122from the official website. Once you\'ve downloaded the file, either
123double-click it to install through the Software Center or run the
124following command:
125 118
126```sh 119```sh
127sudo dpkg -i FILE_NAME.deb 120sudo dpkg -i FILE_NAME.deb
128``` 121```
129 122
130You can also install VS Code as a snap package, but it must be installed 123You can also install VS Code as a snap package, but it must be installed with
131with the `--classic` flag. A [full explanation is 124the `--classic` flag. A [full explanation is
132available](https://language-bash.com/blog/how-to-snap-introducing-classic-confinement) 125available](https://language-bash.com/blog/how-to-snap-introducing-classic-confinement)
133if you\'d like to read more about why you need the classic flag. 126if you'd like to read more about why you need the classic flag.
134 127
135```sh 128```sh
136snap install code --classic 129snap install code --classic
@@ -148,19 +141,18 @@ sudo pacman -S yay binutils make gcc pkg-config fakeroot yay -S visual-studio-co
148![Gnome Tweaks 141![Gnome Tweaks
149Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/gnome-tweaks.png) 142Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/gnome-tweaks.png)
150 143
151[Gnome Tweaks](https://gitlab.gnome.org/GNOME/gnome-tweaks) is the 144[Gnome Tweaks](https://gitlab.gnome.org/GNOME/gnome-tweaks) is the ultimate tool
152ultimate tool to use if you want to customize your GNOME desktop 145to use if you want to customize your GNOME desktop environment. This is how you
153environment. This is how you can switch application themes (GTK), shell 146can switch application themes (GTK), shell themes, icons, fonts, and more. To
154themes, icons, fonts, and more. To install GNOME Tweaks on Ubuntu, you 147install GNOME Tweaks on Ubuntu, you just need to install the official package.
155just need to install the official package.
156 148
157```sh 149```sh
158sudo apt install gnome-tweaks 150sudo apt install gnome-tweaks
159``` 151```
160 152
161If you\'ve installed Manjaro or Arch with Gnome, you should have the 153If you've installed Manjaro or Arch with Gnome, you should have the tweak tool
162tweak tool pre-installed. If you\'re on Fedora, this tool is available 154pre-installed. If you're on Fedora, this tool is available as an official
163as an official package: 155package:
164 156
165```sh 157```sh
166sudo dnf install gnome-tweaks 158sudo dnf install gnome-tweaks
@@ -171,22 +163,20 @@ sudo dnf install gnome-tweaks
171![Steam 163![Steam
172Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png) 164Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png)
173 165
174[Steam](https://steampowered.com) is one of the most popular gaming 166[Steam](https://steampowered.com) is one of the most popular gaming libraries
175libraries for computers and is one of the main reasons that many people 167for computers and is one of the main reasons that many people have been able to
176have been able to switch to Linux in recent years, thanks to Steam 168switch to Linux in recent years, thanks to Steam Proton, which makes it easier
177Proton, which makes it easier to play games not officially created for 169to play games not officially created for Linux platforms.
178Linux platforms.
179 170
180To install Steam on Ubuntu, you just need to install the official 171To install Steam on Ubuntu, you just need to install the official package.
181package.
182 172
183```sh 173```sh
184sudo apt install steam-installer 174sudo apt install steam-installer
185``` 175```
186 176
187For Arch-based systems, you\'ll simply need to install the 177For Arch-based systems, you'll simply need to install the `steam` package.
188`steam` package. However, this requires that you enable the 178However, this requires that you enable the `multilib` source. To do so, use the
189`multilib` source. To do so, use the following command: 179following command:
190 180
191```sh 181```sh
192sudo nano /etc/pacman.conf 182sudo nano /etc/pacman.conf
@@ -220,27 +210,26 @@ Here.](./2020-01-26-steam-on-ntfs-drives.html)
220![Neofetch 210![Neofetch
221Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/neofetch.png) 211Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/neofetch.png)
222 212
223[Neofetch](https://github.com/dylanaraps/neofetch) is a customizable 213[Neofetch](https://github.com/dylanaraps/neofetch) is a customizable tool used
224tool used in the command-line to show system information. This is 214in the command-line to show system information. This is exceptionally useful if
225exceptionally useful if you want to see your system\'s information 215you want to see your system's information quickly without the clutter of some
226quickly without the clutter of some resource-heavy GUI apps. 216resource-heavy GUI apps.
227 217
228This is an official package if you\'re running Ubuntu 17.04 or later, so 218This is an official package if you're running Ubuntu 17.04 or later, so simply
229simply use the following command: 219use the following command:
230 220
231```sh 221```sh
232sudo apt install neofetch 222sudo apt install neofetch
233``` 223```
234 224
235If you\'re running Ubuntu 16.10 or earlier, you\'ll have to use a series 225If you're running Ubuntu 16.10 or earlier, you'll have to use a series of
236of commands: 226commands:
237 227
238```sh 228```sh
239sudo add-apt-repository ppa:dawidd0811/neofetch; sudo apt update; sudo apt install neofetch 229sudo add-apt-repository ppa:dawidd0811/neofetch; sudo apt update; sudo apt install neofetch
240``` 230```
241 231
242Using Arch, Manjaro, or another distro using the AUR? Use this command 232Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
243instead:
244 233
245```sh 234```sh
246sudo pacman -S neofetch 235sudo pacman -S neofetch
@@ -251,31 +240,27 @@ sudo pacman -S neofetch
251![yt-dlp 240![yt-dlp
252Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/yt-dlp.png) 241Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/yt-dlp.png)
253 242
254[yt-dlp](https://github.com/yt-dlp/yt-dlp) is an extremely handy 243[yt-dlp](https://github.com/yt-dlp/yt-dlp) is an extremely handy command-line
255command-line tool that allows you to download video or audio files from 244tool that allows you to download video or audio files from various websites,
256various websites, such as YouTube. There are a ton of different options 245such as YouTube. There are a ton of different options when running this package,
257when running this package, so be sure to run `yt-dlp --help` 246so be sure to run `yt-dlp --help` first to look through everything you can do
258first to look through everything you can do (or give up and search for 247(or give up and search for the best config online).
259the best config online).
260 248
261While this shouldn\'t be a problem for most users, yt-dlp requires 249While this shouldn't be a problem for most users, yt-dlp requires Python 2.6,
262Python 2.6, 2.7, or 3.2+ to work correctly, so install Python if you 2502.7, or 3.2+ to work correctly, so install Python if you don't have it already.
263don\'t have it already. You can check to see if you have Python 251You can check to see if you have Python installed by running:
264installed by running:
265 252
266```sh 253```sh
267python -V 254python -V
268``` 255```
269 256
270To get the youtube-dl package, simply curl the URL and output the 257To get the youtube-dl package, simply curl the URL and output the results.
271results.
272 258
273```sh 259```sh
274sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp 260sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
275``` 261```
276 262
277Finally, make the file executable so that it can be run from the 263Finally, make the file executable so that it can be run from the command-line.
278command-line.
279 264
280```sh 265```sh
281sudo chmod a+rx /usr/local/bin/yt-dlp 266sudo chmod a+rx /usr/local/bin/yt-dlp
content/blog/2020-01-26-steam-on-ntfs.md +30 −33
@@ -10,29 +10,28 @@ draft = false
10![Steam 10![Steam
11Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png) 11Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png)
12 12
13If you want to see how to install Steam on Linux, see my other post: 13If you want to see how to install Steam on Linux, see my other post: [Linux
14[Linux Software](../linux-software/). 14Software](../linux-software/).
15 15
16Are you having trouble launching games, even though they\'ve installed 16Are you having trouble launching games, even though they've installed
17correctly? This may happen if you\'re storing your games on an 17correctly? This may happen if you're storing your games on an NTFS-formatted
18NTFS-formatted drive. This shouldn\'t be an issue if you\'re storing 18drive. This shouldn't be an issue if you're storing your games on the same
19your games on the same drive that Steam is on, but some gamers prefer to 19drive that Steam is on, but some gamers prefer to put Steam on their main drive
20put Steam on their main drive and game files on another SSD or HDD. 20and game files on another SSD or HDD.
21 21
22To fix this problem, you\'ll need to try a few things. First, you\'ll 22To fix this problem, you'll need to try a few things. First, you'll need to
23need to install the `ntfs-3g` package, which is meant for 23install the `ntfs-3g` package, which is meant for better interoperability with
24better interoperability with Linux. 24Linux.
25 25
26```sh 26```sh
27sudo apt install ntfs-3g 27sudo apt install ntfs-3g
28``` 28```
29 29
30Next, you should set up the `/etc/fstab` file to 30Next, you should set up the `/etc/fstab` file to automatically mount your drives
31automatically mount your drives on boot. To automatically mount your 31on boot. To automatically mount your drives when the computer boots up, you'll
32drives when the computer boots up, you\'ll have to create the folders 32have to create the folders you want to mount your drive to first. I store mine
33you want to mount your drive to first. I store mine in the 33in the `/mnt` folder using names that I'll recognize, but you can create your
34`/mnt` folder using names that I\'ll recognize, but you can 34folders wherever you want.
35create your folders wherever you want.
36 35
37```sh 36```sh
38mkdir /path/to/folder 37mkdir /path/to/folder
@@ -44,28 +43,27 @@ For example:
44mkdir /mnt/steam_library 43mkdir /mnt/steam_library
45``` 44```
46 45
47To automatically mount drives upon system boot, you will need to collect 46To automatically mount drives upon system boot, you will need to collect a few
48a few items. The UUID is the identification number connected to 47items. The UUID is the identification number connected to whichever drive
49whichever drive you\'re using to store Steam games. 48you're using to store Steam games.
50 49
51Drives are usually labeled similar to `/dev/nvme0n1p1` or 50Drives are usually labeled similar to `/dev/nvme0n1p1` or `/dev/sda1`, so
52`/dev/sda1`, so you\'ll need to find the line in the output 51you'll need to find the line in the output of the command below that correlates
53of the command below that correlates to your drive and copy the UUID 52to your drive and copy the UUID over to the `/etc/fstab` file.
54over to the `/etc/fstab` file.
55 53
56```sh 54```sh
57sudo blkid | grep UUID= 55sudo blkid | grep UUID=
58``` 56```
59 57
60Next, you\'ll need your `uid` and `gid`. To find 58Next, you'll need your `uid` and `gid`. To find these, run the following
61these, run the following command: 59command:
62 60
63```sh 61```sh
64id -u && id -g 62id -u && id -g
65``` 63```
66 64
67Now that you have collected the necessary information, open the 65Now that you have collected the necessary information, open the `/etc/fstab`
68`/etc/fstab` file: 66file:
69 67
70```sh 68```sh
71sudo nano /etc/fstab 69sudo nano /etc/fstab
@@ -78,9 +76,8 @@ Each drive you want to mount on boot should have its own line in the
78UUID=B64E53824E5339F7 /mnt/steam_library ntfs-3g uid=1000,gid=1000 0 0 76UUID=B64E53824E5339F7 /mnt/steam_library ntfs-3g uid=1000,gid=1000 0 0
79``` 77```
80 78
81Now all you need to do is unmount your drive and re-mount it. You can 79Now all you need to do is unmount your drive and re-mount it. You can unmount
82unmount the drive by doing this (be sure to use the correct drive name 80the drive by doing this (be sure to use the correct drive name here):
83here):
84 81
85```sh 82```sh
86sudo umount /dev/sdxX 83sudo umount /dev/sdxX
@@ -92,6 +89,6 @@ You can re-mount all your drives by executing the following:
92sudo mount -a 89sudo mount -a
93``` 90```
94 91
95If you don\'t know what your drive name is, or you\'re nervous about 92If you don't know what your drive name is, or you're nervous about unmounting
96unmounting and re-mounting, simply reboot your computer, and it will be 93and re-mounting, simply reboot your computer, and it will be done for you
97done for you automatically. 94automatically.
content/blog/2020-02-09-cryptography-basics.md +135 −148
@@ -7,174 +7,161 @@ draft = false
7 7
8# Similar Article Available 8# Similar Article Available
9 9
10If you haven\'t already, feel free to read my post on [AES 10If you haven't already, feel free to read my post on [AES
11Encryption](../aes-encryption/). 11Encryption](../aes-encryption/).
12 12
13# What is Cryptography? 13# What is Cryptography?
14 14
15In layman\'s terms, cryptography is a process that can change data from 15In layman's terms, cryptography is a process that can change data from a
16a readable format into an unreadable format (and vice-versa) through a 16readable format into an unreadable format (and vice-versa) through a series of
17series of processes and secrets. More technically, this is the Internet 17processes and secrets. More technically, this is the Internet Security
18Security Glossary\'s definition: 18Glossary's definition:
19 19
20> \[Cryptography is\] the mathematical science that deals with 20> [Cryptography is] the mathematical science that deals with transforming data
21> transforming data to render its meaning unintelligible (i.e., to hide 21> to render its meaning unintelligible (i.e., to hide its semantic content),
22> its semantic content), prevent its undetected alteration, or prevent 22> prevent its undetected alteration, or prevent its unauthorized use. If the
23> its unauthorized use. If the transformation is reversible, 23> transformation is reversible, cryptography also deals with restoring encrypted
24> cryptography also deals with restoring encrypted data to an 24> data to an intelligible form.
25> intelligible form.
26> 25>
27> - [Internet Security Glossary 26> - [Internet Security Glossary (2000)](https://tools.ietf.org/html/rfc2828)
28> (2000)](https://tools.ietf.org/html/rfc2828)
29 27
30Cryptography cannot offer protection against the loss of data; it simply 28Cryptography cannot offer protection against the loss of data; it simply offers
31offers encryption methods to protect data at-rest and data in-traffic. 29encryption methods to protect data at-rest and data in-traffic. At a high-level,
32At a high-level, encrypted is when plaintext data is encrypted to 30encrypted is when plaintext data is encrypted to ciphertext (a secure form of
33ciphertext (a secure form of text that cannot be understood unless 31text that cannot be understood unless decrypted back to plaintext). The
34decrypted back to plaintext). The encryption process is completed 32encryption process is completed through the use of a mathematical function that
35through the use of a mathematical function that utilizes one or more 33utilizes one or more values called keys to encrypt or decrypt the data.
36values called keys to encrypt or decrypt the data.
37 34
38# Key Elements of Cryptographic Systems 35# Key Elements of Cryptographic Systems
39 36
40To create or evaluate a cryptographic system, you need to know the 37To create or evaluate a cryptographic system, you need to know the essential
41essential pieces to the system: 38pieces to the system:
42 39
43- **Encryption Algorithm (Primitive):\*** A mathematical process that 40- **Encryption Algorithm (Primitive):** A mathematical process that encrypts
44 encrypts and decrypts data. 41 and decrypts data.
45- **Encryption Key:\*** A string of bits used within the encryption 42- **Encryption Key:** A string of bits used within the encryption algorithm as
46 algorithm as the secret that allows successful encryption or 43 the secret that allows successful encryption or decryption of data.
47 decryption of data. 44- **Key Length (Size):** The maximum number of bits within the encryption key.
48- **Key Length (Size):\*** The maximum number of bits within the 45 It's important to remember that key size is regulated in many countries.
49 encryption key. It\'s important to remember that key size is 46- **Message Digest:** A smaller, fixed-size bit string version of the original
50 regulated in many countries. 47 message. This is practically infeasible to reverse, which is why it's
51- **Message Digest:\*** A smaller, fixed-size bit string version of 48 commonly used to verify integrity.
52 the original message. This is practically infeasible to reverse,
53 which is why it\'s commonly used to verify integrity.
54 49
55# Symmetric Systems (Secret Key Cryptography) 50# Symmetric Systems (Secret Key Cryptography)
56 51
57Symmetric cryptography utilizes a secret, bidirectional key to perform 52Symmetric cryptography utilizes a secret, bidirectional key to perform both
58both encryption and decryption of the data. The most common 53encryption and decryption of the data. The most common implementation of
59implementation of symmetric cryptography is the Advanced Encryption 54symmetric cryptography is the Advanced Encryption Standard, which uses keys that
60Standard, which uses keys that are 128 bits to 256 bits in size. This 55are 128 bits to 256 bits in size. This standard came after the National
61standard came after the National Institute of Standards and Technology 56Institute of Standards and Technology (NIST) decided to retire the Data
62(NIST) decided to retire the Data Encryption Standard (DES) in 2001. 57Encryption Standard (DES) in 2001.
63 58
64Since brute force attacks strongly correlate with key length, the 56-bit 59Since brute force attacks strongly correlate with key length, the 56-bit key
65key length of DES was considered insecure after it was publicly broken 60length of DES was considered insecure after it was publicly broken in under 24
66in under 24 hours. However, there is a modern implementation of DES 61hours. However, there is a modern implementation of DES called Triple DES where
67called Triple DES where the DES method is applied three times to each 62the DES method is applied three times to each data block.
68data block. 63
69 64The main advantages to symmetric systems are the ease of use, since only one key
70The main advantages to symmetric systems are the ease of use, since only 65is required for both encryption and decryption, and the simplicity of the
71one key is required for both encryption and decryption, and the 66algorithms. This helps with bulk data encryption that may unnecessarily waste
72simplicity of the algorithms. This helps with bulk data encryption that 67time and power using asymmetric systems.
73may unnecessarily waste time and power using asymmetric systems. 68
74 69However, symmetric systems have disadvantages to keep in mind. Since the key is
75However, symmetric systems have disadvantages to keep in mind. Since the 70private, it can be difficult to safely distribute keys to communication
76key is private, it can be difficult to safely distribute keys to 71partners. Additionally, the key cannot be used to sign messages since it's
77communication partners. Additionally, the key cannot be used to sign 72necessary to keep the key private.
78messages since it\'s necessary to keep the key private.
79 73
80# Asymmetric Systems (Public Key Cryptography) 74# Asymmetric Systems (Public Key Cryptography)
81 75
82Asymmetric cryptography utilizes two keys within the system: a secret 76Asymmetric cryptography utilizes two keys within the system: a secret key that
83key that is privately-held and a public key that can be distributed 77is privately-held and a public key that can be distributed freely. The
84freely. The interesting aspect of asymmetric cryptography is that either 78interesting aspect of asymmetric cryptography is that either key can be used to
85key can be used to encrypt the data, there\'s no rule that dictates 79encrypt the data, there's no rule that dictates which key must be used for
86which key must be used for encryption. Once one key is used to encrypt 80encryption. Once one key is used to encrypt the data, only the other key can be
87the data, only the other key can be used to decrypt the data. This means 81used to decrypt the data. This means that if the private key encrypts the data,
88that if the private key encrypts the data, only the public key can 82only the public key can decrypt the data.
89decrypt the data. 83
90 84An advantage of this system is that if you successfully decrypt data using one
91An advantage of this system is that if you successfully decrypt data 85of the keys, you can be sure of the sender since only the other key could have
92using one of the keys, you can be sure of the sender since only the 86encrypted the data.
93other key could have encrypted the data. 87
94 88One of the major implementations of an asymmetric system is a digital signature.
95One of the major implementations of an asymmetric system is a digital 89A digital signature can be generated using the sender's private key, or a
96signature. A digital signature can be generated using the sender\'s 90one-way hash function and is used to provide assurance for the integrity and
97private key, or a one-way hash function and is used to provide assurance 91authenticity of the message. A couple common message digest algorithms are
98for the integrity and authenticity of the message. A couple common 92SHA-256 and SHA-512, which securely compress data and produce a 128-bit message
99message digest algorithms are SHA-256 and SHA-512, which securely 93digest.
100compress data and produce a 128-bit message digest. 94
101 95It should be noted that man-in-the-middle attacks are one of the risks with
102It should be noted that man-in-the-middle attacks are one of the risks 96digital signatures and public keys. To combat this, applications often use a
103with digital signatures and public keys. To combat this, applications 97public key infrastructure (PKI) to independently authenticate the validity of
104often use a public key infrastructure (PKI) to independently 98signatures and keys.
105authenticate the validity of signatures and keys.
106 99
107Due to the large key size and [inefficient mathematical 100Due to the large key size and [inefficient mathematical
108functions](https://crypto.stackexchange.com/a/591) of asymmetric 101functions](https://crypto.stackexchange.com/a/591) of asymmetric encryption,
109encryption, elliptical curve cryptography (ECC) is often used to 102elliptical curve cryptography (ECC) is often used to increase security while
110increase security while using fewer resources. 103using fewer resources.
111 104
112# Applications of Cryptographic Systems 105# Applications of Cryptographic Systems
113 106
114There are quite a few implementations of cryptographic systems around 107There are quite a few implementations of cryptographic systems around the world.
115the world. Here are a few popular examples: 108Here are a few popular examples:
116 109
117**Transport Layer Security (TLS):\*** One of the most famous 110**Transport Layer Security (TLS):** One of the most famous cryptographic
118cryptographic solutions created is TLS, a session-layered or 111solutions created is TLS, a session-layered or connection-layered internet
119connection-layered internet protocol that allows for secure 112protocol that allows for secure communications between browsers and servers.
120communications between browsers and servers. Using handshakes, peer 113Using handshakes, peer negotiation, and authentication allows TLS to prevent
121negotiation, and authentication allows TLS to prevent eavesdropping and 114eavesdropping and malicious transformation of data. The major reason for TLS
122malicious transformation of data. The major reason for TLS popularity is 115popularity is that a major vulnerability was found in the SSL protocol in 2014.
123that a major vulnerability was found in the SSL protocol in 2014. 116Instead of SSL, TLS can be used with HTTP to form HTTPS and is the preferred
124Instead of SSL, TLS can be used with HTTP to form HTTPS and is the 117method for modern web development due to its increased security.
125preferred method for modern web development due to its increased 118
126security. 119**Secure Hypertext Transfer Protocol (HTTPS):** An application layer protocol
127 120that allows for secure transport of data between servers and web clients. One of
128**Secure Hypertext Transfer Protocol (HTTPS):\*** An application layer 121the unique parts of HTTPS is that it uses a secured port number instead of the
129protocol that allows for secure transport of data between servers and 122default web port address.
130web clients. One of the unique parts of HTTPS is that it uses a secured 123
131port number instead of the default web port address. 124**Virtual Private Network (VPN):** VPNs are made to securely extend a private
132 125network across public networks by utilizing an encrypted layered tunneling
133**Virtual Private Network (VPN):\*** VPNs are made to securely extend a 126protocol paired with an authentication method, such as usernames and passwords.
134private network across public networks by utilizing an encrypted layered 127This technology originally allowed remote employees to access their company's
135tunneling protocol paired with an authentication method, such as 128data but have evolved into one of the top choices for anyone who wishes to mask
136usernames and passwords. This technology originally allowed remote 129their sensitive personal data.
137employees to access their company\'s data but have evolved into one of 130
138the top choices for anyone who wishes to mask their sensitive personal 131**Internet Protocol Security (IPSec):** This protocol suite facilitates
139data. 132communication between two or more hosts or subnets by authenticating and
140 133encrypting the data packets. IPSec is used in a lot of VPNs to establish the VPN
141**Internet Protocol Security (IPSec):\*** This protocol suite 134connection through the transport and tunnel mode encryption methods. IPSec
142facilitates communication between two or more hosts or subnets by 135encrypts just the data portion of packets in the transport methods, but it
143authenticating and encrypting the data packets. IPSec is used in a lot 136encrypts both the data and headers in the tunnel method (introducing an
144of VPNs to establish the VPN connection through the transport and tunnel 137additional header for authentication).
145mode encryption methods. IPSec encrypts just the data portion of packets 138
146in the transport methods, but it encrypts both the data and headers in 139**Secure Shell (SSH):** SSH is another network protocol used to protect
147the tunnel method (introducing an additional header for authentication). 140network services by authenticating users through a secure channel. This protocol
148 141is often used for command-line (shell) functions such as remote shell commands,
149**Secure Shell (SSH):\*** SSH is another network protocol used to 142logins, and file transfers.
150protect network services by authenticating users through a secure 143
151channel. This protocol is often used for command-line (shell) functions 144**Kerberos:** Developed by MIT, Kerberos is a computer-network authentication
152such as remote shell commands, logins, and file transfers. 145protocol that works on the basis of tickets to allow nodes communicating over a
153 146non-secure network to prove their identity to one another securely. This is most
154**Kerberos:\*** Developed by MIT, Kerberos is a computer-network 147commonly used in business environments when used as the authentication and
155authentication protocol that works on the basis of tickets to allow 148encryption method for Windows Active Directory (AD).
156nodes communicating over a non-secure network to prove their identity to
157one another securely. This is most commonly used in business
158environments when used as the authentication and encryption method for
159Windows Active Directory (AD).
160 149
161# Cybersecurity Controls 150# Cybersecurity Controls
162 151
163If you\'re someone who needs solutions on how to control risks 152If you're someone who needs solutions on how to control risks associated with
164associated with utilizing a crytograhpic system, start with a few basic 153utilizing a crytograhpic system, start with a few basic controls:
165controls: 154
166 155- **Policies:** A policy on the use of cryptographic controls for protection
167- **Policies:\*** A policy on the use of cryptographic controls for 156 of information is implemented and is in accordance with organizational
168 protection of information is implemented and is in accordance with 157 objectives.
169 organizational objectives. 158- **Key management:** A policy on the use, protection and lifetime of
170- **Key management:\*** A policy on the use, protection and lifetime 159 cryptographic keys is implemented through the entire application lifecycle.
171 of cryptographic keys is implemented through the entire application 160- **Key size:** The organization has researched the optimal key size for their
172 lifecycle. 161 purposes, considering national laws, required processing power, and longevity
173- **Key size:\*** The organization has researched the optimal key size 162 of the solution.
174 for their purposes, considering national laws, required processing 163- **Algorithm selection:** Implemented algorithms are sufficiently appropriate
175 power, and longevity of the solution. 164 for the business of the organization, robust, and align with recommended
176- **Algorithm selection:\*** Implemented algorithms are sufficiently 165 guidelines.
177 appropriate for the business of the organization, robust, and align 166- **Protocol configuration:** Protocols have been reviewed and configured
178 with recommended guidelines. 167 suitable to the purpose of the business.
179- **Protocol configuration:\*** Protocols have been reviewed and
180 configured suitable to the purpose of the business.
content/blog/2020-03-25-session-messenger.md +64 −69
@@ -7,67 +7,65 @@ draft = false
7 7
8# Privacy Warning 8# Privacy Warning
9 9
10The company behind Session (Loki Foundation) is from Australia. If you 10The company behind Session (Loki Foundation) is from Australia. If you didn't
11didn\'t know, Australia has introduced 11know, Australia has introduced
12[legislation](https://parlinfo.aph.gov.au/parlInfo/download/legislation/bills/r6195_aspassed/toc_pdf/18204b01.pdf) 12[legislation](https://parlinfo.aph.gov.au/parlInfo/download/legislation/bills/r6195_aspassed/toc_pdf/18204b01.pdf)
13mandating companies comply with government requests to build backdoor 13mandating companies comply with government requests to build backdoor access
14access into applications. For more information, read my article on [AES 14into applications. For more information, read my article on [AES
15Encryption](./2020-01-25-aes-encryption.html). 15Encryption](./2020-01-25-aes-encryption.html).
16 16
17# About Session 17# About Session
18 18
19[Session](https://getsession.org) is a private, cross-platform messaging 19[Session](https://getsession.org) is a private, cross-platform messaging app
20app from the [Loki Foundation](https://loki.foundation). As someone who 20from the [Loki Foundation](https://loki.foundation). As someone who has spent
21has spent years looking for quality alternatives to major messaging 21years looking for quality alternatives to major messaging apps, I was excited
22apps, I was excited when I first heard about Session. Reading through 22when I first heard about Session. Reading through [Session's white
23[Session\'s white paper](https://arxiv.org/pdf/2002.04609.pdf), you can 23paper](https://arxiv.org/pdf/2002.04609.pdf), you can learn the technologies
24learn the technologies behind the Session app. Part of the security of 24behind the Session app. Part of the security of Session comes from the Signal
25Session comes from the Signal protocol, which was forked as the origin 25protocol, which was forked as the origin of Session.
26of Session.
27 26
28> Session is an end-to-end encrypted messenger that removes sensitive 27> Session is an end-to-end encrypted messenger that removes sensitive metadata
29> metadata collection, and is designed for people who want privacy and 28> collection, and is designed for people who want privacy and freedom from any
30> freedom from any forms of surveillance. 29> forms of surveillance.
31 30
32In general, this app promises security through end-to-end encryption, 31In general, this app promises security through end-to-end encryption,
33decentralized onion routing, and private identities. The biggest change 32decentralized onion routing, and private identities. The biggest change that the
34that the Loki Foundation has made to the Signal protocol is removing the 33Loki Foundation has made to the Signal protocol is removing the need for a phone
35need for a phone number. Instead, a random identification string is 34number. Instead, a random identification string is generated for any session you
36generated for any session you create. This means you can create a new 35create. This means you can create a new session for each device if you want to,
37session for each device if you want to, or link new devices with your 36or link new devices with your ID.
38ID.
39 37
40Since Session\'s website and white paper describe the details of 38Since Session's website and white paper describe the details of Session's
41Session\'s security, I\'m going to focus on using the app in this post. 39security, I'm going to focus on using the app in this post.
42 40
43# Features 41# Features
44 42
45Since most people are looking for an alternative to a popular chat app, 43Since most people are looking for an alternative to a popular chat app, I am
46I am going to list out the features that Session has so that you are 44going to list out the features that Session has so that you are able to
47able to determine if the app would suit your needs: 45determine if the app would suit your needs:
48 46
49- Multiple device linking (via QR code or ID) 47- Multiple device linking (via QR code or ID)
50- App locking via device screen lock, password, or fingerprint 48- App locking via device screen lock, password, or fingerprint
51- Screenshot blocking 49- Screenshot blocking
52- Incognito keyboard 50- Incognito keyboard
53- Read receipts and typing indicators 51- Read receipts and typing indicators
54- Mobile notification customization 52- Mobile notification customization
55- Old message deletion and conversation limit 53- Old message deletion and conversation limit
56- Backups 54- Backups
57- Recovery phrase 55- Recovery phrase
58- Account deletion, including ID, messages, sessions, and contacts 56- Account deletion, including ID, messages, sessions, and contacts
59 57
60# Downloads 58# Downloads
61 59
62I have tested this app on Ubuntu 19.10, Android 10, macOS Monterey, and 60I have tested this app on Ubuntu 19.10, Android 10, macOS Monterey, and iOS 15.
63iOS 15. All apps have worked well without many issues. 61All apps have worked well without many issues.
64 62
65Below is a brief overview of the Session app on Linux. To get this app, 63Below is a brief overview of the Session app on Linux. To get this app, you'll
66you\'ll need to go to the [Downloads](https://getsession.org/download/) 64need to go to the [Downloads](https://getsession.org/download/) page and click
67page and click to link to the operating system you\'re using. 65to link to the operating system you're using.
68 66
69For Linux, it will download an AppImage that you\'ll need to enable with 67For Linux, it will download an AppImage that you'll need to enable with the
70the following command: 68following command:
71 69
72```sh 70```sh
73sudo chmod u+x session-messenger-desktop-linux-x86_64-1.0.5.AppImage 71sudo chmod u+x session-messenger-desktop-linux-x86_64-1.0.5.AppImage
@@ -78,12 +76,12 @@ Options](https://img.cleberg.net/blog/20200325-session-private-messenger/session
78 76
79# Creating an Account 77# Creating an Account
80 78
81Once you\'ve installed the app, simply run the app and create your 79Once you've installed the app, simply run the app and create your unique
82unique Session ID. It will look something like this: 80Session ID. It will look something like this:
83`05af1835afdd63c947b47705867501d6373f486aa1ae05b1f2f3fcd24570eba608`. 81`05af1835afdd63c947b47705867501d6373f486aa1ae05b1f2f3fcd24570eba608`.
84 82
85You\'ll need to set a display name and, optionally, a password. If you 83You'll need to set a display name and, optionally, a password. If you set a
86set a password, you will need to enter it every time you open the app. 84password, you will need to enter it every time you open the app.
87 85
88![Session Login 86![Session Login
89(Linux)](https://img.cleberg.net/blog/20200325-session-private-messenger/session_linux_login.png) 87(Linux)](https://img.cleberg.net/blog/20200325-session-private-messenger/session_linux_login.png)
@@ -96,42 +94,39 @@ Authentication](https://img.cleberg.net/blog/20200325-session-private-messenger/
96 94
97# Start Messaging 95# Start Messaging
98 96
99Once you\'ve created your account and set up your profile details, the 97Once you've created your account and set up your profile details, the next step
100next step is to start messaging other people. To do so, you\'ll need to 98is to start messaging other people. To do so, you'll need to share your Session
101share your Session ID with other people. From this point, it\'s fairly 99ID with other people. From this point, it's fairly straightforward and acts
102straightforward and acts like any other messaging app, so I won\'t dive 100like any other messaging app, so I won't dive into much detail here.
103into much detail here.
104 101
105## macOS 102## macOS
106 103
107![macOS 104![macOS
108Conversations](https://img.cleberg.net/blog/20200325-session-private-messenger/session_macos_conversations.png) 105Conversations](https://img.cleberg.net/blog/20200325-session-private-messenger/session_macos_conversations.png)
109 106
110One key feature to note is that the desktop application now provides a 107One key feature to note is that the desktop application now provides a helpful
111helpful pop-up box explaining the process that Session uses to hide your 108pop-up box explaining the process that Session uses to hide your IP address:
112IP address:
113 109
114![IP Address Help 110![IP Address Help
115Box](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ip.png) 111Box](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ip.png)
116 112
117## iOS 113## iOS
118 114
119The mobile app is quite simple and effective, giving you all the 115The mobile app is quite simple and effective, giving you all the standard mobile
120standard mobile messaging options you\'d expect. 116messaging options you'd expect.
121 117
122![iOS 118![iOS
123App](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ios.png) 119App](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ios.png)
124 120
125# Potential Issues 121# Potential Issues
126 122
127I\'ve discovered one annoying issue that would prevent from using this 123I've discovered one annoying issue that would prevent from using this app
128app regularly. On a mobile device, there have been issues with receiving 124regularly. On a mobile device, there have been issues with receiving messages on
129messages on time. Even with battery optimization disabled and no network 125time. Even with battery optimization disabled and no network restrictions,
130restrictions, Session notifications sometimes do not display until I 126Session notifications sometimes do not display until I open the app or the
131open the app or the conversation itself and wait a few moments. This is 127conversation itself and wait a few moments. This is actually one of the reasons
132actually one of the reasons I stopped using Signal (this seems fixed as 128I stopped using Signal (this seems fixed as of my updates in 2021/2022, so I
133of my updates in 2021/2022, so I wouldn\'t worry about this issue 129wouldn't worry about this issue anymore).
134anymore). 130
135 131Looking for another messenger instead of Session? I recommend Signal, Matrix,
136Looking for another messenger instead of Session? I recommend Signal, 132and IRC.
137Matrix, and IRC.
content/blog/2020-05-03-homelab.md +87 −98
@@ -7,16 +7,15 @@ draft = false
7 7
8# What is a Homelab? 8# What is a Homelab?
9 9
10Starting as a developer, I have largely stayed away from hardware-based 10Starting as a developer, I have largely stayed away from hardware-based hobbies
11hobbies (other than building a gaming desktop). However, as the 11(other than building a gaming desktop). However, as the quarantine for COVID-19
12quarantine for COVID-19 stretches out further and further, I found 12stretches out further and further, I found myself bored and in search of new
13myself bored and in search of new hobbies. After spending the last few 13hobbies. After spending the last few months browsing the
14months browsing the [r/homelab](https://www.reddit.com/r/homelab/) 14[r/homelab](https://www.reddit.com/r/homelab/) subreddit, I decided it was time
15subreddit, I decided it was time to jump in and try things out for 15to jump in and try things out for myself.
16myself.
17 16
18Since I am a beginner and just recently graduated from college, 17Since I am a beginner and just recently graduated from college, everything I've
19everything I\'ve done so far in my homelab is fairly low-budget. 18done so far in my homelab is fairly low-budget.
20 19
21# Hardware 20# Hardware
22 21
@@ -26,141 +25,131 @@ Diagram](https://img.cleberg.net/blog/20200503-homelab/homelab-min.png)
26### Raspberry Pi 4 25### Raspberry Pi 4
27 26
28Luckily, I had actually purchased a [Raspberry Pi 27Luckily, I had actually purchased a [Raspberry Pi
294](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) before 284](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) before the
30the quarantine started so that I could try to keep Plex Media Center 29quarantine started so that I could try to keep Plex Media Center running, even
31running, even while my desktop computer was turned off. I started here, 30while my desktop computer was turned off. I started here, using the Pi to hold
32using the Pi to hold Plex and Pi-hole until I grew tired with the slow 31Plex and Pi-hole until I grew tired with the slow performance.
33performance.
34 32
35Here are the specifications for the Pi 4: 33Here are the specifications for the Pi 4:
36 34
37- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz 35- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz
38- 4GB LPDDR4-3200 SDRAM 36- 4GB LPDDR4-3200 SDRAM
39- Gigabit Ethernet 37- Gigabit Ethernet
40- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode) 38- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode)
41- 64 GB MicroSD Card 39- 64 GB MicroSD Card
42 40
43## Dell Optiplex 5040 41## Dell Optiplex 5040
44 42
45Since I wasn\'t happy with the Pi as my main server, I turned to 43Since I wasn't happy with the Pi as my main server, I turned to Craigslist. I
46Craigslist. I know a lot of other homelabbers use Ebay, but I can\'t 44know a lot of other homelabbers use Ebay, but I can't seem to ever trust it
47seem to ever trust it enough to purchase items on there. So I used 45enough to purchase items on there. So I used Craigslist and found a Dell
48Craigslist and found a Dell Optiplex 5040 desktop computer on sale for 46Optiplex 5040 desktop computer on sale for $90. While this computer might be
49\$90. While this computer might be underpowered, it was one of the few 47underpowered, it was one of the few computers under $100 that was available
50computers under \$100 that was available during quarantine. 48during quarantine.
51 49
52Here are the specifications for the Dell Optiplex 5040: 50Here are the specifications for the Dell Optiplex 5040:
53 51
54- Intel Core i3 6100 52- Intel Core i3 6100
55- 8GB RAM DDR3 53- 8GB RAM DDR3
56- Intel HD Graphics 54- Intel HD Graphics
57- Gigabit Ethernet 55- Gigabit Ethernet
58- 500GB Hard Drive 56- 500GB Hard Drive
59 57
60While this hardware would be awful for a work computer or a gaming rig, 58While this hardware would be awful for a work computer or a gaming rig, it
61it turned out to be wonderful for my server purposes. The only 59turned out to be wonderful for my server purposes. The only limitation I have
62limitation I have found so far is the CPU. The i3-6100 only has enough 60found so far is the CPU. The i3-6100 only has enough power for a single 4k video
63power for a single 4k video transcode at a time. I haven\'t tested more 61transcode at a time. I haven't tested more than three 1080p streams at a time,
64than three 1080p streams at a time, but the maximum amount of streams 62but the maximum amount of streams I've ever actually used is two.
65I\'ve ever actually used is two.
66 63
67## WD easystore 10TB & 8TB 64## WD easystore 10TB & 8TB
68 65
69Application storage and temporary files are stored on the internal hard 66Application storage and temporary files are stored on the internal hard drive of
70drive of the server, but all media files (movies, tv, games, books, etc) 67the server, but all media files (movies, tv, games, books, etc) are stored
71are stored externally on my WD easystore hard drive. Creating auto-boot 68externally on my WD easystore hard drive. Creating auto-boot configurations in
72configurations in the `/etc/fstab` file on my server allows 69the `/etc/fstab` file on my server allows the hard drives to automatically mount
73the hard drives to automatically mount whenever I need to restart my 70whenever I need to restart my server.
74server.
75 71
76> Update: In March 2022, I shucked the hard drives out of their external 72> Update: In March 2022, I shucked the hard drives out of their external cases,
77> cases, put some Kapton tape on the third power pin to prevent power 73> put some Kapton tape on the third power pin to prevent power shutdowns, and
78> shutdowns, and stuck them inside my server tower using internal SATA 74> stuck them inside my server tower using internal SATA cables.
79> cables.
80 75
81## Netgear Unmanaged Switch 76## Netgear Unmanaged Switch
82 77
83To manage all the ethernet cords used by my homelab, my desktop, and my 78To manage all the ethernet cords used by my homelab, my desktop, and my living
84living room media center, I purchased an 8-port gigabit ethernet switch 79room media center, I purchased an 8-port gigabit ethernet switch for $50 at my
85for \$50 at my local computer store. This is probably much more than I 80local computer store. This is probably much more than I should have spent on an
86should have spent on an unmanaged switch, but I am comfortable with the 81unmanaged switch, but I am comfortable with the choice.
87choice.
88 82
89## TP-Link Managed Switch 83## TP-Link Managed Switch
90 84
91Since I use the unmanaged switch to group all living room devices 85Since I use the unmanaged switch to group all living room devices together, I
92together, I use the managed switch to configure VLANs and secure my 86use the managed switch to configure VLANs and secure my network.
93network.
94 87
95## Arris TM1602A Modem & Sagecom Fast 5280 Router 88## Arris TM1602A Modem & Sagecom Fast 5280 Router
96 89
97My default modem and router, provided by my ISP, are fairly standard. 90My default modem and router, provided by my ISP, are fairly standard. The Arris
98The Arris modem supports DOCSIS 3.0, which is something that I 91modem supports DOCSIS 3.0, which is something that I definitely wanted as a
99definitely wanted as a minimum. The Sagecom router is also standard, no 92minimum. The Sagecom router is also standard, no fancy bells or whistles.
100fancy bells or whistles. However, it does support DHCP and DHCPv6, which 93However, it does support DHCP and DHCPv6, which is something you can use to
101is something you can use to route all household traffic through a 94route all household traffic through a pi-hole or firewall.
102pi-hole or firewall.
103 95
104## TP-Link EAP 96## TP-Link EAP
105 97
106In order to gain better control over the network, I use my own wireless 98In order to gain better control over the network, I use my own wireless access
107access point instead of the one included in the Sagecom router above. 99point instead of the one included in the Sagecom router above. Now I can control
108Now I can control and organize all of my ethernet connections through 100and organize all of my ethernet connections through the VLANs on the managed
109the VLANs on the managed switch and wireless connections through the 101switch and wireless connections through the VLANS on the EAP.
110VLANS on the EAP.
111 102
112## Generic Printer 103## Generic Printer
113 104
114The last piece to my homelab is a standard wireless printer. Nothing 105The last piece to my homelab is a standard wireless printer. Nothing special
115special here. 106here.
116 107
117# Software 108# Software
118 109
119## Ubuntu Server 20.04 110## Ubuntu Server 20.04
120 111
121While the 20.04 version of Ubuntu was just released, I always like to 112While the 20.04 version of Ubuntu was just released, I always like to experiment
122experiment with new features (and I don\'t mind breaking my system - it 113with new features (and I don't mind breaking my system - it just gives me more
123just gives me more experience learning how to fix things). So, I have 114experience learning how to fix things). So, I have Ubuntu Server 20.04 installed
124Ubuntu Server 20.04 installed on the Dell Optiplex server and Ubuntu 115on the Dell Optiplex server and Ubuntu Server 19.10 installed on the Raspberry
125Server 19.10 installed on the Raspberry Pi. Once I find an acceptable 116Pi. Once I find an acceptable use for the Pi, I will most likely switch the
126use for the Pi, I will most likely switch the operating system. 117operating system.
127 118
128## Docker 119## Docker
129 120
130I am *very* new to Docker, but I have had a lot of fun playing with it 121I am *very* new to Docker, but I have had a lot of fun playing with it so far.
131so far. Docker is used to create containers that can hold all the 122Docker is used to create containers that can hold all the contents of a system
132contents of a system without interfering with other software on the same 123without interfering with other software on the same system. So far, I have
133system. So far, I have successfully installed pi-hole, GitLab, Gogs, and 124successfully installed pi-hole, GitLab, Gogs, and Nextcloud in containers.
134Nextcloud in containers. However, I opted to delete all of those so that 125However, I opted to delete all of those so that I can reconfigure them more
135I can reconfigure them more professionally at a later time. 126professionally at a later time.
136 127
137## Plex Media Server 128## Plex Media Server
138 129
139Plex is a media center software that allows you to organize your movies, 130Plex is a media center software that allows you to organize your movies, TV
140TV shows, music, photos, and videos automatically. It will even download 131shows, music, photos, and videos automatically. It will even download metadata
141metadata for you so that you can easily browse these collections. 132for you so that you can easily browse these collections.
142 133
143## Pi-hole 134## Pi-hole
144 135
145Pi-hole is an alternative ad-blocker that runs at the DNS level, 136Pi-hole is an alternative ad-blocker that runs at the DNS level, allowing you to
146allowing you to block traffic when it hits your network, so that you can 137block traffic when it hits your network, so that you can reject any traffic you
147reject any traffic you deem to be bad. Pi-hole uses blacklists and 138deem to be bad. Pi-hole uses blacklists and whitelists to decide which traffic
148whitelists to decide which traffic block and, luckily, there are a lot 139block and, luckily, there are a lot of pre-made lists out there on Reddit,
149of pre-made lists out there on Reddit, GitHub, etc. 140GitHub, etc.
150 141
151## Nextcloud 142## Nextcloud
152 143
153While I had trouble with the Docker version of Nextcloud, I was very 144While I had trouble with the Docker version of Nextcloud, I was very successful
154successful when setting up the snap version. Using this, I was able to 145when setting up the snap version. Using this, I was able to map Nextcloud to a
155map Nextcloud to a subdomain of a domain I own in Namecheap. 146subdomain of a domain I own in Namecheap. Additionally, Nextcloud has an
156Additionally, Nextcloud has an integration with Let\'s Encrypt that 147integration with Let's Encrypt that allows me to issue certificates
157allows me to issue certificates automatically to any new domain I 148automatically to any new domain I authorize.
158authorize.
159 149
160## Webmin 150## Webmin
161 151
162To monitor my servers, and the processes running on them, I use the 152To monitor my servers, and the processes running on them, I use the Webmin
163Webmin dashboard. This was fairly painless to set up, and I currently 153dashboard. This was fairly painless to set up, and I currently access it
164access it straight through the server\'s IP address. In the future, I 154straight through the server's IP address. In the future, I will be looking to
165will be looking to configure Webmin to use a custom domain just like 155configure Webmin to use a custom domain just like Nextcloud.
166Nextcloud.
content/blog/2020-05-19-customizing-ubuntu.md +89 −100
@@ -7,20 +7,20 @@ draft = false
7 7
8# More Information 8# More Information
9 9
10For inspiration on designing your \*nix computer, check out the 10For inspiration on designing your *nix computer, check out the
11[r/unixporn](https://libredd.it/r/unixporn) subreddit! 11[r/unixporn](https://libredd.it/r/unixporn) subreddit!
12 12
13# Customizing Ubuntu 13# Customizing Ubuntu
14 14
15New to Linux and want to add a personal touch to your machine? One of 15New to Linux and want to add a personal touch to your machine? One of the best
16the best perks of Linux is that it is **extremely\*** customizable. You 16perks of Linux is that it is **extremely** customizable. You can change the
17can change the styles of the windows, shell (status bars/docks), icons, 17styles of the windows, shell (status bars/docks), icons, fonts, terminals, and
18fonts, terminals, and more. 18more.
19 19
20In this post, I\'m going to go through customization on Ubuntu 20.04 20In this post, I'm going to go through customization on Ubuntu 20.04 (GNOME)
21(GNOME) since most new users tend to choose Ubuntu-based distros. If 21since most new users tend to choose Ubuntu-based distros. If you've found a way
22you\'ve found a way to install Arch with i3-gaps, I\'m assuming you know 22to install Arch with i3-gaps, I'm assuming you know how to find more advanced
23how to find more advanced tutorials out there on customizations. 23tutorials out there on customizations.
24 24
25## Required Tools 25## Required Tools
26 26
@@ -28,61 +28,55 @@ how to find more advanced tutorials out there on customizations.
28Tweaks](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-tweaks-min.png) 28Tweaks](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-tweaks-min.png)
29 29
30Ubuntu 20.04 ships with the default desktop environment 30Ubuntu 20.04 ships with the default desktop environment
31[Gnome](https://www.gnome.org/), which includes the handy 31[Gnome](https://www.gnome.org/), which includes the handy `gnome-tweaks` tool to
32`gnome-tweaks` tool to quickly change designs. To install 32quickly change designs. To install this, just open your terminal and enter the
33this, just open your terminal and enter the following command: 33following command:
34 34
35```sh 35```sh
36sudo apt install gnome-tweaks 36sudo apt install gnome-tweaks
37``` 37```
38 38
39After you\'ve finished installing the tool, simply launch the Tweaks 39After you've finished installing the tool, simply launch the Tweaks
40application, and you\'ll be able to access the various customization 40application, and you'll be able to access the various customization options
41options available by default on Ubuntu. You might even like some of the 41available by default on Ubuntu. You might even like some of the pre-installed
42pre-installed options. 42options.
43 43
44## GNOME Application Themes 44## GNOME Application Themes
45 45
46To change the themes applied to applications in GNOME, you will need to 46To change the themes applied to applications in GNOME, you will need to change
47change the Applications dropdown in the Appearance section of Tweaks. To 47the Applications dropdown in the Appearance section of Tweaks. To add more
48add more themes, you will have to find your preferred theme online and 48themes, you will have to find your preferred theme online and follow the steps
49follow the steps below to have it show up in the Tweaks tool. While you 49below to have it show up in the Tweaks tool. While you may find themes anywhere,
50may find themes anywhere, one of the most popular sites for GNOME themes 50one of the most popular sites for GNOME themes is
51is [gnome-look.org](https://www.gnome-look.org/). This website contains 51[gnome-look.org](https://www.gnome-look.org/). This website contains themes for
52themes for applications, shells, icons, and cursors. 52applications, shells, icons, and cursors.
53 53
54Steps to import themes into Tweaks: 54Steps to import themes into Tweaks:
55 55
561. Download the theme. 561. Download the theme.
572. These files are usually compressed (.zip, .tar.gz, .tar.xz), so you 572. These files are usually compressed (.zip, .tar.gz, .tar.xz), so you will need
58 will need to extract the contents. This is easiest when opening the 58 to extract the contents. This is easiest when opening the file explorer,
59 file explorer, right-clicking the compressed file, and choosing 59 right-clicking the compressed file, and choosing "Extract here."
60 \"Extract here.\" 603. Move the theme folder to `/usr/share/themes/`. You can do so with the
613. Move the theme folder to `/usr/share/themes/`. You can do 61 following command: `sudo mv theme-folder/ /usr/share/themes/`.
62 so with the following command: 62 - Icons and cursors will be moved to the `/usr/share/icons/` folder.
63 `sudo mv theme-folder/ /usr/share/themes/`. 63 - Fonts will be moved to the `/usr/share/fonts/` folder Alternatively, you
64 - Icons and cursors will be moved to the 64 can move them to the `/usr/share/fonts/opentype/` or
65 `/usr/share/icons/` folder. 65 `/usr/share/fonts/opentype/` folders, if you have a specific font type.
66 - Fonts will be moved to the `/usr/share/fonts/` folder 664. Close tweaks if it is open. Re-open Tweaks and your new theme will be
67 Alternatively, you can move them to the 67 available in the Applications dropdown in the Appearance section of Tweaks.
68 `/usr/share/fonts/opentype/` or 68
69 `/usr/share/fonts/opentype/` folders, if you have a 69If the theme is not showing up after you've moved it into the themes folder,
70 specific font type. 70you may have uncompressed the folder into a sub-folder. You can check this by
714. Close tweaks if it is open. Re-open Tweaks and your new theme will 71entering the theme folder and listing the contents:
72 be available in the Applications dropdown in the Appearance section
73 of Tweaks.
74
75If the theme is not showing up after you\'ve moved it into the themes
76folder, you may have uncompressed the folder into a sub-folder. You can
77check this by entering the theme folder and listing the contents:
78 72
79```sh 73```sh
80cd /usr/share/themes/Mojave-Dark && ls -la 74cd /usr/share/themes/Mojave-Dark && ls -la
81``` 75```
82 76
83This is an example of what the contents of your theme folder should look 77This is an example of what the contents of your theme folder should look like.
84like. If you just see another folder there, you should move that folder 78If you just see another folder there, you should move that folder up into the
85up into the `/usr/share/themes/` folder. 79`/usr/share/themes/` folder.
86 80
87```sh 81```sh
88cinnamon COPYING gnome-shell gtk-2.0 gtk-3.0 index.theme metacity-1 plank xfwm4 82cinnamon COPYING gnome-shell gtk-2.0 gtk-3.0 index.theme metacity-1 plank xfwm4
@@ -90,77 +84,73 @@ cinnamon COPYING gnome-shell gtk-2.0 gtk-3.0 index.theme metacity-1 plank
90 84
91## GNOME Shell Themes 85## GNOME Shell Themes
92 86
93To change the appearance of the title bar, default dock, app menu, and 87To change the appearance of the title bar, default dock, app menu, and other
94other parts of the GNOME shell, you\'ll need to install the [user 88parts of the GNOME shell, you'll need to install the [user
95themes](https://extensions.gnome.org/extension/19/user-themes/) 89themes](https://extensions.gnome.org/extension/19/user-themes/) extension on
96extension on [Gnome Extensions](https://extensions.gnome.org/). To be 90[Gnome Extensions](https://extensions.gnome.org/). To be able to install
97able to install extensions, you will first need to install the browser 91extensions, you will first need to install the browser extension that the
98extension that the website instructs you to. See this screenshot for the 92website instructs you to. See this screenshot for the blue box with a link to
99blue box with a link to the extension. 93the extension.
100 94
101![Gnome 95![Gnome
102Extensions](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-extensions-min.png) 96Extensions](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-extensions-min.png)
103 97
104After the browser extension is installed, you will need to install the 98After the browser extension is installed, you will need to install the native
105native host connector: 99host connector:
106 100
107```sh 101```sh
108sudo apt install chrome-gnome-shell 102sudo apt install chrome-gnome-shell
109``` 103```
110 104
111Finally, you can go the [user 105Finally, you can go the [user
112themes](https://extensions.gnome.org/extension/19/user-themes/) 106themes](https://extensions.gnome.org/extension/19/user-themes/) extension page
113extension page and click the installation button. This will enable the 107and click the installation button. This will enable the Shell option in Tweaks.
114Shell option in Tweaks. Now you can move shell themes to the 108Now you can move shell themes to the `/usr/share/themes` directory, using the
115`/usr/share/themes` directory, using the same steps mentioned 109same steps mentioned in the previous section, and enable the new theme in
116in the previous section, and enable the new theme in Tweaks. 110Tweaks.
117 111
118## Icons & Cursors 112## Icons & Cursors
119 113
120Icons and cursors are installed exactly the same way, so I\'m grouping 114Icons and cursors are installed exactly the same way, so I'm grouping these
121these together in this post. Both of these items will need to follow the 115together in this post. Both of these items will need to follow the same process
122same process as installing themes, except you will want to move your 116as installing themes, except you will want to move your font folders to the
123font folders to the `/usr/share/icons/` directory instead. 117`/usr/share/icons/` directory instead.
124 118
125## Fonts 119## Fonts
126 120
127Fonts are one of the overlooked parts of customization, but a good font 121Fonts are one of the overlooked parts of customization, but a good font can make
128can make the whole screen look different. For example, I have installed 122the whole screen look different. For example, I have installed the [IBM
129the [IBM Plex](https://github.com/IBM/plex/releases) fonts on my system. 123Plex](https://github.com/IBM/plex/releases) fonts on my system. This follows the
130This follows the same process as installing themes, except you will want 124same process as installing themes, except you will want to move your font
131to move your font folders to the `/usr/share/fonts/` 125folders to the `/usr/share/fonts/` directory instead.
132directory instead.
133 126
134## Terminal 127## Terminal
135 128
136If you spend a lot of time typing commands, you know how important the 129If you spend a lot of time typing commands, you know how important the style and
137style and functionality of the terminal is. After spending a lot of time 130functionality of the terminal is. After spending a lot of time using the default
138using the default GNOME terminal with [unix 131GNOME terminal with [unix
139shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), I decided to 132shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), I decided to try some
140try some different options. I ended up choosing 133different options. I ended up choosing
141[Terminator](https://terminator-gtk3.readthedocs.io/en/latest/) with 134[Terminator](https://terminator-gtk3.readthedocs.io/en/latest/) with
142[zsh](https://en.wikipedia.org/wiki/Z_shell). 135[zsh](https://en.wikipedia.org/wiki/Z_shell).
143 136
144Terminator is great if you need to open multiple terminals at one time 137Terminator is great if you need to open multiple terminals at one time by simply
145by simply right-clicking and splitting the screen into as many terminals 138right-clicking and splitting the screen into as many terminals as you want.
146as you want. While this project hasn\'t been updated in a while, [it is 139While this project hasn't been updated in a while, [it is coming under new
147coming under new 140development](https://github.com/gnome-terminator/terminator/issues/1). However,
148development](https://github.com/gnome-terminator/terminator/issues/1). 141this terminal is great and I haven't experienced any errors yet.
149However, this terminal is great and I haven\'t experienced any errors
150yet.
151 142
152For the shell choice, I decided to choose zsh after trying it out on a 143For the shell choice, I decided to choose zsh after trying it out on a fresh
153fresh Manjaro installation. Zsh is great if you like to change the 144Manjaro installation. Zsh is great if you like to change the themes of your
154themes of your terminal, include icons, or add plugins. 145terminal, include icons, or add plugins.
155 146
156The desktop uses the 147The desktop uses the
157[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) 148[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) to
158to suggest past commands as you type. In addition, it suggests 149suggest past commands as you type. In addition, it suggests corrections if you
159corrections if you misspell a command. Lastly, it uses the 150misspell a command. Lastly, it uses the `af-magic` theme, which adds dashed
160`af-magic` theme, which adds dashed lines between commands, 151lines between commands, moving the user@host tag to the right side of the
161moving the user@host tag to the right side of the terminal, and changes 152terminal, and changes the colors. There are plenty of plugins and themes to
162the colors. There are plenty of plugins and themes to choose from. Just 153choose from. Just figure out what you like and add it to your `~/.zshrc` file!
163figure out what you like and add it to your `~/.zshrc` file!
164 154
165### Steps to Replicate My Terminal 155### Steps to Replicate My Terminal
166 156
@@ -194,10 +184,9 @@ To install zsh-autosuggestions via Oh My Zsh:
194git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 184git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
195``` 185```
196 186
197Then, add the following plugin wording to your `~/.zshrc` 187Then, add the following plugin wording to your `~/.zshrc` file (the default
198file (the default config usually has the `git` plugin 188config usually has the `git` plugin activated, so just add any other plugins to
199activated, so just add any other plugins to the parentheses separated by 189the parentheses separated by a space):
200a space):
201 190
202```sh 191```sh
203nano ~/.zshrc 192nano ~/.zshrc
@@ -207,5 +196,5 @@ nano ~/.zshrc
207plugins=(git zsh-autosuggestions) 196plugins=(git zsh-autosuggestions)
208``` 197```
209 198
210Finally, you need to log out of your computer and log back in so your 199Finally, you need to log out of your computer and log back in so your user shell
211user shell can refresh. 200can refresh.
content/blog/2020-07-20-video-game-sales.md +31 −32
@@ -8,26 +8,25 @@ draft = false
8# Background Information 8# Background Information
9 9
10This dataset (obtained from 10This dataset (obtained from
11[Kaggle](https://www.kaggle.com/gregorut/videogamesales/data)) contains 11[Kaggle](https://www.kaggle.com/gregorut/videogamesales/data)) contains a list
12a list of video games with sales greater than 100,000 copies. It was 12of video games with sales greater than 100,000 copies. It was generated by a
13generated by a scrape of vgchartz.com. 13scrape of vgchartz.com.
14 14
15Fields include: 15Fields include:
16 16
17- Rank: Ranking of overall sales 17- Rank: Ranking of overall sales
18- Name: The game name 18- Name: The game name
19- Platform: Platform of the game release (i.e. PC,PS4, etc.) 19- Platform: Platform of the game release (i.e. PC,PS4, etc.)
20- Year: Year of the game\'s release 20- Year: Year of the game's release
21- Genre: Genre of the game 21- Genre: Genre of the game
22- Publisher: Publisher of the game 22- Publisher: Publisher of the game
23- NA~Sales~: Sales in North America (in millions) 23- NA~Sales~: Sales in North America (in millions)
24- EU~Sales~: Sales in Europe (in millions) 24- EU~Sales~: Sales in Europe (in millions)
25- JP~Sales~: Sales in Japan (in millions) 25- JP~Sales~: Sales in Japan (in millions)
26- Other~Sales~: Sales in the rest of the world (in millions) 26- Other~Sales~: Sales in the rest of the world (in millions)
27- Global~Sales~: Total worldwide sales. 27- Global~Sales~: Total worldwide sales.
28 28
29There are 16,598 records. 2 records were dropped due to incomplete 29There are 16,598 records. 2 records were dropped due to incomplete information.
30information.
31 30
32# Import the Data 31# Import the Data
33 32
@@ -166,18 +165,18 @@ Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/0
166 165
167# Discussion 166# Discussion
168 167
169The purpose of exploring datasets is to ask questions, answer questions, 168The purpose of exploring datasets is to ask questions, answer questions, and
170and discover intelligence that can be used to inform decision-making. 169discover intelligence that can be used to inform decision-making. So, what have
171So, what have we found in this dataset? 170we found in this dataset?
172 171
173Today we simply explored a publicly-available dataset to see what kind 172Today we simply explored a publicly-available dataset to see what kind of
174of information it contained. During that exploration, we found that 173information it contained. During that exploration, we found that video game
175video game sales peaked in 2006. That peak was largely due to Nintendo, 174sales peaked in 2006. That peak was largely due to Nintendo, who sold the top 5
176who sold the top 5 games in 2006 and has a number of games in the top-10 175games in 2006 and has a number of games in the top-10 list for the years
177list for the years 1980-2020. Additionally, the top four platforms by 1761980-2020. Additionally, the top four platforms by global sales (Wii, NES, GB,
178global sales (Wii, NES, GB, DS) are owned by Nintendo. 177DS) are owned by Nintendo.
179 178
180We didn\'t explore everything this dataset has to offer, but we can tell 179We didn't explore everything this dataset has to offer, but we can tell from a
181from a brief analysis that Nintendo seems to rule sales in the video 180brief analysis that Nintendo seems to rule sales in the video gaming world.
182gaming world. Further analysis could provide insight into which genres, 181Further analysis could provide insight into which genres, regions, publishers,
183regions, publishers, or world events are correlated with sales. 182or world events are correlated with sales.
content/blog/2020-07-26-business-analysis.md +63 −69
@@ -7,24 +7,24 @@ draft = false
7 7
8# Background Information 8# Background Information
9 9
10This project aims to help investors learn more about a random city in 10This project aims to help investors learn more about a random city in order to
11order to determine optimal locations for business investments. The data 11determine optimal locations for business investments. The data used in this
12used in this project was obtained using Foursquare\'s developer API. 12project was obtained using Foursquare's developer API.
13 13
14Fields include: 14Fields include:
15 15
16- Venue Name 16- Venue Name
17- Venue Category 17- Venue Category
18- Venue Latitude 18- Venue Latitude
19- Venue Longitude 19- Venue Longitude
20 20
21There are 232 records found using the center of Lincoln as the area of 21There are 232 records found using the center of Lincoln as the area of interest
22interest with a radius of 10,000. 22with a radius of 10,000.
23 23
24# Import the Data 24# Import the Data
25 25
26The first step is the simplest: import the applicable libraries. We will 26The first step is the simplest: import the applicable libraries. We will be
27be using the libraries below for this project. 27using the libraries below for this project.
28 28
29``` python 29``` python
30# Import the Python libraries we will be using 30# Import the Python libraries we will be using
@@ -37,10 +37,10 @@ from pandas.io.json import json_normalize
37from sklearn.cluster import KMeans 37from sklearn.cluster import KMeans
38``` 38```
39 39
40To begin our analysis, we need to import the data for this project. The 40To begin our analysis, we need to import the data for this project. The data we
41data we are using in this project comes directly from the Foursquare 41are using in this project comes directly from the Foursquare API. The first step
42API. The first step is to get the latitude and longitude of the city 42is to get the latitude and longitude of the city being studied (Lincoln, NE) and
43being studied (Lincoln, NE) and setting up the folium map. 43setting up the folium map.
44 44
45``` python 45``` python
46# Define the latitude and longitude, then map the results 46# Define the latitude and longitude, then map the results
@@ -54,11 +54,11 @@ map_LNK
54![Blank 54![Blank
55Map](https://img.cleberg.net/blog/20200726-ibm-data-science/01_blank_map-min.png) 55Map](https://img.cleberg.net/blog/20200726-ibm-data-science/01_blank_map-min.png)
56 56
57Now that we have defined our city and created the map, we need to go get 57Now that we have defined our city and created the map, we need to go get the
58the business data. The Foursquare API will limit the results to 100 per 58business data. The Foursquare API will limit the results to 100 per API call, so
59API call, so we use our first API call below to determine the total 59we use our first API call below to determine the total results that Foursquare
60results that Foursquare has found. Since the total results are 232, we 60has found. Since the total results are 232, we perform the API fetching process
61perform the API fetching process three times (100 + 100 + 32 = 232). 61three times (100 + 100 + 32 = 232).
62 62
63``` python 63``` python
64# Foursquare API credentials 64# Foursquare API credentials
@@ -122,13 +122,12 @@ results3 = requests.get(url3).json()
122 122
123# Clean the Data 123# Clean the Data
124 124
125Now that we have our data in three separate dataframes, we need to 125Now that we have our data in three separate dataframes, we need to combine them
126combine them into a single dataframe and make sure to reset the index so 126into a single dataframe and make sure to reset the index so that we have a
127that we have a unique ID for each business. The 127unique ID for each business. The `get~categorytype~` function below will pull
128`get~categorytype~` function below will pull the categories 128the categories and name from each business's entry in the Foursquare data
129and name from each business\'s entry in the Foursquare data 129automatically. Once all the data has been labeled and combined, the results are
130automatically. Once all the data has been labeled and combined, the 130stored in the `nearby_venues` dataframe.
131results are stored in the `nearby_venues` dataframe.
132 131
133``` python 132``` python
134# This function will extract the category of the venue from the API dictionary 133# This function will extract the category of the venue from the API dictionary
@@ -200,9 +199,9 @@ Data](https://img.cleberg.net/blog/20200726-ibm-data-science/02_clean_data-min.p
200 199
201# Visualize the Data 200# Visualize the Data
202 201
203We now have a complete, clean data set. The next step is to visualize 202We now have a complete, clean data set. The next step is to visualize this data
204this data onto the map we created earlier. We will be using folium\'s 203onto the map we created earlier. We will be using folium's `CircleMarker()`
205`CircleMarker()` function to do this. 204function to do this.
206 205
207``` python 206``` python
208# add markers to map 207# add markers to map
@@ -227,15 +226,14 @@ map](https://img.cleberg.net/blog/20200726-ibm-data-science/03_data_map-min.png)
227 226
228# Clustering: *k-means* 227# Clustering: *k-means*
229 228
230To cluster the data, we will be using the *k-means* algorithm. This 229To cluster the data, we will be using the *k-means* algorithm. This algorithm is
231algorithm is iterative and will automatically make sure that data points 230iterative and will automatically make sure that data points in each cluster are
232in each cluster are as close as possible to each other, while being as 231as close as possible to each other, while being as far as possible away from
233far as possible away from other clusters. 232other clusters.
234 233
235However, we first have to figure out how many clusters to use (defined 234However, we first have to figure out how many clusters to use (defined as the
236as the variable *\'k\'*). To do so, we will use the next two functions 235variable *'k'*). To do so, we will use the next two functions to calculate the
237to calculate the sum of squares within clusters and then return the 236sum of squares within clusters and then return the optimal number of clusters.
238optimal number of clusters.
239 237
240``` python 238``` python
241# This function will return the sum of squares found in the data 239# This function will return the sum of squares found in the data
@@ -273,9 +271,9 @@ def optimal_number_of_clusters(wcss):
273n = optimal_number_of_clusters(sum_of_squares) 271n = optimal_number_of_clusters(sum_of_squares)
274``` 272```
275 273
276Now that we have found that our optimal number of clusters is six, we 274Now that we have found that our optimal number of clusters is six, we need to
277need to perform k-means clustering. When this clustering occurs, each 275perform k-means clustering. When this clustering occurs, each business is
278business is assigned a cluster number from 0 to 5 in the dataframe. 276assigned a cluster number from 0 to 5 in the dataframe.
279 277
280``` python 278``` python
281# set number of clusters equal to the optimal number 279# set number of clusters equal to the optimal number
@@ -288,9 +286,8 @@ kmeans = KMeans(n_clusters=kclusters, random_state=0).fit(cluster_df)
288nearby_venues.insert(0, 'Cluster Labels', kmeans.labels_) 286nearby_venues.insert(0, 'Cluster Labels', kmeans.labels_)
289``` 287```
290 288
291Success! We now have a dataframe with clean business data, along with a 289Success! We now have a dataframe with clean business data, along with a cluster
292cluster number for each business. Now let\'s map the data using six 290number for each business. Now let's map the data using six different colors.
293different colors.
294 291
295``` python 292``` python
296# create map with clusters 293# create map with clusters
@@ -318,12 +315,11 @@ Map](https://img.cleberg.net/blog/20200726-ibm-data-science/04_clusters-min.png)
318 315
319# Investigate Clusters 316# Investigate Clusters
320 317
321Now that we have figured out our clusters, let\'s do a little more 318Now that we have figured out our clusters, let's do a little more analysis to
322analysis to provide more insight into the clusters. With the information 319provide more insight into the clusters. With the information below, we can see
323below, we can see which clusters are more popular for businesses and 320which clusters are more popular for businesses and which are less popular. The
324which are less popular. The results below show us that clusters 0 321results below show us that clusters 0 through 3 are popular, while clusters 4
325through 3 are popular, while clusters 4 and 5 are not very popular at 322and 5 are not very popular at all.
326all.
327 323
328``` python 324``` python
329# Show how many venues are in each cluster 325# Show how many venues are in each cluster
@@ -337,9 +333,9 @@ for x in range(0,6):
337![Venues per 333![Venues per
338Cluster](https://img.cleberg.net/blog/20200726-ibm-data-science/05_venues_per_cluster-min.png) 334Cluster](https://img.cleberg.net/blog/20200726-ibm-data-science/05_venues_per_cluster-min.png)
339 335
340Our last piece of analysis is to summarize the categories of businesses 336Our last piece of analysis is to summarize the categories of businesses within
341within each cluster. With these results, we can clearly see that 337each cluster. With these results, we can clearly see that restaurants, coffee
342restaurants, coffee shops, and grocery stores are the most popular. 338shops, and grocery stores are the most popular.
343 339
344``` python 340``` python
345# Calculate how many venues there are in each category 341# Calculate how many venues there are in each category
@@ -371,19 +367,17 @@ with pd.option_context('display.max_rows', None, 'display.max_columns', None):
371 367
372# Discussion 368# Discussion
373 369
374In this project, we gathered location data for Lincoln, Nebraska, USA 370In this project, we gathered location data for Lincoln, Nebraska, USA and
375and clustered the data using the k-means algorithm in order to identify 371clustered the data using the k-means algorithm in order to identify the unique
376the unique clusters of businesses in Lincoln. Through these actions, we 372clusters of businesses in Lincoln. Through these actions, we found that there
377found that there are six unique business clusters in Lincoln and that 373are six unique business clusters in Lincoln and that two of the clusters are
378two of the clusters are likely unsuitable for investors. The remaining 374likely unsuitable for investors. The remaining four clusters have a variety of
379four clusters have a variety of businesses, but are largely dominated by 375businesses, but are largely dominated by restaurants and grocery stores.
380restaurants and grocery stores. 376
381 377Using this project, investors can now make more informed decisions when deciding
382Using this project, investors can now make more informed decisions when 378the location and category of business in which to invest.
383deciding the location and category of business in which to invest. 379
384 380Further studies may involve other attributes for business locations, such as
385Further studies may involve other attributes for business locations, 381population density, average wealth across the city, or crime rates. In addition,
386such as population density, average wealth across the city, or crime 382further studies may include additional location data and businesses by utilizing
387rates. In addition, further studies may include additional location data 383multiple sources, such as Google Maps and OpenStreetMap.
388and businesses by utilizing multiple sources, such as Google Maps and
389OpenStreetMap.
content/blog/2020-08-22-redirect-github-pages.md +53 −66
@@ -9,18 +9,17 @@ draft = false
9 9
10## Step 1 10## Step 1
11 11
12Add a new file CNAME to your GitHub Pages repository containing only one 12Add a new file CNAME to your GitHub Pages repository containing only one line:
13line: your top-level domain name. E.g.: `example.com` 13your top-level domain name. E.g.: `example.com`
14 14
15## Step 2 15## Step 2
16 16
17\[Optional\] but highly recommended 17[Optional] but highly recommended
18 18
192.1: Remove all other top-level records (prefixed with @) of type A from 192.1: Remove all other top-level records (prefixed with @) of type A from your
20your DNS configuration. 20DNS configuration.
21 21
222.2: Remove a CNAME record for the second-level domain www if it is 222.2: Remove a CNAME record for the second-level domain www if it is present.
23present.
24 23
25## Step 3 24## Step 3
26 25
@@ -34,70 +33,61 @@ Add these 5 entries to the very top of your DNS configuration:
34www CNAME your_github_username.github.io. 33www CNAME your_github_username.github.io.
35``` 34```
36 35
37Replace `your_github_username` with your actual GitHub 36Replace `your_github_username` with your actual GitHub username.
38username.
39 37
40## Step 4 38## Step 4
41 39
42Wait for your DNS changes to propagate. DNS changes aren\'t effective 40Wait for your DNS changes to propagate. DNS changes aren't effective
43immediately. They can take up to a full day to propagate. 41immediately. They can take up to a full day to propagate.
44 42
45# Long answer 43# Long answer
46 44
47This issue has two sides. One is the DNS configuration itself. Another 45This issue has two sides. One is the DNS configuration itself. Another one is
48one is the way GitHub Pages will forward HTTP requests. 46the way GitHub Pages will forward HTTP requests.
49 47
50We need to know a few things to understand what GitHub is trying to say 48We need to know a few things to understand what GitHub is trying to say in their
51in their documentation. 49documentation.
52 50
53## DNS Entry Types 51## DNS Entry Types
54 52
55There are two types of DNS records which interest us: CNAME and A. 53There are two types of DNS records which interest us: CNAME and A.
56 54
57`A` is also known as `Apex` or sometimes as 55`A` is also known as `Apex` or sometimes as `root entry`. It forwards requests
58`root entry`. It forwards requests to a specified fixed IP 56to a specified fixed IP address. `CNAME` entry forwards requests to a specified
59address. `CNAME` entry forwards requests to a specified URL 57URL (actual valid plain text URL, not an IP address).
60(actual valid plain text URL, not an IP address).
61 58
62## DNS Load balancing 59## DNS Load balancing
63 60
64GitHub has one central URL address which accepts all DNS requests for 61GitHub has one central URL address which accepts all DNS requests for GitHub
65GitHub Pages: `http://username.github.io`. That URL is 62Pages: `http://username.github.io`. That URL is resolved to different IP
66resolved to different IP addresses based on your geographical location. 63addresses based on your geographical location. Website hosted on GitHub Pages is
67Website hosted on GitHub Pages is a simple collection of 64a simple collection of `HTML`, `CSS` and `JS` files. GitHub distributes these
68`HTML`, `CSS` and `JS` files. GitHub 65files to different servers across the globe. So that when your browser sends a
69distributes these files to different servers across the globe. So that 66request from Europe, it receives data from a server in Europe. The same is valid
70when your browser sends a request from Europe, it receives data from a 67for the requests from Asia and the USA.
71server in Europe. The same is valid for the requests from Asia and the
72USA.
73 68
74## What GitHub is trying to say 69## What GitHub is trying to say
75 70
76Since `A` records in DNS must contain IP addresses, and they 71Since `A` records in DNS must contain IP addresses, and they must be either
77must be either `185.199.108.153` or 72`185.199.108.153` or `185.199.109.153` or `185.199.110.153` or
78`185.199.109.153` or `185.199.110.153` or 73`185.199.111.153`, there is no way to forward requests to a server located
79`185.199.111.153`, there is no way to forward requests to a 74somewhere in Europe or Asia. Your website hosted at GitHub Pages will be
80server located somewhere in Europe or Asia. Your website hosted at 75downloaded from a central GitHub Pages server. There is a minor risk that if
81GitHub Pages will be downloaded from a central GitHub Pages server. 76GitHub Pages DNS servers (`x.x.x.153`) are down for some reason, all custom
82There is a minor risk that if GitHub Pages DNS servers 77domains which use fixed GitHub Pages IP addresses will not be accessible (their
83(`x.x.x.153`) are down for some reason, all custom domains
84which use fixed GitHub Pages IP addresses will not be accessible (their
85DNS requests will not be resolvable). 78DNS requests will not be resolvable).
86 79
87That is why GitHub strongly suggests to either use a second-level domain 80That is why GitHub strongly suggests to either use a second-level domain for
88for your GitHub Pages (e.g. `blog.example.com`) or use a DNS 81your GitHub Pages (e.g. `blog.example.com`) or use a DNS service provider that
89service provider that supports a record type `ALIAS` that 82supports a record type `ALIAS` that acts as `A` record but forwards request to a
90acts as `A` record but forwards request to a URL address 83URL address (e.g. `username.github.io`) instead of a fixed IP address.
91(e.g. `username.github.io`) instead of a fixed IP address.
92 84
93## How GitHub Pages treats HTTP requests 85## How GitHub Pages treats HTTP requests
94 86
95After a DNS request for `your_github_username.github.io` is 87After a DNS request for `your_github_username.github.io` is resolved into an IP
96resolved into an IP address, e.g. `185.199.108.153` your 88address, e.g. `185.199.108.153` your browser sends an HTTP request to that
97browser sends an HTTP request to that server with an HTTP header 89server with an HTTP header `Host`. Below are `curl` examples that load the same
98`Host`. Below are `curl` examples that load the 90website (these examples might not work if you are behind a proxy server):
99same website (these examples might not work if you are behind a proxy
100server):
101 91
102```sh 92```sh
103curl --header "Host: your_github_username.github.io" http://185.199.108.153/ 93curl --header "Host: your_github_username.github.io" http://185.199.108.153/
@@ -107,31 +97,28 @@ curl --header "Host: example.com" http://185.199.108.153/
107 97
108This way GitHub Pages servers know which user website to serve. 98This way GitHub Pages servers know which user website to serve.
109 99
110> GitHub Pages server will automatically redirect HTTP requests to the 100> GitHub Pages server will automatically redirect HTTP requests to the top-level
111> top-level domain if your `CNAME` file contains 101> domain if your `CNAME` file contains `example.com` but `www.example.com` is
112> `example.com` but `www.example.com` is
113> requested. 102> requested.
114> 103>
115> The same is valid if your `CNAME` file contains 104> The same is valid if your `CNAME` file contains `www.example.com` but the
116> `www.example.com` but the header `Host` in the 105> header `Host` in the `HTTP` request contains `example.com`.
117> `HTTP` request contains `example.com`.
118 106
119## Why can\'t I add a `CNAME` record entry that accepts a top-level request (`@`) to my DNS configuration? 107## Why can't I add a `CNAME` record entry that accepts a top-level request (`@`) to my DNS configuration?
120 108
121Quote from the GitHub Pages documentation: 109Quote from the GitHub Pages documentation:
122 110
123> Warning: Do not create a CNAME record for your custom apex domain! 111> Warning: Do not create a CNAME record for your custom apex domain! Doing so
124> Doing so may cause issues with other services, such as email, on that 112> may cause issues with other services, such as email, on that domain.
125> domain.
126 113
127## References: 114## References:
128 115
1291. [Setting up a custom domain with GitHub 1161. [Setting up a custom domain with GitHub
130 Pages](https://docs.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site) 117 Pages](https://docs.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site)
1312. [My custom domain isn\'t 1182. [My custom domain isn't
132 working](https://docs.github.com/en/github/working-with-github-pages/troubleshooting-custom-domains-and-github-pages) 119 working](https://docs.github.com/en/github/working-with-github-pages/troubleshooting-custom-domains-and-github-pages)
1333. [Cannot access my GitHub Pages website by IP 1203. [Cannot access my GitHub Pages website by IP
134 Address](https://serverfault.com/questions/589370/cannot-access-my-github-pages-website-by-ip-address) 121 Address](https://serverfault.com/questions/589370/cannot-access-my-github-pages-website-by-ip-address)
1354. [How do I set up GitHub Pages to redirect DNS requests from a 1224. [How do I set up GitHub Pages to redirect DNS requests from a subdomain (e.g.
136 subdomain (e.g. www) to the top-level domain (TLD, Apex 123 www) to the top-level domain (TLD, Apex
137 record)?](https://stackoverflow.com/questions/23375422/how-do-i-set-up-github-pages-to-redirect-dns-requests-from-a-subdomain-e-g-www) 124 record)?](https://stackoverflow.com/questions/23375422/how-do-i-set-up-github-pages-to-redirect-dns-requests-from-a-subdomain-e-g-www)
content/blog/2020-08-29-php-auth-flow.md +38 −42
@@ -7,16 +7,15 @@ draft = false
7 7
8# Introduction 8# Introduction
9 9
10When creating websites that will allow users to create accounts, the 10When creating websites that will allow users to create accounts, the developer
11developer always needs to consider the proper authentication flow for 11always needs to consider the proper authentication flow for their app. For
12their app. For example, some developers will utilize an API for 12example, some developers will utilize an API for authentication, some will use
13authentication, some will use OAuth, and some may just use their own 13OAuth, and some may just use their own simple database.
14simple database.
15 14
16For those using pre-built libraries, authentication may simply be a 15For those using pre-built libraries, authentication may simply be a problem of
17problem of copying and pasting the code from their library\'s 16copying and pasting the code from their library's documentation. For example,
18documentation. For example, here\'s the code I use to authenticate users 17here's the code I use to authenticate users with the Tumblr OAuth API for my
19with the Tumblr OAuth API for my Tumblr client, Vox Populi: 18Tumblr client, Vox Populi:
20 19
21``` php 20``` php
22// Start the session 21// Start the session
@@ -41,24 +40,23 @@ $client = new Tumblr\API\Client(
41); 40);
42``` 41```
43 42
44However, developers creating authentication flows from scratch will need 43However, developers creating authentication flows from scratch will need to
45to think carefully about when to make sure a web page will check the 44think carefully about when to make sure a web page will check the user's
46user\'s authenticity. 45authenticity.
47 46
48In this article, we\'re going to look at a simple authentication flow 47In this article, we're going to look at a simple authentication flow using a
49using a MySQL database and PHP. 48MySQL database and PHP.
50 49
51# Creating User Accounts 50# Creating User Accounts
52 51
53The beginning to any type of user authentication is to create a user 52The beginning to any type of user authentication is to create a user account.
54account. This process can take many formats, but the simplest is to 53This process can take many formats, but the simplest is to accept user input
55accept user input from a form (e.g., username and password) and send it 54from a form (e.g., username and password) and send it over to your database. For
56over to your database. For example, here\'s a snippet that shows how to 55example, here's a snippet that shows how to get username and password
57get username and password parameters that would come when a user submits 56parameters that would come when a user submits a form to your PHP script.
58a form to your PHP script.
59 57
60**Note**: Ensure that your password column is large enough to hold the 58**Note**: Ensure that your password column is large enough to hold the hashed
61hashed value (at least 60 characters or longer). 59value (at least 60 characters or longer).
62 60
63``` php 61``` php
64// Get the values from the URL 62// Get the values from the URL
@@ -97,9 +95,9 @@ $conn->close();
97 95
98## Validate Returning Users 96## Validate Returning Users
99 97
100To be able to verify that a returning user has a valid username and 98To be able to verify that a returning user has a valid username and password in
101password in your database is as simple as having users fill out a form 99your database is as simple as having users fill out a form and comparing their
102and comparing their inputs to your database. 100inputs to your database.
103 101
104``` php 102``` php
105// Query the database for username and password 103// Query the database for username and password
@@ -116,24 +114,23 @@ if(password_verify($password_input, $hashed_password)) {
116 114
117# Storing Authentication State 115# Storing Authentication State
118 116
119Once you\'ve created the user\'s account, now you\'re ready to 117Once you've created the user's account, now you're ready to initialize the
120initialize the user\'s session. **You will need to do this on every page 118user's session. **You will need to do this on every page you load while the
121you load while the user is logged in.\*** To do so, simply enter the 119user is logged in.** To do so, simply enter the following code snippet:
122following code snippet:
123 120
124``` php 121``` php
125session_start(); 122session_start();
126``` 123```
127 124
128Once you\'ve initialized the session, the next step is to store the 125Once you've initialized the session, the next step is to store the session in a
129session in a cookie so that you can access it later. 126cookie so that you can access it later.
130 127
131``` php 128``` php
132setcookie(session_name()); 129setcookie(session_name());
133``` 130```
134 131
135Now that the session name has been stored, you\'ll be able to check if 132Now that the session name has been stored, you'll be able to check if there's
136there\'s an active session whenever you load a page. 133an active session whenever you load a page.
137 134
138``` php 135``` php
139if(isset(session_name())) { 136if(isset(session_name())) {
@@ -143,9 +140,9 @@ if(isset(session_name())) {
143 140
144## Removing User Authentication 141## Removing User Authentication
145 142
146The next logical step is to give your users the option to log out once 143The next logical step is to give your users the option to log out once they are
147they are done using your application. This can be tricky in PHP since a 144done using your application. This can be tricky in PHP since a few of the
148few of the standard ways do not always work. 145standard ways do not always work.
149 146
150``` php 147``` php
151// Initialize the session. 148// Initialize the session.
@@ -183,14 +180,13 @@ die();
183 180
184# Wrapping Up 181# Wrapping Up
185 182
186Now you should be ready to begin your authentication programming with 183Now you should be ready to begin your authentication programming with PHP. You
187PHP. You can create user accounts, create sessions for users across 184can create user accounts, create sessions for users across different pages of
188different pages of your site, and then destroy the user data when 185your site, and then destroy the user data when they're ready to leave.
189they\'re ready to leave.
190 186
191For more information on this subject, I recommend reading the [PHP 187For more information on this subject, I recommend reading the [PHP
192Documentation](https://www.php.net/). Specifically, you may want to look 188Documentation](https://www.php.net/). Specifically, you may want to look at
193at [HTTP Authentication with 189[HTTP Authentication with
194PHP](https://www.php.net/manual/en/features.http-auth.php), [session 190PHP](https://www.php.net/manual/en/features.http-auth.php), [session
195handling](https://www.php.net/manual/en/book.session.php), and 191handling](https://www.php.net/manual/en/book.session.php), and
196[hash](https://www.php.net/manual/en/function.hash.php). 192[hash](https://www.php.net/manual/en/function.hash.php).
content/blog/2020-09-01-visual-recognition.md +71 −77
@@ -7,42 +7,41 @@ draft = false
7 7
8# What is IBM Watson? 8# What is IBM Watson?
9 9
10If you\'ve never heard of [Watson](https://www.ibm.com/watson), this 10If you've never heard of [Watson](https://www.ibm.com/watson), this service is
11service is a suite of enterprise-ready AI services, applications, and 11a suite of enterprise-ready AI services, applications, and tooling provided by
12tooling provided by IBM. Watson contains quite a few useful tools for 12IBM. Watson contains quite a few useful tools for data scientists and students,
13data scientists and students, including the subject of this post today: 13including the subject of this post today: visual recognition.
14visual recognition. 14
15 15If you'd like to view the official documentation for the Visual Recognition
16If you\'d like to view the official documentation for the Visual 16API, visit the [API
17Recognition API, visit the [API
18Docs](https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?code=python). 17Docs](https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?code=python).
19 18
20# Prerequisites 19# Prerequisites
21 20
22To be able to use Watson Visual Recognition, you\'ll need the following: 21To be able to use Watson Visual Recognition, you'll need the following:
23 22
241. Create a free account on [IBM Watson 231. Create a free account on [IBM Watson
25 Studio](https://www.ibm.com/cloud/watson-studio). 24 Studio](https://www.ibm.com/cloud/watson-studio).
262. Add the [Watson Visual 252. Add the [Watson Visual
27 Recognition](https://www.ibm.com/cloud/watson-visual-recognition) 26 Recognition](https://www.ibm.com/cloud/watson-visual-recognition) service to
28 service to your IBM Watson account. 27 your IBM Watson account.
293. Get your API key and URL. To do this, first go to the [profile 283. Get your API key and URL. To do this, first go to the [profile
30 dashboard](https://dataplatform.cloud.ibm.com/home2?context=cpdaas) 29 dashboard](https://dataplatform.cloud.ibm.com/home2?context=cpdaas) for your
31 for your IBM account and click on the Watson Visual Recognition 30 IBM account and click on the Watson Visual Recognition service you created.
32 service you created. This will be listed in the section titled 31 This will be listed in the section titled **Your services**. Then click the
33 **Your services**. Then click the **Credentials\*** tab and open the 32 **Credentials** tab and open the **Auto-generated credentials** dropdown.
34 **Auto-generated credentials\*** dropdown. Copy your API key and URL 33 Copy your API key and URL so that you can use them in the Python script
35 so that you can use them in the Python script later. 34 later.
364. **\[Optional\]\*** While not required, you can also create the 354. **[Optional]** While not required, you can also create the Jupyter Notebook
37 Jupyter Notebook for this project right inside [Watson 36 for this project right inside [Watson
38 Studio](https://www.ibm.com/cloud/watson-studio). Watson Studio will 37 Studio](https://www.ibm.com/cloud/watson-studio). Watson Studio will save
39 save your notebooks inside an organized project and allow you to use 38 your notebooks inside an organized project and allow you to use their other
40 their other integrated products, such as storage containers, AI 39 integrated products, such as storage containers, AI models, documentation,
41 models, documentation, external sharing, etc. 40 external sharing, etc.
42 41
43# Calling the IBM Watson Visual Recognition API 42# Calling the IBM Watson Visual Recognition API
44 43
45Okay, now let\'s get started. 44Okay, now let's get started.
46 45
47To begin, we need to install the proper Python package for IBM Watson. 46To begin, we need to install the proper Python package for IBM Watson.
48 47
@@ -50,8 +49,8 @@ To begin, we need to install the proper Python package for IBM Watson.
50pip install --upgrade --user "ibm-watson>=4.5.0" 49pip install --upgrade --user "ibm-watson>=4.5.0"
51``` 50```
52 51
53Next, we need to specify the API key, version, and URL given to us when 52Next, we need to specify the API key, version, and URL given to us when we
54we created the Watson Visual Recognition service. 53created the Watson Visual Recognition service.
55 54
56``` python 55``` python
57apikey = "<your-apikey>" 56apikey = "<your-apikey>"
@@ -59,7 +58,7 @@ version = "2018-03-19"
59url = "<your-url>" 58url = "<your-url>"
60``` 59```
61 60
62Now, let\'s import the necessary libraries and authenticate our service. 61Now, let's import the necessary libraries and authenticate our service.
63 62
64``` python 63``` python
65import json 64import json
@@ -75,16 +74,15 @@ visual_recognition = VisualRecognitionV3(
75visual_recognition.set_service_url(url) 74visual_recognition.set_service_url(url)
76``` 75```
77 76
78**\[Optional\]** If you\'d like to tell the API not to use any data to 77**[Optional]** If you'd like to tell the API not to use any data to improve
79improve their products, set the following header. 78their products, set the following header.
80 79
81``` python 80``` python
82visual_recognition.set_default_headers({'x-watson-learning-opt-out': "true"}) 81visual_recognition.set_default_headers({'x-watson-learning-opt-out': "true"})
83``` 82```
84 83
85Now we have our API all set and ready to go. For this example, I\'m 84Now we have our API all set and ready to go. For this example, I'm going to
86going to include a `dict` of photos to load as we test out 85include a `dict` of photos to load as we test out the API.
87the API.
88 86
89``` python 87``` python
90data = [ 88data = [
@@ -115,14 +113,14 @@ data = [
115] 113]
116``` 114```
117 115
118Now that we\'ve set up our libraries and have the photos ready, let\'s 116Now that we've set up our libraries and have the photos ready, let's create a
119create a loop to call the API for each image. The code below shows a 117loop to call the API for each image. The code below shows a loop that calls the
120loop that calls the URL of each image and sends it to the API, 118URL of each image and sends it to the API, requesting results with at least 60%
121requesting results with at least 60% confidence. The results are output 119confidence. The results are output to the console with dotted lines separating
122to the console with dotted lines separating each section. 120each section.
123 121
124In the case of an API error, the codes and explanations are output to 122In the case of an API error, the codes and explanations are output to the
125the console. 123console.
126 124
127``` python 125``` python
128from ibm_watson import ApiException 126from ibm_watson import ApiException
@@ -149,23 +147,22 @@ except ApiException as ex:
149 147
150# The Results 148# The Results
151 149
152Here we can see the full result set of our function above. If you view 150Here we can see the full result set of our function above. If you view each of
153each of the URLs that we sent to the API, you\'ll be able to see that it 151the URLs that we sent to the API, you'll be able to see that it was remarkably
154was remarkably accurate. To be fair, these are clear high-resolution, 152accurate. To be fair, these are clear high-resolution, clear photos shot with a
155clear photos shot with a professional camera. In reality, you will most 153professional camera. In reality, you will most likely be processing images that
156likely be processing images that are lower quality and may have a lot of 154are lower quality and may have a lot of noise in the photo.
157noise in the photo.
158 155
159However, we can clearly see the benefit of being able to call this API 156However, we can clearly see the benefit of being able to call this API instead
160instead of attempting to write our own image recognition function. Each 157of attempting to write our own image recognition function. Each of the
161of the classifications returned was a fair description of the image. 158classifications returned was a fair description of the image.
162 159
163If you wanted to restrict the results to those that are at least 90% 160If you wanted to restrict the results to those that are at least 90% confident
164confident or greater, you would simply adjust the `threshold` 161or greater, you would simply adjust the `threshold` in the
165in the `visual_recognition.classify()` function. 162`visual_recognition.classify()` function.
166 163
167When your program runs, it should show the output below for each photo 164When your program runs, it should show the output below for each photo you
168you provide. 165provide.
169 166
170``` txt 167``` txt
171---------------------------------------------------------------- 168----------------------------------------------------------------
@@ -184,22 +181,19 @@ greenishness color ( 0.975 )
184 181
185# Discussion 182# Discussion
186 183
187Now, this was a very minimal implementation of the API. We simply 184Now, this was a very minimal implementation of the API. We simply supplied some
188supplied some images and looked to see how accurate the results were. 185images and looked to see how accurate the results were. However, you could
189However, you could implement this type of API into many machine learning 186implement this type of API into many machine learning (ML) models.
190(ML) models. 187
191 188For example, you could be working for a company that scans their warehouses or
192For example, you could be working for a company that scans their 189inventory using drones. Would you want to pay employees to sit there and watch
193warehouses or inventory using drones. Would you want to pay employees to 190drone footage all day in order to identify or count things in the video?
194sit there and watch drone footage all day in order to identify or count 191Probably not. Instead, you could use a classification system similar to this one
195things in the video? Probably not. Instead, you could use a 192in order to train your machine learning model to correctly identify items that
196classification system similar to this one in order to train your machine 193the drones show through video. More specifically, you could have your machine
197learning model to correctly identify items that the drones show through 194learning model watch a drone fly over a field of sheep in order to count how
198video. More specifically, you could have your machine learning model 195many sheep are living in that field.
199watch a drone fly over a field of sheep in order to count how many sheep 196
200are living in that field. 197There are many ways to implement machine learning functionality, but hopefully
201 198this post helped inspire some deeper thought about the tools that can help
202There are many ways to implement machine learning functionality, but 199propel us further into the future of machine learning and AI.
203hopefully this post helped inspire some deeper thought about the tools
204that can help propel us further into the future of machine learning and
205AI.
content/blog/2020-09-22-internal-audit.md +165 −181
@@ -10,66 +10,64 @@ Overview](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-
10 10
11# Definitions 11# Definitions
12 12
13One of the many reasons that Internal Audit needs such thorough 13One of the many reasons that Internal Audit needs such thorough explaining to
14explaining to non-auditors is that Internal Audit can serve many 14non-auditors is that Internal Audit can serve many purposes, depending on the
15purposes, depending on the organization\'s size and needs. However, the 15organization's size and needs. However, the Institute of Internal Auditors
16Institute of Internal Auditors (IIA) defines Internal Auditing as: 16(IIA) defines Internal Auditing as:
17 17
18> Internal auditing is an independent, objective assurance and 18> Internal auditing is an independent, objective assurance and consulting
19> consulting activity designed to add value and improve an 19> activity designed to add value and improve an organization's operations. It
20> organization\'s operations. It helps an organization accomplish its 20> helps an organization accomplish its objectives by bringing a systematic,
21> objectives by bringing a systematic, disciplined approach to evaluate 21> disciplined approach to evaluate and improve the effectiveness of risk
22> and improve the effectiveness of risk management, control, and 22> management, control, and governance processes.
23> governance processes. 23
24 24However, this definition uses quite a few terms that aren't clear unless the
25However, this definition uses quite a few terms that aren\'t clear 25reader already has a solid understanding of the auditing profession. To further
26unless the reader already has a solid understanding of the auditing 26explain, the following is a list of definitions that can help supplement
27profession. To further explain, the following is a list of definitions 27understanding of internal auditing.
28that can help supplement understanding of internal auditing.
29 28
30## Independent 29## Independent
31 30
32Independence is the freedom from conditions that threaten the ability of 31Independence is the freedom from conditions that threaten the ability of the
33the internal audit activity to carry out internal audit responsibilities 32internal audit activity to carry out internal audit responsibilities in an
34in an unbiased manner. To achieve the degree of independence necessary 33unbiased manner. To achieve the degree of independence necessary to effectively
35to effectively carry out the responsibilities of the internal audit 34carry out the responsibilities of the internal audit activity, the chief audit
36activity, the chief audit executive has direct and unrestricted access 35executive has direct and unrestricted access to senior management and the board.
37to senior management and the board. This can be achieved through a 36This can be achieved through a dual-reporting relationship. Threats to
38dual-reporting relationship. Threats to independence must be managed at 37independence must be managed at the individual auditor, engagement, functional,
39the individual auditor, engagement, functional, and organizational 38and organizational levels.
40levels.
41 39
42## Objective 40## Objective
43 41
44Objectivity is an unbiased mental attitude that allows internal auditors 42Objectivity is an unbiased mental attitude that allows internal auditors to
45to perform engagements in such a manner that they believe in their work 43perform engagements in such a manner that they believe in their work product and
46product and that no quality compromises are made. Objectivity requires 44that no quality compromises are made. Objectivity requires that internal
47that internal auditors do not subordinate their judgment on audit 45auditors do not subordinate their judgment on audit matters to others. Threats
48matters to others. Threats to objectivity must be managed at the 46to objectivity must be managed at the individual auditor, engagement,
49individual auditor, engagement, functional, and organizational levels. 47functional, and organizational levels.
50 48
51## Assurance 49## Assurance
52 50
53Assurance services involve the internal auditor\'s objective assessment 51Assurance services involve the internal auditor's objective assessment of
54of evidence to provide opinions or conclusions regarding an entity, 52evidence to provide opinions or conclusions regarding an entity, operation,
55operation, function, process, system, or other subject matters. The 53function, process, system, or other subject matters. The internal auditor
56internal auditor determines the nature and scope of an assurance 54determines the nature and scope of an assurance engagement. Generally, three
57engagement. Generally, three parties are participants in assurance 55parties are participants in assurance services: (1) the person or group directly
58services: (1) the person or group directly involved with the entity, 56involved with the entity, operation, function, process, system, or other subject
59operation, function, process, system, or other subject - (the process 57- (the process owner), (2) the person or group making the assessment - (the
60owner), (2) the person or group making the assessment - (the internal 58internal auditor), and (3) the person or group using the assessment - (the
61auditor), and (3) the person or group using the assessment - (the user). 59user).
62 60
63## Consulting 61## Consulting
64 62
65Consulting services are advisory in nature and are generally performed 63Consulting services are advisory in nature and are generally performed at the
66at the specific request of an engagement client. The nature and scope of 64specific request of an engagement client. The nature and scope of the consulting
67the consulting engagement are subject to agreement with the engagement 65engagement are subject to agreement with the engagement client. Consulting
68client. Consulting services generally involve two parties: (1) the 66services generally involve two parties: (1) the person or group offering the
69person or group offering the advice (the internal auditor), and (2) the 67advice (the internal auditor), and (2) the person or group seeking and receiving
70person or group seeking and receiving the advice (the engagement 68the advice (the engagement client). When performing consulting services, the
71client). When performing consulting services, the internal auditor 69internal auditor should maintain objectivity and not assume management
72should maintain objectivity and not assume management responsibility. 70responsibility.
73 71
74## Governance, Risk Management, & Compliance (GRC) 72## Governance, Risk Management, & Compliance (GRC)
75 73
@@ -78,187 +76,173 @@ reliably achieve objectives, address uncertainty and act with integrity.
78 76
79# Audit Charter & Standards 77# Audit Charter & Standards
80 78
81First, it\'s important to note that not every organization needs 79First, it's important to note that not every organization needs internal
82internal auditors. In fact, it\'s unwise for an organization to hire 80auditors. In fact, it's unwise for an organization to hire internal auditors
83internal auditors unless they have regulatory requirements for auditing 81unless they have regulatory requirements for auditing and have the capital to
84and have the capital to support the department. Internal audit is a cost 82support the department. Internal audit is a cost center that can only affect
85center that can only affect revenue indirectly. 83revenue indirectly.
86 84
87Once an organization determines the need for internal assurance 85Once an organization determines the need for internal assurance services, they
88services, they will hire a Chief Audit Executive and create the audit 86will hire a Chief Audit Executive and create the audit charter. This charter is
89charter. This charter is a document, approved by the company\'s 87a document, approved by the company's governing body, that will define internal
90governing body, that will define internal audit\'s purpose, authority, 88audit's purpose, authority, responsibility, and position within the
91responsibility, and position within the organization. Fortunately, the 89organization. Fortunately, the IIA has model charters available to IIA members
92IIA has model charters available to IIA members for those developing or 90for those developing or improving their charter.
93improving their charter. 91
94 92Beyond the charter and organizational documents, internal auditors follow a few
95Beyond the charter and organizational documents, internal auditors 93different standards in order to perform their job. First is the International
96follow a few different standards in order to perform their job. First is 94Professional Practices Framework (IPPF) by the IIA, which is the model of
97the International Professional Practices Framework (IPPF) by the IIA, 95standards for internal auditing. In addition, ISACA's Information Technology
98which is the model of standards for internal auditing. In addition, 96Assurance Framework (ITAF) helps guide auditors in reference to information
99ISACA\'s Information Technology Assurance Framework (ITAF) helps guide 97technology (IT) compliance and assurance. Finally, additional standards such as
100auditors in reference to information technology (IT) compliance and 98FASB, GAAP, and industry-specific standards are used when performing internal
101assurance. Finally, additional standards such as FASB, GAAP, and 99audit work.
102industry-specific standards are used when performing internal audit
103work.
104 100
105# Three Lines of Defense 101# Three Lines of Defense
106 102
107[The IIA](https://theiia.org) released the original Three Lines of 103[The IIA](https://theiia.org) released the original Three Lines of Defense model
108Defense model in 2013, but have released an updated version in 2020. 104in 2013, but have released an updated version in 2020. Here is what the Three
109Here is what the Three Lines of Defense model has historically looked 105Lines of Defense model has historically looked like:
110like:
111 106
112![2013 Three Lines of Defense 107![2013 Three Lines of Defense
113Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/three_lines_model.png) 108Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/three_lines_model.png)
114 109
115I won\'t go into depth about the changes made to the model in this 110I won't go into depth about the changes made to the model in this article.
116article. Instead, let\'s take a look at the most current model. 111Instead, let's take a look at the most current model.
117 112
118![2020 Three Lines of Defense 113![2020 Three Lines of Defense
119Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/updated_three_lines_model.png) 114Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/updated_three_lines_model.png)
120 115
121The updated model forgets the strict idea of areas performing their own 116The updated model forgets the strict idea of areas performing their own
122functions or line of defense. Instead of talking about management, risk, 117functions or line of defense. Instead of talking about management, risk, and
123and internal audit as 1-2-3, the new model creates a more fluid and 118internal audit as 1-2-3, the new model creates a more fluid and cooperative
124cooperative model. 119model.
125 120
126Looking at this model from an auditing perspective shows us that 121Looking at this model from an auditing perspective shows us that auditors will
127auditors will need to align, communicate, and collaborate with 122need to align, communicate, and collaborate with management, including business
128management, including business area managers and chief officers, as well 123area managers and chief officers, as well as reporting to the governing body.
129as reporting to the governing body. The governing body will instruct 124The governing body will instruct internal audit *functionally* on their goals
130internal audit *functionally* on their goals and track their progress 125and track their progress periodically.
131periodically. 126
132 127However, the internal audit department will report *administratively* to a chief
133However, the internal audit department will report *administratively* to 128officer in the company for the purposes of collaboration, direction, and
134a chief officer in the company for the purposes of collaboration, 129assistance with the business. Note that in most situations, the governing body
135direction, and assistance with the business. Note that in most 130is the audit committee on the company's board of directors.
136situations, the governing body is the audit committee on the company\'s 131
137board of directors. 132The result of this structure is that internal audit is an independent and
138 133objective function that can provide assurance over the topics they audit.
139The result of this structure is that internal audit is an independent
140and objective function that can provide assurance over the topics they
141audit.
142 134
143# Audit Process 135# Audit Process
144 136
145A normal audit will generally follow the same process, regardless of the 137A normal audit will generally follow the same process, regardless of the topic.
146topic. However, certain special projects or abnormal business areas may 138However, certain special projects or abnormal business areas may call for
147call for changes to the audit process. The audit process is not set in 139changes to the audit process. The audit process is not set in stone, it's
148stone, it\'s simply a set of best practices so that audits can be 140simply a set of best practices so that audits can be performed consistently.
149performed consistently.
150 141
151![The Internal Audit 142![The Internal Audit
152Process](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-audit-process.jpg) 143Process](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-audit-process.jpg)
153 144
154While different organizations may tweak the process, it will generally 145While different organizations may tweak the process, it will generally follow
155follow this flow: 146this flow:
156 147
157## 1. Risk Assessment 148## 1. Risk Assessment
158 149
159The risk assessment part of the process has historically been performed 150The risk assessment part of the process has historically been performed
160annually, but many organizations have moved to performing this process 151annually, but many organizations have moved to performing this process much more
161much more frequently. In fact, some organizations are moving to an agile 152frequently. In fact, some organizations are moving to an agile approach that can
162approach that can take new risks into the risk assessment and 153take new risks into the risk assessment and re-prioritize risk areas on-the-go.
163re-prioritize risk areas on-the-go. To perform a risk assessment, 154To perform a risk assessment, leaders in internal audit will research industry
164leaders in internal audit will research industry risks, consult with 155risks, consult with business leaders around the company, and perform analyses on
165business leaders around the company, and perform analyses on company 156company data.
166data.
167 157
168Once a risk assessment has been documented, the audit department has a 158Once a risk assessment has been documented, the audit department has a
169prioritized list of risks that can be audited. This is usually in the 159prioritized list of risks that can be audited. This is usually in the form of
170form of auditable entities, such as business areas or departments. 160auditable entities, such as business areas or departments.
171 161
172## 2. Planning 162## 2. Planning
173 163
174During the planning phase of an audit, auditors will meet with the 164During the planning phase of an audit, auditors will meet with the business area
175business area to discuss the various processes, controls, and risks 165to discuss the various processes, controls, and risks applicable to the
176applicable to the business. This helps the auditors determine the scope 166business. This helps the auditors determine the scope limits for the audit, as
177limits for the audit, as well as timing and subject-matter experts. 167well as timing and subject-matter experts. Certain documents will be created in
178Certain documents will be created in this phase that will be used to 168this phase that will be used to keep the audit on-track an in-scope as it goes
179keep the audit on-track an in-scope as it goes forward. 169forward.
180 170
181## 3. Testing 171## 3. Testing
182 172
183The testing phase, also known as fieldwork or execution, is where 173The testing phase, also known as fieldwork or execution, is where internal
184internal auditors will take the information they\'ve discovered and test 174auditors will take the information they've discovered and test it against
185it against regulations, industry standards, company rules, best 175regulations, industry standards, company rules, best practices, as well as
186practices, as well as validating that any processes are complete and 176validating that any processes are complete and accurate. For example, an audit
187accurate. For example, an audit of HR would most likely examine 177of HR would most likely examine processes such as employee on-boarding, employee
188processes such as employee on-boarding, employee termination, security 178termination, security of personally identifiable information (PII), or the IT
189of personally identifiable information (PII), or the IT systems involved 179systems involved in these processes. Company standards would be examined and
190in these processes. Company standards would be examined and compared 180compared against how the processes are actually being performed day-to-day, as
191against how the processes are actually being performed day-to-day, as 181well as compared against regulations such as the Equal Employment Opportunity
192well as compared against regulations such as the Equal Employment 182(EEO), American with Disabilities Act, and National Labor Relations Act.
193Opportunity (EEO), American with Disabilities Act, and National Labor
194Relations Act.
195 183
196## 4. Reporting 184## 4. Reporting
197 185
198Once all the tests have been completed, the audit will enter the 186Once all the tests have been completed, the audit will enter the reporting
199reporting phase. This is when the audit team will conclude on the 187phase. This is when the audit team will conclude on the evidence they've
200evidence they\'ve collected, interviews they\'ve held, and any opinions 188collected, interviews they've held, and any opinions they've formed on the
201they\'ve formed on the controls in place. A summary of the audit 189controls in place. A summary of the audit findings, conclusions, and specific
202findings, conclusions, and specific recommendations are officially 190recommendations are officially communicated to the client through a draft
203communicated to the client through a draft report. Clients have the 191report. Clients have the opportunity to respond to the report and submit an
204opportunity to respond to the report and submit an action plan and time 192action plan and time frame. These responses become part of the final report
205frame. These responses become part of the final report which is 193which is distributed to the appropriate level of administration.
206distributed to the appropriate level of administration.
207 194
208## 5. Follow-Up 195## 5. Follow-Up
209 196
210After audits have been completed and management has formed action plans 197After audits have been completed and management has formed action plans and time
211and time frames for audit issues, internal audit will follow up once 198frames for audit issues, internal audit will follow up once that due date has
212that due date has arrived. In most cases, the follow-up will simply 199arrived. In most cases, the follow-up will simply consist of a meeting to
213consist of a meeting to discuss how the action plan has been completed 200discuss how the action plan has been completed and to request documentation to
214and to request documentation to prove it. 201prove it.
215 202
216# Audit Department Structure 203# Audit Department Structure
217 204
218While an internal audit department is most often thought of as a team of 205While an internal audit department is most often thought of as a team of
219full-time employees, there are actually many different ways in which a 206full-time employees, there are actually many different ways in which a
220department can be structured. As the world becomes more digital and 207department can be structured. As the world becomes more digital and fast-paced,
221fast-paced, outsourcing has become a more attractive option for some 208outsourcing has become a more attractive option for some organizations. Internal
222organizations. Internal audit can be fully outsourced or partially 209audit can be fully outsourced or partially outsourced, allowing for flexibility
223outsourced, allowing for flexibility in cases where turnover is high. 210in cases where turnover is high.
224 211
225In addition, departments can implement a rotational model. This allows 212In addition, departments can implement a rotational model. This allows for
226for interested employees around the organization to rotate into the 213interested employees around the organization to rotate into the internal audit
227internal audit department for a period of time, allowing them to obtain 214department for a period of time, allowing them to obtain knowledge of risks and
228knowledge of risks and controls and allowing the internal audit team to 215controls and allowing the internal audit team to obtain more business area
229obtain more business area knowledge. This program is popular in very 216knowledge. This program is popular in very large organizations, but
230large organizations, but organizations tend to rotate lower-level audit 217organizations tend to rotate lower-level audit staff instead of managers. This
231staff instead of managers. This helps prevent any significant knowledge 218helps prevent any significant knowledge loss as auditors rotate out to business
232loss as auditors rotate out to business areas. 219areas.
233 220
234# Consulting 221# Consulting
235 222
236Consulting is not an easy task at any organization, especially for a 223Consulting is not an easy task at any organization, especially for a department
237department that can have negative perceptions within the organization as 224that can have negative perceptions within the organization as the "compliance
238the \"compliance police.\" However, once an internal audit department 225police." However, once an internal audit department has delivered value to
239has delivered value to organization, adding consulting to their suite of 226organization, adding consulting to their suite of services is a smart move. In
240services is a smart move. In most cases, Internal Audit can insert 227most cases, Internal Audit can insert themselves into a consulting role without
241themselves into a consulting role without affecting the process of 228affecting the process of project management at the company. This means that
242project management at the company. This means that internal audit can 229internal audit can add objective assurance and opinions to business areas as
243add objective assurance and opinions to business areas as they develop 230they develop new processes, instead of coming in periodically to audit an area
244new processes, instead of coming in periodically to audit an area and 231and file issues that could have been fixed at the beginning.
245file issues that could have been fixed at the beginning.
246 232
247# Data Science & Data Analytics 233# Data Science & Data Analytics
248 234
249![Data Science Skill 235![Data Science Skill
250Set](https://img.cleberg.net/blog/20200922-what-is-internal-audit/data-science-skillset.png) 236Set](https://img.cleberg.net/blog/20200922-what-is-internal-audit/data-science-skillset.png)
251 237
252One major piece of the internal audit function in the modern world is 238One major piece of the internal audit function in the modern world is data
253data science. While the process is data science, most auditors will 239science. While the process is data science, most auditors will refer to anything
254refer to anything in this realm as data analytics. Hot topics such as 240in this realm as data analytics. Hot topics such as robotic process automation
255robotic process automation (RPA), machine learning (ML), and data mining 241(RPA), machine learning (ML), and data mining have taken over the auditing world
256have taken over the auditing world in recent years. These technologies 242in recent years. These technologies have been immensely helpful with increasing
257have been immensely helpful with increasing the effectiveness and 243the effectiveness and efficiency of auditors.
258efficiency of auditors. 244
259 245For example, mundane and repetitive tasks can be automated in order for auditors
260For example, mundane and repetitive tasks can be automated in order for 246to make more room in their schedules for labor-intensive work. Further, auditors
261auditors to make more room in their schedules for labor-intensive work. 247will need to adapt technologies like machine learning in order to extract more
262Further, auditors will need to adapt technologies like machine learning 248value from the data they're using to form conclusions.
263in order to extract more value from the data they\'re using to form
264conclusions.
content/blog/2020-09-25-happiness-map.md +46 −49
@@ -8,28 +8,28 @@ draft = false
8# Background Information 8# Background Information
9 9
10The dataset (obtained from 10The dataset (obtained from
11[Kaggle](https://www.kaggle.com/unsdsn/world-happiness)) used in this 11[Kaggle](https://www.kaggle.com/unsdsn/world-happiness)) used in this article
12article contains a list of countries around the world, their happiness 12contains a list of countries around the world, their happiness rankings and
13rankings and scores, as well as other national scoring measures. 13scores, as well as other national scoring measures.
14 14
15Fields include: 15Fields include:
16 16
17- Overall rank 17- Overall rank
18- Country or region 18- Country or region
19- GDP per capita 19- GDP per capita
20- Social support 20- Social support
21- Healthy life expectancy 21- Healthy life expectancy
22- Freedom to make life choices 22- Freedom to make life choices
23- Generosity 23- Generosity
24- Perceptions of corruption 24- Perceptions of corruption
25 25
26There are 156 records. Since there are \~195 countries in the world, we 26There are 156 records. Since there are ~195 countries in the world, we can see
27can see that around 40 countries will be missing from this dataset. 27that around 40 countries will be missing from this dataset.
28 28
29# Install Packages 29# Install Packages
30 30
31As always, run the `install` command for all packages needed 31As always, run the `install` command for all packages needed to perform
32to perform analysis. 32analysis.
33 33
34``` python 34``` python
35!pip install folium geopandas matplotlib numpy pandas 35!pip install folium geopandas matplotlib numpy pandas
@@ -38,9 +38,9 @@ to perform analysis.
38# Import the Data 38# Import the Data
39 39
40We only need a couple packages to create a choropleth map. We will use 40We only need a couple packages to create a choropleth map. We will use
41[Folium](https://python-visualization.github.io/folium/), which provides 41[Folium](https://python-visualization.github.io/folium/), which provides map
42map visualizations in Python. We will also use geopandas and pandas to 42visualizations in Python. We will also use geopandas and pandas to wrangle our
43wrangle our data before we put it on a map. 43data before we put it on a map.
44 44
45``` python 45``` python
46# Import the necessary Python packages 46# Import the necessary Python packages
@@ -49,14 +49,14 @@ import geopandas as gpd
49import pandas as pd 49import pandas as pd
50``` 50```
51 51
52To get anything to show up on a map, we need a file that will specify 52To get anything to show up on a map, we need a file that will specify the
53the boundaries of each country. Luckily, GeoJSON files exist (for free!) 53boundaries of each country. Luckily, GeoJSON files exist (for free!) on the
54on the internet. To get the boundaries of every country in the world, we 54internet. To get the boundaries of every country in the world, we will use the
55will use the GeoJSON link shown below. 55GeoJSON link shown below.
56 56
57GeoPandas will take this data and load it into a dataframe so that we 57GeoPandas will take this data and load it into a dataframe so that we can easily
58can easily match it to the data we\'re trying to analyze. Let\'s look at 58match it to the data we're trying to analyze. Let's look at the GeoJSON
59the GeoJSON dataframe: 59dataframe:
60 60
61``` python 61``` python
62# Load the GeoJSON data with geopandas 62# Load the GeoJSON data with geopandas
@@ -67,9 +67,9 @@ geo_data.head()
67![GeoJSON 67![GeoJSON
68Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/geojson_df.png) 68Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/geojson_df.png)
69 69
70Next, let\'s load the data from the Kaggle dataset. I\'ve downloaded 70Next, let's load the data from the Kaggle dataset. I've downloaded this file,
71this file, so update the file path if you have it somewhere else. After 71so update the file path if you have it somewhere else. After loading, let's
72loading, let\'s take a look at this dataframe: 72take a look at this dataframe:
73 73
74``` python 74``` python
75# Load the world happiness data with pandas 75# Load the world happiness data with pandas
@@ -82,12 +82,11 @@ Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/happiness_
82 82
83# Clean the Data 83# Clean the Data
84 84
85Some countries need to be renamed, or they will be lost when you merge 85Some countries need to be renamed, or they will be lost when you merge the
86the happiness and GeoJSON dataframes. This is something I discovered 86happiness and GeoJSON dataframes. This is something I discovered when the map
87when the map below showed empty countries. I searched both data frames 87below showed empty countries. I searched both data frames for the missing
88for the missing countries to see the naming differences. Any countries 88countries to see the naming differences. Any countries that do not have records
89that do not have records in the `happy_data` df will not show 89in the `happy_data` df will not show up on the map.
90up on the map.
91 90
92``` python 91``` python
93# Rename some countries to match our GeoJSON data 92# Rename some countries to match our GeoJSON data
@@ -112,11 +111,11 @@ happy_data.at[democratic_congo_index, 'Country or region'] = 'Democratic Republi
112# Merge the Data 111# Merge the Data
113 112
114Now that we have clean data, we need to merge the GeoJSON data with the 113Now that we have clean data, we need to merge the GeoJSON data with the
115happiness data. Since we\'ve stored them both in dataframes, we just 114happiness data. Since we've stored them both in dataframes, we just need to
116need to call the `.merge()` function. 115call the `.merge()` function.
117 116
118We will also rename a couple columns, just so that they\'re a little 117We will also rename a couple columns, just so that they're a little easier to
119easier to use when we create the map. 118use when we create the map.
120 119
121``` python 120``` python
122# Merge the two previous dataframes into a single geopandas dataframe 121# Merge the two previous dataframes into a single geopandas dataframe
@@ -133,10 +132,9 @@ Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/merged_df.
133# Create the Map 132# Create the Map
134 133
135The data is finally ready to be added to a map. The code below shows the 134The data is finally ready to be added to a map. The code below shows the
136simplest way to find the center of the map and create a Folium map 135simplest way to find the center of the map and create a Folium map object. The
137object. The important part is to remember to reference the merged 136important part is to remember to reference the merged dataframe for our GeoJSON
138dataframe for our GeoJSON data and value data. The columns specify which 137data and value data. The columns specify which geo data and value data to use.
139geo data and value data to use.
140 138
141``` python 139``` python
142# Assign centroids to map 140# Assign centroids to map
@@ -164,17 +162,16 @@ folium.Choropleth(
164).add_to(world_map) 162).add_to(world_map)
165``` 163```
166 164
167Let\'s look at the resulting map. 165Let's look at the resulting map.
168 166
169![Choropleth 167![Choropleth
170Map](https://img.cleberg.net/blog/20200925-world-choropleth-map/map.png) 168Map](https://img.cleberg.net/blog/20200925-world-choropleth-map/map.png)
171 169
172# Create a Tooltip on Hover 170# Create a Tooltip on Hover
173 171
174Now that we have a map set up, we could stop. However, I want to add a 172Now that we have a map set up, we could stop. However, I want to add a tooltip
175tooltip so that I can see more information about each country. The 173so that I can see more information about each country. The `tooltip_data` code
176`tooltip_data` code below will show a popup on hover with all 174below will show a popup on hover with all the data fields shown.
177the data fields shown.
178 175
179``` python 176``` python
180 # Adding labels to map 177 # Adding labels to map
@@ -219,8 +216,8 @@ folium.LayerControl().add_to(world_map)
219world_map 216world_map
220``` 217```
221 218
222The final image below will show you what the tooltip looks like whenever 219The final image below will show you what the tooltip looks like whenever you
223you hover over a country. 220hover over a country.
224 221
225![Choropleth Map 222![Choropleth Map
226Tooltip](https://img.cleberg.net/blog/20200925-world-choropleth-map/tooltip_map.png) 223Tooltip](https://img.cleberg.net/blog/20200925-world-choropleth-map/tooltip_map.png)
content/blog/2020-10-12-mediocrity.md +97 −102
@@ -7,115 +7,110 @@ draft = false
7 7
8# Perfect is the Enemy of Good 8# Perfect is the Enemy of Good
9 9
10As the saying goes, \"the best is the enemy of the good.\" As we strive 10As the saying goes, "the best is the enemy of the good." As we strive for
11for perfection, we often fail to realize the implications of such an 11perfection, we often fail to realize the implications of such an undertaking.
12undertaking. Attempting to reach perfection is often unrealistic. Even 12Attempting to reach perfection is often unrealistic. Even worse, it can get in
13worse, it can get in the way of achieving a good outcome. In certain 13the way of achieving a good outcome. In certain situations, we try so hard to
14situations, we try so hard to achieve the ideal solution that we have 14achieve the ideal solution that we have burned the bridges that would have
15burned the bridges that would have allowed us to reach a lesser yet 15allowed us to reach a lesser yet still superb solution.
16still superb solution. 16
17 17Philosophers throughout history have inspected this plight from many viewpoints.
18Philosophers throughout history have inspected this plight from many 18Greek mythology speaks of the [golden
19viewpoints. Greek mythology speaks of the [golden 19mean](https://en.wikipedia.org/wiki/Golden_mean_(philosophy)), which uses the
20mean](https://en.wikipedia.org/wiki/Golden_mean_(philosophy)), which 20story of Icarus to illustrate that sometimes "the middle course" is the best
21uses the story of Icarus to illustrate that sometimes \"the middle 21solution. In this story, Daedalus, a famous artist of his time, built feathered
22course\" is the best solution. In this story, Daedalus, a famous artist 22wings for himself and his son so that they might escape the clutches of King
23of his time, built feathered wings for himself and his son so that they 23Minos. Daedalus warns his beloved son whom he loved so much to "fly the middle
24might escape the clutches of King Minos. Daedalus warns his beloved son 24course", between the sea spray and the sun's heat. Icarus did not heed his
25whom he loved so much to \"fly the middle course\", between the sea 25father; he flew up and up until the sun melted the wax off his wings. For not
26spray and the sun\'s heat. Icarus did not heed his father; he flew up 26heeding the middle course, he fell into the sea and drowned.
27and up until the sun melted the wax off his wings. For not heeding the
28middle course, he fell into the sea and drowned.
29 27
30More recently, management scholars have explored the [Pareto 28More recently, management scholars have explored the [Pareto
31principle](https://en.wikipedia.org/wiki/Pareto_principle) and found 29principle](https://en.wikipedia.org/wiki/Pareto_principle) and found that as we
32that as we increase the frequency of something, or strive to perform 30increase the frequency of something, or strive to perform actions to achieve
33actions to achieve some form of perfection, we run into [diminishing 31some form of perfection, we run into [diminishing
34returns](https://en.wikipedia.org/wiki/Diminishing_returns). 32returns](https://en.wikipedia.org/wiki/Diminishing_returns).
35 33
36Even further, Harold Demsetz is noted as coining the term [the Nirvana 34Even further, Harold Demsetz is noted as coining the term [the Nirvana
37fallacy](https://en.wikipedia.org/wiki/Nirvana_fallacy) in 1969, which 35fallacy](https://en.wikipedia.org/wiki/Nirvana_fallacy) in 1969, which shows the
38shows the fallacy of comparing actual things with unrealistic, idealized 36fallacy of comparing actual things with unrealistic, idealized alternatives.
39alternatives. This is another trap that we may fall into, where we are 37This is another trap that we may fall into, where we are constantly thinking of
40constantly thinking of the ultimate solutions to problems, when 38the ultimate solutions to problems, when something more realistic needs to be
41something more realistic needs to be considered. 39considered.
42 40
43Over and over throughout history, we\'ve found that perfection is often 41Over and over throughout history, we've found that perfection is often
44unrealistic and unachievable. However, we push ourselves and our peers 42unrealistic and unachievable. However, we push ourselves and our peers to "give
45to \"give 100%\" or \"go the extra mile,\" while it may be that the 43100%" or "go the extra mile," while it may be that the better course is to
46better course is to give a valuable level of effort while considering 44give a valuable level of effort while considering the effects of further effort
47the effects of further effort on the outcome. Working harder does not 45on the outcome. Working harder does not always help us achieve loftier goals.
48always help us achieve loftier goals. 46
49 47This has presented itself to me most recently during my time studying at my
50This has presented itself to me most recently during my time studying at 48university. I was anxious and feeling the stresses of my courses, career, and
51my university. I was anxious and feeling the stresses of my courses, 49personal life for quite a while, which was greatly affecting how well I was
52career, and personal life for quite a while, which was greatly affecting 50doing at school and my level of effort at work. One day, I happened to be
53how well I was doing at school and my level of effort at work. One day, 51talking to my father when he said something simple that hit home:
54I happened to be talking to my father when he said something simple that 52
55hit home: 53> All you can do is show up and do your best. Worrying about the outcomes won't
56 54> affect the outcome itself.
57> All you can do is show up and do your best. Worrying about the
58> outcomes won\'t affect the outcome itself.
59 55
60The thought was extremely straightforward and uncomplicated, yet it was 56The thought was extremely straightforward and uncomplicated, yet it was
61something that I had lost sight of during my stress-filled years at 57something that I had lost sight of during my stress-filled years at school. Ever
62school. Ever since then, I\'ve found myself pausing and remembering that 58since then, I've found myself pausing and remembering that quote every time I
63quote every time I get anxious or stressed. It helps to stop and think 59get anxious or stressed. It helps to stop and think "Can I do anything to
64\"Can I do anything to affect the outcome, or am I simply worrying over 60affect the outcome, or am I simply worrying over something I can't change?"
65something I can\'t change?\" 61
66 62# When Mediocrity Isn't Enough
67# When Mediocrity Isn\'t Enough 63
68 64One problem with the philosophies presented in this post is that they are
69One problem with the philosophies presented in this post is that they 65implemented far too often in situations where mediocrity simply isn't adequate.
70are implemented far too often in situations where mediocrity simply 66For example, let's take a look at digital user data, specifically
71isn\'t adequate. For example, let\'s take a look at digital user data, 67personally-identifiable information (PII). As a cybersecurity auditor in the
72specifically personally-identifiable information (PII). As a 68United States, I have found that most companies are concerned more with
73cybersecurity auditor in the United States, I have found that most 69compliance than any actual safeguards over the privacy or protection of user
74companies are concerned more with compliance than any actual safeguards 70data. Other than companies who have built their reputation on privacy and
75over the privacy or protection of user data. Other than companies who 71security, most companies will use
76have built their reputation on privacy and security, most companies will 72[satisficing](https://en.wikipedia.org/wiki/Satisficing) as their primary
77use [satisficing](https://en.wikipedia.org/wiki/Satisficing) as their 73decision-making strategy around user data.
78primary decision-making strategy around user data. 74
79 75> Satisficing is a decision-making strategy or cognitive heuristic that entails
80> Satisficing is a decision-making strategy or cognitive heuristic that 76> searching through the available alternatives until an acceptability threshold
81> entails searching through the available alternatives until an 77> is met.
82> acceptability threshold is met. 78
83 79This means that each decision will be met with certain possible solutions until
84This means that each decision will be met with certain possible 80one of the solutions meets their minimum acceptable standards. For companies
85solutions until one of the solutions meets their minimum acceptable 81that deal with user data, the minimum-acceptable standards come from three
86standards. For companies that deal with user data, the 82areas:
87minimum-acceptable standards come from three areas: 83
88 841. Laws and regulations
891. Laws and regulations 852. Competitive pressure
902. Competitive pressure 863. Risk of monetary or reputation loss
913. Risk of monetary or reputation loss 87
92 88Working with project management or auditing, the primary concern here is the
93Working with project management or auditing, the primary concern here is 89risk of legal ramifications. Since the primary risk comes from laws and
94the risk of legal ramifications. Since the primary risk comes from laws 90regulations, companies will require that any project that involves user data
95and regulations, companies will require that any project that involves 91must follow all the rules of those laws so that the company can protect itself
96user data must follow all the rules of those laws so that the company 92from fines or other penalties.
97can protect itself from fines or other penalties. 93
98 94Following this, companies will consider best practices in order to place itself
99Following this, companies will consider best practices in order to place 95in a competitive position (e.g. Google vs. Apple) and review any recent or
100itself in a competitive position (e.g. Google vs. Apple) and review any 96ongoing litigation against companies regarding user data. In a perfect company,
101recent or ongoing litigation against companies regarding user data. In a 97management would then consider the ethical responsibilities of their
102perfect company, management would then consider the ethical 98organization and discuss their responsibilities over things like
103responsibilities of their organization and discuss their 99personally-identifiable information.
104responsibilities over things like personally-identifiable information. 100
105 101However, as we mentioned above, most companies follow the idea of satisficing,
106However, as we mentioned above, most companies follow the idea of 102which states that they have met the minimum acceptable standards and can now
107satisficing, which states that they have met the minimum acceptable 103move on to other decisions. Modern business culture in the United States
108standards and can now move on to other decisions. Modern business 104dictates that profits are the golden measure of how well a company or manager is
109culture in the United States dictates that profits are the golden 105performing, so we often don't think about our responsibilities beyond these
110measure of how well a company or manager is performing, so we often 106basic standards.
111don\'t think about our responsibilities beyond these basic standards. 107
112 108Not all situations demand excellence, but I believe that applying any philosophy
113Not all situations demand excellence, but I believe that applying any 109as a broad stroke across one's life can be a mistake. We must be able to think
114philosophy as a broad stroke across one\'s life can be a mistake. We 110critically about what we are doing as we do it and ask ourselves a few
115must be able to think critically about what we are doing as we do it and 111questions. Have I done everything I can in this situation? Is mediocrity an
116ask ourselves a few questions. Have I done everything I can in this 112acceptable outcome, or should we strive for perfection, even if we can't attain
117situation? Is mediocrity an acceptable outcome, or should we strive for 113it?
118perfection, even if we can\'t attain it?
119 114
120Taking a few moments to think critically throughout our day, as we make 115Taking a few moments to think critically throughout our day, as we make
121decisions, can have a tremendous effect on the outcomes we create. 116decisions, can have a tremendous effect on the outcomes we create.
content/blog/2020-12-27-website-redesign.md +72 −81
@@ -7,98 +7,89 @@ draft = false
7 7
8# A Brief History 8# A Brief History
9 9
10As a form of continuous learning and entertainment, I\'ve been running a 10As a form of continuous learning and entertainment, I've been running a handful
11handful of websites since 2016 when I took my first programming courses 11of websites since 2016 when I took my first programming courses in college. I
12in college. I maintain one main website, the place I consider the 12maintain one main website, the place I consider the official website to
13official website to represent me. Under this site, I have a handful of 13represent me. Under this site, I have a handful of subdirectories and
14subdirectories and subdomains. 14subdomains.
15 15
16One of the parts I\'ve enjoyed the most about web development is the 16One of the parts I've enjoyed the most about web development is the aspect of
17aspect of designing an identity for a web page and working to find 17designing an identity for a web page and working to find exciting ways to
18exciting ways to display the site\'s content. Inevitably, this means 18display the site's content. Inevitably, this means I've changed the designs
19I\'ve changed the designs for my websites more times than I could 19for my websites more times than I could possibly count. Since I don't really
20possibly count. Since I don\'t really host anything on my main webpage 20host anything on my main webpage that's vital, it allows me the freedom to
21that\'s vital, it allows me the freedom to change things as inspiration 21change things as inspiration strikes.
22strikes. 22
23 23Historically, I've relied on core utilities for spacing, components, and
24Historically, I\'ve relied on core utilities for spacing, components, 24layouts from [Bootstrap](https://getbootstrap.com) and added custom CSS for
25and layouts from [Bootstrap](https://getbootstrap.com) and added custom 25fonts, accents, colors, and other items. I also tend to create sites with no
26CSS for fonts, accents, colors, and other items. I also tend to create 26border radius on items, visible borders, and content that takes up the entire
27sites with no border radius on items, visible borders, and content that 27screen (using whitespace inside components instead of whitespace around my
28takes up the entire screen (using whitespace inside components instead 28components).
29of whitespace around my components).
30 29
31# The Redesign Process 30# The Redesign Process
32 31
33About a week ago, I found myself wishing for a new design yet again. The 32About a week ago, I found myself wishing for a new design yet again. The prior
34prior design was largely inspired by IBM\'s [Carbon Design 33design was largely inspired by IBM's [Carbon Design
35System](https://www.carbondesignsystem.com) and relied on jQuery, 34System](https://www.carbondesignsystem.com) and relied on jQuery, Bootstrap,
36Bootstrap, along with some compressed 35along with some compressed [.webp](https://en.wikipedia.org/wiki/WebP) images.
37[.webp](https://en.wikipedia.org/wiki/WebP) images.
38 36
39To anyone who knows my preferences toward web design - and even in my 37To anyone who knows my preferences toward web design - and even in my personal
40personal life - it should be no surprise that I immediately started 38life - it should be no surprise that I immediately started looking for
41looking for inspiration on minimalism. While there are some decent 39inspiration on minimalism. While there are some decent minimalistic designs on
42minimalistic designs on sites like 40sites like
43[Dribbble](https://dribbble.com/search/shots/popular/web-design?q=minimalism), 41[Dribbble](https://dribbble.com/search/shots/popular/web-design?q=minimalism),
44people seem to mostly discuss [brutalist web 42people seem to mostly discuss [brutalist web
45design](https://brutalist-web.design) when you ask about minimalism. 43design](https://brutalist-web.design) when you ask about minimalism. While
46While brutalist web design doesn\'t have to be minimal, it often is. 44brutalist web design doesn't have to be minimal, it often is.
47 45
48I suppose, in a way, I did create a brutalist website since my HTML is 46I suppose, in a way, I did create a brutalist website since my HTML is semantic
49semantic and accessible, hyperlinks are colored and underlined, and all 47and accessible, hyperlinks are colored and underlined, and all native browser
50native browser functions like scrolling and the back button work as 48functions like scrolling and the back button work as expected. However, I
51expected. However, I didn\'t think about brutalism while designing these 49didn't think about brutalism while designing these sites.
52sites. 50
53 51The new design followed a simple design process. I walked through the screens on
54The new design followed a simple design process. I walked through the 52my blog and asked myself: "Is this element necessary for a user?" This allowed
55screens on my blog and asked myself: \"Is this element necessary for a 53me to first start by removing all javascript, which had the sole purpose of
56user?\" This allowed me to first start by removing all javascript, which 54allowing users to open a collapsed navbar on mobile. Replacing the collapsible
57had the sole purpose of allowing users to open a collapsed navbar on 55navbar allowed me to remove both jQuery and Bootstrap's javascript.
58mobile. Replacing the collapsible navbar allowed me to remove both 56
59jQuery and Bootstrap\'s javascript. 57Next, I removed things like author names (since I'm literally the only person
60 58who will ever write on this site), multiple ways to click on a blog post card,
61Next, I removed things like author names (since I\'m literally the only 59blog post descriptions, and the scroll-to-top button. It also helped to move all
62person who will ever write on this site), multiple ways to click on a 60categories to a single page, rather than have each category on its own page.
63blog post card, blog post descriptions, and the scroll-to-top button. It
64also helped to move all categories to a single page, rather than have
65each category on its own page.
66 61
67The final big piece to finish the 62The final big piece to finish the
68\"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)\"-like 63"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)"-like
69part of my process was to remove Bootstrap CSS in its entirety. However, 64part of my process was to remove Bootstrap CSS in its entirety. However, this
70this meant pulling out a few very useful classes, such as 65meant pulling out a few very useful classes, such as `.img-fluid` and the
71`.img-fluid` and the default font stacks to keep in my custom 66default font stacks to keep in my custom CSS.
72CSS. 67
73 68After removing all the unnecessary pieces, I was finally able to reorganize my
74After removing all the unnecessary pieces, I was finally able to 69content and add a very small amount of custom CSS to make everything pretty.
75reorganize my content and add a very small amount of custom CSS to make 70This took a brief amount of time, effectively just consisting of me converting
76everything pretty. This took a brief amount of time, effectively just 71`<div>` tags into things like `<ul>` lists and choosing accent colors.
77consisting of me converting `<div>` tags into things like
78`<ul>` lists and choosing accent colors.
79 72
80# The Results 73# The Results
81 74
82## Reflection 75## Reflection
83 76
84So, what did all of this reorganizing do to my webpages? Well, first, my 77So, what did all of this reorganizing do to my webpages? Well, first, my
85websites are now **ridiculously fast**. Since the prior designs were 78websites are now **ridiculously fast**. Since the prior designs were also
86also minimal and didn\'t have many images, they measured up in 79minimal and didn't have many images, they measured up in Firefox's Network
87Firefox\'s Network Monitor around 300 KB - 600KB. After making the 80Monitor around 300 KB - 600KB. After making the changes, my main site is at 5 KB
88changes, my main site is at 5 KB transferred (22 KB total), and my blog 81transferred (22 KB total), and my blog is at 6.5 KB transferred (13 KB total).
89is at 6.5 KB transferred (13 KB total). **That means the redesigned 82**That means the redesigned pages are less than 2% the size of the old
90pages are less than 2% the size of the old designs.** 83designs.**
91 84
92Google Lighthouse ranks the new webpage as 100 in performance, 85Google Lighthouse ranks the new webpage as 100 in performance, accessibility,
93accessibility, and best practices, with SEO at 92 since they think tap 86and best practices, with SEO at 92 since they think tap targets are not sized
94targets are not sized appropriately for mobile users. First contextual 87appropriately for mobile users. First contextual paints of the pages are under
95paints of the pages are under 0.8 seconds with 0 ms of blocking time. 880.8 seconds with 0 ms of blocking time. However, the blog subdomain ranks at 100
96However, the blog subdomain ranks at 100 for all four categories! First 89for all four categories! First contextual paints of the blog homepage are under
97contextual paints of the blog homepage are under 1.0 seconds with 0 ms 901.0 seconds with 0 ms of blocking time, due to the fact that the CSS for my blog
98of blocking time, due to the fact that the CSS for my blog is within a 91is within a separate CSS file, and the CSS for my main website is simply
99separate CSS file, and the CSS for my main website is simply embedded in 92embedded in the HTML file.
100the HTML file. 93
101 94Now that everything is complete, I can confidently say I'm happy with the
102Now that everything is complete, I can confidently say I\'m happy with 95result and proud to look at the fastest set of websites I've created so far.
103the result and proud to look at the fastest set of websites I\'ve
104created so far.
content/blog/2020-12-28-neon-drive.md +48 −51
@@ -7,51 +7,49 @@ draft = false
7 7
8# Game Description 8# Game Description
9 9
10[Neon Drive](https://store.steampowered.com/app/433910/Neon_Drive/) 10[Neon Drive](https://store.steampowered.com/app/433910/Neon_Drive/) presents
11presents itself as a simple arcade-style game inspired by the arcade 11itself as a simple arcade-style game inspired by the arcade race games of the
12race games of the 1980s, yet it has managed to take up hours of my life 121980s, yet it has managed to take up hours of my life without much effort. The
13without much effort. The game description, directly from the Steam page, 13game description, directly from the Steam page, is intriguing enough to entice
14is intriguing enough to entice anyone who\'s been looking for a good 14anyone who's been looking for a good arcade racing game:
15arcade racing game:
16 15
17> Neon Drive is a slick retro-futuristic arcade game that will make your 16> Neon Drive is a slick retro-futuristic arcade game that will make your brain
18> brain melt. You\'ve been warned. From beautiful cityscapes and ocean 17> melt. You've been warned. From beautiful cityscapes and ocean roads to
19> roads to exploding enemy spaceships, Neon Drive has it all. 18> exploding enemy spaceships, Neon Drive has it all.
20 19
21# Gameplay 20# Gameplay
22 21
23The game holds true to the 22The game holds true to the
24[retro-futurism](https://en.wikipedia.org/wiki/Retrofuturism) style, 23[retro-futurism](https://en.wikipedia.org/wiki/Retrofuturism) style, including
25including chrome female robots, pixelated arcade machines, and 24chrome female robots, pixelated arcade machines, and
26[outrun](https://teddit.net/r/outrun/) aesthetics. 25[outrun](https://teddit.net/r/outrun/) aesthetics.
27 26
28Each level of the game is shown as a separate arcade machine. Each 27Each level of the game is shown as a separate arcade machine. Each arcade
29arcade machine lets you play on Normal, Hard, Insane, Practice, and Free 28machine lets you play on Normal, Hard, Insane, Practice, and Free Run. To beat
30Run. To beat each arcade, you must reach the end of the level without 29each arcade, you must reach the end of the level without crashing your car into
31crashing your car into the various obstacles on the course. Basic levels 30the various obstacles on the course. Basic levels let you move left or right to
32let you move left or right to avoid blocks in the road. Later levels put 31avoid blocks in the road. Later levels put you through other tests, such as
33you through other tests, such as dodging traffic or blasting asteroids. 32dodging traffic or blasting asteroids.
34 33
35The game uses synthwave music to keep you on track to make the correct 34The game uses synthwave music to keep you on track to make the correct moves by
36moves by timing the beats of the songs to the correct moves on the 35timing the beats of the songs to the correct moves on the screen. It reminds me
37screen. It reminds me of the early Guitar Hero games, as well as mobile 36of the early Guitar Hero games, as well as mobile apps like VOEZ - repetition
38apps like VOEZ - repetition and staying on-beat is the only way to win. 37and staying on-beat is the only way to win.
39 38
40# In-Game Screenshots 39# In-Game Screenshots
41 40
42Taking a look at the main menu, you can see that Neon Drive plays into 41Taking a look at the main menu, you can see that Neon Drive plays into every
43every stereotype you can think of around retro-futuristic, synthwave 42stereotype you can think of around retro-futuristic, synthwave arcades (in a
44arcades (in a good way). 43good way).
45 44
46![Neon Drive 45![Neon Drive
47Menu](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_menu.png) 46Menu](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_menu.png)
48 47
49Once you get into the first level, we see that the choice of car fits 48Once you get into the first level, we see that the choice of car fits right in
50right in with the stereotypical cars of the 80s, like the 49with the stereotypical cars of the 80s, like the
51[DeLorean](https://en.wikipedia.org/wiki/DMC_DeLorean) or the [Ferrari 50[DeLorean](https://en.wikipedia.org/wiki/DMC_DeLorean) or the [Ferrari
52F40](https://en.wikipedia.org/wiki/Ferrari_F40). Each new level comes 51F40](https://en.wikipedia.org/wiki/Ferrari_F40). Each new level comes with new
53with new color schemes and cars, so you should never get tired of the 52color schemes and cars, so you should never get tired of the aesthetic.
54aesthetic.
55 53
56![Neon Drive 54![Neon Drive
57Race](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_race.png) 55Race](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_race.png)
@@ -61,35 +59,34 @@ Personally, I love the orange and blue colors used in level 2:
61![Level 59![Level
622](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_level_2.png) 602](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_level_2.png)
63 61
64If you\'re the competitive type and getting 100% on all arcade machines 62If you're the competitive type and getting 100% on all arcade machines isn't
65isn\'t enough, there are leaderboards for the regular part of the game, 63enough, there are leaderboards for the regular part of the game, and the
66and the endurance game mode. 64endurance game mode.
67 65
68![Leaderboard](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_leaderboard.png) 66![Leaderboard](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_leaderboard.png)
69 67
70# Other Suggestions 68# Other Suggestions
71 69
72Neon Drive sits nicely within the well-founded cult genre of Outrun. 70Neon Drive sits nicely within the well-founded cult genre of Outrun. Other games
73Other games that I\'ve enjoyed in this same spectrum are: 71that I've enjoyed in this same spectrum are:
74 72
75- [Far Cry 3: Blood 73- [Far Cry 3: Blood
76 Dragon](https://store.steampowered.com/app/233270/Far_Cry_3__Blood_Dragon/) 74 Dragon](https://store.steampowered.com/app/233270/Far_Cry_3__Blood_Dragon/)
77- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/) 75- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/)
78- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/) 76- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/)
79 77
80Although these games aren\'t necessarily in the same genre, they do have 78Although these games aren't necessarily in the same genre, they do have aspects
81aspects that place them close enough to interest gamers that enjoyed 79that place them close enough to interest gamers that enjoyed Neon Drive:
82Neon Drive:
83 80
84- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/) 81- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/)
85- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/) 82- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/)
86- [Need for Speed: 83- [Need for Speed:
87 Heat](https://store.steampowered.com/app/1222680/Need_for_Speed_Heat/) 84 Heat](https://store.steampowered.com/app/1222680/Need_for_Speed_Heat/)
88- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/) 85- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/)
89 86
90Of course, if all you really care about is the arcade aspect of these 87Of course, if all you really care about is the arcade aspect of these games, you
91games, you can check out the [Atari 88can check out the [Atari
92Vault](https://store.steampowered.com/app/400020/Atari_Vault/) or any of 89Vault](https://store.steampowered.com/app/400020/Atari_Vault/) or any of the
93the other classic games sold on Steam by companies like Namco, Atari. 90other classic games sold on Steam by companies like Namco, Atari. For something
94For something like Nintendo, you\'d have to settle for buying used 91like Nintendo, you'd have to settle for buying used classic consoles or delve
95classic consoles or delve into the world of emulation. 92into the world of emulation.
content/blog/2020-12-29-zork.md +59 −68
@@ -7,34 +7,33 @@ draft = false
7 7
8# Download (Free) 8# Download (Free)
9 9
10Before we get into the game itself, you should know that you can 10Before we get into the game itself, you should know that you can download Zork
11download Zork for free from Infocom\'s [download 11for free from Infocom's [download
12page](http://infocom-if.org/downloads/downloads.html). So feel free to 12page](http://infocom-if.org/downloads/downloads.html). So feel free to boot it
13boot it up and take a ride back to the 1980s with this masterpiece. 13up and take a ride back to the 1980s with this masterpiece.
14 14
15# Game Description 15# Game Description
16 16
17Zork is an interactive, text-based computer game originally released in 17Zork is an interactive, text-based computer game originally released in
181980. This series, split into three separate games, introduced a robust 181980. This series, split into three separate games, introduced a robust and
19and sophisticated text parser to gamers. People were largely used to the 19sophisticated text parser to gamers. People were largely used to the simple
20simple commands used in the popular game [Colossal Cave 20commands used in the popular game [Colossal Cave
21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but 21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but Zork
22Zork allowed users to send more complex commands that included 22allowed users to send more complex commands that included prepositions and
23prepositions and conjunctions. 23conjunctions.
24 24
25Zork tracks your score as you explore the map, find tools, and collect 25Zork tracks your score as you explore the map, find tools, and collect trophy
26trophy items (e.g., a jewel-encrusted egg). When you place your trophy 26items (e.g., a jewel-encrusted egg). When you place your trophy items in the
27items in the trophy case found in the Living Room area, you gain score 27trophy case found in the Living Room area, you gain score points. Collecting the
28points. Collecting the Twenty Treasures of Zork and placing them within 28Twenty Treasures of Zork and placing them within the trophy case wins the game.
29the trophy case wins the game. However, you must explore the map, solve 29However, you must explore the map, solve puzzles, and avoid being eaten by a
30puzzles, and avoid being eaten by a grue to collect these treasures. 30grue to collect these treasures.
31 31
32# The Map 32# The Map
33 33
34Since Zork is a vast and complex game, it helps to have a map as you 34Since Zork is a vast and complex game, it helps to have a map as you explore and
35explore and collect your trophies. However, if you want to play the game 35collect your trophies. However, if you want to play the game as it was truly
36as it was truly intended, you should try to play it without using the 36intended, you should try to play it without using the map.
37map.
38 37
39![Zork Map](https://img.cleberg.net/blog/20201229-zork/zork_map.png) 38![Zork Map](https://img.cleberg.net/blog/20201229-zork/zork_map.png)
40 39
@@ -42,55 +41,47 @@ map.
42 41
43# In-Game Screenshots 42# In-Game Screenshots
44 43
45After playing the game (for the first time ever) for several weeks 44After playing the game (for the first time ever) for several weeks around 2014,
46around 2014, I was finally able to beat the game with some online help 45I was finally able to beat the game with some online help to find the last
47to find the last couple items. As I was writing this post, I installed 46couple items. As I was writing this post, I installed the game again to grab
48the game again to grab some screenshots to show off the true glory of 47some screenshots to show off the true glory of this game. As noted in [Jimmy
49this game. As noted in [Jimmy Maher\'s 48Maher's playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/),
50playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/), the 49the original Zork games looked quite a bit different due to the older hardware
51original Zork games looked quite a bit different due to the older 50of computers like the Apple II and multiple bug fixes that Infocom pushed out
52hardware of computers like the Apple II and multiple bug fixes that 51after the game's initial release. My play-through uses the [Zork
53Infocom pushed out after the game\'s initial release. My play-through 52Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/) version,
54uses the [Zork 53which utilizes DOSBox on Windows.
55Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/) 54
56version, which utilizes DOSBox on Windows. 55The first screenshot here shows the introductory information, which doesn't
57 56include instructions of any kind for the player. If you haven't played text
58The first screenshot here shows the introductory information, which 57adventures before, try to use simple commands like "go west," "look around,"
59doesn\'t include instructions of any kind for the player. If you 58or "hit troll with elvish sword."
60haven\'t played text adventures before, try to use simple commands like 59
61\"go west,\" \"look around,\" or \"hit troll with elvish sword.\" 60![Zork Screen, pt. 1](https://img.cleberg.net/blog/20201229-zork/zork_01.png)
62 61
63![Zork Screen, pt. 62In this second screenshot, we see the player has entered the house and found the
641](https://img.cleberg.net/blog/20201229-zork/zork_01.png) 63trophy case in the living room. The lantern and sword in this room allow the
65 64player to explore dark areas and attack enemies. If you don't use the lantern,
66In this second screenshot, we see the player has entered the house and 65you won't be able to see anything in dark areas, and you may be eaten by a
67found the trophy case in the living room. The lantern and sword in this 66grue.
68room allow the player to explore dark areas and attack enemies. If you 67
69don\'t use the lantern, you won\'t be able to see anything in dark 68![Zork Screen, pt. 2](https://img.cleberg.net/blog/20201229-zork/zork_02.png)
70areas, and you may be eaten by a grue. 69
71 70Finally, we see that the player has found the first treasure: a jewel-encrusted
72![Zork Screen, pt. 71egg. These treasures can be taken back to the house and placed in the trophy
732](https://img.cleberg.net/blog/20201229-zork/zork_02.png) 72case or carried until you feel like you want to put things away.
74 73
75Finally, we see that the player has found the first treasure: a 74![Zork Screen, pt 3.](https://img.cleberg.net/blog/20201229-zork/zork_03.png)
76jewel-encrusted egg. These treasures can be taken back to the house and
77placed in the trophy case or carried until you feel like you want to put
78things away.
79
80![Zork Screen, pt
813.](https://img.cleberg.net/blog/20201229-zork/zork_03.png)
82 75
83# Conclusion 76# Conclusion
84 77
85It\'s been quite a few years since I first played Zork, but I clearly 78It's been quite a few years since I first played Zork, but I clearly remember
86remember the late nights and bloodshot eyes that helped me find all the 79the late nights and bloodshot eyes that helped me find all the treasures. This
87treasures. This game is well worth the time and effort, even though the 80game is well worth the time and effort, even though the text-based aspect may be
88text-based aspect may be off-putting to gamers who didn\'t have to grow 81off-putting to gamers who didn't have to grow up playing games without
89up playing games without graphics. However, I believe that the strategy 82graphics. However, I believe that the strategy and skills learned in early video
90and skills learned in early video games like Zork can actually help you, 83games like Zork can actually help you, even when playing newer games.
91even when playing newer games.
92 84
93If you do decide to play Zork, you can download Zork I, II, and III from 85If you do decide to play Zork, you can download Zork I, II, and III from
94Infocom\'s [download 86Infocom's [download page](http://infocom-if.org/downloads/downloads.html) for
95page](http://infocom-if.org/downloads/downloads.html) for free or search 87free or search the internet for an online version.
96the internet for an online version.
content/blog/2021-01-01-seum.md +51 −58
@@ -8,86 +8,79 @@ draft = false
8# Game Description 8# Game Description
9 9
10[SEUM: Speedrunners from 10[SEUM: Speedrunners from
11Hell](https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/) 11Hell](https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/) is
12is an incredibly fast-paced mashup of a puzzle game and a free-running 12an incredibly fast-paced mashup of a puzzle game and a free-running game.
13game. Created by [Pine Studio](https://pinestudio.co) in early 2016 and 13Created by [Pine Studio](https://pinestudio.co) in early 2016 and first released
14first released as a [demo on 14as a [demo on
15GameJolt](https://gamejolt.com/games/seum-speedrunners-from-hell-demo/154868), 15GameJolt](https://gamejolt.com/games/seum-speedrunners-from-hell-demo/154868),
16this game was successfully green-lit on Steam and has amassed a cult 16this game was successfully green-lit on Steam and has amassed a cult following
17following on multiple consoles. 17on multiple consoles.
18 18
19Here\'s the game description straight from the developers: 19Here's the game description straight from the developers:
20 20
21> Like a bastard child of Quake 3 and Super Meat Boy, SEUM: Speedrunners 21> Like a bastard child of Quake 3 and Super Meat Boy, SEUM: Speedrunners from
22> from Hell is truly hardcore and focuses on speed and fast reaction. 22> Hell is truly hardcore and focuses on speed and fast reaction.
23 23
24# Story 24# Story
25 25
26SEUM does a great job setting the stage when you open the game for the 26SEUM does a great job setting the stage when you open the game for the first
27first time, playing an animated video in the form of comic book images. 27time, playing an animated video in the form of comic book images. You see Marty,
28You see Marty, the protagonist, sitting around drinking his beer as 28the protagonist, sitting around drinking his beer as Satan busts down the door,
29Satan busts down the door, cuts his hand off, and steals all his beer 29cuts his hand off, and steals all his beer and bacon. As Satan is leaving, Marty
30and bacon. As Satan is leaving, Marty whips a vinyl record across the 30whips a vinyl record across the room and cuts off one of Satan's hands. This
31room and cuts off one of Satan\'s hands. This hand is what allows you to 31hand is what allows you to use all the powers in the game.
32use all the powers in the game.
33 32
34Check out the screenshot below for one of the first panels of the 33Check out the screenshot below for one of the first panels of the storyline:
35storyline:
36 34
37![SEUM Story](https://img.cleberg.net/blog/20210101-seum/seum_story.png) 35![SEUM Story](https://img.cleberg.net/blog/20210101-seum/seum_story.png)
38 36
39# Gameplay 37# Gameplay
40 38
41To accomplish each level, you will need to get to the final blue portal 39To accomplish each level, you will need to get to the final blue portal under a
42under a certain time limit. You can beat a level by getting to the 40certain time limit. You can beat a level by getting to the portal before the
43portal before the time meter runs out or \"Dominate\" a level by beating 41time meter runs out or "Dominate" a level by beating it within a shorter time
44it within a shorter time limit (noted by a bright red/orange color in 42limit (noted by a bright red/orange color in the time meter).
45the time meter). 43
46 44The portal is usually set behind locked gates, protected by dangerous defenses,
47The portal is usually set behind locked gates, protected by dangerous 45or in hard-to-reach places. To reach the portal, you'll need to go through any
48defenses, or in hard-to-reach places. To reach the portal, you\'ll need 46existing orange portals, light all yellow beacons, avoid things like fireballs
49to go through any existing orange portals, light all yellow beacons, 47and blades, or use any satanic power orbs lying around. These special abilities
50avoid things like fireballs and blades, or use any satanic power orbs 48include:
51lying around. These special abilities include: 49
52 50- Gravity
53- Gravity 51- Teleport
54- Teleport 52- Rewind
55- Rewind 53- Spawn platform
56- Spawn platform 54- Roar (DLC)
57- Roar (DLC) 55- Rocket (DLC)
58- Rocket (DLC) 56- Shadow world (DLC)
59- Shadow world (DLC) 57
60 58For the main storyline, there are nine floors to beat. Each floor contains nine
61For the main storyline, there are nine floors to beat. Each floor 59regular levels, one boss level, and one bonus level; although you don't
62contains nine regular levels, one boss level, and one bonus level; 60technically need to beat all levels to advance to the next floor.
63although you don\'t technically need to beat all levels to advance to 61
64the next floor. 62![SEUM Floor Menu](https://img.cleberg.net/blog/20210101-seum/seum_floor.png)
65
66![SEUM Floor
67Menu](https://img.cleberg.net/blog/20210101-seum/seum_floor.png)
68 63
69# In-Game Screenshots 64# In-Game Screenshots
70 65
71The main menu gives you plenty of options for tuning your system, 66The main menu gives you plenty of options for tuning your system, playing main
72playing main levels, playing the DLC, or exploring the other game modes. 67levels, playing the DLC, or exploring the other game modes.
73 68
74![SEUM Main 69![SEUM Main Menu](https://img.cleberg.net/blog/20210101-seum/seum_menu.png)
75Menu](https://img.cleberg.net/blog/20210101-seum/seum_menu.png)
76 70
77Once you enter a level, you can look around and strategize before 71Once you enter a level, you can look around and strategize before starting.
78starting. Clicking any button will start the menu, and you\'ll have to 72Clicking any button will start the menu, and you'll have to restart if you die.
79restart if you die. One of the great things about SEUM is that it has 73One of the great things about SEUM is that it has great keyboard shortcuts. You
80great keyboard shortcuts. You can quickly smash `R` to 74can quickly smash `R` to restart the level or `M` to return to the level menu.
81restart the level or `M` to return to the level menu.
82 75
83![SEUM Level](https://img.cleberg.net/blog/20210101-seum/seum_level.png) 76![SEUM Level](https://img.cleberg.net/blog/20210101-seum/seum_level.png)
84 77
85Once you\'re able to win a level, you\'ll see the high scores and can 78Once you're able to win a level, you'll see the high scores and can watch
86watch replays of the best scores. 79replays of the best scores.
87 80
88![SEUM Win](https://img.cleberg.net/blog/20210101-seum/seum_win.png) 81![SEUM Win](https://img.cleberg.net/blog/20210101-seum/seum_win.png)
89 82
90Each regular level contains a beer in a disguised location that may take 83Each regular level contains a beer in a disguised location that may take some
91some out-of-the-box thinking. 84out-of-the-box thinking.
92 85
93![SEUM Beer](https://img.cleberg.net/blog/20210101-seum/seum_beer.png) 86![SEUM Beer](https://img.cleberg.net/blog/20210101-seum/seum_beer.png)
content/blog/2021-01-04-fediverse.md +56 −60
@@ -7,101 +7,97 @@ draft = false
7 7
8# What is the Fediverse? 8# What is the Fediverse?
9 9
10The fediverse is a federated universe of servers commonly used for 10The fediverse is a federated universe of servers commonly used for sharing
11sharing content, like social media. So, instead of having to rely on a 11content, like social media. So, instead of having to rely on a single
12single organization to run the server (e.g. Facebook), the fediverse is 12organization to run the server (e.g. Facebook), the fediverse is a giant
13a giant collection of servers across the world, owned by many people and 13collection of servers across the world, owned by many people and organizations.
14organizations. 14
15 15Take a look at this depiction of a federated network. Each server in this photo
16Take a look at this depiction of a federated network. Each server in 16is owned and run by different administrators/owners. Federated networks are best
17this photo is owned and run by different administrators/owners. 17explained as email servers: you have an email account that exists on a server
18Federated networks are best explained as email servers: you have an 18(e.g. Outlook), your friend has an account on a different server (e.g. GMail),
19email account that exists on a server (e.g. Outlook), your friend has an 19and another friend has an account on a third server (e.g. ProtonMail). All three
20account on a different server (e.g. GMail), and another friend has an 20of you can talk and communicate back and forth without having to be on the same
21account on a third server (e.g. ProtonMail). All three of you can talk 21server. However, responsible email admins are there to set rules and control the
22and communicate back and forth without having to be on the same server.
23However, responsible email admins are there to set rules and control the
24traffic going in/out of the server. 22traffic going in/out of the server.
25 23
26![Federated services 24![Federated services
27diagram](https://img.cleberg.net/blog/20210104-a-simple-guide-to-the-fediverse/federated-example.svg) 25diagram](https://img.cleberg.net/blog/20210104-a-simple-guide-to-the-fediverse/federated-example.svg)
28 26
29The main objective of this architecture is to decentralize the control 27The main objective of this architecture is to decentralize the control within
30within the internet connections. For example, if you run your own 28the internet connections. For example, if you run your own Mastodon instance,
31Mastodon instance, you and your users can\'t be censored or impacted in 29you and your users can't be censored or impacted in any way by authorities of
32any way by authorities of another Mastodon instance. Some users have 30another Mastodon instance. Some users have praised these features due to recent
33praised these features due to recent criticism of popular social media 31criticism of popular social media websites that may be over-censoring their
34websites that may be over-censoring their users. 32users.
35 33
36This strategy is great for making sure control of the social web isn\'t 34This strategy is great for making sure control of the social web isn't
37controlled by a single organization, but it also has some downsides. If 35controlled by a single organization, but it also has some downsides. If I create
38I create a Mastodon instance and get a ton of users to sign up, I can 36a Mastodon instance and get a ton of users to sign up, I can shut the server
39shut the server down at any time. That means you\'re at risk of losing 37down at any time. That means you're at risk of losing the content you've
40the content you\'ve created unless you back it up, or the server backs 38created unless you back it up, or the server backs it up for you. Also,
41it up for you. Also, depending on the software used (e.g. Mastodon, 39depending on the software used (e.g. Mastodon, Pixelfed, etc.), censorship may
42Pixelfed, etc.), censorship may still be an issue if the server admins 40still be an issue if the server admins decide they want to censor their users.
43decide they want to censor their users. Now, censorship isn\'t always a 41Now, censorship isn't always a bad thing and can even benefit the community as
44bad thing and can even benefit the community as a whole, but you\'ll 42a whole, but you'll want to determine which servers align with your idea of
45want to determine which servers align with your idea of proper 43proper censorship.
46censorship. 44
47 45However, these are risks that we take when we sign up for any online platform.
48However, these are risks that we take when we sign up for any online 46Whatever your reason is for trying out federated social networks, they are part
49platform. Whatever your reason is for trying out federated social 47of the future of the internet. However, the popularity of these services is
50networks, they are part of the future of the internet. However, the 48still yet to be determined, especially with the increased difficulty
51popularity of these services is still yet to be determined, especially 49understanding and signing up for these platforms. Perhaps increased regulation
52with the increased difficulty understanding and signing up for these 50and litigation against current social media sites will push more users into the
53platforms. Perhaps increased regulation and litigation against current 51fediverse.
54social media sites will push more users into the fediverse.
55 52
56# Federated Alternatives to Popular Sites 53# Federated Alternatives to Popular Sites
57 54
58The list below is a small guide that will show you federated 55The list below is a small guide that will show you federated alternatives to
59alternatives to current popular websites. There are many more out there, 56current popular websites. There are many more out there, so go and explore: you
60so go and explore: you might just find the perfect home. 57might just find the perfect home.
61 58
62## Reddit 59## Reddit
63 60
64- [Lemmy](https://lemmy.ml/instances) 61- [Lemmy](https://lemmy.ml/instances)
65 62
66## Twitter/Facebook/Tumblr 63## Twitter/Facebook/Tumblr
67 64
68- [Mastodon](https://joinmastodon.org) 65- [Mastodon](https://joinmastodon.org)
69- [Diaspora](https://diasporafoundation.org) 66- [Diaspora](https://diasporafoundation.org)
70- [Friendica](https://friendi.ca) 67- [Friendica](https://friendi.ca)
71- [GNU Social](https://gnusocial.network) 68- [GNU Social](https://gnusocial.network)
72- [Pleroma](https://pleroma.social) 69- [Pleroma](https://pleroma.social)
73 70
74## Instagram 71## Instagram
75 72
76- [Pixelfed](https://pixelfed.org) 73- [Pixelfed](https://pixelfed.org)
77 74
78## Slack/Discord 75## Slack/Discord
79 76
80- [Matrix](https://element.io) 77- [Matrix](https://element.io)
81 78
82## Youtube/Vimeo 79## Youtube/Vimeo
83 80
84- [Peertube](https://joinpeertube.org) 81- [Peertube](https://joinpeertube.org)
85 82
86## Spotify/Soundcloud 83## Spotify/Soundcloud
87 84
88- [Funkwhale](https://funkwhale.audio) 85- [Funkwhale](https://funkwhale.audio)
89 86
90## Podcasting 87## Podcasting
91 88
92- [Pubcast](https://pubcast.pub) 89- [Pubcast](https://pubcast.pub)
93 90
94## Medium/Blogger 91## Medium/Blogger
95 92
96- [WriteFreely](https://writefreely.org) 93- [WriteFreely](https://writefreely.org)
97 94
98# Get Started 95# Get Started
99 96
100The best way to get started is to simply sign up and learn as you go. If 97The best way to get started is to simply sign up and learn as you go. If you're
101you\'re comfortable signing up through a Mastodon, Pleroma, or Friendica 98comfortable signing up through a Mastodon, Pleroma, or Friendica server, here is
102server, here is [a list of themed 99[a list of themed servers](https://fediverse.party/en/portal/servers) to choose
103servers](https://fediverse.party/en/portal/servers) to choose from. If 100from. If you're looking for something else, try a web search for a federated
104you\'re looking for something else, try a web search for a federated
105alternative to your favorite sites. 101alternative to your favorite sites.
106 102
107Find a server that focuses on your passions and start there! 103Find a server that focuses on your passions and start there!
content/blog/2021-01-07-ufw.md +52 −57
@@ -7,30 +7,29 @@ draft = false
7 7
8# Uncomplicated Firewall 8# Uncomplicated Firewall
9 9
10Uncomplicated Firewall, also known as ufw, is a convenient and 10Uncomplicated Firewall, also known as ufw, is a convenient and beginner-friendly
11beginner-friendly way to enforce OS-level firewall rules. For those who 11way to enforce OS-level firewall rules. For those who are hosting servers or any
12are hosting servers or any device that is accessible to the world (i.e., 12device that is accessible to the world (i.e., by public IP or domain name),
13by public IP or domain name), it\'s critical that a firewall is properly 13it's critical that a firewall is properly implemented and active.
14implemented and active. 14
15 15Ufw is available by default in all Ubuntu installations after 8.04 LTS. For
16Ufw is available by default in all Ubuntu installations after 8.04 LTS. 16other distributions, you can look to install ufw or check if there are
17For other distributions, you can look to install ufw or check if there 17alternative firewalls installed already. There are usually alternatives
18are alternative firewalls installed already. There are usually 18available, such as Fedora's `firewall` and the package available on most
19alternatives available, such as Fedora\'s `firewall` and the 19distributions: `iptables`. Ufw is considered a beginner-friendly front-end to
20package available on most distributions: `iptables`. Ufw is 20iptables.
21considered a beginner-friendly front-end to iptables. 21
22 22[Gufw](https://gufw.org) is available as a graphical user interface (GUI)
23[Gufw](https://gufw.org) is available as a graphical user interface 23application for users who are uncomfortable setting up a firewall through a
24(GUI) application for users who are uncomfortable setting up a firewall 24terminal.
25through a terminal.
26 25
27![Gufw 26![Gufw
28Screenshot](https://img.cleberg.net/blog/20210107-secure-your-network-with-the-uncomplicated-firewall/gufw.png) 27Screenshot](https://img.cleberg.net/blog/20210107-secure-your-network-with-the-uncomplicated-firewall/gufw.png)
29 28
30# Getting Help 29# Getting Help
31 30
32If you need help figuring out commands, remember that you can run the 31If you need help figuring out commands, remember that you can run the `--help`
33`--help` flag to get a list of options. 32flag to get a list of options.
34 33
35```sh 34```sh
36sudo ufw --help 35sudo ufw --help
@@ -38,20 +37,19 @@ sudo ufw --help
38 37
39# Set Default State 38# Set Default State
40 39
41The proper way to run a firewall is to set a strict default state and 40The proper way to run a firewall is to set a strict default state and slowly
42slowly open up ports that you want to allow. This helps prevent anything 41open up ports that you want to allow. This helps prevent anything malicious from
43malicious from slipping through the cracks. The following command 42slipping through the cracks. The following command prevents all incoming traffic
44prevents all incoming traffic (other than the rules we specify later), 43(other than the rules we specify later), but you can also set this for outgoing
45but you can also set this for outgoing connections, if necessary. 44connections, if necessary.
46 45
47```sh 46```sh
48sudo ufw default deny incoming 47sudo ufw default deny incoming
49``` 48```
50 49
51You should also allow outgoing traffic if you want to allow the device 50You should also allow outgoing traffic if you want to allow the device to
52to communicate back to you or other parties. For example, media servers 51communicate back to you or other parties. For example, media servers like Plex
53like Plex need to be able to send out data related to streaming the 52need to be able to send out data related to streaming the media.
54media.
55 53
56```sh 54```sh
57sudo ufw default allow outgoing 55sudo ufw default allow outgoing
@@ -59,24 +57,23 @@ sudo ufw default allow outgoing
59 57
60# Adding Port Rules 58# Adding Port Rules
61 59
62Now that we\'ve disabled all incoming traffic by default, we need to 60Now that we've disabled all incoming traffic by default, we need to open up
63open up some ports (or else no traffic would be able to come in). If you 61some ports (or else no traffic would be able to come in). If you need to be able
64need to be able to `ssh` into the machine, you\'ll need to 62to `ssh` into the machine, you'll need to open up port 22.
65open up port 22.
66 63
67```sh 64```sh
68sudo ufw allow 22 65sudo ufw allow 22
69``` 66```
70 67
71You can also issue more restrictive rules. The following rule will allow 68You can also issue more restrictive rules. The following rule will allow `ssh`
72`ssh` connections only from machines on the local subnet. 69connections only from machines on the local subnet.
73 70
74```sh 71```sh
75sudo ufw allow proto tcp from 192.168.0.0/24 to any port 22 72sudo ufw allow proto tcp from 192.168.0.0/24 to any port 22
76``` 73```
77 74
78If you need to set a rule that isn\'t tcp, just append your connection 75If you need to set a rule that isn't tcp, just append your connection type to
79type to the end of the rule. 76the end of the rule.
80 77
81```sh 78```sh
82sudo ufw allow 1900/udp 79sudo ufw allow 1900/udp
@@ -99,8 +96,7 @@ sudo reboot now
99 96
100# Checking Status 97# Checking Status
101 98
102Now that the firewall is enabled, let\'s check and see what the rules 99Now that the firewall is enabled, let's check and see what the rules look like.
103look like.
104 100
105```sh 101```sh
106sudo ufw status numbered 102sudo ufw status numbered
@@ -117,9 +113,9 @@ Status: active
117 113
118# Deleting Rules 114# Deleting Rules
119 115
120If you need to delete a rule, you need to know the number associated 116If you need to delete a rule, you need to know the number associated with that
121with that rule. Let\'s delete the first rule in the table above. You\'ll 117rule. Let's delete the first rule in the table above. You'll be asked to
122be asked to confirm the deletion as part of this process. 118confirm the deletion as part of this process.
123 119
124```sh 120```sh
125sudo ufw delete 1 121sudo ufw delete 1
@@ -127,11 +123,10 @@ sudo ufw delete 1
127 123
128# Managing App Rules 124# Managing App Rules
129 125
130Luckily, there\'s a convenient way for installed applications to create 126Luckily, there's a convenient way for installed applications to create files
131files that ufw can easily implement so that you don\'t have to search 127that ufw can easily implement so that you don't have to search and find which
132and find which ports your application requires. To see if your device 128ports your application requires. To see if your device has any applications with
133has any applications with pre-installed ufw rules, execute the following 129pre-installed ufw rules, execute the following command:
134command:
135 130
136```sh 131```sh
137sudo ufw app list 132sudo ufw app list
@@ -148,14 +143,14 @@ Available applications:
148 plexmediaserver-dlna 143 plexmediaserver-dlna
149``` 144```
150 145
151If you want to get more information on a specific app rule, use the 146If you want to get more information on a specific app rule, use the `info`
152`info` command. 147command.
153 148
154```sh 149```sh
155sudo ufw app info plexmediaserver-dlna 150sudo ufw app info plexmediaserver-dlna
156``` 151```
157 152
158You\'ll get a blurb of info back like this: 153You'll get a blurb of info back like this:
159 154
160``` txt 155``` txt
161Profile: plexmediaserver-dlna 156Profile: plexmediaserver-dlna
@@ -167,8 +162,8 @@ Ports:
167 32469/tcp 162 32469/tcp
168``` 163```
169 164
170You can add or delete app rules the same way that you\'d add or delete 165You can add or delete app rules the same way that you'd add or delete specific
171specific port rules. 166port rules.
172 167
173```sh 168```sh
174sudo ufw allow plexmediaserver-dlna 169sudo ufw allow plexmediaserver-dlna
@@ -180,12 +175,12 @@ sudo ufw delete RULE|NUM
180 175
181# Creating App Rules 176# Creating App Rules
182 177
183If you\'d like to create you own app rule, you\'ll need to create a file 178If you'd like to create you own app rule, you'll need to create a file in the
184in the `/etc/ufw/applications.d` directory. Within the file 179`/etc/ufw/applications.d` directory. Within the file you create, you need to
185you create, you need to make sure the content is properly formatted. 180make sure the content is properly formatted.
186 181
187For example, here are the contents my `plexmediaserver` file, 182For example, here are the contents my `plexmediaserver` file, which creates
188which creates three distinct app rules for ufw: 183three distinct app rules for ufw:
189 184
190``` config 185``` config
191[plexmediaserver] 186[plexmediaserver]
@@ -204,8 +199,8 @@ description=The Plex Media Server (with additional DLNA capability)
204ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp 199ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp
205``` 200```
206 201
207So, if I wanted to create a custom app rule called \"mycustomrule,\" 202So, if I wanted to create a custom app rule called "mycustomrule," I'd create
208I\'d create a file and add my content like this: 203a file and add my content like this:
209 204
210```sh 205```sh
211sudo nano /etc/ufw/applications.d/mycustomrule 206sudo nano /etc/ufw/applications.d/mycustomrule
content/blog/2021-02-19-macos.md +79 −92
@@ -7,79 +7,74 @@ draft = false
7 7
8# Diving into macOS 8# Diving into macOS
9 9
10After spending nearly 15 years working with Windows and 8 years on 10After spending nearly 15 years working with Windows and 8 years on Linux, I have
11Linux, I have experienced macOS for the first time. By chance, my spouse 11experienced macOS for the first time. By chance, my spouse happened to buy a new
12happened to buy a new MacBook and gifted me their 2013 model. Of course, 12MacBook and gifted me their 2013 model. Of course, I still consider my Linux
13I still consider my Linux desktop to be my daily driver and keep Windows 13desktop to be my daily driver and keep Windows around for gaming needs, but over
14around for gaming needs, but over the past week I\'ve found myself using 14the past week I've found myself using the MacBook more and more for things that
15the MacBook more and more for things that don\'t require gaming specs or 15don't require gaming specs or advanced dev tools.
16advanced dev tools.
17 16
18# Initial Thoughts 17# Initial Thoughts
19 18
20Before I move on to the technical aspects of my set-up, I want to take 19Before I move on to the technical aspects of my set-up, I want to take some time
21some time and express my thoughts on the overall OS. 20and express my thoughts on the overall OS.
22 21
23![macOS 22![macOS
24Desktop](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/macos-desktop.png) 23Desktop](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/macos-desktop.png)
25 24
26As expected, the initial computer setup is a breeze with Mac\'s guided 25As expected, the initial computer setup is a breeze with Mac's guided GUI
27GUI installer. 26installer.
28 27
29The desktop itself reminds me of GNOME more than anything else I\'ve 28The desktop itself reminds me of GNOME more than anything else I've seen: even
30seen: even Pantheon from [ElementaryOS](https://elementary.io/), which 29Pantheon from [ElementaryOS](https://elementary.io/), which people commonly
31people commonly refer to as the closest Linux distro to macOS. The 30refer to as the closest Linux distro to macOS. The desktop toolbar is great and
32desktop toolbar is great and far surpasses the utility of the GNOME 31far surpasses the utility of the GNOME toolbar due to the fact that the
33toolbar due to the fact that the extensions and icons *actually work*. I 32extensions and icons *actually work*. I launch macOS and immediately see my
34launch macOS and immediately see my shortcuts for Tresorit, Bitwarden, 33shortcuts for Tresorit, Bitwarden, and Mullvad pop up as the computer loads.
35and Mullvad pop up as the computer loads. 34
36 35Even further, the app dock is very useful and will be yet another familiarity
37Even further, the app dock is very useful and will be yet another 36for GNOME users. I know many people like panels instead of docks, but I've
38familiarity for GNOME users. I know many people like panels instead of 37always found docks to have a more pleasing UI. However, I had to disable the
39docks, but I\'ve always found docks to have a more pleasing UI. However, 38"Show recent applications in Dock" preference; I can't stand items taking up
40I had to disable the \"Show recent applications in Dock\" preference; I 39precious screen space if I'm not currently using them. On that same note, it's
41can\'t stand items taking up precious screen space if I\'m not currently 40taking me some time to get use to the fact that I have to manually quit an app
42using them. On that same note, it\'s taking me some time to get use to 41or else it will still stay open/active in the dock, even if I've closed out all
43the fact that I have to manually quit an app or else it will still stay 42windows for that app (e.g. Firefox).
44open/active in the dock, even if I\'ve closed out all windows for that 43
45app (e.g. Firefox). 44Overall, I'm having a lot of fun and for users who spend a large majority of
46 45their time performing basic tasks like web browsing, writing, watching media,
47Overall, I\'m having a lot of fun and for users who spend a large 46etc., macOS is a fantastic option.
48majority of their time performing basic tasks like web browsing,
49writing, watching media, etc., macOS is a fantastic option.
50 47
51The rest of this post explains the technicalities of how I set up my CLI 48The rest of this post explains the technicalities of how I set up my CLI
52environment to make me feel more at-home, similar to the environments I 49environment to make me feel more at-home, similar to the environments I set up
53set up on Fedora, Ubuntu, etc. 50on Fedora, Ubuntu, etc.
54 51
55# Making it Feel Like Home 52# Making it Feel Like Home
56 53
57If you\'re someone who uses Linux primarily, no doubt your first thought 54If you're someone who uses Linux primarily, no doubt your first thought when
58when booting macOS will be the same as mine was: \"Where is the terminal 55booting macOS will be the same as mine was: "Where is the terminal and how do I
59and how do I set up my favorite utilities?\" 56set up my favorite utilities?"
60 57
61Luckily, macOS hasn\'t completely hidden away the development tools from 58Luckily, macOS hasn't completely hidden away the development tools from the
62the average user. You can easily find the Terminal app in the Launchpad 59average user. You can easily find the Terminal app in the Launchpad area, but
63area, but it\'s probably not what you\'re used to. I was surprised (and 60it's probably not what you're used to. I was surprised (and happy) to see that
64happy) to see that the default shell is `zsh`, the shell I 61the default shell is `zsh`, the shell I use on all of my Linux distros. However,
65use on all of my Linux distros. However, the commands are not the same - 62the commands are not the same - even the ones you may think are native to the
66even the ones you may think are native to the shell. Commands like 63shell. Commands like `dir` do not exist, so other native commands like `ls -la`
67`dir` do not exist, so other native commands like 64or `pwd` are more useful here.
68`ls -la` or `pwd` are more useful here.
69 65
70With only a few minutes of installing and tweaking a few packages, I was 66With only a few minutes of installing and tweaking a few packages, I was able to
71able to recreate a terminal environment that I feel very comfortable 67recreate a terminal environment that I feel very comfortable using. See the
72using. See the image below for a preview of the iTerm2 app with a split 68image below for a preview of the iTerm2 app with a split view between my macOS
73view between my macOS desktop shell and an SSH session into my server. 69desktop shell and an SSH session into my server.
74 70
75![iTerm2](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/iterm2.png) 71![iTerm2](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/iterm2.png)
76 72
77# Xcode 73# Xcode
78 74
79My first step was to search the web for any hints on how to get 75My first step was to search the web for any hints on how to get `zsh` back up to
80`zsh` back up to the state I like, with extensions, themes, 76the state I like, with extensions, themes, etc. My first step was to install the
81etc. My first step was to install the CLI tools for 77CLI tools for [Xcode](https://developer.apple.com/xcode/), Apple's suite of
82[Xcode](https://developer.apple.com/xcode/), Apple\'s suite of
83development tools. 78development tools.
84 79
85```sh 80```sh
@@ -92,8 +87,8 @@ sudo xcode-select --install
92 87
93# Homebrew 88# Homebrew
94 89
95Next up is to install [Homebrew](https://brew.sh), a nifty package 90Next up is to install [Homebrew](https://brew.sh), a nifty package manager for
96manager for macOS. 91macOS.
97 92
98```sh 93```sh
99/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 94/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
@@ -107,10 +102,9 @@ Error: Failed to link all completions, docs and manpages:
107Failed during: /usr/local/bin/brew update --force --quiet 102Failed during: /usr/local/bin/brew update --force --quiet
108``` 103```
109 104
110I found that the following permission modification worked like a charm. 105I found that the following permission modification worked like a charm. However,
111However, I noted that some users online discussed the fact that this 106I noted that some users online discussed the fact that this solution may not
112solution may not work if your system has multiple users who use 107work if your system has multiple users who use Homebrew.
113Homebrew.
114 108
115```sh 109```sh
116sudo chown -R $(whoami) $(brew --prefix)/* 110sudo chown -R $(whoami) $(brew --prefix)/*
@@ -128,17 +122,16 @@ brew cleanup
128 122
129# iTerm2 123# iTerm2
130 124
131Now that I\'ve installed the basic utilities for development, I moved 125Now that I've installed the basic utilities for development, I moved onto
132onto installing iTerm2, a much better terminal than the default. 126installing iTerm2, a much better terminal than the default.
133 127
134```sh 128```sh
135brew install --cask iterm2 129brew install --cask iterm2
136``` 130```
137 131
138I also used the `Make iTerm2 Default Term` and 132I also used the `Make iTerm2 Default Term` and `Install Shell Integration`
139`Install Shell Integration` options in the iTerm2 application 133options in the iTerm2 application menu to make sure I don't run into any issues
140menu to make sure I don\'t run into any issues later on with different 134later on with different terminals.
141terminals.
142 135
143We will also install `zsh` so we can use it in iTerm2. 136We will also install `zsh` so we can use it in iTerm2.
144 137
@@ -148,9 +141,9 @@ brew install zsh
148 141
149# Oh-My-Zsh 142# Oh-My-Zsh
150 143
151I\'ve shown the great aspects of [Oh My Zsh](https://ohmyz.sh) in other 144I've shown the great aspects of [Oh My Zsh](https://ohmyz.sh) in other blog
152blog posts, so I\'ll skip over that speech for now. Simply install it 145posts, so I'll skip over that speech for now. Simply install it and run an
153and run an update. 146update.
154 147
155```sh 148```sh
156sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" 149sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
@@ -160,41 +153,36 @@ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/mas
160omz update 153omz update
161``` 154```
162 155
163Finally, restart the iTerm2 application to ensure all changes go into 156Finally, restart the iTerm2 application to ensure all changes go into effect.
164effect.
165 157
166# Oh-My-Zsh Themes 158# Oh-My-Zsh Themes
167 159
168Let\'s change the theme of the terminal to make it a little more 160Let's change the theme of the terminal to make it a little more friendly.
169friendly.
170 161
171```sh 162```sh
172open ~/.zshrc 163open ~/.zshrc
173``` 164```
174 165
175The third section of this file should contain a line like the code 166The third section of this file should contain a line like the code below. Change
176below. Change that theme to [any theme you 167that theme to [any theme you
177want](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes), save the file, 168want](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes), save the file, and exit.
178and exit.
179 169
180```sh 170```sh
181ZSH_THEME="af-magic" 171ZSH_THEME="af-magic"
182``` 172```
183 173
184After changing the `.zshrc` file, you\'ll need to close your 174After changing the `.zshrc` file, you'll need to close your terminal and
185terminal and re-open it to see the changes. Optionally, just open a new 175re-open it to see the changes. Optionally, just open a new tab if you're using
186tab if you\'re using iTerm2, and you\'ll see the new shell config. 176iTerm2, and you'll see the new shell config.
187 177
188# Oh-My-Zsh Plugins 178# Oh-My-Zsh Plugins
189 179
190Of course, my customization of `zsh` would not be complete 180Of course, my customization of `zsh` would not be complete without
191without 181[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions). This
192[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions). 182will bring up commands you've run in the past as you type them. For example, if
193This will bring up commands you\'ve run in the past as you type them. 183you've run `ssh user@192.168.1.99` before, the terminal will show this command
194For example, if you\'ve run `ssh user@192.168.1.99` before, 184as soon as you start typing it (e.g. `zsh u`), and you can hit the right arrow
195the terminal will show this command as soon as you start typing it (e.g. 185to autocomplete the command.
196`zsh u`), and you can hit the right arrow to autocomplete the
197command.
198 186
199```sh 187```sh
200git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 188git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
@@ -209,7 +197,6 @@ open ~/.zshrc
209plugins=(git zsh-autosuggestions) 197plugins=(git zsh-autosuggestions)
210``` 198```
211 199
212Remember: After changing the `.zshrc` file, you\'ll need to 200Remember: After changing the `.zshrc` file, you'll need to close your terminal
213close your terminal and re-open it to see the changes. Optionally, just 201and re-open it to see the changes. Optionally, just open a new tab if you're
214open a new tab if you\'re using iTerm2, and you\'ll see the new shell 202using iTerm2, and you'll see the new shell config.
215config.
content/blog/2021-03-19-clone-github-repos.md +30 −35
@@ -7,29 +7,27 @@ draft = false
7 7
8# Cloning from GitHub 8# Cloning from GitHub
9 9
10If you\'re like me and use a lot of different devices (and sometimes 10If you're like me and use a lot of different devices (and sometimes decide to
11decide to just wipe your device and start with a new OS), you probably 11just wipe your device and start with a new OS), you probably know the pain of
12know the pain of cloning all your old code repositories down to your 12cloning all your old code repositories down to your local file system.
13local file system.
14 13
15If you\'re using GitHub, you can easily clone all of your code back down 14If you're using GitHub, you can easily clone all of your code back down in just
16in just seconds. First, create a bash script. I do so by opening a new 15seconds. First, create a bash script. I do so by opening a new file in `nano`,
17file in `nano`, but you can use `gedit`, 16but you can use `gedit`, `vim`, or something else:
18`vim`, or something else:
19 17
20```sh 18```sh
21nano clone_github_repos.sh 19nano clone_github_repos.sh
22``` 20```
23 21
24Next, paste in the following information. Note that you can replace the 22Next, paste in the following information. Note that you can replace the word
25word `users` in the first line with `orgs` and 23`users` in the first line with `orgs` and type an organization's name instead
26type an organization\'s name instead of a user\'s name. 24of a user's name.
27 25
28```sh 26```sh
29CNTX=users; NAME=YOUR-USERNAME; PAGE=1 27CNTX=users; NAME=YOUR-USERNAME; PAGE=1
30curl "https://api.github.com/$CNTX/$NAME/repos?page=$PAGE&per_page=100" | 28curl "https://api.github.com/$CNTX/$NAME/repos?page=$PAGE&per_page=100" |
31 grep -e 'git_url*' | 29 grep -e 'git_url*' |
32 cut -d \" -f 4 | 30 cut -d " -f 4 |
33 xargs -L1 git clone 31 xargs -L1 git clone
34``` 32```
35 33
@@ -47,12 +45,12 @@ Now you can run the script and should see the cloning process begin.
47 45
48# Cloning from Sourcehut 46# Cloning from Sourcehut
49 47
50I haven\'t fully figured out how to directly incorporate Sourcehut\'s 48I haven't fully figured out how to directly incorporate Sourcehut's GraphQL
51GraphQL API into a bash script yet, so this one will take two steps. 49API into a bash script yet, so this one will take two steps.
52 50
53First, log-in to Sourcehut and go to their [GraphQL playground for 51First, log-in to Sourcehut and go to their [GraphQL playground for
54Git](https://git.sr.ht/graphql). Next, paste the following query into 52Git](https://git.sr.ht/graphql). Next, paste the following query into the left
55the left box: 53box:
56 54
57```sh 55```sh
58query { 56query {
@@ -68,24 +66,22 @@ query {
68} 66}
69``` 67```
70 68
71The output on the right side will give you an object of all your 69The output on the right side will give you an object of all your repositories.
72repositories. Just grab that text and remove all the characters such as 70Just grab that text and remove all the characters such as quotation marks and
73quotation marks and curly brackets. You will need a single-line list of 71curly brackets. You will need a single-line list of space-separated values for
74space-separated values for the next step. 72the next step.
75 73
76Now let\'s create the bash script: 74Now let's create the bash script:
77 75
78```sh 76```sh
79nano clone_sourcehut_repos.sh 77nano clone_sourcehut_repos.sh
80``` 78```
81 79
82Next, paste the following bash script in with the list of repositories 80Next, paste the following bash script in with the list of repositories you
83you obtained above and replace `your-username` with your 81obtained above and replace `your-username` with your username.
84username.
85 82
86Note that this uses the SSH-based Git cloning method (e.g. 83Note that this uses the SSH-based Git cloning method (e.g. `git@git...`), so
87`git@git...`), so you\'ll need to ensure you have set up 84you'll need to ensure you have set up Sourcehut with your SSH key.
88Sourcehut with your SSH key.
89 85
90```sh 86```sh
91repos=(repo1 repo2 repo3) 87repos=(repo1 repo2 repo3)
@@ -112,19 +108,18 @@ Now you can run the script and should see the cloning process begin.
112 108
113# Moving Repositories to a New Host 109# Moving Repositories to a New Host
114 110
115Now that you have all of your code repositories cloned to your local 111Now that you have all of your code repositories cloned to your local computer,
116computer, you may want to change the remote host (e.g., moving from 112you may want to change the remote host (e.g., moving from GitHub to GitLab). To
117GitHub to GitLab). To do this, let\'s create another bash script: 113do this, let's create another bash script:
118 114
119```sh 115```sh
120nano change_remote_urls.sh 116nano change_remote_urls.sh
121``` 117```
122 118
123Past the following information and be sure to change the URL information 119Past the following information and be sure to change the URL information to
124to whichever host you are moving to. For this example, I am looping 120whichever host you are moving to. For this example, I am looping through all of
125through all of my cloned GitHub directories and changing them to 121my cloned GitHub directories and changing them to Sourcehut (e.g.
126Sourcehut (e.g. `<YOUR_NEW_REMOTE_URL>` -\> 122`<YOUR_NEW_REMOTE_URL>` -> `git@git.sr.ht:~myusername`).
127`git@git.sr.ht:~myusername`).
128 123
129```sh 124```sh
130# List all sub-directories in the current directory 125# List all sub-directories in the current directory
content/blog/2021-03-28-gemini-capsule.md +67 −78
@@ -7,23 +7,20 @@ draft = false
7 7
8# What is Gemini? 8# What is Gemini?
9 9
10[Gemini](https://gemini.circumlunar.space/) is an internet protocol 10[Gemini](https://gemini.circumlunar.space/) is an internet protocol introduced
11introduced in June 2019 as an alternative to HTTP(S) or Gopher. In 11in June 2019 as an alternative to HTTP(S) or Gopher. In layman's terms, it's
12layman\'s terms, it\'s an alternative way to browse sites (called 12an alternative way to browse sites (called capsules) that requires a special
13capsules) that requires a special browser. Since Gemini is not 13browser. Since Gemini is not standardized as an internet standard, normal web
14standardized as an internet standard, normal web browsers won\'t be able 14browsers won't be able to load a Gemini capsule. Instead, you'll need to use
15to load a Gemini capsule. Instead, you\'ll need to use [a 15[a Gemini-specific browser](https://gemini.%20circumlunar.space/clients.html).
16Gemini-specific
17browser](https://gemini.%20circumlunar.space/clients.html).
18 16
19The content found within a Gemini page is called 17The content found within a Gemini page is called
20[Gemtext](https://gemini.circumlunar.space/docs/cheatsheet.gmi) and is 18[Gemtext](https://gemini.circumlunar.space/docs/cheatsheet.gmi) and is
21*extremely* basic (on purpose). Gemini only processes the text, no media 19*extremely* basic (on purpose). Gemini only processes the text, no media content
22content like images. However, you\'re able to style 3 levels of 20like images. However, you're able to style 3 levels of headings, regular text,
23headings, regular text, links (which will display on their own line), 21links (which will display on their own line), quotes, and an unordered list.
24quotes, and an unordered list.
25 22
26Here\'s a complete listing of valid Gemtext: 23Here's a complete listing of valid Gemtext:
27 24
28``` txt 25``` txt
29# Heading 1 26# Heading 1
@@ -46,79 +43,72 @@ My List:
46 43
47### Free Option 44### Free Option
48 45
49There are probably numerous websites that allow you to create your 46There are probably numerous websites that allow you to create your personal
50personal Gemini capsule, but I\'m going to focus on the two sites that I 47Gemini capsule, but I'm going to focus on the two sites that I have personally
51have personally tested. The first option below, Midnight Pub, allows you 48tested. The first option below, Midnight Pub, allows you to create/edit any
52to create/edit any Gemini files you want in your account. This is 49Gemini files you want in your account. This is essentially a GUI option with a
53essentially a GUI option with a built-in text box for editing. The 50built-in text box for editing. The second option below, Sourcehut, allows you to
54second option below, Sourcehut, allows you to use a Git repository and 51use a Git repository and automatic build process to deploy your personal Gemini
55automatic build process to deploy your personal Gemini capsule every 52capsule every time you push a commit.
56time you push a commit.
57 53
58## Midnight Pub - Beginner Friendly 54## Midnight Pub - Beginner Friendly
59 55
60[Midnight Pub](https://midnight.pub/) is a small, virtual community 56[Midnight Pub](https://midnight.pub/) is a small, virtual community meant to
61meant to reflect the atmosphere of wandering into a small alley pub. The 57reflect the atmosphere of wandering into a small alley pub. The site is built in
62site is built in Gemtext and has a server-side process to convert 58Gemtext and has a server-side process to convert Gemtext to HTML if someone
63Gemtext to HTML if someone loads the site in an HTTP(S) browser. 59loads the site in an HTTP(S) browser.
64 60
65To create an account, you\'ll need to email the owner of the website to 61To create an account, you'll need to email the owner of the website to obtain a
66obtain a key. You can find their email on the Midnight Pub homepage. 62key. You can find their email on the Midnight Pub homepage. Once registered,
67Once registered, head to [your account](https://midnight.pub/account) 63head to [your account](https://midnight.pub/account) and select [manage
68and select [manage site](https://midnight.pub/site). This is the screen 64site](https://midnight.pub/site). This is the screen where you can upload or
69where you can upload or create any files to be displayed on the 65create any files to be displayed on the internet.
70internet.
71 66
72For example, I\'ve created both an HTML file and a Gemini file. Remember 67For example, I've created both an HTML file and a Gemini file. Remember that
73that Gemini is automatically converted to HTML on the Pub, so you don\'t 68Gemini is automatically converted to HTML on the Pub, so you don't need an HTML
74need an HTML version. For example, I created an HTML version to add in 69version. For example, I created an HTML version to add in some extra styling.
75some extra styling.
76 70
77All you need to do is create a page like `index.gmi` and use 71All you need to do is create a page like `index.gmi` and use your Gemini browser
78your Gemini browser to head over to your-username.midnight.pub to see 72to head over to your-username.midnight.pub to see the result.
79the result.
80 73
81That\'s all there is to it! Easy enough, right? Let\'s check out a more 74That's all there is to it! Easy enough, right? Let's check out a more advanced
82advanced version in the next section. 75version in the next section.
83 76
84# Paid Option 77# Paid Option
85 78
86As of 2021, Sourcehut has decided to require users to have a paid 79As of 2021, Sourcehut has decided to require users to have a paid account in
87account in order to utilize their automated build system. For now, paid 80order to utilize their automated build system. For now, paid accounts can be as
88accounts can be as low as \$2/month. 81low as $2/month.
89 82
90## Sourcehut 83## Sourcehut
91 84
92[Sourcehut](https://sourcehut.org/) is a collection of software 85[Sourcehut](https://sourcehut.org/) is a collection of software development
93development tools, but mostly surrounds their hosted Git repository 86tools, but mostly surrounds their hosted Git repository service. Simply put,
94service. Simply put, it\'s a minimal and more private alternative to 87it's a minimal and more private alternative to services like GitHub.
95services like GitHub.
96 88
97This walkthrough is more advanced and involves things like Git, SSH, the 89This walkthrough is more advanced and involves things like Git, SSH, the command
98command line. If you don\'t think you know enough to do this, check out 90line. If you don't think you know enough to do this, check out my walkthrough
99my walkthrough on creating a Gemini capsule for the Midnight Pub 91on creating a Gemini capsule for the Midnight Pub instead.
100instead.
101 92
102The first thing you\'ll need to do is create an SSH key pair, if you 93The first thing you'll need to do is create an SSH key pair, if you don't
103don\'t already have one on your system. Once created, grab the contents 94already have one on your system. Once created, grab the contents of `id_rsa.pub`
104of `id_rsa.pub` and add it to your Sourcehut account 95and add it to your Sourcehut account settings - this will allow you to push and
105settings - this will allow you to push and pull code changes without 96pull code changes without using a username/password.
106using a username/password.
107 97
108```sh 98```sh
109ssh keygen 99ssh keygen
110``` 100```
111 101
112Next up, let\'s create a repository with the proper name so that the 102Next up, let's create a repository with the proper name so that the Sourcehut
113Sourcehut build system will know we want them to host a website for us. 103build system will know we want them to host a website for us. Use the following
114Use the following format exactly: 104format exactly:
115 105
116```sh 106```sh
117mkdir your-username.srht.site && cd your-username.srht.site 107mkdir your-username.srht.site && cd your-username.srht.site
118``` 108```
119 109
120Now that we\'ve created the repo, let\'s initialize Git and add the 110Now that we've created the repo, let's initialize Git and add the proper
121proper remote URL. 111remote URL.
122 112
123```sh 113```sh
124git init 114git init
@@ -128,14 +118,14 @@ git init
128git remote add origin git@git.sr.ht:~your-username/your-username.srht.site 118git remote add origin git@git.sr.ht:~your-username/your-username.srht.site
129``` 119```
130 120
131Now that our repository is set up and configured, we will need to create 121Now that our repository is set up and configured, we will need to create at
132at least two files: 122least two files:
133 123
134- `index.gmi` 124- `index.gmi`
135- `.build.yml` 125- `.build.yml`
136 126
137For your `.build.yml` file, use the following content and be 127For your `.build.yml` file, use the following content and be sure to update the
138sure to update the `site` line with your username! 128`site` line with your username!
139 129
140``` yaml 130``` yaml
141image: alpine/latest 131image: alpine/latest
@@ -150,11 +140,11 @@ tasks:
150 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI 140 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI
151``` 141```
152 142
153For the `index.gmi` file, put whatever you want in there and 143For the `index.gmi` file, put whatever you want in there and save it. You could
154save it. You could even just copy and paste the Gemtext cheatsheet. 144even just copy and paste the Gemtext cheatsheet.
155 145
156If you want to serve both HTML and Gemini files from this repository, 146If you want to serve both HTML and Gemini files from this repository, just add a
157just add a second command to the `upload` section: 147second command to the `upload` section:
158 148
159``` yaml 149``` yaml
160- upload: | 150- upload: |
@@ -168,19 +158,18 @@ Lastly, commit your changes and push them to the remote repo.
168git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD 158git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD
169``` 159```
170 160
171If you\'ve successfully created the files with the proper format, 161If you've successfully created the files with the proper format, you'll see
172you\'ll see the terminal print a message that lets you know where the 162the terminal print a message that lets you know where the automatic build is
173automatic build is taking place. For example, here\'s what the terminal 163taking place. For example, here's what the terminal tells me:
174tells me:
175 164
176```sh 165```sh
177remote: Build started: 166remote: Build started:
178remote: https://builds.sr.ht/~user/job/689803 [.build.yml] 167remote: https://builds.sr.ht/~user/job/689803 [.build.yml]
179``` 168```
180 169
181Now that you\'ve properly built your Sourcehut page, you can browse to 170Now that you've properly built your Sourcehut page, you can browse to
182your-username.srht.site in a Gemini browser and view the final results. 171your-username.srht.site in a Gemini browser and view the final results. Take a
183Take a look at the image below for my Sourcehut Gemini capsule. 172look at the image below for my Sourcehut Gemini capsule.
184 173
185![Gemini page on the amfora 174![Gemini page on the amfora
186browser](https://img.cleberg.net/blog/20210328-launching-a-gemini-capsule/amfora.png) 175browser](https://img.cleberg.net/blog/20210328-launching-a-gemini-capsule/amfora.png)
content/blog/2021-03-28-vaporwave-vs-outrun.md +69 −76
@@ -7,15 +7,14 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10When it comes to an aesthetic that originated primarily online, there 10When it comes to an aesthetic that originated primarily online, there tends to
11tends to be a lot of confusion around what falls into each specific 11be a lot of confusion around what falls into each specific genre. This post
12genre. This post discusses Vaporwave and Outrun, which have become 12discusses Vaporwave and Outrun, which have become almost synonymous in the minds
13almost synonymous in the minds of those online who aren\'t hardcore into 13of those online who aren't hardcore into these genres of media. More
14these genres of media. More specifically, Outrun is largely an unknown 14specifically, Outrun is largely an unknown term while all aesthetics in these
15term while all aesthetics in these two genres are usually attributed to 15two genres are usually attributed to Vaporwave. For example, take a look at the
16Vaporwave. For example, take a look at the image search results for 16image search results for Vaporwave: the results include **a lot** of
17Vaporwave: the results include **a lot\*** of Outrun-themed images. 17Outrun-themed images. You'll find a similar trend almost everywhere.
18You\'ll find a similar trend almost everywhere.
19 18
20![Vaporwave Search 19![Vaporwave Search
21Results](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/vaporwave-search-results.png) 20Results](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/vaporwave-search-results.png)
@@ -25,99 +24,93 @@ Results](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/vaporwave-sea
25![Macintosh Plus Album 24![Macintosh Plus Album
26Cover](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/macintosh-plus.png) 25Cover](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/macintosh-plus.png)
27 26
28Okay, so what is Vaporwave? I\'m going to just copy-and-paste some 27Okay, so what is Vaporwave? I'm going to just copy-and-paste some general info
29general info from the Wikipedia article on 28from the Wikipedia article on
30[Vaporwave](https://en.wikipedia.org/wiki/Vaporwave), so that I\'m not 29[Vaporwave](https://en.wikipedia.org/wiki/Vaporwave), so that I'm not repeating
31repeating everything you can already search for online: 30everything you can already search for online:
32 31
33> Vaporwave is a microgenre of electronic music, a visual art style, and 32> Vaporwave is a microgenre of electronic music, a visual art style, and an
34> an Internet meme that emerged in the early 2010s. It is defined partly 33> Internet meme that emerged in the early 2010s. It is defined partly by its
35> by its slowed-down, chopped and screwed samples of smooth jazz, 34> slowed-down, chopped and screwed samples of smooth jazz, elevator, R&B, and
36> elevator, R&B, and lounge music from the 1980s and 1990s. The 35> lounge music from the 1980s and 1990s. The surrounding subculture is sometimes
37> surrounding subculture is sometimes associated with an ambiguous or 36> associated with an ambiguous or satirical take on consumer capitalism and pop
38> satirical take on consumer capitalism and pop culture, and tends to be 37> culture, and tends to be characterized by a nostalgic or surrealist engagement
39> characterized by a nostalgic or surrealist engagement with the popular 38> with the popular entertainment, technology and advertising of previous
40> entertainment, technology and advertising of previous decades. 39> decades. Visually, it incorporates early Internet imagery, late 1990s web
41> Visually, it incorporates early Internet imagery, late 1990s web 40> design, glitch art, anime, 3D-rendered objects, and cyberpunk tropes in its
42> design, glitch art, anime, 3D-rendered objects, and cyberpunk tropes 41> cover artwork and music videos.
43> in its cover artwork and music videos. 42
44 43This is an excellent summary, and it helps address my point here: there are
45This is an excellent summary, and it helps address my point here: there 44specific aspects that make Vaporwave unique:
46are specific aspects that make Vaporwave unique:
47 45
48## Time Frame 46## Time Frame
49 47
50The time frame for references, logos, etc. focuses mostly on the 1990s 48The time frame for references, logos, etc. focuses mostly on the 1990s in
51in Vaporwave. You\'ll see old school Pepsi logos, Microsoft 95 screens, 49Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, tropical
52tropical plants, classic marble sculptures, and many references from 50plants, classic marble sculptures, and many references from Japan's influence
53Japan\'s influence in the 90s. 51in the 90s.
54 52
55## Art 53## Art
56 54
57The color scheme is generally a soft, light palette that uses pastel 55The color scheme is generally a soft, light palette that uses pastel colors. The
58colors. The backdrop will often be in a light-pink or teal blue. 56backdrop will often be in a light-pink or teal blue.
59 57
60## Music 58## Music
61 59
62The musical genre of Vaporwave incorporates soft tunes, lounge music, 60The musical genre of Vaporwave incorporates soft tunes, lounge music, and sound
63and sound effects that will make the listener reminisce of the 90s. The 61effects that will make the listener reminisce of the 90s. The sounds of the
64sounds of the genre are generally slower-paced and calming. The major 62genre are generally slower-paced and calming. The major breakthrough artist for
65breakthrough artist for Vaporwave was [Macintosh 63Vaporwave was [Macintosh Plus](https://en.wikipedia.org/wiki/Vektroid), who
66Plus](https://en.wikipedia.org/wiki/Vektroid), who released the album 64released the album [Floral
67[Floral 65Shoppe](https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete) in
68Shoppe](https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete) 662011. Another more recent example is the artist
69in 2011. Another more recent example is the artist 67[sadbert](https://sadbert.bandcamp.com/), whose latest album incorporates the
70[sadbert](https://sadbert.bandcamp.com/), whose latest album 68upbeat tones of the 1999 Dilbert TV series.
71incorporates the upbeat tones of the 1999 Dilbert TV series. 69
72 70Notice that Vaporwave doesn't include things like racing cars, futuristic
73Notice that Vaporwave doesn\'t include things like racing cars, 71technology, chrome, or the deep orange/purple color scheme. Vaporwave is a focus
74futuristic technology, chrome, or the deep orange/purple color scheme. 72on the idyllic state of the world when technology was becoming common in
75Vaporwave is a focus on the idyllic state of the world when technology 73households, a reality that we have already experienced. Focus on the most
76was becoming common in households, a reality that we have already 74aesthetically-pleasing parts of that past is a large part of Vaporwave.
77experienced. Focus on the most aesthetically-pleasing parts of that past
78is a large part of Vaporwave.
79 75
80# Outrun 76# Outrun
81 77
82![Outrun](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/outrun.png) 78![Outrun](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/outrun.png)
83 79
84Now, let\'s get to Outrun. This one is a little trickier since the genre 80Now, let's get to Outrun. This one is a little trickier since the genre has
85has largely been lumped under the Vaporwave title for so long. However, 81largely been lumped under the Vaporwave title for so long. However, it stems
86it stems from the [Synthwave](https://en.wikipedia.org/wiki/Synthwave) 82from the [Synthwave](https://en.wikipedia.org/wiki/Synthwave) music genre and is
87music genre and is likely named after the 1986 racer game, [Out 83likely named after the 1986 racer game, [Out
88Run](https://en.wikipedia.org/wiki/Out_Run). 84Run](https://en.wikipedia.org/wiki/Out_Run).
89 85
90## Time Frame 86## Time Frame
91 87
92Outrun can be thought of as a retro-futuristic aesthetic born from the 88Outrun can be thought of as a retro-futuristic aesthetic born from the 1980s.
931980s.
94 89
95## Art 90## Art
96 91
97The color scheme uses a very dark color palette with the main colors 92The color scheme uses a very dark color palette with the main colors being deep
98being deep oranges, blues, and purples. Red edges are common around 93oranges, blues, and purples. Red edges are common around objects in Outrun art.
99objects in Outrun art. The background of the Outrun aesthetic is almost 94The background of the Outrun aesthetic is almost always a neon grid like you'd
100always a neon grid like you\'d expect to see in Tron or a 1980s arcade 95expect to see in Tron or a 1980s arcade machine.
101machine.
102 96
103Classic sports cars, chrome robots, computer generated graphics and 97Classic sports cars, chrome robots, computer generated graphics and fonts, and
104fonts, and the occasional use of rain or palm trees can be found in 98the occasional use of rain or palm trees can be found in Outrun art.
105Outrun art.
106 99
107## Music 100## Music
108 101
109This aesthetic has a more aggressive and fast-paced style of music, 102This aesthetic has a more aggressive and fast-paced style of music, which tends
110which tends to match the subject of the art in this aesthetic. 103to match the subject of the art in this aesthetic.
111 104
112Outrun enthusiasts love what people in the 1980s thought the future 105Outrun enthusiasts love what people in the 1980s thought the future would look
113would look like. Take a look at a common video game discussed in Outrun 106like. Take a look at a common video game discussed in Outrun circles, Far Cry 3:
114circles, Far Cry 3: Blood Dragon: 107Blood Dragon:
115 108
116![Fry Cry 3: Blood 109![Fry Cry 3: Blood
117Dragon](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/far-cry.png) 110Dragon](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/far-cry.png)
118 111
119Another example that doesn\'t force the color scheme as hard as some 112Another example that doesn't force the color scheme as hard as some online art
120online art does is Kung Fury: 113does is Kung Fury:
121 114
122![Kung 115![Kung
123Fury](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/kung-fury.png) 116Fury](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/kung-fury.png)
@@ -127,7 +120,7 @@ Scene](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/kung-fury-hacke
127 120
128# Conclusion 121# Conclusion
129 122
130While Vaporwave and Outrun share similarities, they are two distinct 123While Vaporwave and Outrun share similarities, they are two distinct aesthetics
131aesthetics with many important distinctions. Someone who enjoys one may 124with many important distinctions. Someone who enjoys one may not necessarily
132not necessarily enjoy the other, so it\'s important to make sure we 125enjoy the other, so it's important to make sure we properly describe the
133properly describe the aesthetic we\'re looking for. 126aesthetic we're looking for.
content/blog/2021-03-30-vps-web-server.md +162 −183
@@ -7,105 +7,96 @@ draft = false
7 7
8# Shared Hosting vs. VPS 8# Shared Hosting vs. VPS
9 9
10Choosing a place to host a website is one of the most confusing 10Choosing a place to host a website is one of the most confusing decisions for
11decisions for beginner web developers. Even for experienced web devs, 11beginner web developers. Even for experienced web devs, choosing between
12choosing between different forms of web hosting can be a daunting 12different forms of web hosting can be a daunting choice.
13choice. 13
14 14First, let's take a look at [shared web
15First, let\'s take a look at [shared web 15hosting](https://en.wikipedia.org/wiki/Shared_web_hosting_service). Shared web
16hosting](https://en.wikipedia.org/wiki/Shared_web_hosting_service). 16hosting is a product where you are purchasing a small piece of a web server that
17Shared web hosting is a product where you are purchasing a small piece 17is being shared between many websites. As a result, the cost of shared hosting
18of a web server that is being shared between many websites. As a result, 18is extremely low. You won't have access to the server itself, which means you
19the cost of shared hosting is extremely low. You won\'t have access to 19can't install your own software on the server, such as Docker. Usually, you are
20the server itself, which means you can\'t install your own software on 20simply allowed to connect your domains to the server, set up domain security,
21the server, such as Docker. Usually, you are simply allowed to connect 21and other small utilities.
22your domains to the server, set up domain security, and other small
23utilities.
24 22
25In contrast, a [virtual private 23In contrast, a [virtual private
26server](https://en.wikipedia.org/wiki/Virtual_private_server) (VPS) is a 24server](https://en.wikipedia.org/wiki/Virtual_private_server) (VPS) is a virtual
27virtual machine that replicates the environment of having a dedicated 25machine that replicates the environment of having a dedicated server to
28server to yourself. You are able to control the virtual server\'s host 26yourself. You are able to control the virtual server's host names, base file
29names, base file system, package manager, etc. Another great upside of a 27system, package manager, etc. Another great upside of a VPS is that since it's
30VPS is that since it\'s virtual, the company providing the VPS can 28virtual, the company providing the VPS can dynamically increase the disk size,
31dynamically increase the disk size, RAM size, or number of CPUs at any 29RAM size, or number of CPUs at any time. However, the virtual server is still
32time. However, the virtual server is still physically located on a 30physically located on a server that is shared between multiple virtual servers.
33server that is shared between multiple virtual servers. 31
34 32The choice between shared hosting and VPS mostly depends on your skill level
35The choice between shared hosting and VPS mostly depends on your skill 33with system administration. If you're comforting working on a server that is
36level with system administration. If you\'re comforting working on a 34mostly left up to you (or you're willing to learn), then a VPS is usually a
37server that is mostly left up to you (or you\'re willing to learn), then 35better option. However, shared hosting is a fantastic option for people who
38a VPS is usually a better option. However, shared hosting is a fantastic 36don't want to have to learn how to manage their server.
39option for people who don\'t want to have to learn how to manage their
40server.
41 37
42# My Situation 38# My Situation
43 39
44I had used shared hosting for approximately 5 years before trying my 40I had used shared hosting for approximately 5 years before trying my first VPS.
45first VPS. I manage a homelab and have had success running a server and 41I manage a homelab and have had success running a server and performing typical
46performing typical sysadmin duties, but I was still hesitant to get a 42sysadmin duties, but I was still hesitant to get a VPS. One fear was that I
47VPS. One fear was that I always struggled to properly set up the 43always struggled to properly set up the networking part of a server - DNS and
48networking part of a server - DNS and hostname configurations were not 44hostname configurations were not my friend.
49my friend.
50 45
51As a little bit of background, I originally used 46As a little bit of background, I originally used
52[Siteground](https://www.siteground.com) for my initially shared hosting 47[Siteground](https://www.siteground.com) for my initially shared hosting and
53and stayed on that platform for at least a year. However, the UI was 48stayed on that platform for at least a year. However, the UI was clunky, and I
54clunky, and I didn\'t like how they handled certain technical aspects, 49didn't like how they handled certain technical aspects, so I switched to
55so I switched to [Namecheap](https://www.namecheap.com). Namecheap was 50[Namecheap](https://www.namecheap.com). Namecheap was great because it is the
56great because it is the service I primarily use for purchasing domain 51service I primarily use for purchasing domain names, which made it incredibly
57names, which made it incredibly easy to link them to my hosting service. 52easy to link them to my hosting service. However, it was still mediocre shared
58However, it was still mediocre shared hosting, and Namecheap is 53hosting, and Namecheap is notorious for not letting you use [Let's
59notorious for not letting you use [Let\'s 54Encrypt](https://letsencrypt.org) to obtain free SSL/TLS certificates; Namecheap
60Encrypt](https://letsencrypt.org) to obtain free SSL/TLS certificates; 55wants to make you purchase certificates through their store.
61Namecheap wants to make you purchase certificates through their store. 56
62 57Finally, I settled down with [iWebFusion](https://www.iwebfusion.net) for about
63Finally, I settled down with [iWebFusion](https://www.iwebfusion.net) 58the last year of my shared hosting. This service was pretty great, came with
64for about the last year of my shared hosting. This service was pretty 59free SSL/TLS, and I never had any complaints.
65great, came with free SSL/TLS, and I never had any complaints. 60
66 61However, I finally grew tired of not being able to install software on my own
67However, I finally grew tired of not being able to install software on 62web server. I wanted to be able to try out things like
68my own web server. I wanted to be able to try out things like 63[Postmill](https://postmill.xyz) or [Matrix](https://matrix.org). This is
69[Postmill](https://postmill.xyz) or [Matrix](https://matrix.org). This 64possible with a VPS, so I decided to grab a new domain name to try it out.
70is possible with a VPS, so I decided to grab a new domain name to try it
71out.
72 65
73# Getting Started: Buying a VPS 66# Getting Started: Buying a VPS
74 67
75The first step to moving over to a VPS is (you guessed it): finding a 68The first step to moving over to a VPS is (you guessed it): finding a VPS
76VPS provider. For my VPSs, I use [1984](https://1984hosting.com) and 69provider. For my VPSs, I use [1984](https://1984hosting.com) and prefer their
77prefer their services much more than any alternative, due to their 70services much more than any alternative, due to their location (Iceland), their
78location (Iceland), their [privacy 71[privacy policy](https://1984hosting.com/GDPR/), their respect for GDPR, and the
79policy](https://1984hosting.com/GDPR/), their respect for GDPR, and the
80ability to remain anonymous if you pay in Bitcoin or Monero. 72ability to remain anonymous if you pay in Bitcoin or Monero.
81 73
82[Njalla](https://njal.la) is another good, privacy-oriented option for 74[Njalla](https://njal.la) is another good, privacy-oriented option for VPS
83VPS services. 75services.
84 76
85You\'ll have to decide what specifications you want on your VPS. For me, 77You'll have to decide what specifications you want on your VPS. For me, I only
86I only build and deploy low-resource HTML, PHP, and Python websites. 78build and deploy low-resource HTML, PHP, and Python websites. This means I can
87This means I can survive on the smallest VPS: 1 CPU, 1GB of RAM, and 79survive on the smallest VPS: 1 CPU, 1GB of RAM, and 25GB SSD for $5.00 per
8825GB SSD for \$5.00 per month. 80month.
89 81
90As noted above, the great thing about a VPS is you can request your 82As noted above, the great thing about a VPS is you can request your provider to
91provider to increase the resources at any time. 83increase the resources at any time.
92 84
93# Configuring DNS Settings 85# Configuring DNS Settings
94 86
95Okay, so now let\'s get into some actual work that has to be done to get 87Okay, so now let's get into some actual work that has to be done to get content
96content moved from a shared host to a VPS. At this point, I\'m assuming 88moved from a shared host to a VPS. At this point, I'm assuming you have a
97you have a shared host with website content that you can still access, 89shared host with website content that you can still access, and you've
98and you\'ve purchased a new VPS and can SSH into that server. 90purchased a new VPS and can SSH into that server.
99 91
100The first change is minor, but it should be done immediately in order to 92The first change is minor, but it should be done immediately in order to get
101get things moving: DNS settings. Go to wherever your DNS settings are 93things moving: DNS settings. Go to wherever your DNS settings are handled. If
102handled. If your shared host also managed your DNS settings, you\'ll 94your shared host also managed your DNS settings, you'll need to first move that
103need to first move that DNS over to your new VPS provider. For me, I 95DNS over to your new VPS provider. For me, I route my DNS through
104route my DNS through [Gandi](https://www.gandi.net). 96[Gandi](https://www.gandi.net).
105 97
106Once you know where your DNS settings are, go ahead and update the 98Once you know where your DNS settings are, go ahead and update the `A` records
107`A` records to match the public IP address of your VPS. For 99to match the public IP address of your VPS. For example:
108example:
109 100
110``` txt 101``` txt
111A example.com xxx.xxx.xxx.xxx 102A example.com xxx.xxx.xxx.xxx
@@ -113,37 +104,36 @@ A subdomain xxx.xxx.xxx.xxx
113CNAME www example.com. 104CNAME www example.com.
114``` 105```
115 106
116If you have any other records that require updates, such as MX or TXT 107If you have any other records that require updates, such as MX or TXT records
117records for a mail server, be sure to update those accordingly. 108for a mail server, be sure to update those accordingly. Personally, I don't
118Personally, I don\'t host my own mail server. I route all mail on my 109host my own mail server. I route all mail on my custom domains to
119custom domains to [Migadu](https://www.migadu.com). Hosting your own 110[Migadu](https://www.migadu.com). Hosting your own email server can become
120email server can become complex quickly and is not for beginners. 111complex quickly and is not for beginners.
121 112
122DNS changes can take up to 48 hours to propagate, so be sure to give it 113DNS changes can take up to 48 hours to propagate, so be sure to give it some
123some time before assuming you\'ve made an error. 114time before assuming you've made an error.
124 115
125# Server Updates and Packages 116# Server Updates and Packages
126 117
127Now that the DNS settings have been changed, let\'s set up our server 118Now that the DNS settings have been changed, let's set up our server while we
128while we wait for the DNS to propagate. First up is to ssh into your 119wait for the DNS to propagate. First up is to ssh into your server. If you've
129server. If you\'ve signed up with a service like DigitalOcean, you can 120signed up with a service like DigitalOcean, you can add your SSH key to your
130add your SSH key to your account and to your VPS droplet so that you 121account and to your VPS droplet so that you don't need a password in order to
131don\'t need a password in order to SSH. 122SSH.
132 123
133```sh 124```sh
134ssh root@xxx.xxx.xxx.xxx 125ssh root@xxx.xxx.xxx.xxx
135``` 126```
136 127
137The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache 128The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache web
138web server. If you\'re working on a different operating system (OS) or 129server. If you're working on a different operating system (OS) or want a
139want a different web server, such as Nginx, you\'ll have to use 130different web server, such as Nginx, you'll have to use different commands to
140different commands to set it up. 131set it up.
141 132
142First, let\'s update and upgrade our server. 133First, let's update and upgrade our server.
143 134
144**NOTE:** Since we have logged in to the server as `root` for 135**NOTE:** Since we have logged in to the server as `root` for now, we don't
145now, we don\'t need to use the `sudo` modifier before our 136need to use the `sudo` modifier before our commands.
146commands.
147 137
148```sh 138```sh
149apt update && apt upgrade -y 139apt update && apt upgrade -y
@@ -151,11 +141,11 @@ apt update && apt upgrade -y
151 141
152# Create A User Account 142# Create A User Account
153 143
154While being able to use `root` can be beneficial at times, 144While being able to use `root` can be beneficial at times, you shouldn't use
155you shouldn\'t use `root` unless you have to. 145`root` unless you have to.
156 146
157So let\'s set up a new user in our system. The `-m` option 147So let's set up a new user in our system. The `-m` option below tells the OS to
158below tells the OS to create a home directory for the new user. 148create a home directory for the new user.
159 149
160```sh 150```sh
161adduser USERNAME 151adduser USERNAME
@@ -167,41 +157,40 @@ Now, create a password for that user.
167passwd USERNAME 157passwd USERNAME
168``` 158```
169 159
170Finally, add the user to the sudoers file, so they can perform 160Finally, add the user to the sudoers file, so they can perform priveleged
171priveleged commands. 161commands.
172 162
173```sh 163```sh
174usermod -a -G sudo USERNAME 164usermod -a -G sudo USERNAME
175``` 165```
176 166
177If you are using SSH keys and not passwords, you\'ll need to copy your 167If you are using SSH keys and not passwords, you'll need to copy your SSH key
178SSH key from your local machine to the VPS. If you haven\'t disabled 168from your local machine to the VPS. If you haven't disabled password-based SSH
179password-based SSH yet, the easiest way to do this is 169yet, the easiest way to do this is `ssh-copy-id` from your local computer (not
180`ssh-copy-id` from your local computer (not from the VPS): 170from the VPS):
181 171
182```sh 172```sh
183ssh-copy-id testuser@xxx.xxx.xxx.xxx 173ssh-copy-id testuser@xxx.xxx.xxx.xxx
184``` 174```
185 175
186If you\'ve disabled password-based SSH, you\'ll need to manually copy 176If you've disabled password-based SSH, you'll need to manually copy your SSH
187your SSH key into the `~/.ssh/authorized_keys` file. 177key into the `~/.ssh/authorized_keys` file.
188 178
189# Install Software 179# Install Software
190 180
191Our goal here is to host a web server, so the next step is to install 181Our goal here is to host a web server, so the next step is to install the Apache
192the Apache web server and any other packages we need. 182web server and any other packages we need.
193 183
194From this point on, I will be logged in as a user (not 184From this point on, I will be logged in as a user (not `root`) and will need to
195`root`) and will need to use the `sudo` modifier 185use the `sudo` modifier for most commands.
196for most commands.
197 186
198```sh 187```sh
199sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y 188sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
200sudo apt install apache2 189sudo apt install apache2
201``` 190```
202 191
203If you need other language support, such as PHP, you\'ll need to install 192If you need other language support, such as PHP, you'll need to install that
204that too. 193too.
205 194
206```sh 195```sh
207sudo apt install libapache2-mod-php php-dom 196sudo apt install libapache2-mod-php php-dom
@@ -211,20 +200,18 @@ sudo systemctl restart apache2
211 200
212# Website Files & Folders 201# Website Files & Folders
213 202
214Next up is to create the directories for the domain(s) we want to be 203Next up is to create the directories for the domain(s) we want to be hosted on
215hosted on this web server. 204this web server.
216 205
217```sh 206```sh
218cd /var/www 207cd /var/www
219sudo mkdir example.com 208sudo mkdir example.com
220``` 209```
221 210
222We have a folder for `example.com` now, so let\'s add an 211We have a folder for `example.com` now, so let's add an `index.html` file and
223`index.html` file and put it within a specific 212put it within a specific `public_html` folder. You don't need this
224`public_html` folder. You don\'t need this 213`public_html` if you don't want it, but it helps with organizing items related
225`public_html` if you don\'t want it, but it helps with 214to `example.com` that you don't want to publish to the internet.
226organizing items related to `example.com` that you don\'t
227want to publish to the internet.
228 215
229```sh 216```sh
230cd example.com 217cd example.com
@@ -232,8 +219,8 @@ sudo mkdir public_html && cd public_html
232sudo nano index.html 219sudo nano index.html
233``` 220```
234 221
235You can put anything you want in this `index.html` file. If 222You can put anything you want in this `index.html` file. If you can't think of
236you can\'t think of anything, paste this in there: 223anything, paste this in there:
237 224
238``` html 225``` html
239<!DOCTYPE html> 226<!DOCTYPE html>
@@ -249,10 +236,9 @@ you can\'t think of anything, paste this in there:
249</html> 236</html>
250``` 237```
251 238
252If you want something to be served at 239If you want something to be served at `example.com/page01/file.txt`, you'll
253`example.com/page01/file.txt`, you\'ll have to create the 240have to create the `page01` directory under the `example.com` directory. For
254`page01` directory under the `example.com` 241example:
255directory. For example:
256 242
257```sh 243```sh
258cd /var/www/example.com/public_html 244cd /var/www/example.com/public_html
@@ -262,9 +248,9 @@ sudo nano file.txt
262 248
263# Apache Configuration 249# Apache Configuration
264 250
265Now, let\'s set up the files that will tell the server where to find the 251Now, let's set up the files that will tell the server where to find the files
266files for `example.com`. We will copy the default 252for `example.com`. We will copy the default configuration file and create our
267configuration file and create our own. 253own.
268 254
269```sh 255```sh
270cd /etc/apache2/sites-available 256cd /etc/apache2/sites-available
@@ -272,9 +258,8 @@ sudo cp 000-default.conf example.com.conf
272sudo nano example.com.conf 258sudo nano example.com.conf
273``` 259```
274 260
275This configuration file will have a few default lines, but you\'ll need 261This configuration file will have a few default lines, but you'll need to edit
276to edit it to look similar to this (settings may change based on your 262it to look similar to this (settings may change based on your personal needs):
277personal needs):
278 263
279``` config 264``` config
280<VirtualHost *:80> 265<VirtualHost *:80>
@@ -296,35 +281,33 @@ sudo a2dissite 000-default.conf
296sudo systemctl reload apache2 281sudo systemctl reload apache2
297``` 282```
298 283
299You can always run a test to make sure no errors or warnings are found 284You can always run a test to make sure no errors or warnings are found in your
300in your configuration files. 285configuration files.
301 286
302```sh 287```sh
303sudo apache2ctl configtest 288sudo apache2ctl configtest
304``` 289```
305 290
306Now, restart the web server entirely. After this, you should be able to 291Now, restart the web server entirely. After this, you should be able to browse
307browse to `http://example.com` and see the HTML content you 292to `http://example.com` and see the HTML content you provided earlier. Note that
308provided earlier. Note that SSL/TLS has not been enabled yet, so you 293SSL/TLS has not been enabled yet, so you won't be able to use the secure
309won\'t be able to use the secure version yet 294version yet (`https://example.com`).
310(`https://example.com`).
311 295
312```sh 296```sh
313sudo systemctl restart apache2 297sudo systemctl restart apache2
314``` 298```
315 299
316You can repeat this for as many websites as you need. Just create the 300You can repeat this for as many websites as you need. Just create the domain
317domain folders in `/var/www/`, add the configuration file, 301folders in `/var/www/`, add the configuration file, enable the configuration,
318enable the configuration, and restart `apache2`. 302and restart `apache2`.
319 303
320# SSL/TLS Certificates: Serve Websites Over HTTPS 304# SSL/TLS Certificates: Serve Websites Over HTTPS
321 305
322In order to serve secure content, you\'ll need to obtain SSL/TLS 306In order to serve secure content, you'll need to obtain SSL/TLS certificates.
323certificates. Luckily, there\'s a free tool called 307Luckily, there's a free tool called [Certbot](https://certbot.eff.org) that
324[Certbot](https://certbot.eff.org) that helps us with the process. 308helps us with the process.
325 309
326The first step is to install `snapd` and `core` 310The first step is to install `snapd` and `core` for Ubuntu.
327for Ubuntu.
328 311
329```sh 312```sh
330sudo apt install snapd 313sudo apt install snapd
@@ -338,8 +321,7 @@ Next, install the `certbot` snap package.
338sudo snap install --classic certbot 321sudo snap install --classic certbot
339``` 322```
340 323
341Execute the following command to ensure that the `certbot` 324Execute the following command to ensure that the `certbot` command can be run.
342command can be run.
343 325
344```sh 326```sh
345sudo ln -s /snap/bin/certbot /usr/bin/certbot 327sudo ln -s /snap/bin/certbot /usr/bin/certbot
@@ -347,10 +329,10 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
347 329
348Finally, you can run `certbot` one of two ways: 330Finally, you can run `certbot` one of two ways:
349 331
3501. run it and let it alter your Apache configuration files 3321. run it and let it alter your Apache configuration files automatically to
351 automatically to enable HTTPS redirects. 333 enable HTTPS redirects.
3522. run it and only allow it to create certificates. You\'ll need to 3342. run it and only allow it to create certificates. You'll need to manually
353 manually alter the config files to enable HTTPS redirects. 335 alter the config files to enable HTTPS redirects.
354 336
355Run certbot and allow automatic config changes: 337Run certbot and allow automatic config changes:
356 338
@@ -358,18 +340,16 @@ Run certbot and allow automatic config changes:
358sudo certbot --apache 340sudo certbot --apache
359``` 341```
360 342
361Run certbot for certificates only and don\'t allow it to alter config 343Run certbot for certificates only and don't allow it to alter config files:
362files:
363 344
364```sh 345```sh
365sudo certbot certonly --apache 346sudo certbot certonly --apache
366``` 347```
367 348
368The Certbot packages on your system come with a cron job or systemd 349The Certbot packages on your system come with a cron job or systemd timer that
369timer that will renew your certificates automatically before they 350will renew your certificates automatically before they expire. You will not need
370expire. You will not need to run Certbot again unless you change your 351to run Certbot again unless you change your configuration. You can test
371configuration. You can test automatic renewal for your certificates by 352automatic renewal for your certificates by running this command:
372running this command:
373 353
374```sh 354```sh
375sudo certbot renew --dry-run 355sudo certbot renew --dry-run
@@ -379,13 +359,13 @@ Now, test your domains by going to `https://example.com`.
379 359
380# Firewall Security 360# Firewall Security
381 361
382To enable better security on your server, you\'ll need to enable a basic 362To enable better security on your server, you'll need to enable a basic
383firewall. For Ubuntu, we\'ll use [the uncomplicated 363firewall. For Ubuntu, we'll use [the uncomplicated
384firewall](../secure-your-network-with-the-uncomplicated-firewall/). 364firewall](../secure-your-network-with-the-uncomplicated-firewall/).
385 365
386Now, add the following rules to the firewall allow SSH, Apache, and 366Now, add the following rules to the firewall allow SSH, Apache, and HTTP(S)
387HTTP(S) connections. If you need to, you can enable different ports for 367connections. If you need to, you can enable different ports for specifics
388specifics applications, SFTP, etc. 368applications, SFTP, etc.
389 369
390```sh 370```sh
391sudo ufw default deny incoming 371sudo ufw default deny incoming
@@ -395,7 +375,7 @@ sudo ufw allow Apache
395sudo ufw allow proto tcp from any to any port 80,443 375sudo ufw allow proto tcp from any to any port 80,443
396``` 376```
397 377
398Once you\'ve added all the rules you need, enable the firewall. 378Once you've added all the rules you need, enable the firewall.
399 379
400```sh 380```sh
401sudo ufw enable 381sudo ufw enable
@@ -403,16 +383,15 @@ sudo ufw enable
403 383
404# Troubleshooting 384# Troubleshooting
405 385
406If you run into any issues during your VPS set-up, be sure to walk back 386If you run into any issues during your VPS set-up, be sure to walk back through
407through your actions and make sure you didn\'t miss any steps. 387your actions and make sure you didn't miss any steps.
408 388
409Many websites have fantastic guides to setting up various web servers. 389Many websites have fantastic guides to setting up various web servers. This is
410This is one of the areas [where DigitalOcean 390one of the areas [where DigitalOcean
411shines](https://www.digitalocean.%20com/community/tutorials). For 391shines](https://www.digitalocean.%20com/community/tutorials). For simpler or
412simpler or more Linux-oriented questions, I suggest using \[Linuxize\] 392more Linux-oriented questions, I suggest using [Linuxize]
413(<https://linuxize.com>). 393(<https://linuxize.com>).
414 394
415If you\'re getting certain errors (e.g. 395If you're getting certain errors (e.g. `500 Internal Server Error`) and need to
416`500 Internal Server Error`) and need to debug locally, you 396debug locally, you can view the `access.log` and `error.log` files in the
417can view the `access.log` and `error.log` files in 397`/var/log/apache/` directory.
418the `/var/log/apache/` directory.
content/blog/2021-04-17-gemini-server.md +36 −40
@@ -7,28 +7,27 @@ draft = false
7 7
8# Similar Article Available 8# Similar Article Available
9 9
10To read more about Gemini and ways to test out this new protocol without 10To read more about Gemini and ways to test out this new protocol without your
11your own server, see my previous post [Launching a Gemini 11own server, see my previous post [Launching a Gemini
12Capsule](../launching-a-gemini-capsule/). 12Capsule](../launching-a-gemini-capsule/).
13 13
14# Preparation 14# Preparation
15 15
16This guide assumes you have access to a server accessible to the world 16This guide assumes you have access to a server accessible to the world through a
17through a public IP address and that you own a domain name used for this 17public IP address and that you own a domain name used for this Gemini capsule.
18Gemini capsule.
19 18
20# Getting Started with Agate 19# Getting Started with Agate
21 20
22We are going to use [Agate](https://github.com/mbrubeck/agate) for this 21We are going to use [Agate](https://github.com/mbrubeck/agate) for this
23tutorial. This is a basic Gemini server written in Rust. It takes very 22tutorial. This is a basic Gemini server written in Rust. It takes very little
24little time and maintenance to get it running. 23time and maintenance to get it running.
25 24
26# Install Dependencies 25# Install Dependencies
27 26
28First, you will need to install the Rust package for your system. On 27First, you will need to install the Rust package for your system. On Ubuntu, use
29Ubuntu, use the following commands (remember to use `sudo` if 28the following commands (remember to use `sudo` if you are not the root user).
30you are not the root user). The Rust installation will give you options 29The Rust installation will give you options to customize the installation; I
31to customize the installation; I used the default installation options. 30used the default installation options.
32 31
33```sh 32```sh
34sudo apt update && sudo apt upgrade -y 33sudo apt update && sudo apt upgrade -y
@@ -41,15 +40,14 @@ Remember to configure your shell with the new configuration:
41source $HOME/.cargo/env 40source $HOME/.cargo/env
42``` 41```
43 42
44Before we install agate, make sure you have the `gcc` package 43Before we install agate, make sure you have the `gcc` package installed:
45installed:
46 44
47```sh 45```sh
48sudo apt install gcc 46sudo apt install gcc
49``` 47```
50 48
51Next, you\'ll need to install the agate executable with Rust\'s Cargo 49Next, you'll need to install the agate executable with Rust's Cargo package
52package maintainer: 50maintainer:
53 51
54```sh 52```sh
55cargo install agate 53cargo install agate
@@ -57,18 +55,17 @@ cargo install agate
57 55
58# Create Symlinks 56# Create Symlinks
59 57
60Once Cargo has finished installing all the required packages, symlink 58Once Cargo has finished installing all the required packages, symlink the
61the executable to your \$PATH. 59executable to your $PATH.
62 60
63```sh 61```sh
64sudo ln -s $HOME/.cargo/bin/agate /usr/local/bin/agate 62sudo ln -s $HOME/.cargo/bin/agate /usr/local/bin/agate
65``` 63```
66 64
67# Using Agate\'s Built-In Installation Tool 65# Using Agate's Built-In Installation Tool
68 66
69If you\'re running Ubuntu or Debian, use the Debian installation script 67If you're running Ubuntu or Debian, use the Debian installation script found in
70found in Agate\'s GitHub repository, under the `tools/debian` 68Agate's GitHub repository, under the `tools/debian` folder.
71folder.
72 69
73```sh 70```sh
74git clone https://github.com/mbrubeck/agate 71git clone https://github.com/mbrubeck/agate
@@ -78,11 +75,10 @@ sudo ./install.sh
78 75
79# Configure the Gemini Service 76# Configure the Gemini Service
80 77
81We have a little more to do, but since this script tries to immediately 78We have a little more to do, but since this script tries to immediately run the
82run the service, it will likely fail with an exit code. Let\'s add our 79service, it will likely fail with an exit code. Let's add our finishing
83finishing touches. Edit the following file and replace the hostname with 80touches. Edit the following file and replace the hostname with your desired URL.
84your desired URL. You can also change the directory where content will 81You can also change the directory where content will be served.
85be served.
86 82
87```sh 83```sh
88sudo nano /etc/systemd/system/gemini.service 84sudo nano /etc/systemd/system/gemini.service
@@ -101,8 +97,8 @@ WorkingDirectory=/var/gemini/
101ExecStart=agate --hostname gemini.example.com --lang en 97ExecStart=agate --hostname gemini.example.com --lang en
102``` 98```
103 99
104Since we\'ve altered the systemd configuration files, we have to reload 100Since we've altered the systemd configuration files, we have to reload the
105the daemon. Let\'s do that, restart our service, and check its status. 101daemon. Let's do that, restart our service, and check its status.
106 102
107```sh 103```sh
108sudo systemctl daemon-reload 104sudo systemctl daemon-reload
@@ -112,8 +108,8 @@ sudo systemctl status gemini.service
112 108
113# Fixing Systemd Errors 109# Fixing Systemd Errors
114 110
115If you\'re still getting errors, the installation process may not have 111If you're still getting errors, the installation process may not have properly
116properly enabled the gemini service. Fix it with the following commands. 112enabled the gemini service. Fix it with the following commands.
117 113
118```sh 114```sh
119sudo systemctl enable gemini.service 115sudo systemctl enable gemini.service
@@ -123,9 +119,9 @@ sudo systemctl status gemini.service
123 119
124# Firewall Rules 120# Firewall Rules
125 121
126Great! Our server is now functional and running. The first consideration 122Great! Our server is now functional and running. The first consideration now is
127now is that you need to be able to access port 1965 on the server. If 123that you need to be able to access port 1965 on the server. If you have a
128you have a firewall enabled, you\'ll need to open that port up. 124firewall enabled, you'll need to open that port up.
129 125
130```sh 126```sh
131sudo ufw allow 1965 127sudo ufw allow 1965
@@ -134,19 +130,19 @@ sudo ufw reload
134 130
135# Creating Content 131# Creating Content
136 132
137Let\'s create the Gemini capsule. Note that wherever you set the 133Let's create the Gemini capsule. Note that wherever you set the
138WorkingDirectory variable to earlier, Agate will expect you to put your 134WorkingDirectory variable to earlier, Agate will expect you to put your Gemini
139Gemini capsule contents in a sub-folder called \"content.\" So, I place 135capsule contents in a sub-folder called "content." So, I place my files in
140my files in \"/var/gmi/content.\" I\'m going to create that folder now 136"/var/gmi/content." I'm going to create that folder now and put a file in
141and put a file in there. 137there.
142 138
143```sh 139```sh
144sudo mkdir /var/gemini/content 140sudo mkdir /var/gemini/content
145sudo nano /var/gemini/content/index.gmi 141sudo nano /var/gemini/content/index.gmi
146``` 142```
147 143
148You can put whatever you want in the \"index.gmi\" file, just make sure 144You can put whatever you want in the "index.gmi" file, just make sure it's
149it\'s valid Gemtext. 145valid Gemtext.
150 146
151# The Results 147# The Results
152 148
content/blog/2021-04-23-php-comment-system.md +89 −105
@@ -7,85 +7,78 @@ draft = false
7 7
8# The Terrible-ness of Commenting Systems 8# The Terrible-ness of Commenting Systems
9 9
10The current state of affairs regarding interactive comment systems is, 10The current state of affairs regarding interactive comment systems is, well,
11well, terrible. It is especially awful if you\'re a privacy conscious 11terrible. It is especially awful if you're a privacy conscious person who does
12person who does not generally load third-party scripts or frames on the 12not generally load third-party scripts or frames on the websites you visit.
13websites you visit.
14 13
15Even further, many comment systems are charging exorbitant fees for 14Even further, many comment systems are charging exorbitant fees for something
16something that should be standard. 15that should be standard.
17 16
18Of course, there are some really terrible options: 17Of course, there are some really terrible options:
19 18
20- Facebook Comments 19- Facebook Comments
21- Discourse 20- Discourse
22 21
23There are some options that are better but still use too many scripts, 22There are some options that are better but still use too many scripts, frames,
24frames, or social integrations on your web page that could impact some 23or social integrations on your web page that could impact some users:
25users:
26 24
27- Disqus 25- Disqus
28- Isso 26- Isso
29- Remark42 27- Remark42
30 28
31Lastly, I looked into a few unique ways of generating blog comments, 29Lastly, I looked into a few unique ways of generating blog comments, such as
32such as using Twitter threads or GitHub issues to automatically post 30using Twitter threads or GitHub issues to automatically post issues. However,
33issues. However, these both rely on external third-party sites that I 31these both rely on external third-party sites that I don't currently use.
34don\'t currently use.
35 32
36# Stay Static with Server-Side Comments 33# Stay Static with Server-Side Comments
37 34
38The main issue for my personal use-case is that my blog is completely, 35The main issue for my personal use-case is that my blog is completely, 100%
39100% static. I use PHP on the back-end but website visitors only see 36static. I use PHP on the back-end but website visitors only see HTML and a
40HTML and a single CSS file. No external javascript and no embedded 37single CSS file. No external javascript and no embedded frames.
41frames. 38
42 39So, how do we keep a site static and still allow users to interact with blog
43So, how do we keep a site static and still allow users to interact with 40posts? The key actually pretty simple - I'm already using PHP, so why not rely
44blog posts? The key actually pretty simple - I\'m already using PHP, so 41on the classic HTML `<form>` and a PHP script to save the comments somewhere? As
45why not rely on the classic HTML `<form>` and a PHP script to 42it turns out, this was a perfect solution for me.
46save the comments somewhere? As it turns out, this was a perfect 43
47solution for me. 44The second issue for my personal use-case is that I am trying to keep the
48 45contents of my website accessible over time, as described by @brandur, in his
49The second issue for my personal use-case is that I am trying to keep 46post entitled [Blog with Markdown + Git, and degrade gracefully through
50the contents of my website accessible over time, as described by
51@brandur, in his post entitled [Blog with Markdown + Git, and degrade
52gracefully through
53time](https://brandur.org/fragments/graceful-degradation-time) . 47time](https://brandur.org/fragments/graceful-degradation-time) .
54 48
55This means I cannot rely on a database for comments, since I do not rely 49This means I cannot rely on a database for comments, since I do not rely on a
56on a database for any other part of my websites. 50database for any other part of my websites.
57 51
58I blog in plain Markdown files, commit all articles to Git, and ensure 52I blog in plain Markdown files, commit all articles to Git, and ensure that
59that future readers will be able to see the source data long after I\'m 53future readers will be able to see the source data long after I'm gone, or the
60gone, or the website has gone offline. However, I still haven\'t 54website has gone offline. However, I still haven't committed any images served
61committed any images served on my blog to Git, as I\'m not entirely sold 55on my blog to Git, as I'm not entirely sold on Git LFS yet - for now, images
62on Git LFS yet - for now, images can be found at 56can be found at [img.cleberg.net](https://img.cleberg.net).
63[img.cleberg.net](https://img.cleberg.net).
64 57
65Saving my comments back to the Git repository ensures that another 58Saving my comments back to the Git repository ensures that another aspect of my
66aspect of my site will degrade gracefully. 59site will degrade gracefully.
67 60
68# Create a Comment Form 61# Create a Comment Form
69 62
70Okay, let\'s get started. The first step is to create an HTML form that 63Okay, let's get started. The first step is to create an HTML form that users
71users can see and utilize to submit comments. This is fairly easy and 64can see and utilize to submit comments. This is fairly easy and can be changed
72can be changed depending on your personal preferences. 65depending on your personal preferences.
73 66
74Take a look at the code block below for the form I currently use. Note 67Take a look at the code block below for the form I currently use. Note that
75that `<current-url>` is replaced automatically in PHP with 68`<current-url>` is replaced automatically in PHP with the current post's URL,
76the current post\'s URL, so that my PHP script used later will know 69so that my PHP script used later will know which blog post the comment is
77which blog post the comment is related to. 70related to.
78 71
79The form contains the following structure: 72The form contains the following structure:
80 73
811. `<form>` - This is the form and will determine which PHP 741. `<form>` - This is the form and will determine which PHP script to send the
82 script to send the comment to. 75 comment to.
832. `<section hidden>` - This section is hidden from the user 762. `<section hidden>` - This section is hidden from the user and is used to
84 and is used to ensure that we know which blog post sent the comment. 77 ensure that we know which blog post sent the comment.
853. `<section>` Display Name (Optional) - Used to accept a 783. `<section>` Display Name (Optional) - Used to accept a display name, if
86 display name, if entered. 79 entered.
874. `<section>` Comment (Required) - Used to accept the 804. `<section>` Comment (Required) - Used to accept the user's full comment.
88 user\'s full comment. Markdown is allowed. 81 Markdown is allowed.
895. `<button>` - A button to submit the form. 825. `<button>` - A button to submit the form.
90 83
91``` html 84``` html
@@ -132,13 +125,12 @@ The form contains the following structure:
132 125
133# Handle Comments via POST 126# Handle Comments via POST
134 127
135Now that we have a form and can submit comments, we need to create a PHP 128Now that we have a form and can submit comments, we need to create a PHP script
136script so that the server can fetch the comment data and save it. Make 129so that the server can fetch the comment data and save it. Make sure your PHP
137sure your PHP script name matches the name you entered in the 130script name matches the name you entered in the `action` field in your form.
138`action` field in your form.
139 131
140See the code block below for the contents of my `comment.php` 132See the code block below for the contents of my `comment.php` script. We perform
141script. We perform the following tasks in this script: 133the following tasks in this script:
142 134
1431. Grab the POST data from the HTML form. 1351. Grab the POST data from the HTML form.
1442. Sanitize the comment data with `htmlentities`. 1362. Sanitize the comment data with `htmlentities`.
@@ -146,12 +138,11 @@ script. We perform the following tasks in this script:
1464. Create a PHP object that combines all of this data. 1384. Create a PHP object that combines all of this data.
1475. Check if our destination file `comments.json` exists. 1395. Check if our destination file `comments.json` exists.
1486. If so, convert the PHP object to JSON and save it to the file. 1406. If so, convert the PHP object to JSON and save it to the file.
1497. If the `comments.json` file does not exist, the script 1417. If the `comments.json` file does not exist, the script will exit with an
150 will exit with an error. You can alter this to ensure it creates the 142 error. You can alter this to ensure it creates the script, but my source
151 script, but my source code includes the file by default, so it will 143 code includes the file by default, so it will always exist.
152 always exist. 1448. Finally, send the user back to the `#comments` section of the blog post they
1538. Finally, send the user back to the `#comments` section of 145 just read.
154 the blog post they just read.
155 146
156``` php 147``` php
157// Get the content sent from the comment form 148// Get the content sent from the comment form
@@ -190,9 +181,9 @@ if (file_exists($file_name)) {
190header('Location: ' . $post_url . '#comments'); 181header('Location: ' . $post_url . '#comments');
191``` 182```
192 183
193If you\'re using Apache, make sure the `www-data` user on 184If you're using Apache, make sure the `www-data` user on your server has the
194your server has the correct permissions to your website directory or 185correct permissions to your website directory or else it will not be able to
195else it will not be able to write to `comments.json`. 186write to `comments.json`.
196 187
197```sh 188```sh
198chgrp -R www-data /path/to/website/ 189chgrp -R www-data /path/to/website/
@@ -201,18 +192,15 @@ chmod -R g+w comments.json
201 192
202# Display User Comments 193# Display User Comments
203 194
204Now that we can submit comments, and they are saved to the 195Now that we can submit comments, and they are saved to the `comments.json` file,
205`comments.json` file, let\'s make sure we can show those 196let's make sure we can show those comments in each blog post.
206comments in each blog post.
207 197
208The code block below shows the function I use to decode my 198The code block below shows the function I use to decode my `comments.json` file,
209`comments.json` file, check if the comments apply to the 199check if the comments apply to the current post, and then display them.
210current post, and then display them.
211 200
212This piece of code should **really\*** be inside a function (or at least 201This piece of code should **really** be inside a function (or at least in an
213in an organized PHP workflow). Don\'t just copy-and-paste and expect it 202organized PHP workflow). Don't just copy-and-paste and expect it to work. You
214to work. You need to at least supply a `$query` variable 203need to at least supply a `$query` variable depending on the page visited.
215depending on the page visited.
216 204
217``` php 205``` php
218$query = 'your-blog-post.html'; 206$query = 'your-blog-post.html';
@@ -248,30 +236,26 @@ foreach ($comments as $comment) {
248echo $comment_section; 236echo $comment_section;
249``` 237```
250 238
251# Bonus: Create a \'Recent Comments\' Page 239# Bonus: Create a 'Recent Comments' Page
252 240
253Finally, the last part of my current system is to create a Recent 241Finally, the last part of my current system is to create a Recent Comments page
254Comments page so that I can easily check-in on my blog and moderate any 242so that I can easily check-in on my blog and moderate any spam. As an
255spam. As an alternative, you could use PHP\'s `mail()` 243alternative, you could use PHP's `mail()` function to email you for each blog
256function to email you for each blog comment. 244comment.
257 245
258The code to do this is literally the same code as the previous section, 246The code to do this is literally the same code as the previous section, I just
259I just make sure it is printed when someone visits 247make sure it is printed when someone visits `https://example.com/comments/`.
260`https://example.com/comments/`.
261 248
262# Possible Enhancements 249# Possible Enhancements
263 250
264This comment system is by no means a fully-developed system. I have 251This comment system is by no means a fully-developed system. I have noted a few
265noted a few possible enhancements here that I may implement in the 252possible enhancements here that I may implement in the future:
266future: 253
267 254- Create a secure moderator page with user authentication at
268- Create a secure moderator page with user authentication at 255 `https://blog.example.com/mod/`. This page could have the option to edit or
269 `https://blog.example.com/mod/`. This page could have the 256 delete any comment found in `comments.json`.
270 option to edit or delete any comment found in 257- Create a temporary file, such as `pending_comments.json`, that will store
271 `comments.json`. 258 newly-submitted comments and won't display on blog posts until approved by a
272- Create a temporary file, such as `pending_comments.json`, 259 moderator.
273 that will store newly-submitted comments and won\'t display on blog 260- Create a `/modlog/` page with a chronological log, showing which moderator
274 posts until approved by a moderator. 261 approved which comments and why certain comments were rejected.
275- Create a `/modlog/` page with a chronological log,
276 showing which moderator approved which comments and why certain
277 comments were rejected.
content/blog/2021-04-28-photography.md +42 −47
@@ -7,67 +7,62 @@ draft = false
7 7
8# Why Photography? 8# Why Photography?
9 9
10I\'ve often wondered why photography is as enticing as it is. You can 10I've often wondered why photography is as enticing as it is. You can see
11see billions of people around the world taking photographs every single 11billions of people around the world taking photographs every single moment of
12moment of the day. New technology often boasts about their photographic 12the day. New technology often boasts about their photographic capabilities,
13capabilities, especially smartphones. I would even assume that we live 13especially smartphones. I would even assume that we live in a world where there
14in a world where there is never a moment in which a photograph is not 14is never a moment in which a photograph is not being taken somewhere on Earth.
15being taken somewhere on Earth.
16 15
17As for myself, I would simply say that I enjoy preserving a memory in 16As for myself, I would simply say that I enjoy preserving a memory in physical
18physical (or digital) form. I\'ve never had the best memory when it 17(or digital) form. I've never had the best memory when it comes to recalling
19comes to recalling details of places and people gone by, so it helps to 18details of places and people gone by, so it helps to have a frame of reference
20have a frame of reference lying around. 19lying around.
21 20
22Regardless of the reason, I think most people would agree that you 21Regardless of the reason, I think most people would agree that you simply cannot
23simply cannot have too many hobbies. 22have too many hobbies.
24 23
25# Older Cameras 24# Older Cameras
26 25
27I started playing around with the idea of photography when my family 26I started playing around with the idea of photography when my family purchased a
28purchased a Fujifilm camera for family-specific events. I don\'t recall 27Fujifilm camera for family-specific events. I don't recall the specific model,
29the specific model, but I do recall it was a point-and-shoot camera 28but I do recall it was a point-and-shoot camera without an interchangeable lens.
30without an interchangeable lens. However, it was of great value to 29However, it was of great value to someone, like myself, who couldn't afford any
31someone, like myself, who couldn\'t afford any other camera. I took 30other camera. I took about 10,000 shots with that camera over a 3-5 year span.
32about 10,000 shots with that camera over a 3-5 year span. Most notably, 31Most notably, all of my trips to California were documented through this camera.
33all of my trips to California were documented through this camera.
34 32
35When possible, I would borrow my sister\'s camera, which is a Sony 33When possible, I would borrow my sister's camera, which is a Sony SLT-A58. This
36SLT-A58. This camera was great and allowed for some of my best early 34camera was great and allowed for some of my best early shots, especially those
37shots, especially those taken in Utah\'s and Nevada\'s parks. 35taken in Utah's and Nevada's parks.
38 36
39# My Current Kit 37# My Current Kit
40 38
41I\'ve finally come to a point in my life where I have the disposable 39I've finally come to a point in my life where I have the disposable income to
42income to invest in a solid photography kit. I played around with the 40invest in a solid photography kit. I played around with the idea of a lot of
43idea of a lot of different cameras, different types, new vs used, etc. 41different cameras, different types, new vs used, etc. Finally, I settled on the
44Finally, I settled on the [Sony α7 42[Sony α7 III](https://en.wikipedia.org/wiki/Sony_%CE%B17_III). This camera is
45III](https://en.wikipedia.org/wiki/Sony_%CE%B17_III). This camera is 43mirror-less and uses a full-frame image sensor at 24 megapixels. I don't create
46mirror-less and uses a full-frame image sensor at 24 megapixels. I 44large prints, and I am mostly focused on preserving memories in high quality for
47don\'t create large prints, and I am mostly focused on preserving 45the next 5-10 years with this camera, so the specifications here are just
48memories in high quality for the next 5-10 years with this camera, so 46perfect for me.
49the specifications here are just perfect for me.
50 47
51For lenses, I decided to buy two lenses that could carry me through most 48For lenses, I decided to buy two lenses that could carry me through most
52situations: 49situations:
53 50
54- [Vario-Tessar T\*\* FE 24-70 mm F4 ZA 51- [Vario-Tessar T** FE 24-70 mm F4 ZA
55 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z) 52 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z)
56- [Tamron 70-300mm f4.5-6.3 Di III 53- [Tamron 70-300mm f4.5-6.3 Di III
57 RXD](https://www.tamron-usa.com/product/lenses/a047.html) 54 RXD](https://www.tamron-usa.com/product/lenses/a047.html)
58 55
59In addition, I grabbed a couple [HGX Prime 56In addition, I grabbed a couple [HGX Prime
6067mm](https://www.promaster.com/Product/6725) protection filters for the 5767mm](https://www.promaster.com/Product/6725) protection filters for the lenses.
61lenses.
62 58
63As I delve further into photography and pick up more skills, I will most 59As I delve further into photography and pick up more skills, I will most likely
64likely go back and grab a lens with a higher f-stop value, such as 60go back and grab a lens with a higher f-stop value, such as f/1.8. I toyed with
65f/1.8. I toyed with the idea of grabbing a 50 mm at `f/1.8`, 61the idea of grabbing a 50 mm at `f/1.8`, but decided to keep things in a
66but decided to keep things in a reasonable price range instead. 62reasonable price range instead.
67 63
68Finally, I made sure to buy a photography-specific backpack with a rain 64Finally, I made sure to buy a photography-specific backpack with a rain guard,
69guard, and the zipper on the back panel, to protect the equipment while 65and the zipper on the back panel, to protect the equipment while wearing the
70wearing the bag. If you\'ve ever had to haul around a DSLR (or camera of 66bag. If you've ever had to haul around a DSLR (or camera of similar heft) in a
71similar heft) in a bag that only has a shoulder strap, you\'ll know the 67bag that only has a shoulder strap, you'll know the pain it can cause. Putting
72pain it can cause. Putting all my equipment in a backpack was an easy 68all my equipment in a backpack was an easy decision.
73decision.
content/blog/2021-05-30-changing-git-authors.md +12 −12
@@ -7,25 +7,25 @@ draft = false
7 7
8# Changing Git Author/Email Based on Previously Committed Email 8# Changing Git Author/Email Based on Previously Committed Email
9 9
10Here\'s the dilemma: You\'ve been committing changes to your git 10Here's the dilemma: You've been committing changes to your git repository with
11repository with an incorrect name or email (or multiple repositories), 11an incorrect name or email (or multiple repositories), and now you want to fix
12and now you want to fix it. Luckily, there\'s a semi-reliable way to fix 12it. Luckily, there's a semi-reliable way to fix that. While I have never
13that. While I have never experienced issues with this method, some 13experienced issues with this method, some people have warned that it can mess
14people have warned that it can mess with historical hashes and integrity 14with historical hashes and integrity of commits, so use this method only if
15of commits, so use this method only if you\'re okay accepting that risk. 15you're okay accepting that risk.
16 16
17Okay, let\'s create the bash script: 17Okay, let's create the bash script:
18 18
19```sh 19```sh
20nano change_git_authors.sh 20nano change_git_authors.sh
21``` 21```
22 22
23The following information can be pasted directly into your bash script. 23The following information can be pasted directly into your bash script. The only
24The only changes you need to make are to the following variables: 24changes you need to make are to the following variables:
25 25
26- `OLD_EMAIL` 26- `OLD_EMAIL`
27- `CORRECT_NAME` 27- `CORRECT_NAME`
28- `CORRECT_EMAIL` 28- `CORRECT_EMAIL`
29 29
30```sh 30```sh
31#!/bin/sh 31#!/bin/sh
content/blog/2021-07-15-delete-gitlab-repos.md +21 −22
@@ -7,31 +7,31 @@ draft = false
7 7
8# Background 8# Background
9 9
10Have you ever used GitLab to host your source code, moved to a different 10Have you ever used GitLab to host your source code, moved to a different host,
11host, and wanted to delete everything from your GitLab account? Well, 11and wanted to delete everything from your GitLab account? Well, this post covers
12this post covers any scenario where you would want to delete all 12any scenario where you would want to delete all repositories from your GitLab
13repositories from your GitLab account. 13account.
14 14
15For me, I currently maintain around 30 repositories and don\'t like to 15For me, I currently maintain around 30 repositories and don't like to manually
16manually delete them whenever I switch host. GitHub has a few different 16delete them whenever I switch host. GitHub has a few different tools online to
17tools online to delete all repositories for you, but I have not found 17delete all repositories for you, but I have not found anything similar for
18anything similar for GitLab, so I needed an alternative solution. 18GitLab, so I needed an alternative solution.
19 19
20# Use a Python Script 20# Use a Python Script
21 21
22## Requirements 22## Requirements
23 23
24Before we look at the script, make sure you know your GitLab username. 24Before we look at the script, make sure you know your GitLab username. Next,
25Next, [create an authorization 25[create an authorization
26token](https://gitlab.com/-/profile/personal_access_tokens) so that the 26token](https://gitlab.com/-/profile/personal_access_tokens) so that the Python
27Python script can delete your repositories. Don\'t lose this token or 27script can delete your repositories. Don't lose this token or else you'll need
28else you\'ll need to create a new one. 28to create a new one.
29 29
30## Create the Script 30## Create the Script
31 31
32To run a Python script, you must first create it. Open a terminal and 32To run a Python script, you must first create it. Open a terminal and enter the
33enter the following commands in whichever directory you prefer to store 33following commands in whichever directory you prefer to store the script. You
34the script. You can do the same things in a file manager if you prefer. 34can do the same things in a file manager if you prefer.
35 35
36```sh 36```sh
37mkdir delete-gitlab 37mkdir delete-gitlab
@@ -103,13 +103,12 @@ if __name__ == "__main__":
103 main() 103 main()
104``` 104```
105 105
106Now that you have the proper information, replace `{user-id}` 106Now that you have the proper information, replace `{user-id}` with your GitLab
107with your GitLab username and `{auth-token}` with the 107username and `{auth-token}` with the authorization token you created earlier.
108authorization token you created earlier.
109 108
110Finally, simply run the script and watch the output. You can also use 109Finally, simply run the script and watch the output. You can also use PyCharm
111PyCharm Community Edition to edit and run the Python script if you 110Community Edition to edit and run the Python script if you don't want to work
112don\'t want to work in a terminal. 111in a terminal.
113 112
114```sh 113```sh
115python3 main.py 114python3 main.py
content/blog/2021-08-25-audit-sampling.md +92 −101
@@ -8,44 +8,43 @@ draft = false
8# Introduction 8# Introduction
9 9
10For anyone who is familiar with internal auditing, external auditing, or 10For anyone who is familiar with internal auditing, external auditing, or
11consulting, you will understand how tedious audit testing can become 11consulting, you will understand how tedious audit testing can become when you
12when you are required to test large swaths of data. When we cannot 12are required to test large swaths of data. When we cannot establish an automated
13establish an automated means of testing an entire population, we 13means of testing an entire population, we generate samples to represent the
14generate samples to represent the population of data. This helps ensure 14population of data. This helps ensure we can have a small enough data pool to
15we can have a small enough data pool to test and that our results still 15test and that our results still represent the population.
16represent the population. 16
17 17However, sampling data within the world of audit still seems to confuse quite a
18However, sampling data within the world of audit still seems to confuse 18lot of people. While some audit-focused tools have introduced sampling
19quite a lot of people. While some audit-focused tools have introduced 19functionality (e.g. Wdesk), many audit departments and firms cannot use software
20sampling functionality (e.g. Wdesk), many audit departments and firms 20like this due to certain constraints, such as the team's budget or knowledge.
21cannot use software like this due to certain constraints, such as the 21Here is where this article comes in: we're going to use
22team\'s budget or knowledge. Here is where this article comes in: we\'re 22[Python](https://www.python.org), a free and open-source programming language,
23going to use [Python](https://www.python.org), a free and open-source 23to generate random samples from a dataset in order to suffice numerous audit
24programming language, to generate random samples from a dataset in order 24situations.
25to suffice numerous audit situations.
26 25
27# Audit Requirements for Sampling 26# Audit Requirements for Sampling
28 27
29Before we get into the details of how to sample with Python, I want to 28Before we get into the details of how to sample with Python, I want to make sure
30make sure I discuss the different requirements that auditors may have of 29I discuss the different requirements that auditors may have of samples used
31samples used within their projects. 30within their projects.
32 31
33## Randomness 32## Randomness
34 33
35First, let\'s discuss randomness. When testing out new technology to 34First, let's discuss randomness. When testing out new technology to help assist
36help assist with audit sampling, you need to understand exactly how your 35with audit sampling, you need to understand exactly how your samples are being
37samples are being generated. For example, if the underlying function is 36generated. For example, if the underlying function is just picking every 57th
38just picking every 57th element from a list, that\'s not truly random; 37element from a list, that's not truly random; it's a systematic form of
39it\'s a systematic form of sampling. Luckily, since Python is 38sampling. Luckily, since Python is open-source, we have access to its codebase.
40open-source, we have access to its codebase. Through this blog post, I 39Through this blog post, I will be using the [pandas](https://pandas.pydata.org)
41will be using the [pandas](https://pandas.pydata.org) module in order to 40module in order to generate the random samples. More specifically, I will be
42generate the random samples. More specifically, I will be using the 41using the
43[pandas.DataFrame.sample](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html) 42[pandas.DataFrame.sample](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html)
44function provided by Pandas. 43function provided by Pandas.
45 44
46Now that you know what you\'re using, you can always check out the code 45Now that you know what you're using, you can always check out the code behind
47behind `pandas.DataFrame.sample`. This function does a lot of 46`pandas.DataFrame.sample`. This function does a lot of work, but we really only
48work, but we really only care about the following snippets of code: 47care about the following snippets of code:
49 48
50``` python 49``` python
51# Process random_state argument 50# Process random_state argument
@@ -61,67 +60,59 @@ result.index = ibase.default_index(len(result))
61return result 60return result
62``` 61```
63 62
64The block of code above shows you that if you assign a 63The block of code above shows you that if you assign a `random_state` argument
65`random_state` argument when you run the function, that will 64when you run the function, that will be used as a seed number in the random
66be used as a seed number in the random generation and will allow you to 65generation and will allow you to reproduce a sample, given that nothing else
67reproduce a sample, given that nothing else changes. This is critical to 66changes. This is critical to the posterity of audit work. After all, how can you
68the posterity of audit work. After all, how can you say your audit 67say your audit process is adequately documented if the next person can't run
69process is adequately documented if the next person can\'t run the code 68the code and get the same sample? The final piece here on randomness is to look
70and get the same sample? The final piece here on randomness is to look 69at the [choice](https://docs.%20python.org/3/library/random.html#random.choice)
71at the 70function used above. This is the crux of the generation and can also be examined
72[choice](https://docs.%20python.org/3/library/random.html#random.choice) 71for more detailed analysis on its reliability. As far as auditing goes, we will
73function used above. This is the crux of the generation and can also be 72trust that these functions are mathematically random.
74examined for more detailed analysis on its reliability. As far as
75auditing goes, we will trust that these functions are mathematically
76random.
77 73
78## Sample Sizes 74## Sample Sizes
79 75
80As mentioned in the intro, sampling is only an effective method of 76As mentioned in the intro, sampling is only an effective method of auditing when
81auditing when it truly represents the entire population. While some 77it truly represents the entire population. While some audit departments or firms
82audit departments or firms may consider certain judgmental sample sizes 78may consider certain judgmental sample sizes to be adequate, you may need to
83to be adequate, you may need to rely on statistically-significant 79rely on statistically-significant confidence levels of sample testing at certain
84confidence levels of sample testing at certain points. I will 80points. I will demonstrate both here. For statistically-significant confidence
85demonstrate both here. For statistically-significant confidence levels, 81levels, most people will assume a 90% - 99% confidence level. In order to
86most people will assume a 90% - 99% confidence level. In order to 82actually calculate the correct sample size, it is best to use statistical tools
87actually calculate the correct sample size, it is best to use 83due to the tedious math work required. For example, for a population of 1000,
88statistical tools due to the tedious math work required. For example, 84and a 90% confidence level that no more than 5% of the items are nonconforming,
89for a population of 1000, and a 90% confidence level that no more than 85you would sample 45 items.
905% of the items are nonconforming, you would sample 45 items. 86
91 87However, in my personal experience, many audit departments and firms do not use
92However, in my personal experience, many audit departments and firms do 88statistical sampling. Most people use a predetermined, often proprietary, table
93not use statistical sampling. Most people use a predetermined, often 89that will instruct auditors which sample sizes to choose. This allows for
94proprietary, table that will instruct auditors which sample sizes to 90uniform testing and reduces overall workload. See the table below for a common
95choose. This allows for uniform testing and reduces overall workload. 91implementation of sample sizes:
96See the table below for a common implementation of sample sizes:
97 92
98 Control Frequency Sample Size - High Risk Sample Size - Low Risk 93 Control Frequency Sample Size - High Risk Sample Size - Low Risk
99 ------------------- ------------------------- ------------------------ 94 ------------------- ------------------------- ------------------------
100 More Than Daily 40 25 95 More Than Daily 40 25 Daily 40
101 Daily 40 25 96 25 Weekly 12 5 Monthly 5
102 Weekly 12 5 97 3 Quarterly 2 2 Semi-Annually 1
103 Monthly 5 3 98 1 Annually 1 1 Ad-hoc 1
104 Quarterly 2 2 99 1
105 Semi-Annually 1 1
106 Annually 1 1
107 Ad-hoc 1 1
108 100
109### Sampling with Python & Pandas 101### Sampling with Python & Pandas
110 102
111In this section, I am going to cover a few basic audit situations that 103In this section, I am going to cover a few basic audit situations that require
112require sampling. While some situations may require more effort, the 104sampling. While some situations may require more effort, the syntax,
113syntax, organization, and intellect used remain largely the same. If 105organization, and intellect used remain largely the same. If you've never used
114you\'ve never used Python before, note that lines starting with a 106Python before, note that lines starting with a '`#`' symbol are called
115\'`#`\' symbol are called comments, and they will be skipped 107comments, and they will be skipped by Python. I highly recommend taking a quick
116by Python. I highly recommend taking a quick tutorial online to 108tutorial online to understand the basics of Python if any of the code below is
117understand the basics of Python if any of the code below is confusing to 109confusing to you.
118you.
119 110
120## Simple Random Sample 111## Simple Random Sample
121 112
122First, let\'s look at a simple, random sample. The code block below will 113First, let's look at a simple, random sample. The code block below will import
123import the `pandas` module, load a data file, sample the 114the `pandas` module, load a data file, sample the data, and export the sample to
124data, and export the sample to a file. 115a file.
125 116
126``` python 117``` python
127# Import the Pandas module 118# Import the Pandas module
@@ -145,8 +136,8 @@ sample.to_excel(file_output)
145 136
146## Simple Random Sample: Using Multiple Input Files 137## Simple Random Sample: Using Multiple Input Files
147 138
148Now that we\'ve created a simple sample, let\'s create a sample from 139Now that we've created a simple sample, let's create a sample from multiple
149multiple files. 140files.
150 141
151``` python 142``` python
152# Import the Pandas module 143# Import the Pandas module
@@ -179,9 +170,9 @@ sample.to_excel(file_output)
179 170
180## Stratified Random Sample 171## Stratified Random Sample
181 172
182Well, what if you need to sample distinct parts of a single file? For 173Well, what if you need to sample distinct parts of a single file? For example,
183example, let\'s write some code to separate our data by \"Region\" and 174let's write some code to separate our data by "Region" and sample those
184sample those regions independently. 175regions independently.
185 176
186``` python 177``` python
187# Import the Pandas module 178# Import the Pandas module
@@ -213,10 +204,10 @@ sample.to_excel(file_output)
213 204
214## Stratified Systematic Sample 205## Stratified Systematic Sample
215 206
216This next example is quite useful if you need audit coverage over a 207This next example is quite useful if you need audit coverage over a certain time
217certain time period. This code will generate samples for each month in 208period. This code will generate samples for each month in the data and combine
218the data and combine them all together at the end. Obviously, this code 209them all together at the end. Obviously, this code can be modified to stratify
219can be modified to stratify by something other than months, if needed. 210by something other than months, if needed.
220 211
221``` python 212``` python
222# Import the Pandas module 213# Import the Pandas module
@@ -262,17 +253,17 @@ sample.to_excel(file_output)
262 253
263### Documenting the Results 254### Documenting the Results
264 255
265Once you\'ve generated a proper sample, there are a few things left to 256Once you've generated a proper sample, there are a few things left to do in
266do in order to properly ensure your process is reproducible. 257order to properly ensure your process is reproducible.
267 258
2681. Document the sample. Make sure the resulting file is readable and 2591. Document the sample. Make sure the resulting file is readable and includes
269 includes the documentation listed in the next bullet. 260 the documentation listed in the next bullet.
2702. Include documentation around the data source, extraction techniques, 2612. Include documentation around the data source, extraction techniques, any
271 any modifications made to the data, and be sure to include a copy of 262 modifications made to the data, and be sure to include a copy of the script
272 the script itself. 263 itself.
2733. Whenever possible, perform a completeness and accuracy test to 2643. Whenever possible, perform a completeness and accuracy test to ensure your
274 ensure your sample is coming from a complete and accurate 265 sample is coming from a complete and accurate population. To ensure
275 population. To ensure completeness, compare the record count from 266 completeness, compare the record count from the data source to the record
276 the data source to the record count loaded into Python. To ensure 267 count loaded into Python. To ensure accuracy, test a small sample against the
277 accuracy, test a small sample against the source data (e.g., test 5 268 source data (e.g., test 5 sales against the database to see if the details
278 sales against the database to see if the details are accurate). 269 are accurate).
content/blog/2021-10-09-apache-redirect.md +22 −24
@@ -7,26 +7,25 @@ draft = false
7 7
8# The Problem 8# The Problem
9 9
10After recently switching static site generators (SSG), my blog URLs 10After recently switching static site generators (SSG), my blog URLs changed with
11changed with no option to preserve the classic `.html` 11no option to preserve the classic `.html` extension at the end of my blog post
12extension at the end of my blog post URLs. 12URLs.
13 13
14I really disliked using my old SSG ([Jekyll](https://jekyllrb.com)) and 14I really disliked using my old SSG ([Jekyll](https://jekyllrb.com)) and prefer
15prefer my new tool ([Zola](https://www.getzola.org)) much more, so I was 15my new tool ([Zola](https://www.getzola.org)) much more, so I was determined to
16determined to figure out a way to get the proper redirect set up so that 16figure out a way to get the proper redirect set up so that people who find my
17people who find my posts online aren\'t constantly met by 404 errors. 17posts online aren't constantly met by 404 errors.
18 18
19# The Solution 19# The Solution
20 20
21To solve this problem, I really needed to solve two pieces: 21To solve this problem, I really needed to solve two pieces:
22 22
231. Redirect all blog post URL requests from 231. Redirect all blog post URL requests from `/blog/some-post.html` to
24 `/blog/some-post.html` to `/blog/some-post/`. 24 `/blog/some-post/`.
252. Ensure that no other `.html` files are redirected, such 252. Ensure that no other `.html` files are redirected, such as `index.html`.
26 as `index.html`.
27 26
28After *a lot* of tweaking and testing, I believe I have finally found 27After *a lot* of tweaking and testing, I believe I have finally found the
29the solution. The solution is shown below. 28solution. The solution is shown below.
30 29
31``` conf 30``` conf
32RewriteEngine On 31RewriteEngine On
@@ -34,14 +33,13 @@ RewriteCond %{REQUEST_URI} !\index.html$ [NC]
34RewriteRule ^(.*).html$ https://example.com/$1 [R=301,L] 33RewriteRule ^(.*).html$ https://example.com/$1 [R=301,L]
35``` 34```
36 35
37This piece of code in the Apache `.conf` or 36This piece of code in the Apache `.conf` or `.htaccess` file will do the
38`.htaccess` file will do the following: 37following:
39 38
401. Turn on the RewriteEngine so that we can modify URLs. 391. Turn on the RewriteEngine so that we can modify URLs.
412. Ignore any `index.html` files from the rule we are about 402. Ignore any `index.html` files from the rule we are about to specify.
42 to specify. 413. Find any `.html` files within the website directory and redirect it to
433. Find any `.html` files within the website directory and 42 exclude the file extension.
44 redirect it to exclude the file extension. 434. The final piece is adding the trailing slash (`/`) at the end of the URL -
454. The final piece is adding the trailing slash (`/`) at the 44 you'll notice that I don't have an Apache rule for that since Apache
46 end of the URL - you\'ll notice that I don\'t have an Apache rule 45 handles that automatically.
47 for that since Apache handles that automatically.
content/blog/2021-12-04-cisa.md +152 −167
@@ -8,208 +8,193 @@ draft = false
8# What is the CISA? 8# What is the CISA?
9 9
10For those of you lucky enough not to be knee-deep in the world of IT/IS 10For those of you lucky enough not to be knee-deep in the world of IT/IS
11Auditing, [CISA](https://www.isaca.org/credentialing/cisa) stands for 11Auditing, [CISA](https://www.isaca.org/credentialing/cisa) stands for Certified
12Certified Information Systems Auditor. This certification and exam are 12Information Systems Auditor. This certification and exam are part of ISACA's
13part of ISACA\'s suite of certifications. As I often explain it to 13suite of certifications. As I often explain it to people like my family, it
14people like my family, it basically means you\'re employed to use your 14basically means you're employed to use your knowledge of information systems,
15knowledge of information systems, regulations, common threats, risks, 15regulations, common threats, risks, etc. in order to assess an organization's
16etc. in order to assess an organization\'s current control of their 16current control of their risk. If a risk isn't controlled (and the company
17risk. If a risk isn\'t controlled (and the company doesn\'t want to 17doesn't want to accept the risk), an IS auditor will suggest implementing a
18accept the risk), an IS auditor will suggest implementing a control to 18control to address that risk.
19address that risk. 19
20 20Now, the CISA certification itself is, in my opinion, the main certification for
21Now, the CISA certification itself is, in my opinion, the main 21this career. While certifications such as the CPA or CISSP are beneficial,
22certification for this career. While certifications such as the CPA or 22nothing matches the power of the CISA for an IS auditor when it comes to getting
23CISSP are beneficial, nothing matches the power of the CISA for an IS 23hired, getting a raise/bonus, or earning respect in the field.
24auditor when it comes to getting hired, getting a raise/bonus, or 24
25earning respect in the field. 25However, to be honest, I am a skeptic of most certifications. I understand the
26 26value they hold in terms of how much you need to commit to studying or learning
27However, to be honest, I am a skeptic of most certifications. I 27on the job, as well as the market value for certifications such as the CISA. But
28understand the value they hold in terms of how much you need to commit 28I also have known some very ~~incompetent~~ *less than stellar* auditors who
29to studying or learning on the job, as well as the market value for 29have CPAs, CISAs, CIAs, etc.
30certifications such as the CISA. But I also have known some very 30
31~~incompetent~~ *less than stellar* auditors who have CPAs, CISAs, CIAs, 31The same goes for most industries: if a person is good at studying, they can
32etc. 32earn the certification. However, that knowledge means nothing unless you're
33 33actually able to use it in real life and perform as expected of a certification
34The same goes for most industries: if a person is good at studying, they 34holder. The challenge comes when people are hired or connected strictly because
35can earn the certification. However, that knowledge means nothing unless 35of their certifications or resume; you need to see a person work before you can
36you\'re actually able to use it in real life and perform as expected of 36assume them having a CISA means they're better than someone without the CISA.
37a certification holder. The challenge comes when people are hired or 37
38connected strictly because of their certifications or resume; you need 38Okay, rant over. Certifications are generally accepted as a measuring stick of
39to see a person work before you can assume them having a CISA means 39commitment and quality of an employee, so I am accepting it too.
40they\'re better than someone without the CISA.
41
42Okay, rant over. Certifications are generally accepted as a measuring
43stick of commitment and quality of an employee, so I am accepting it
44too.
45 40
46# Exam Content 41# Exam Content
47 42
48The CISA is broken down into five sections, each weighted with a 43The CISA is broken down into five sections, each weighted with a percentage of
49percentage of test questions that may appear. 44test questions that may appear.
50 45
51![CISA exam 46![CISA exam
52sections](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-exam-sections.png) 47sections](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-exam-sections.png)
53 48
54Since the exam contains 150 questions, here\'s how those sections break 49Since the exam contains 150 questions, here's how those sections break down:
55down:
56 50
57 Exam Section Percentage of Exam Questions 51| Exam Section | Percentage of Exam | Questions |
58 ----------------- -------------------- ----------- 52|-----------------|--------------------|-----------|
59 1 21% 32 53| 1 | 21% | 32 |
60 2 17% 26 54| 2 | 17% | 26 |
61 3 12% 18 55| 3 | 12% | 18 |
62 4 23% 34 56| 4 | 23% | 34 |
63 5 27% 40 57| 5 | 27% | 40 |
64 **Grand Total** **100%** **150** 58| **Grand Total** | **100%** | **150** |
65 59
66# My Studying Habits 60# My Studying Habits
67 61
68This part is a little hard for me to break down into specific detail due 62This part is a little hard for me to break down into specific detail due to the
69to the craziness of the last year. While I officially purchased my 63craziness of the last year. While I officially purchased my studying materials
70studying materials in December 2020 and opened them to \"start 64in December 2020 and opened them to "start studying" in January 2021, I really
71studying\" in January 2021, I really wasn\'t able to study much due to 65wasn't able to study much due to the demands of my job and personal life.
72the demands of my job and personal life.
73 66
74Let me approach this from a few different viewpoints. 67Let me approach this from a few different viewpoints.
75 68
76## Study Materials 69## Study Materials
77 70
78Let\'s start by discussing the study materials I purchased. I\'ll be 71Let's start by discussing the study materials I purchased. I'll be referring
79referring to #1 as the CRM and #2 as the QAE. 72to #1 as the CRM and #2 as the QAE.
80 73
811. [CISA Review Manual, 27th Edition \| 741. [CISA Review Manual, 27th Edition |
82 Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK) 75Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK)
832. \[\[<https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK>\]\[CISA 762. [CISA Review Questions, Answers & Explanations Manual, 12th Edition |
84 Review Questions, Answers & Explanations Manual, 12th Edition \| 77Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK)
85 Print\]\] 78
86 79The CRM is an excellent source of information and could honestly be used as a
87The CRM is an excellent source of information and could honestly be used 80reference for most IS auditors as a learning reference during their daily audit
88as a reference for most IS auditors as a learning reference during their 81responsibilities. However, it is **full** of information and can be
89daily audit responsibilities. However, it is **full\*** of information 82overloading if you're not good at filtering out useless information while
90and can be overloading if you\'re not good at filtering out useless 83studying.
91information while studying. 84
92 85The QAE is the real star of the show here. This book contains 1000 questions,
93The QAE is the real star of the show here. This book contains 1000 86separated by exam section, and a practice exam. My only complaint about the QAE
94questions, separated by exam section, and a practice exam. My only 87is that each question is immediately followed with the correct answer and
95complaint about the QAE is that each question is immediately followed 88explanations below it, which means I had to use something to constantly cover
96with the correct answer and explanations below it, which means I had to 89the answers while I was studying.
97use something to constantly cover the answers while I was studying. 90
98 91I didn't use the online database version of the QAE, but I've heard that it's
99I didn\'t use the online database version of the QAE, but I\'ve heard 92easier to use than the printed book. However, it is more expensive ($299
100that it\'s easier to use than the printed book. However, it is more 93database vs $129 book) which might be important if you're paying for materials
101expensive (\$299 database vs \$129 book) which might be important if 94yourself.
102you\'re paying for materials yourself. 95
103 96In terms of question difficulty, I felt that the QAE was a good representation
104In terms of question difficulty, I felt that the QAE was a good 97of the actual exam. I've seen a lot of people online say it wasn't accurate to
105representation of the actual exam. I\'ve seen a lot of people online say 98the exam or that it was much easier/harder, but I disagree with all of those.
106it wasn\'t accurate to the exam or that it was much easier/harder, but I 99The exam was fairly similar to the QAE, just focusing on whichever topics they
107disagree with all of those. The exam was fairly similar to the QAE, just 100chose for my version of the exam.
108focusing on whichever topics they chose for my version of the exam. 101
109 102If you understand the concepts, skim the CRM (and read in-depth on topics you
110If you understand the concepts, skim the CRM (and read in-depth on 103struggle with), and use the QAE to continue practicing exam-like questions, you
111topics you struggle with), and use the QAE to continue practicing 104should be fine. I didn't use any online courses, videos, etc. - the ISACA
112exam-like questions, you should be fine. I didn\'t use any online 105materials are more than enough.
113courses, videos, etc. - the ISACA materials are more than enough.
114 106
115## Studying Process 107## Studying Process
116 108
117While I was able to briefly read through sections 1 and 2 in early 2021, 109While I was able to briefly read through sections 1 and 2 in early 2021, I had
118I had to stop and take a break from February/March to September. I 110to stop and take a break from February/March to September. I switched jobs in
119switched jobs in September, which allowed me a lot more free time to 111September, which allowed me a lot more free time to study.
120study.
121 112
122In September, I studied sections 3-5, took notes, and did a quick review 113In September, I studied sections 3-5, took notes, and did a quick review of the
123of the section topics. Once I felt comfortable with my notes, I took a 114section topics. Once I felt comfortable with my notes, I took a practice exam
124practice exam from the QAE manual and scored 70% (105/150). 115from the QAE manual and scored 70% (105/150).
125 116
126Here\'s a breakdown of my initial practice exam: 117Here's a breakdown of my initial practice exam:
127 118
128 Exam Section Incorrect Correct Grand Total Percent 119| Exam Section | Incorrect | Correct | Grand Total | Percent |
129 ------------------- ----------- ----------- ------------- ----------- 120|-----------------|-----------|---------|-------------|---------|
130 1 8 25 33 76% 121| 1 | 8 | 25 | 33 | 76% |
131 2 5 20 25 80% 122| 2 | 5 | 20 | 25 | 80% |
132 3 6 12 18 67% 123| 3 | 6 | 12 | 18 | 67% |
133 4 10 23 33 70% 124| 4 | 10 | 23 | 33 | 70% |
134 5 16 25 41 61% 125| 5 | 16 | 25 | 41 | 61% |
135 **Grand Total\*** **45\*** **105\*** **150\*** **70%\*** 126| **Grand Total** | **45** | **105** | **150** | **70%** |
136 127
137As I expected, my toughest sections were related to project management, 128As I expected, my toughest sections were related to project management,
138development, implementation, and security. 129development, implementation, and security.
139 130
140This just leaves October and November. For these months, I tried to 131This just leaves October and November. For these months, I tried to practice
141practice every few days, doing 10 questions for each section, until the 132every few days, doing 10 questions for each section, until the exam. This came
142exam. This came out to 13 practice sessions, \~140 questions per 133out to 13 practice sessions, ~140 questions per section, and ~700 questions
143section, and \~700 questions total. 134total.
144 135
145While some practice sessions were worse and some were better, the final 136While some practice sessions were worse and some were better, the final results
146results were similar to my practice exam results. As you can see below, 137were similar to my practice exam results. As you can see below, my averages were
147my averages were slightly worse than my practice exam. However, I got in 138slightly worse than my practice exam. However, I got in over 700 questions of
148over 700 questions of practice and, most importantly, \*I read through 139practice and, most importantly, *I read through the explanations every time I
149the explanations every time I answered incorrectly and learned from my 140answered incorrectly and learned from my mistakes*.
150mistakes\*. 141
151 142| Exam Section | Incorrect | Correct | Grand Total | Percent |
152 Exam Section Incorrect Correct Grand Total Percent 143|-----------------|-----------|---------|-------------|---------|
153 ------------------- ----------- ----------- ------------- ----------- 144| 1 | 33 | 108 | 141 | 77% |
154 1 33 108 141 77% 145| 2 | 33 | 109 | 142 | 77% |
155 2 33 109 142 77% 146| 3 | 55 | 89 | 144 | 62% |
156 3 55 89 144 62% 147| 4 | 52 | 88 | 140 | 63% |
157 4 52 88 140 63% 148| 5 | 55 | 85 | 140 | 61% |
158 5 55 85 140 61% 149| **Grand Total** | **228** | **479** | **707** | **68%** |
159 **Grand Total\*** **228\*** **479\*** **707\*** **68%\***
160 150
161![CISA practice question 151![CISA practice question
162results](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-practice-questions-results.png) 152results](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-practice-questions-results.png)
163 153
164# Results 154# Results
165 155
166Now, how do the practice scores reflect my actual results? After all, 156Now, how do the practice scores reflect my actual results? After all, it's hard
167it\'s hard to tell how good a practice regimen is unless you see how it 157to tell how good a practice regimen is unless you see how it turns out.
168turns out. 158
169 159| Exam Section | Section Name | Score |
170 Exam Section Section Name Score 160|--------------|------------------------------------------------------------------|-------|
171 -------------- ------------------------------------------------------------------ --------- 161| 1 | Information Systems Auditing Process | 678 |
172 1 Information Systems Auditing Process 678 162| 2 | Governance and Management of IT | 590 |
173 2 Governance and Management of IT 590 163| 3 | Information Systems Acquisition, Development, and Implementation | 721 |
174 3 Information Systems Acquisition, Development, and Implementation 721 164| 4 | Information Systems Operations and Business Resilience | 643 |
175 4 Information Systems Operations and Business Resilience 643 165| 5 | Protection of Information Assets | 511 |
176 5 Protection of Information Assets 511 166
177 **TOTAL** **616** 167Now, in order to pass the CISA, you need at least 450 on a sliding scale of
178 168200-800. Personally, I really have no clue what an average CISA score is. After
179Now, in order to pass the CISA, you need at least 450 on a sliding scale 169a *very* brief look online, I can see that the high end is usually in the low
180of 200-800. Personally, I really have no clue what an average CISA score 170700s. In addition, only about 50-60% of people pass the exam.
181is. After a *very* brief look online, I can see that the high end is 171
182usually in the low 700s. In addition, only about 50-60% of people pass 172Given this information, I feel great about my scores. 616 may not be phenomenal,
183the exam. 173and I wish I had done better on sections 2 & 5, but my practicing seems to have
184 174worked very well overall.
185Given this information, I feel great about my scores. 616 may not be 175
186phenomenal, and I wish I had done better on sections 2 & 5, but my 176However, the practice results do not conform to the actual results. Section 2
187practicing seems to have worked very well overall. 177was one of my highest practice sections and was my second-lowest score in the
188 178exam. Conversely, section 3 was my second-lowest practice section and turned out
189However, the practice results do not conform to the actual results. 179to be my highest actual score!
190Section 2 was one of my highest practice sections and was my 180
191second-lowest score in the exam. Conversely, section 3 was my 181After reflecting, it is obvious that if you have any background on the CISA
192second-lowest practice section and turned out to be my highest actual 182topics at all, the most important part of studying is doing practice questions.
193score! 183You really need to understand how to read the questions critically and pick the
194 184best answer.
195After reflecting, it is obvious that if you have any background on the
196CISA topics at all, the most important part of studying is doing
197practice questions. You really need to understand how to read the
198questions critically and pick the best answer.
199 185
200# Looking Forward 186# Looking Forward
201 187
202I am extremely happy that I was finally able to pass the CISA. Looking 188I am extremely happy that I was finally able to pass the CISA. Looking to the
203to the future, I\'m not sure what\'s next in terms of professional 189future, I'm not sure what's next in terms of professional learning. My current
204learning. My current company offers internal learning courses, so I will 190company offers internal learning courses, so I will most likely focus on that if
205most likely focus on that if I need to gain more knowledge in certain 191I need to gain more knowledge in certain areas.
206areas. 192
207 193To be fair, even if you pass the CISA, it's hard to become an expert on any
208To be fair, even if you pass the CISA, it\'s hard to become an expert on 194specific topic found within. My career may take me in a different direction, and
209any specific topic found within. My career may take me in a different 195I might need to focus more on security or networking certifications (or possibly
210direction, and I might need to focus more on security or networking 196building a better analysis/visualization portfolio if I want to go into data
211certifications (or possibly building a better analysis/visualization 197analysis/science).
212portfolio if I want to go into data analysis/science).
213 198
214All I know is that I am content at the moment and extremely proud of my 199All I know is that I am content at the moment and extremely proud of my
215accomplishment. 200accomplishment.
content/blog/2022-02-10-leaving-the-office.md +141 −160
@@ -7,195 +7,180 @@ draft = false
7 7
8# The Working World is Changing 8# The Working World is Changing
9 9
10There has been a trend for the past few years of companies slowly 10There has been a trend for the past few years of companies slowly realizing that
11realizing that the pandemic is not just a temporary state that will go 11the pandemic is not just a temporary state that will go away eventually and let
12away eventually and let everything return to the way it was before. In 12everything return to the way it was before. In terms of business and employment,
13terms of business and employment, this means that more and more jobs are 13this means that more and more jobs are being offered as permanently remote
14being offered as permanently remote roles. 14roles.
15 15
16I had always dreamt of working from home but thought of it as a fantasy, 16I had always dreamt of working from home but thought of it as a fantasy,
17especially since I did not want to move over into the software 17especially since I did not want to move over into the software development
18development field. However, I have found that almost all roles being 18field. However, I have found that almost all roles being sent to me via
19sent to me via recruiters are permanently remote (although most are 19recruiters are permanently remote (although most are limited to US citizens or
20limited to US citizens or even region-locked for companies who only 20even region-locked for companies who only operate in select states).
21operate in select states).
22 21
23I decided to take a look back at my relatively short career so far and 22I decided to take a look back at my relatively short career so far and compare
24compare the positive and negative effects of the different work 23the positive and negative effects of the different work environments I've been
25environments I\'ve been in. 24in.
26 25
27# In-Person Offices 26# In-Person Offices
28 27
29## Retail Internship 28## Retail Internship
30 29
31I started my first job as a management intern at a busy retail pharmacy, 30I started my first job as a management intern at a busy retail pharmacy, working
32working my 40-hour weeks on my feet. As these retail stores don\'t 31my 40-hour weeks on my feet. As these retail stores don't believe in resting or
33believe in resting or sitting down, you can guarantee that you will 32sitting down, you can guarantee that you will spend entire shifts standing,
34spend entire shifts standing, walking, or running around the store. 33walking, or running around the store. Unfortunately, I worked at a time when our
35Unfortunately, I worked at a time when our store didn\'t have enough 34store didn't have enough managers, so I spent the majority of my tenure at the
36managers, so I spent the majority of my tenure at the store running and 35store running and breaking a sweat.
37breaking a sweat. 36
38 37Now, things aren't all bad in retail stores like this. It is definitely tiring
39Now, things aren\'t all bad in retail stores like this. It is definitely 38and inefficient to force employees to work constantly, or pretend to work if
40tiring and inefficient to force employees to work constantly, or pretend 39there's nothing to do, and not allow anyone to sit down. However, if you are
41to work if there\'s nothing to do, and not allow anyone to sit down. 40able to operate a retail store with a limited crew and provide enough comfort
42However, if you are able to operate a retail store with a limited crew 41and support, I believe these jobs could be both comfortable and efficient.
43and provide enough comfort and support, I believe these jobs could be
44both comfortable and efficient.
45 42
46## Semi-Private Cubicles 43## Semi-Private Cubicles
47 44
48![Semi-Private 45![Semi-Private
49Cubicles](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/private_cubicles.png) 46Cubicles](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/private_cubicles.png)
50 47
51After about a year, I was able to find another internship - this time, 48After about a year, I was able to find another internship - this time, it was in
52it was in my field of interest: internal auditing. This was for a life 49my field of interest: internal auditing. This was for a life insurance company
53insurance company that was well over 100 years old. The age of the 50that was well over 100 years old. The age of the company shows if you work
54company shows if you work there, as most people in management are well 51there, as most people in management are well into their 40s-60s with little to
55into their 40s-60s with little to no youthful leadership in the company. 52no youthful leadership in the company. Likewise, they owned a large headquarters
56Likewise, they owned a large headquarters in a nice area of town with 53in a nice area of town with plenty of space, parking, etc.
57plenty of space, parking, etc. 54
58 55One upside is that each person gets their own large L-shaped desk, formed into
59One upside is that each person gets their own large L-shaped desk, 56cubicles that house 4 desks/employees. These "pods" of 4-person cubicles are
60formed into cubicles that house 4 desks/employees. These \"pods\" of 57linked throughout each floor of the headquarters (except the sales people, who
614-person cubicles are linked throughout each floor of the headquarters 58had that open-floor concept going on). The walls of the cubicle were tall and
62(except the sales people, who had that open-floor concept going on). The 59provided a lot of privacy and sound-proofing, except when I used the standing
63walls of the cubicle were tall and provided a lot of privacy and 60desk feature (I'm over 6 feet tall, so probably not an issue for most people).
64sound-proofing, except when I used the standing desk feature (I\'m over
656 feet tall, so probably not an issue for most people).
66 61
67I loved this environment, it allowed me to focus on my work with minimal 62I loved this environment, it allowed me to focus on my work with minimal
68distractions, but also allowed easy access, so I could spin around in my 63distractions, but also allowed easy access, so I could spin around in my chair
69chair and chat with my friends without leaving my chair. This is the 64and chat with my friends without leaving my chair. This is the closest I've
70closest I\'ve been to a home office environment (which is my personal 65been to a home office environment (which is my personal favorite, as I'll get
71favorite, as I\'ll get to later in this post). 66to later in this post).
72 67
73## Semi-Open Floor Concept 68## Semi-Open Floor Concept
74 69
75![Semi-Open Floor 70![Semi-Open Floor
76Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/semi_open_office.png) 71Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/semi_open_office.png)
77 72
78When I shifted to my first full-time internal audit job out of college, 73When I shifted to my first full-time internal audit job out of college, I was
79I was working at a company that was headquartered on a floor in a 74working at a company that was headquartered on a floor in a downtown high-rise
80downtown high-rise building. The company was only about 20 years old 75building. The company was only about 20 years old when I worked there and were
81when I worked there and were trying a lot of new things to attract young 76trying a lot of new things to attract young talent, one of which was a semi-open
82talent, one of which was a semi-open floor concept for the office. My 77floor concept for the office. My department worked just around the hallway
83department worked just around the hallway corner from the executive 78corner from the executive offices and used that "modern" layout young tech
84offices and used that \"modern\" layout young tech companies started 79companies started using in the 2000s/2010s.
85using in the 2000s/2010s. 80
86 81Each desk was brief, and you could look most coworkers in the face without
87Each desk was brief, and you could look most coworkers in the face 82moving from your chair, I hated this so much. Directly to my left was the Chief
88without moving from your chair, I hated this so much. Directly to my 83Audit Executive (our department's leading boss), and his desk was pointed so
89left was the Chief Audit Executive (our department\'s leading boss), and 84that his face would stare straight at my desk all day. I spent more time
90his desk was pointed so that his face would stare straight at my desk 85thinking about who was looking at me or checking on me than actually working.
91all day. I spent more time thinking about who was looking at me or 86
92checking on me than actually working. 87The other annoying part of the open concept they used was that the kitchen area
93 88and pathways were too close to everyone's desks (since the desks were spread
94The other annoying part of the open concept they used was that the 89out, to provide space or something), so noise and conversation would be constant
95kitchen area and pathways were too close to everyone\'s desks (since the 90throughout the day while you try to work. For someone like me, who needs silence
96desks were spread out, to provide space or something), so noise and 91to get work done, that was a non-starter.
97conversation would be constant throughout the day while you try to work.
98For someone like me, who needs silence to get work done, that was a
99non-starter.
100 92
101## Hotel Office Concept 93## Hotel Office Concept
102 94
103![Hotel Office 95![Hotel Office
104Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/hotel_desks.png) 96Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/hotel_desks.png)
105 97
106I currently work for a company remotely (for now) and travel to the 98I currently work for a company remotely (for now) and travel to the office every
107office every once in a while for events and to help coach the staff 99once in a while for events and to help coach the staff underneath me. The office
108underneath me. The office I visit uses the hotel desk concept, where you 100I visit uses the hotel desk concept, where you need to check in at a touch
109need to check in at a touch screen when you enter the office and 101screen when you enter the office and "rent" a desk for the day. The same goes
110\"rent\" a desk for the day. The same goes for offices and meeting 102for offices and meeting rooms.
111rooms. 103
112 104These desks are flat-top only and do not have any walls at all. In addition,
113These desks are flat-top only and do not have any walls at all. In 105they're stacked with one row of 4 desks facing another row of 4 desks. These
114addition, they\'re stacked with one row of 4 desks facing another row of 106pairs of desk rows are repeated through the office.
1154 desks. These pairs of desk rows are repeated through the office. 107
116 108This means that when I go, I need to rent a random desk or try to remember the
117This means that when I go, I need to rent a random desk or try to 109unique ID numbers on desks I like. Once I rent it, I have to make sure no one
118remember the unique ID numbers on desks I like. Once I rent it, I have 110sat down in that desk without renting it. Then, I can sit down and work, but
119to make sure no one sat down in that desk without renting it. Then, I 111will probably need to adjust the monitors so that I'm not staring in the face
120can sit down and work, but will probably need to adjust the monitors so 112of the person across from me all day. Finally, I need to wear headphones as this
121that I\'m not staring in the face of the person across from me all day. 113environment does nothing to provide you with peace or quiet.
122Finally, I need to wear headphones as this environment does nothing to 114
123provide you with peace or quiet. 115Luckily, you can rent offices with doors that offer quiet and privacy, which can
124 116be very nice if you have a lot of meetings or webinars on a certain day.
125Luckily, you can rent offices with doors that offer quiet and privacy,
126which can be very nice if you have a lot of meetings or webinars on a
127certain day.
128 117
129# Home Office 118# Home Office
130 119
131![Home 120![Home
132Office](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/home_office.png) 121Office](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/home_office.png)
133 122
134Okay, now let\'s finally get to the home office concept. I have worked 123Okay, now let's finally get to the home office concept. I have worked from home
135from home for a little over two years at this point, across three 124for a little over two years at this point, across three different
136different jobs/employers. Over this time, I have experimented with a 125jobs/employers. Over this time, I have experimented with a plethora of different
137plethora of different organizational ideas, desks, and room layouts to 126organizational ideas, desks, and room layouts to find what works best for me.
138find what works best for me.
139 127
140These things might not apply to you, and that\'s fine. Everyone has a 128These things might not apply to you, and that's fine. Everyone has a different
141different situation, and I really don\'t think you\'ll know what works 129situation, and I really don't think you'll know what works until you try.
142until you try.
143 130
144## Tip #1 131## Tip #1
145 132
146Let\'s start with my top rule for a home office: 133Let's start with my top rule for a home office:
147 134
148> If you live with others, working in a shared space is not effective. 135> If you live with others, working in a shared space is not effective.
149 136
150It just does not work. If you have another person sleeping in your 137It just does not work. If you have another person sleeping in your bedroom, it
151bedroom, it is difficult to manage your work schedule with their 138is difficult to manage your work schedule with their sleeping/work/school
152sleeping/work/school schedule. If they wake up after you need to start 139schedule. If they wake up after you need to start work, you might wake them up
153work, you might wake them up or have to suffer the agony of staring at 140or have to suffer the agony of staring at bright screens in a dark room.
154bright screens in a dark room.
155 141
156In a similar vein, working from a location such as the living room 142In a similar vein, working from a location such as the living room likely won't
157likely won\'t work either. Distractions will come far more frequently: 143work either. Distractions will come far more frequently: televisions, cooking,
158televisions, cooking, cleaning, deliveries, etc. If you\'re like me, 144cleaning, deliveries, etc. If you're like me, you'll end up playing a game
159you\'ll end up playing a game instead of actually doing any work. 145instead of actually doing any work.
160 146
161## Tip #2 147## Tip #2
162 148
163Okay, the second thing I\'ve discovered that works for me: 149Okay, the second thing I've discovered that works for me:
164 150
165> Use the pomodoro method (or something similar) to balance work tasks 151> Use the pomodoro method (or something similar) to balance work tasks with
166> with personal tasks. 152> personal tasks.
167 153
168I use a very casual version of the pomodoro method where I will work for 154I use a very casual version of the pomodoro method where I will work for 1-2
1691-2 hours (usually set in strict intervals like 1, 1.5, 2 hours) and 155hours (usually set in strict intervals like 1, 1.5, 2 hours) and then will allow
170then will allow myself 30-60 minutes for personal tasks. This schedule 156myself 30-60 minutes for personal tasks. This schedule works for me, since my
171works for me, since my work schedule really only comes to 3-6 hours of 157work schedule really only comes to 3-6 hours of work per day.
172work per day.
173 158
174In this case, I\'ll work through my list of tasks for an hour or two and 159In this case, I'll work through my list of tasks for an hour or two and then
175then give myself personal time to get drinks and food, wash dishes, put 160give myself personal time to get drinks and food, wash dishes, put clothes in
176clothes in the washer, get the mail, etc. If you\'re in a convenient 161the washer, get the mail, etc. If you're in a convenient location, this usually
177location, this usually gives time for things like getting groceries (as 162gives time for things like getting groceries (as long as you're not a slow
178long as you\'re not a slow shopper). 163shopper).
179 164
180## Tip #3 165## Tip #3
181 166
182While I listed this one as number three, I don\'t think I\'d accomplish 167While I listed this one as number three, I don't think I'd accomplish anything
183anything without it: 168without it:
184 169
185> Document everything: even things you didn\'t before - such as task 170> Document everything: even things you didn't before - such as task lists and
186> lists and notes from casual calls or meetings. 171> notes from casual calls or meetings.
187 172
188I\'ve noticed that staying in an office gave me more constant reminders 173I've noticed that staying in an office gave me more constant reminders of
189of outstanding tasks or facts I had learned in a conversation. 174outstanding tasks or facts I had learned in a conversation. Translating
190Translating everything to a digital world has made me lose a bit of that 175everything to a digital world has made me lose a bit of that focus (perhaps
191focus (perhaps since I don\'t have visual reminders?). 176since I don't have visual reminders?).
192 177
193Keeping a running task list of all things I have to do - even potential 178Keeping a running task list of all things I have to do - even potential tasks! -
194tasks! - has helped me keep up without missing anything small. Likewise, 179has helped me keep up without missing anything small. Likewise, keeping notes
195keeping notes for ALL meetings and calls, no matter how casual/quick, 180for ALL meetings and calls, no matter how casual/quick, has improved my
196has improved my retention immensely. Beyond helping my mental 181retention immensely. Beyond helping my mental recollection, it has saved me
197recollection, it has saved me numerous times when I need to do a keyword 182numerous times when I need to do a keyword search for some topic that was
198search for some topic that was discussed 6+ months ago. 183discussed 6+ months ago.
199 184
200## Tip #4 185## Tip #4
201 186
@@ -203,39 +188,35 @@ Okay, last one for now.
203 188
204> Keep your work area clean. 189> Keep your work area clean.
205 190
206This one is straightforward, but I know some people struggle with 191This one is straightforward, but I know some people struggle with cleanliness or
207cleanliness or may not believe it makes a difference. Trust me, keeping 192may not believe it makes a difference. Trust me, keeping your desk area clean
208your desk area clean and organized makes a huge difference, both 193and organized makes a huge difference, both mentally and emotionally.
209mentally and emotionally.
210 194
211Just think about it, you walk into your home office and see a clean desk 195Just think about it, you walk into your home office and see a clean desk with a
212with a laptop, dock, monitors, keyboard, mouse, and a notepad with a pen 196laptop, dock, monitors, keyboard, mouse, and a notepad with a pen on top.
213on top.
214 197
215Now imagine the opposite, there\'s an office with the same equipment, 198Now imagine the opposite, there's an office with the same equipment, but there
216but there are clothes hanging on the chair, empty drink bottles, candy 199are clothes hanging on the chair, empty drink bottles, candy wrappers and dirty
217wrappers and dirty plates. This can take both a mental and emotional 200plates. This can take both a mental and emotional toll by bringing constant
218toll by bringing constant disarray and stress into your working 201disarray and stress into your working environment.
219environment.
220 202
221Just keep things clean each day, and you won\'t need to do any big 203Just keep things clean each day, and you won't need to do any big cleaning days
222cleaning days to recover. 204to recover.
223 205
224# My Preferences 206# My Preferences
225 207
226I\'ve talked about the different environments I\'ve worked in and 208I've talked about the different environments I've worked in and expressed some
227expressed some honest thoughts on pros or cons to each, but what do I 209honest thoughts on pros or cons to each, but what do I prefer? Well, if you're
228prefer? Well, if you\'re reading along, you should be able to tell that 210reading along, you should be able to tell that I much prefer a home office above
229I much prefer a home office above all else. 211all else.
230 212
231Being able to control my own day and allot my time as needed has brought 213Being able to control my own day and allot my time as needed has brought a
232a calmness to my life and has allowed me to maximize each day. I feel 214calmness to my life and has allowed me to maximize each day. I feel far more
233far more effective and efficient in a home office than any other office, 215effective and efficient in a home office than any other office, especially
234especially open-office layouts. 216open-office layouts.
235 217
236If I do need to return to an office part-time in the future, I really 218If I do need to return to an office part-time in the future, I really hope the
237hope the office will have privacy and quietness in order for me to get 219office will have privacy and quietness in order for me to get my work done.
238my work done.
239 220
240Cubicles are good! I agree with Alice (from the comic Dilbert): 221Cubicles are good! I agree with Alice (from the comic Dilbert):
241 222
content/blog/2022-02-10-njalla-dns-api.md +47 −56
@@ -5,48 +5,46 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Njalla\'s API 8# Njalla's API
9 9
10As noted in my recent post about [switching to Njalla from 10As noted in my recent post about [switching to Njalla from
11Cloudflare](file:///blog/ditching-cloudflare/), I was searching for a 11Cloudflare](file:///blog/ditching-cloudflare/), I was searching for a way to
12way to replace my very easy-to-use bash script to [update Cloudflare\'s 12replace my very easy-to-use bash script to [update Cloudflare's DNS via their
13DNS via their API](file:///blog/cloudflare-dns-api/). 13API](file:///blog/cloudflare-dns-api/).
14 14
15To reiterate what I said in those posts, this is a common necessity for 15To reiterate what I said in those posts, this is a common necessity for those of
16those of us who have non-static IP addresses that can change at any 16us who have non-static IP addresses that can change at any moment due to ISP
17moment due to ISP policy. 17policy.
18 18
19In order to keep a home server running smoothly, the server admin needs 19In order to keep a home server running smoothly, the server admin needs to have
20to have a process to constantly monitor their public IP address and 20a process to constantly monitor their public IP address and update their
21update their domain\'s DNS records if it changes. 21domain's DNS records if it changes.
22 22
23This post explains how to use Python to update Njalla\'s DNS records 23This post explains how to use Python to update Njalla's DNS records whenever a
24whenever a machine\'s public IP address changes. 24machine's public IP address changes.
25 25
26## Creating a Token 26## Creating a Token
27 27
28To use Njalla\'s API, you will first need to create a token that will be 28To use Njalla's API, you will first need to create a token that will be used to
29used to authenticate you every time you call the API. Luckily, this is 29authenticate you every time you call the API. Luckily, this is very easy to do
30very easy to do if you have an account with Njalla. 30if you have an account with Njalla.
31 31
32Simply go the [API Settings](https://njal.la/settings/api/) page and 32Simply go the [API Settings](https://njal.la/settings/api/) page and click the
33click the `Add Token` button. Next, enter a name for the 33`Add Token` button. Next, enter a name for the token and click `Add`.
34token and click `Add`.
35 34
36Finally, click the `Manage` button next to your newly created 35Finally, click the `Manage` button next to your newly created token and copy the
37token and copy the `API Token` field. 36`API Token` field.
38 37
39## Finding the Correct API Request 38## Finding the Correct API Request
40 39
41Once you have a token, you\'re ready to call the Njalla API for any 40Once you have a token, you're ready to call the Njalla API for any number of
42number of requests. For a full listing of available requests, see the 41requests. For a full listing of available requests, see the [Njalla API
43[Njalla API Documentation](https://njal.la/api/). 42Documentation](https://njal.la/api/).
44 43
45For this demo, we are using the `list-records` and 44For this demo, we are using the `list-records` and `edit-record` requests.
46`edit-record` requests.
47 45
48The `list-records` request requires the following payload to 46The `list-records` request requires the following payload to be sent when
49be sent when calling the API: 47calling the API:
50 48
51``` txt 49``` txt
52params: { 50params: {
@@ -54,8 +52,8 @@ params: {
54} 52}
55``` 53```
56 54
57The `edit-record` request requires the following payload to 55The `edit-record` request requires the following payload to be sent when calling
58be sent when calling the API: 56the API:
59 57
60``` txt 58``` txt
61params: { 59params: {
@@ -67,14 +65,14 @@ params: {
67 65
68# Server Set-Up 66# Server Set-Up
69 67
70To create this script, we will be using Python. By default, I use Python 68To create this script, we will be using Python. By default, I use Python 3 on my
713 on my servers, so please note that I did not test this in Python 2, 69servers, so please note that I did not test this in Python 2, and I do not know
72and I do not know if Python 2 will work for this. 70if Python 2 will work for this.
73 71
74## Creating the Script 72## Creating the Script
75 73
76First, find a suitable place to create your script. Personally, I just 74First, find a suitable place to create your script. Personally, I just create a
77create a directory called `ddns` in my home directory: 75directory called `ddns` in my home directory:
78 76
79```sh 77```sh
80mkdir ~/ddns 78mkdir ~/ddns
@@ -86,23 +84,17 @@ Next, create a Python script file:
86nano ~/ddns/ddns.py 84nano ~/ddns/ddns.py
87``` 85```
88 86
89The following code snippet is quite long, so I won\'t go into depth on 87The following code snippet is quite long, so I won't go into depth on each
90each part. However, I suggest you read through the entire script before 88part. However, I suggest you read through the entire script before running it;
91running it; it is quite simple and contains comments to help explain 89it is quite simple and contains comments to help explain each code block.
92each code block.
93 90
94:warning: **Note**: You will need to update the following variables for 91:warning: **Note**: You will need to update the following variables for this to
95this to work: 92work:
96 93
97- `token`: This is the Njalla API token you created 94- `token`: This is the Njalla API token you created earlier.
98 earlier. 95- `user_domain`: This is the top-level domain you want to modify.
99- `user_domain`: This is the top-level domain you want to 96- `include_subdomains`: Set this to `True` if you also want to modify subdomains found under the TLD.
100 modify. 97- `subdomains`: If `include_subdomains` = `True`, you can include your list of subdomains to be modified here.
101- `include_subdomains`: Set this to `True` if
102 you also want to modify subdomains found under the TLD.
103- `subdomains`: If `include_subdomains` =
104 `True`, you can include your list of subdomains to be
105 modified here.
106 98
107``` python 99``` python
108#!/usr/bin/python 100#!/usr/bin/python
@@ -187,8 +179,8 @@ for record in data['records']:
187 179
188## Running the Script 180## Running the Script
189 181
190Once you\'ve created the script and are ready to test it, run the 182Once you've created the script and are ready to test it, run the following
191following command: 183command:
192 184
193```sh 185```sh
194python3 ~/ddns/ddns.py 186python3 ~/ddns/ddns.py
@@ -196,16 +188,15 @@ python3 ~/ddns/ddns.py
196 188
197## Setting the Script to Run Automatically 189## Setting the Script to Run Automatically
198 190
199To make sure the scripts run automatically, add it to the 191To make sure the scripts run automatically, add it to the `cron` file so that it
200`cron` file so that it will run on a schedule. To do this, 192will run on a schedule. To do this, open the `cron` file:
201open the `cron` file:
202 193
203```sh 194```sh
204crontab -e 195crontab -e
205``` 196```
206 197
207In the cron file, paste the following at the bottom of the editor in 198In the cron file, paste the following at the bottom of the editor in order to
208order to check the IP every five minutes: 199check the IP every five minutes:
209 200
210```sh 201```sh
211*/5 ** ** ** ** python3 /home/<your_username>/ddns/ddns.py 202*/5 ** ** ** ** python3 /home/<your_username>/ddns/ddns.py
content/blog/2022-02-16-debian-and-nginx.md +60 −68
@@ -10,34 +10,33 @@ draft = false
10![Debian + 10![Debian +
11neofetch](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/neofetch.png) 11neofetch](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/neofetch.png)
12 12
13I\'ve used various Linux distributions throughout the years, but I\'ve 13I've used various Linux distributions throughout the years, but I've never
14never used anything except Ubuntu for my servers. Why? I really have no 14used anything except Ubuntu for my servers. Why? I really have no idea, mostly
15idea, mostly just comfort around the commands and software availability. 15just comfort around the commands and software availability.
16 16
17However, I have always wanted to try Debian as a server OS after testing 17However, I have always wanted to try Debian as a server OS after testing it out
18it out in a VM a few years ago (side-note: I\'d love to try Alpine too, 18in a VM a few years ago (side-note: I'd love to try Alpine too, but I always
19but I always struggle with compatibility). So, I decided to launch a new 19struggle with compatibility). So, I decided to launch a new VPS and use
20VPS and use [Debian](https://www.debian.org) 11 as the OS. Spoiler 20[Debian](https://www.debian.org) 11 as the OS. Spoiler alert: it feels identical
21alert: it feels identical to Ubuntu for my purposes. 21to Ubuntu for my purposes.
22 22
23I did the normal things when first launching the VPS, such as adding a 23I did the normal things when first launching the VPS, such as adding a new user,
24new user, locking down SSH, etc. If you want to see that level of 24locking down SSH, etc. If you want to see that level of detail, read my other
25detail, read my other post about [How to Set Up a VPS Web 25post about [How to Set Up a VPS Web
26Server](https://cleberg.net/blog/how-to-set-up-a-vps-web-server/). 26Server](https://cleberg.net/blog/how-to-set-up-a-vps-web-server/).
27 27
28All of this has been similar, apart from small things such as the 28All of this has been similar, apart from small things such as the location of
29location of users\' home folders. No complaints at all from me - Debian 29users' home folders. No complaints at all from me - Debian seems great.
30seems great.
31 30
32# Web Server: Nginx 31# Web Server: Nginx
33 32
34![Nginx 33![Nginx
35status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/nginx.png) 34status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/nginx.png)
36 35
37Once I had the baseline server configuration set-up for Debian, I moved 36Once I had the baseline server configuration set-up for Debian, I moved on to
38on to trying out [Nginx](https://nginx.org) as my web server software. 37trying out [Nginx](https://nginx.org) as my web server software. This required
39This required me to install the `nginx` and `ufw` 38me to install the `nginx` and `ufw` packages, as well as setting up the initial
40packages, as well as setting up the initial UFW config: 39UFW config:
41 40
42```sh 41```sh
43sudo apt install nginx ufw 42sudo apt install nginx ufw
@@ -48,9 +47,9 @@ sudo ufw status
48sudo systemctl status nginx 47sudo systemctl status nginx
49``` 48```
50 49
51Once I had the firewall set, I moved on to creating the directories and 50Once I had the firewall set, I moved on to creating the directories and files
52files for my website. This is very easy and is basically the same as 51for my website. This is very easy and is basically the same as setting up an
53setting up an Apache server, so no struggles here. 52Apache server, so no struggles here.
54 53
55```sh 54```sh
56sudo mkdir -p /var/www/your_domain/html 55sudo mkdir -p /var/www/your_domain/html
@@ -59,10 +58,9 @@ sudo chmod -R 755 /var/www/your_domain
59nano /var/www/your_domain/html/index.html 58nano /var/www/your_domain/html/index.html
60``` 59```
61 60
62The next part, creating the Nginx configuration files, is quite a bit 61The next part, creating the Nginx configuration files, is quite a bit different
63different from Apache. First, you need to create the files in the 62from Apache. First, you need to create the files in the `sites-available` folder
64`sites-available` folder and symlink it the 63and symlink it the `sites-enabled` folder.
65`sites-enabled` folder.
66 64
67Creating the config file for your domain: 65Creating the config file for your domain:
68 66
@@ -95,11 +93,10 @@ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
95``` 93```
96 94
97This will make your site available to the public (as long as you have 95This will make your site available to the public (as long as you have
98`your_domain` DNS records pointed at the server\'s IP 96`your_domain` DNS records pointed at the server's IP address)!
99address)!
100 97
101Next, I used [certbot](https://certbot.eff.org/) to issue an HTTPS 98Next, I used [certbot](https://certbot.eff.org/) to issue an HTTPS certificate
102certificate for my domains using the following commands: 99for my domains using the following commands:
103 100
104```sh 101```sh
105sudo apt install snapd; sudo snap install core; sudo snap refresh core 102sudo apt install snapd; sudo snap install core; sudo snap refresh core
@@ -108,17 +105,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
108sudo certbot --nginx 105sudo certbot --nginx
109``` 106```
110 107
111Now that certbot ran successfully and updated my Nginx config files to 108Now that certbot ran successfully and updated my Nginx config files to include a
112include a `443` server block of code, I went back in and 109`443` server block of code, I went back in and edited the config file to include
113edited the config file to include security HTTP headers. This part is 110security HTTP headers. This part is optional, but is recommended for security
114optional, but is recommended for security purposes; you can even test a 111purposes; you can even test a website's HTTP header security at [Security
115website\'s HTTP header security at [Security
116Headers](https://securityheaders.com/). 112Headers](https://securityheaders.com/).
117 113
118The configuration below shows a set-up where you only want your website 114The configuration below shows a set-up where you only want your website to serve
119to serve content from its own domain, except for images and scripts, 115content from its own domain, except for images and scripts, which may come from
120which may come from `nullitics.com`. All other content would 116`nullitics.com`. All other content would be blocked from loading in a browser.
121be blocked from loading in a browser.
122 117
123```sh 118```sh
124sudo nano /etc/nginx/sites-available/your_domain 119sudo nano /etc/nginx/sites-available/your_domain
@@ -143,39 +138,36 @@ sudo systemctl restart nginx
143 138
144## Nginx vs. Apache 139## Nginx vs. Apache
145 140
146As I stated at the beginning, my historical hesitation with trying Nginx 141As I stated at the beginning, my historical hesitation with trying Nginx was
147was that the differences in configuration formats scared me away from 142that the differences in configuration formats scared me away from leaving
148leaving Apache. However, I prefer Nginx to Apache for a few reasons: 143Apache. However, I prefer Nginx to Apache for a few reasons:
149 144
1501. Nginx uses only one config file (`your_domain`) vs. 1451. Nginx uses only one config file (`your_domain`) vs. Apache's two-file
151 Apache\'s two-file approach for HTTP vs. HTTPS 146 approach for HTTP vs. HTTPS (`your_domain.conf` and
152 (`your_domain.conf` and 147 `your_domain-le-ssl.conf`).
153 `your_domain-le-ssl.conf`). 1482. Symlinking new configurations files and reloading Nginx are way easier than
1542. Symlinking new configurations files and reloading Nginx are way 149 Apache's process of having to enable headers with `a2enmod mod_headers`,
155 easier than Apache\'s process of having to enable headers with 150 enable PHP with `a2enmod php` (plus any other mods you need), and then
156 `a2enmod mod_headers`, enable PHP with 151 enabling sites with `a2ensite`, and THEN reloading Apache.
157 `a2enmod php` (plus any other mods you need), and then 1523. The contents of the Nginx config files seem more organized and logical with
158 enabling sites with `a2ensite`, and THEN reloading 153 the curly-bracket approach. This is a minor reason, but everything just felt
159 Apache. 154 cleaner while I was installing my sites and that had a big quality of life
1603. The contents of the Nginx config files seem more organized and 155 impact on the installation for me.
161 logical with the curly-bracket approach. This is a minor reason, but 156
162 everything just felt cleaner while I was installing my sites and 157They're both great software packages, but Nginx just seems more organized and
163 that had a big quality of life impact on the installation for me. 158easier to use these days. I will certainly be exploring the Nginx docs to see
164 159what other fun things I can do with all of this.
165They\'re both great software packages, but Nginx just seems more
166organized and easier to use these days. I will certainly be exploring
167the Nginx docs to see what other fun things I can do with all of this.
168 160
169# Gemini Server: Agate 161# Gemini Server: Agate
170 162
171![Agate 163![Agate
172status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/agate.png) 164status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/agate.png)
173 165
174Finally, I set up the Agate software on this server again to host my 166Finally, I set up the Agate software on this server again to host my Gemini
175Gemini server content, using Rust as I have before. You can read my 167server content, using Rust as I have before. You can read my other post for more
176other post for more information on installing Agate: [Hosting a Gemini 168information on installing Agate: [Hosting a Gemini
177Server](https://cleberg.net/blog/hosting-a-gemini-server/). 169Server](https://cleberg.net/blog/hosting-a-gemini-server/).
178 170
179All in all, Debian + Nginx is very slick and I prefer it over my old 171All in all, Debian + Nginx is very slick and I prefer it over my old combination
180combination of Ubuntu + Apache (although it\'s really just Nginx \> 172of Ubuntu + Apache (although it's really just Nginx > Apache for me, since
181Apache for me, since Debian seems mostly the same as Ubuntu is so far). 173Debian seems mostly the same as Ubuntu is so far).
content/blog/2022-02-17-exiftool.md +30 −34
@@ -7,36 +7,34 @@ draft = false
7 7
8## Why Strip Metadata? 8## Why Strip Metadata?
9 9
10Okay, so you want to strip metadata from your photos. Perhaps you take 10Okay, so you want to strip metadata from your photos. Perhaps you take pictures
11pictures of very rare birds, and the location metadata is a gold mine 11of very rare birds, and the location metadata is a gold mine for poachers, or
12for poachers, or perhaps you\'re just privacy-oriented like me and 12perhaps you're just privacy-oriented like me and prefer to strip metadata from
13prefer to strip metadata from publicly-available images. 13publicly-available images.
14 14
15There are various components of image metadata that you may want to 15There are various components of image metadata that you may want to delete
16delete before releasing a photo to the public. Here\'s an incomplete 16before releasing a photo to the public. Here's an incomplete list of things I
17list of things I could easily see just by inspecting a photo on my 17could easily see just by inspecting a photo on my laptop:
18laptop:
19 18
20- Location (Latitude & Longitude) 19- Location (Latitude & Longitude)
21- Dimensions 20- Dimensions
22- Device Make & Model 21- Device Make & Model
23- Color Space 22- Color Space
24- Color Profile 23- Color Profile
25- Focal Length 24- Focal Length
26- Alpha Channel 25- Alpha Channel
27- Red Eye 26- Red Eye
28- Metering Mode 27- Metering Mode
29- F Number 28- F Number
30 29
31Regardless of your reasoning, I\'m going to explain how I used the 30Regardless of your reasoning, I'm going to explain how I used the `exiftool`
32`exiftool` package in Linux to automatically strip metadata 31package in Linux to automatically strip metadata from all images in a directory
33from all images in a directory (+ subdirectories). 32(+ subdirectories).
34 33
35## Installing `exiftool` 34## Installing `exiftool`
36 35
37First things first: we need to install the tool. I\'m running Debian 11 36First things first: we need to install the tool. I'm running Debian 11 on my
38on my server (Ubuntu will work the same), so the command is as simple 37server (Ubuntu will work the same), so the command is as simple as:
39as:
40 38
41```sh 39```sh
42sudo apt install exiftool 40sudo apt install exiftool
@@ -47,22 +45,20 @@ distributions, but I really only care to test out this one package.
47 45
48## Recursively Strip Data 46## Recursively Strip Data
49 47
50I actually use this tool extensively to strip any photos uploaded to the 48I actually use this tool extensively to strip any photos uploaded to the website
51website that serves all the images for my blog 49that serves all the images for my blog (`img.cleberg.net`).
52(`img.cleberg.net`).
53 50
54The following command is incredibly useful and can be modified to 51The following command is incredibly useful and can be modified to include any
55include any image extensions that `exiftool` supports: 52image extensions that `exiftool` supports:
56 53
57```sh 54```sh
58exiftool -r -all= -ext jpg -ext png /path/to/directory/ 55exiftool -r -all= -ext jpg -ext png /path/to/directory/
59``` 56```
60 57
61See below for the results of my most recent usage of 58See below for the results of my most recent usage of `exiftool` after I uploaded
62`exiftool` after I uploaded the image for this blog post. You 59the image for this blog post. You can see that the command will let you know how
63can see that the command will let you know how many directories were 60many directories were scanned, how many images were updated, and how many images
64scanned, how many images were updated, and how many images were 61were unchanged.
65unchanged.
66 62
67![exiftool 63![exiftool
68results](https://img.cleberg.net/blog/20220217-stripping-metadata-with-exiftool/exiftool.png) 64results](https://img.cleberg.net/blog/20220217-stripping-metadata-with-exiftool/exiftool.png)
content/blog/2022-02-20-nginx-caching.md +30 −35
@@ -7,16 +7,15 @@ draft = false
7 7
8# Update Your Nginx Config to Cache Static Files 8# Update Your Nginx Config to Cache Static Files
9 9
10If you run a website on Nginx that serves static content (i.e., content 10If you run a website on Nginx that serves static content (i.e., content that is
11that is not dynamic and changing with interactions from the user), you 11not dynamic and changing with interactions from the user), you would likely
12would likely benefit from caching that content on the client-side. If 12benefit from caching that content on the client-side. If you're used to Apache
13you\'re used to Apache and looking for the Nginx equivalent, this post 13and looking for the Nginx equivalent, this post should help.
14should help.
15 14
16Luckily, setting up the cache is as easy as identifying the file types 15Luckily, setting up the cache is as easy as identifying the file types you want
17you want to cache and determining the expiration length. To include more 16to cache and determining the expiration length. To include more file types,
18file types, simply use the bar separator (`|`) and type the 17simply use the bar separator (`|`) and type the new file extension you want to
19new file extension you want to include. 18include.
20 19
21``` config 20``` config
22server { 21server {
@@ -30,44 +29,40 @@ server {
30} 29}
31``` 30```
32 31
33I have seen some people who prefer to set `expires` as 32I have seen some people who prefer to set `expires` as `365d` or even `max`, but
34`365d` or even `max`, but that is only for stable, 33that is only for stable, infrequently changing websites. As my site often
35infrequently changing websites. As my site often changes (i.e., I\'m 34changes (i.e., I'm never content with my website), I need to know that my
36never content with my website), I need to know that my readers are 35readers are seeing the new content without waiting too long.
37seeing the new content without waiting too long.
38 36
39So, I went ahead and set the expiration date at `30d`, which 37So, I went ahead and set the expiration date at `30d`, which is short enough to
40is short enough to refresh for readers but long enough that 38refresh for readers but long enough that clients/browsers won't be
41clients/browsers won\'t be re-requesting the static files too often, 39re-requesting the static files too often, hopefully resulting in faster loading
42hopefully resulting in faster loading times, as images should be the 40times, as images should be the only thing slowing down my site.
43only thing slowing down my site.
44 41
45# Testing Results 42# Testing Results
46 43
47To test my changes to the Nginx configuration, I used the [HTTP Header 44To test my changes to the Nginx configuration, I used the [HTTP Header
48Live](https://addons.mozilla.org/en-US/firefox/addon/http-header-live/) 45Live](https://addons.mozilla.org/en-US/firefox/addon/http-header-live/)
49extension on my Gecko browser and used the sidebar to inspect the 46extension on my Gecko browser and used the sidebar to inspect the headers of a
50headers of a recent image from my blog. 47recent image from my blog.
51 48
52In the image below, you can see that the `Cache-Control` 49In the image below, you can see that the `Cache-Control` header is now present
53header is now present and set to 2592000, which is 30 days represented 50and set to 2592000, which is 30 days represented in seconds (30 days \_ 24
54in seconds (30 days \_ 24 hours/day \_ 60 minutes/hour \*\* 60 51hours/day \_ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds).
55seconds/minute = 2,592,000 seconds).
56 52
57The `Expires` field is now showing 22 March 2022, which is 30 53The `Expires` field is now showing 22 March 2022, which is 30 days from the day
58days from the day of this post, 20 February 2022. 54of this post, 20 February 2022.
59 55
60![Image 56![Image
61Headers](https://img.cleberg.net/blog/20220220-caching-static-content-with-nginx/image_headers.png) 57Headers](https://img.cleberg.net/blog/20220220-caching-static-content-with-nginx/image_headers.png)
62 58
63# Caveats 59# Caveats
64 60
65Remember that this caching system is **client-side**, which means that 61Remember that this caching system is **client-side**, which means that content
66content is only cached for as long as a client allows it. For example, 62is only cached for as long as a client allows it. For example, my browser purges
67my browser purges all caches, data, etc. upon exit, so this caching 63all caches, data, etc. upon exit, so this caching policy will only work as long
68policy will only work as long as my browser remains open and running. 64as my browser remains open and running.
69 65
70If you need to test updates to your site, you\'ll need to clear the 66If you need to test updates to your site, you'll need to clear the cache to see
71cache to see updates for any file extension you configured. This can 67updates for any file extension you configured. This can often be done with the
72often be done with the `Shift + F5` or `Ctrl + F5` 68`Shift + F5` or `Ctrl + F5` key combinations in most browsers.
73key combinations in most browsers.
content/blog/2022-02-22-tuesday.md +23 −30
@@ -7,36 +7,29 @@ draft = false
7 7
8# Tuesday, Twosday 8# Tuesday, Twosday
9 9
10I\'m taking a break from my usual technology-related posts and writing 10I'm taking a break from my usual technology-related posts and writing about
11about something a little more enjoyable today. 11something a little more enjoyable today.
12 12
13Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is 13Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is Twosday.
14Twosday.
15 14
16Let\'s look at everything that fell in place today: 15Let's look at everything that fell in place today:
17 16
181. Written in the `m-dd-yy` or `dd-m-yy` formats, 171. Written in the `m-dd-yy` or `dd-m-yy` formats, today is 2-22-22 or 22-2-22,
19 today is 2-22-22 or 22-2-22, which is a neat little palindrome in 18 which is a neat little palindrome in either format. (The last ubiquitous
20 either format. (The last ubiquitous six-digit palindrome was 19 six-digit palindrome was 1-11-11.)
21 1-11-11.) 202. Today is Tuesday, which is why everyone is using the nickname Twosday to call
222. Today is Tuesday, which is why everyone is using the nickname 21 out these similarities.
23 Twosday to call out these similarities. 223. Falling on Tuesday means today is the 2nd day of the week (for most cultures.
243. Falling on Tuesday means today is the 2nd day of the week (for most 23 For the US, it's the 3rd day of the week since we start on Sunday).
25 cultures. For the US, it\'s the 3rd day of the week since we start 244. The only culture I could find with a connection to a `2` is that some Slavic
26 on Sunday). 25 languages derived their version of Tuesday from the Old Church Slavonic word
274. The only culture I could find with a connection to a `2` 26 `въторъ`, meaning "the second."
28 is that some Slavic languages derived their version of Tuesday from 275. Written in the classic monospaced, digital font (think of digital clocks from
29 the Old Church Slavonic word `въторъ`, meaning \"the 28 the 80s/90s), there is nice symmetry to the numbers ([view the image
30 second.\" 29 here](https://img.cleberg.net/blog/20220222-tuesday/digital_font.png)!).
315. Written in the classic monospaced, digital font (think of digital 306. This one isn't naturally-occurring, but it seems people around the world are
32 clocks from the 80s/90s), there is nice symmetry to the numbers 31 celebrating the day. For example, a group is putting together [a wedding of
33 ([view the image 32 222 couples at the California State Capitol in
34 here](https://img.cleberg.net/blog/20220222-tuesday/digital_font.png)!). 33 Sacramento](https://www.eventbrite.com/e/2-22-22-a-collective-wedding-ceremony-at-the-state-capitol-tickets-211434605597),
356. This one isn\'t naturally-occurring, but it seems people around the 34 concluding at exactly 2:22 PM. These couples will record their marriage dates
36 world are celebrating the day. For example, a group is putting 35 as 2-22-22 2:22 PM. Tickets were on sale for $222.22.
37 together
38 \[\[<https://www.eventbrite.com/e/2-22-22-a-collective-wedding-ceremony-at-the-state-capitol-tickets-211434605597>\]\[a
39 wedding of 222 couples at the California State Capitol in
40 Sacramento\]\], concluding at exactly 2:22 PM. These couples will
41 record their marriage dates as 2-22-22 2:22 PM. Tickets were on sale
42 for \$222.22.
content/blog/2022-03-02-reliable-notes.md +72 −83
@@ -7,132 +7,121 @@ draft = false
7 7
8# Choosing Durable File Formats 8# Choosing Durable File Formats
9 9
10> TL;DR: Write in a format that can be easily rendered and read in 10> TL;DR: Write in a format that can be easily rendered and read in plain-text
11> plain-text mode (e.g., `.txt`, `.md`, etc.). 11> mode (e.g., `.txt`, `.md`, etc.).
12 12
13As I\'ve written more and more over the years, I\'ve found that my love 13As I've written more and more over the years, I've found that my love of
14of note-taking is always growing. Everything I learn or need to remember 14note-taking is always growing. Everything I learn or need to remember can be
15can be written down in a note and saved digitally, with no cost to 15written down in a note and saved digitally, with no cost to myself. Unlike paper
16myself. Unlike paper copies that need physical storage space, digital 16copies that need physical storage space, digital files simply need space on your
17files simply need space on your local disk or cloud storage, which is 17local disk or cloud storage, which is fairly abundant these days.
18fairly abundant these days.
19 18
20However, I had a historical struggle with migration of notes between 19However, I had a historical struggle with migration of notes between different
21different apps that require different formats and applied proprietary 20apps that require different formats and applied proprietary styling. This meant
22styling. This meant that I had to go through each note during migration 21that I had to go through each note during migration and edit the file to look
23and edit the file to look presentable again. 22presentable again.
24 23
25For the last year or two, I have written everything exclusively in 24For the last year or two, I have written everything exclusively in
26[Markdown](https://en.wikipedia.org/wiki/Markdown) format. Small notes, 25[Markdown](https://en.wikipedia.org/wiki/Markdown) format. Small notes,
27long-form writings, and even these blog posts are all written in 26long-form writings, and even these blog posts are all written in Markdown.
28Markdown. 27
29 28Why Markdown? While I do appreciate the simplicity of plain-text files without
30Why Markdown? While I do appreciate the simplicity of plain-text files 29any formatting, I often need visual cues such as heading and code blocks to keep
31without any formatting, I often need visual cues such as heading and 30my thoughts straight. Markdown provides a minimal set of styling indicators for
32code blocks to keep my thoughts straight. Markdown provides a minimal 31me to style my notes without adding any proprietary, embedded data into the
33set of styling indicators for me to style my notes without adding any 32files. If I want a top-level heading, I simply add a hash (`#`) before the line.
34proprietary, embedded data into the files. If I want a top-level 33An added bonus is that even if a system doesn't understand Markdown, it will
35heading, I simply add a hash (`#`) before the line. An added
36bonus is that even if a system doesn\'t understand Markdown, it will
37render it as plain-text and I can read it just as easily. 34render it as plain-text and I can read it just as easily.
38 35
39For example, here\'s how TextEdit on macOS will open and display a 36For example, here's how TextEdit on macOS will open and display a Markdown file
40Markdown file in plain-text, since it does contain any features to 37in plain-text, since it does contain any features to preview Markdown as HTML:
41preview Markdown as HTML:
42 38
43![Plain Text 39![Plain Text
44Markdown](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.png) 40Markdown](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.png)
45 41
46## Saving & Syncing Files 42## Saving & Syncing Files
47 43
48In order to read and edit my notes across platforms, I use my personal 44In order to read and edit my notes across platforms, I use my personal cloud
49cloud storage through Tresorit due to its native integration with macOS 45storage through Tresorit due to its native integration with macOS and iOS file
50and iOS file managers. In addition, Tresorit works well on Debian-based 46managers. In addition, Tresorit works well on Debian-based Linux distros, which
51Linux distros, which I used before macOS (and will likely switch back to 47I used before macOS (and will likely switch back to in a few years).
52in a few years).
53 48
54You can use whatever sync software you want - syncing plain-text or 49You can use whatever sync software you want - syncing plain-text or markdown
55markdown files is incredibly easy and fast, since the files are 50files is incredibly easy and fast, since the files are generally tiny.
56generally tiny.
57 51
58Since the cloud storage syncs files automatically, there is no need for 52Since the cloud storage syncs files automatically, there is no need for me to
59me to sync anything manually or kick-off a sync job to update my files. 53sync anything manually or kick-off a sync job to update my files. This means
60This means that I can edit on mobile, and it takes about 5-10 seconds to 54that I can edit on mobile, and it takes about 5-10 seconds to see the changes on
61see the changes on desktop. 55desktop.
62 56
63### Version Control with Git 57### Version Control with Git
64 58
65A different approach I\'ve contemplated is storing my notes and 59A different approach I've contemplated is storing my notes and attachments is
66attachments is using a hosted Git repository to track changes to the 60using a hosted Git repository to track changes to the files. However, I don't
67files. However, I don\'t want to rely on an external service that could 61want to rely on an external service that could potentially see into my data,
68potentially see into my data, even if the repository is private. 62even if the repository is private.
69 63
70I might just do `git init` locally and then commit my changes 64I might just do `git init` locally and then commit my changes each time I write
71each time I write or update a note, but that seems to be a lot of work 65or update a note, but that seems to be a lot of work just for tracking changes -
72just for tracking changes - which I don\'t necessarily care to know. 66which I don't necessarily care to know.
73 67
74### Backups! 68### Backups!
75 69
76One small addition to the storage/sync conversation is the idea of 70One small addition to the storage/sync conversation is the idea of backups.
77backups. Personally, I manually create periodic backups of my entire 71Personally, I manually create periodic backups of my entire cloud storage,
78cloud storage, compress it into an archive, and store it on my home 72compress it into an archive, and store it on my home server.
79server.
80 73
81To improve my workflow, I am going to be exploring options to 74To improve my workflow, I am going to be exploring options to automatically
82automatically compress the mounted cloud directory and send it over to 75compress the mounted cloud directory and send it over to my server on a set
83my server on a set schedule. 76schedule.
84 77
85## Writing on Desktop 78## Writing on Desktop
86 79
87> **Update (06.14.22)**: Since writing this post, I have reverted to 80> **Update (06.14.22)**: Since writing this post, I have reverted to simply
88> simply keeping my `notes` folder open and opening notes 81> keeping my `notes` folder open and opening notes individually in TextEdit for
89> individually in TextEdit for a more minimal and relaxing writing 82> a more minimal and relaxing writing experience on the desktop.
90> experience on the desktop.
91 83
92The bulk of my writing occurs in a desktop environment, with a full 84The bulk of my writing occurs in a desktop environment, with a full keyboard
93keyboard layout and wide screen. I don\'t illustrate with a smart pen, I 85layout and wide screen. I don't illustrate with a smart pen, I rarely use
94rarely use embedded images, and I love being able to see all of my 86embedded images, and I love being able to see all of my notes/directories in a
95notes/directories in a sidebar. 87sidebar.
96 88
97With this simple set of requirements, I chose 89With this simple set of requirements, I chose [Obsidian](https://obsidian.md) as
98[Obsidian](https://obsidian.md) as my desktop text editor. Obsidian has 90my desktop text editor. Obsidian has some in-depth tools like a graph view,
99some in-depth tools like a graph view, command palette, mentions, etc., 91command palette, mentions, etc., but I've found that using it as a simple
100but I\'ve found that using it as a simple Markdown editor is incredibly 92Markdown editor is incredibly easy and straightforward.
101easy and straightforward.
102 93
103Here\'s an example of how my Markdown notes look when opened in 94Here's an example of how my Markdown notes look when opened in plain-text mode:
104plain-text mode:
105 95
106![Obsidian Markdown Source 96![Obsidian Markdown Source
107Mode](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.png) 97Mode](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.png)
108 98
109Here\'s the \"live preview\" version, where the Markdown is rendered 99Here's the "live preview" version, where the Markdown is rendered into its
110into its HTML format: 100HTML format:
111 101
112![Obsidian Markdown Live 102![Obsidian Markdown Live
113Preview](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.png) 103Preview](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.png)
114 104
115### Programming on Desktop 105### Programming on Desktop
116 106
117While I was writing this, I realized I should specify that I don\'t use 107While I was writing this, I realized I should specify that I don't use the same
118the same editor for writing notes and for writing code. For programming 108editor for writing notes and for writing code. For programming purposes, I use
119purposes, I use [VSCodium](https://vscodium.com) as my development IDE. 109[VSCodium](https://vscodium.com) as my development IDE.
120 110
121## Writing on Mobile 111## Writing on Mobile
122 112
123Personally, I write very little on mobile, except when needing to take 113Personally, I write very little on mobile, except when needing to take important
124important notes on-the-go. Any long-form writing, journals, etc. are 114notes on-the-go. Any long-form writing, journals, etc. are done at home, where I
125done at home, where I always have my laptop available. 115always have my laptop available.
126 116
127I wanted a simple and foolproof editor for iOS, preferably open-source. 117I wanted a simple and foolproof editor for iOS, preferably open-source. After a
128After a long journey of testing the few (& terrible) open-source iOS 118long journey of testing the few (& terrible) open-source iOS note-taking apps, I
129note-taking apps, I finally found a phenomenal one: 119finally found a phenomenal one:
130[Runestone](https://github.com/simonbs/runestone). This app is fantastic 120[Runestone](https://github.com/simonbs/runestone). This app is fantastic for
131for note-taking, has plenty of optional features, and integrates 121note-taking, has plenty of optional features, and integrates natively with the
132natively with the iOS file manager. 122iOS file manager.
133 123
134This app opens the iOS file manager and allows you to click any file you 124This app opens the iOS file manager and allows you to click any file you want,
135want, opens it up in an editor, and lets me save and close out of that 125opens it up in an editor, and lets me save and close out of that note.
136note.
137 126
138Quite simple but effective. 127Quite simple but effective.
content/blog/2022-03-03-financial-database.md +157 −173
@@ -7,54 +7,50 @@ draft = false
7 7
8# Personal Financial Tracking 8# Personal Financial Tracking
9 9
10For the last 6-ish years, I\'ve tracked my finances in a spreadsheet. 10For the last 6-ish years, I've tracked my finances in a spreadsheet. This is
11This is common practice in the business world, but any good dev will 11common practice in the business world, but any good dev will cringe at the
12cringe at the thought of storing long-term data in a spreadsheet. A 12thought of storing long-term data in a spreadsheet. A spreadsheet is not for
13spreadsheet is not for long-term storage or as a source of data to pull 13long-term storage or as a source of data to pull data/reports.
14data/reports. 14
15 15As I wanted to expand the functionality of my financial data (e.g., adding more
16As I wanted to expand the functionality of my financial data (e.g., 16reports), I decided to migrate the data into a database. To run reports, I would
17adding more reports), I decided to migrate the data into a database. To 17query the database and use a language like Python or Javascript to process the
18run reports, I would query the database and use a language like Python 18data, perform calculations, and visualize the data.
19or Javascript to process the data, perform calculations, and visualize
20the data.
21 19
22# SQLite 20# SQLite
23 21
24When choosing the type of database I wanted to use for this project, I 22When choosing the type of database I wanted to use for this project, I was split
25was split between three options: 23between three options:
26 24
271. MySQL: The database I have the most experience with and have used 251. MySQL: The database I have the most experience with and have used for years.
28 for years. 262. PostgreSQL: A database I'm new to, but want to learn.
292. PostgreSQL: A database I\'m new to, but want to learn. 273. SQLite: A database that I've used for a couple projects and have moderate
303. SQLite: A database that I\'ve used for a couple projects and have 28 experience.
31 moderate experience.
32 29
33I ended up choosing SQLite since it can be maintained within a single 30I ended up choosing SQLite since it can be maintained within a single `.sqlite`
34`.sqlite` file, which allows me more flexibility for storage 31file, which allows me more flexibility for storage and backup. I keep this file
35and backup. I keep this file in my cloud storage and pull it up whenever 32in my cloud storage and pull it up whenever needed.
36needed.
37 33
38## GUI Editing 34## GUI Editing
39 35
40Since I didn\'t want to try and import 1000--1500 records into my new 36Since I didn't want to try and import 1000--1500 records into my new database
41database via the command line, I opted to use [DB Browser for SQLite 37via the command line, I opted to use [DB Browser for SQLite
42(DB4S)](https://sqlitebrowser.org/) as a GUI tool. This application is 38(DB4S)](https://sqlitebrowser.org/) as a GUI tool. This application is
43excellent, and I don\'t see myself going back to the CLI when working in 39excellent, and I don't see myself going back to the CLI when working in this
44this database. 40database.
45 41
46DB4S allows you to copy a range of cells from a spreadsheet and paste it 42DB4S allows you to copy a range of cells from a spreadsheet and paste it
47straight into the SQL table. I used this process for all 36 accounts, 43straight into the SQL table. I used this process for all 36 accounts, 1290
481290 account statements, and 126 pay statements. Overall, I\'m guessing 44account statements, and 126 pay statements. Overall, I'm guessing this took
49this took anywhere between 4--8 hours. In comparison, it probably took 45anywhere between 4--8 hours. In comparison, it probably took me 2-3 days to
50me 2-3 days to initially create the spreadsheet. 46initially create the spreadsheet.
51 47
52![DB4S](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/db4s.png) 48![DB4S](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/db4s.png)
53 49
54## Schema 50## Schema
55 51
56The schema for this database is actually extremely simple and involves 52The schema for this database is actually extremely simple and involves only
57only three tables (for now): 53three tables (for now):
58 54
591. Accounts 551. Accounts
602. Statements 562. Statements
@@ -62,9 +58,9 @@ only three tables (for now):
62 58
63**Accounts** 59**Accounts**
64 60
65The Accounts table contains summary information about an account, such 61The Accounts table contains summary information about an account, such as a car
66as a car loan or a credit card. By viewing this table, you can find 62loan or a credit card. By viewing this table, you can find high-level data, such
67high-level data, such as interest rate, credit line, or owner. 63as interest rate, credit line, or owner.
68 64
69``` sql 65``` sql
70CREATE TABLE "Accounts" ( 66CREATE TABLE "Accounts" (
@@ -82,10 +78,10 @@ CREATE TABLE "Accounts" (
82 78
83**Statements** 79**Statements**
84 80
85The Statements table uses the same unique identifier as the Accounts 81The Statements table uses the same unique identifier as the Accounts table,
86table, meaning you can join the tables to find a monthly statement for 82meaning you can join the tables to find a monthly statement for any of the
87any of the accounts listed in the Accounts table. Each statement has an 83accounts listed in the Accounts table. Each statement has an account ID,
88account ID, statement date, and total balance. 84statement date, and total balance.
89 85
90``` sql 86``` sql
91CREATE TABLE "Statements" ( 87CREATE TABLE "Statements" (
@@ -100,10 +96,10 @@ CREATE TABLE "Statements" (
100 96
101**Payroll** 97**Payroll**
102 98
103The Payroll table is a separate entity, unrelated to the Accounts or 99The Payroll table is a separate entity, unrelated to the Accounts or Statements
104Statements tables. This table contains all information you would find on 100tables. This table contains all information you would find on a pay statement
105a pay statement from an employer. As you change employers or obtain new 101from an employer. As you change employers or obtain new perks/benefits, just add
106perks/benefits, just add new columns to adapt to the new data. 102new columns to adapt to the new data.
107 103
108``` sql 104``` sql
109CREATE TABLE "Payroll" ( 105CREATE TABLE "Payroll" (
@@ -139,134 +135,122 @@ CREATE TABLE "Payroll" (
139 135
140## Python Reporting 136## Python Reporting
141 137
142Once I created the database tables and imported all my data, the only 138Once I created the database tables and imported all my data, the only step left
143step left was to create a process to report and visualize on various 139was to create a process to report and visualize on various aspects of the data.
144aspects of the data. 140
145 141In order to explore and create the reports I'm interested in, I utilized a
146In order to explore and create the reports I\'m interested in, I 142two-part process involving Jupyter Notebooks and Python scripts.
147utilized a two-part process involving Jupyter Notebooks and Python 143
148scripts. 144### Step 1: Jupyter Notebooks
149 145
1501. Step 1: Jupyter Notebooks 146When I need to explore data, try different things, and re-run my code
151 147cell-by-cell, I use Jupyter Notebooks. For example, I explored the
152 When I need to explore data, try different things, and re-run my 148`Accounts` table until I found the following useful information:
153 code cell-by-cell, I use Jupyter Notebooks. For example, I explored 149
154 the `Accounts` table until I found the following useful 150``` python
155 information: 151import sqlite3
156 152import pandas as pd
157 ``` python 153import matplotlib
158 import sqlite3 154
159 import pandas as pd 155# Set up database filename and connect
160 import matplotlib 156db = "finances.sqlite"
161 157connection = sqlite3.connect(db)
162 # Set up database filename and connect 158df = pd.read_sql_query("SELECT ** FROM Accounts", connection)
163 db = "finances.sqlite" 159
164 connection = sqlite3.connect(db) 160# Set global matplotlib variables
165 df = pd.read_sql_query("SELECT ** FROM Accounts", connection) 161%matplotlib inline
166 162matplotlib.rcParams['text.color'] = 'white'
167 # Set global matplotlib variables 163matplotlib.rcParams['axes.labelcolor'] = 'white'
168 %matplotlib inline 164matplotlib.rcParams['xtick.color'] = 'white'
169 matplotlib.rcParams['text.color'] = 'white' 165matplotlib.rcParams['ytick.color'] = 'white'
170 matplotlib.rcParams['axes.labelcolor'] = 'white' 166matplotlib.rcParams['legend.labelcolor'] = 'black'
171 matplotlib.rcParams['xtick.color'] = 'white' 167
172 matplotlib.rcParams['ytick.color'] = 'white' 168# Display graph
173 matplotlib.rcParams['legend.labelcolor'] = 'black' 169df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%')
174 170```
175 # Display graph 171
176 df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%') 172### Step 2: Python Scripts
177 ``` 173
178 174Once I explored enough through the notebooks and had a list of reports I
1792. Step 2: Python Scripts 175wanted, I moved on to create a Python project with the following structure:
180 176
181 Once I explored enough through the notebooks and had a list of 177``` txt
182 reports I wanted, I moved on to create a Python project with the 178finance/
183 following structure: 179├── notebooks/
184 180│ │ ├── account_summary.ipynb
185 ``` txt 181│ │ ├── account_details.ipynb
186 finance/ 182│ │ └── payroll.ipynb
187 ├── notebooks/ 183├── public/
188 │ │ ├── account_summary.ipynb 184│ │ ├── image-01.png
189 │ │ ├── account_details.ipynb 185│ │ └── image-0X.png
190 │ │ └── payroll.ipynb 186├── src/
191 ├── public/ 187│ └── finance.sqlite
192 │ │ ├── image-01.png 188├── venv/
193 │ │ └── image-0X.png 189├── _init.py
194 ├── src/ 190├── database.py
195 │ └── finance.sqlite 191├── process.py
196 ├── venv/ 192├── requirements.txt
197 ├── _init.py 193└── README.md
198 ├── database.py 194```
199 ├── process.py 195
200 ├── requirements.txt 196This structure allows me to:
201 └── README.md 197
202 ``` 1981. Compile all required python packages into `requirements.txt` for easy
203 199 installation if I move to a new machine.
204 This structure allows me to: 2002. Activate a virtual environment in `venv/` so I don't need to maintain a
205 201 system-wide Python environment just for this project.
206 1. Compile all required python packages into 2023. Keep my `notebooks/` folder to continuously explore the data as I see
207 `requirements.txt` for easy installation if I move to 203 fit.
208 a new machine. 2044. Maintain a local copy of the database in `src/` for easy access.
209 2. Activate a virtual environment in `venv/` so I don\'t 2055. Export reports, images, HTML files, etc. to `public/`.
210 need to maintain a system-wide Python environment just for this 206
211 project. 207Now, onto the differences between the code in a Jupyter Notebook and the
212 3. Keep my `notebooks/` folder to continuously explore 208actual Python files. To create the report in the Notebook snippet above, I
213 the data as I see fit. 209created the following function inside `process.py`:
214 4. Maintain a local copy of the database in `src/` for 210
215 easy access. 211``` python
216 5. Export reports, images, HTML files, etc. to 212# Create summary pie chart
217 `public/`. 213def summary_data(accounts: pandas.DataFrame) -> None:
218 214 accounts_01 = accounts[accounts["Owner"] == "Person01"]
219 Now, onto the differences between the code in a Jupyter Notebook and 215 accounts_02 = accounts[accounts["Owner"] == "Person02"]
220 the actual Python files. To create the report in the Notebook 216 for x in range(1, 4):
221 snippet above, I created the following function inside 217 if x == 1:
222 `process.py`: 218 df = accounts
223 219 account_string = "All Accounts"
224 ``` python 220 elif x == 2:
225 # Create summary pie chart 221 df = accounts_01
226 def summary_data(accounts: pandas.DataFrame) -> None: 222 account_string = "Person01's Accounts"
227 accounts_01 = accounts[accounts["Owner"] == "Person01"] 223 elif x == 3:
228 accounts_02 = accounts[accounts["Owner"] == "Person02"] 224 df = accounts_02
229 for x in range(1, 4): 225 account_string = "Person02's Accounts"
230 if x == 1: 226 print(f"Generating pie chart summary image for {account_string}...")
231 df = accounts 227 summary_chart = (
232 account_string = "All Accounts" 228 df.groupby(["AccountType"])
233 elif x == 2: 229 .sum()
234 df = accounts_01 230 .plot.pie(
235 account_string = "Person01's Accounts" 231 title=f"Credit Line by Type for {account_string}",
236 elif x == 3: 232 y="CreditLine",
237 df = accounts_02 233 autopct="%1.1f%%",
238 account_string = "Person02's Accounts"
239 print(f"Generating pie chart summary image for {account_string}...")
240 summary_chart = (
241 df.groupby(["AccountType"])
242 .sum()
243 .plot.pie(
244 title=f"Credit Line by Type for {account_string}",
245 y="CreditLine",
246 autopct="%1.1f%%",
247 )
248 ) 234 )
249 summary_chart.figure.savefig(f"public/summary_chart_{x}.png", dpi=1200) 235 )
250 ``` 236 summary_chart.figure.savefig(f"public/summary_chart_{x}.png", dpi=1200)
251 237```
252 The result? A high-quality pie chart that is read directly by the 238
253 `public/index.html` template I use. 239The result? A high-quality pie chart that is read directly by the
254 240`public/index.html` template I use.
255 ![Summary Pie 241
256 Chart](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/summary_chart.png) 242![Summary Pie
257 243Chart](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/summary_chart.png)
258 Other charts generated by this project include: 244
259 245Other charts generated by this project include:
260 - Charts of account balances over time. 246
261 - Line chart of effective tax rate (taxes divided by taxable 247- Charts of account balances over time.
262 income). 248- Line chart of effective tax rate (taxes divided by taxable income).
263 - Salary projections and error limits using past income and 249- Salary projections and error limits using past income and inflation
264 inflation rates. 250 rates.
265 - Multi-line chart of gross income, taxable income, and net 251- Multi-line chart of gross income, taxable income, and net income.
266 income. 252
267 253The best thing about this project? I can improve it at any given time,
268 The best thing about this project? I can improve it at any given 254shaping it into whatever helps me the most for that time. I imagine that I
269 time, shaping it into whatever helps me the most for that time. I 255will be introducing an asset tracking table soon to track the depreciating
270 imagine that I will be introducing an asset tracking table soon to 256value of cars, houses, etc. Who knows what's next?
271 track the depreciating value of cars, houses, etc. Who knows what\'s
272 next?
content/blog/2022-03-08-plex-migration.md +86 −102
@@ -7,15 +7,13 @@ draft = false
7 7
8# Migration Phases 8# Migration Phases
9 9
10I recently decided to migrate my server from an old OptiPlex desktop 10I recently decided to migrate my server from an old OptiPlex desktop machine to
11machine to a custom-built tower with better hardware in every category. 11a custom-built tower with better hardware in every category. In order to do
12In order to do this, I would need to properly migrate a full Plex 12this, I would need to properly migrate a full Plex installation.
13installation.
14 13
15The second part of this migration is that the new server uses an Nvidia 14The second part of this migration is that the new server uses an Nvidia GPU and
16GPU and does not have any integrated graphics, which requires extra work 15does not have any integrated graphics, which requires extra work for
17for installation, but provides much better hardware transcoding options 16installation, but provides much better hardware transcoding options for Plex.
18for Plex.
19 17
20Therefore, I have broken this migration down into three phases: 18Therefore, I have broken this migration down into three phases:
21 19
@@ -28,42 +26,38 @@ Therefore, I have broken this migration down into three phases:
28## Choosing an OS 26## Choosing an OS
29 27
30In order to migrate Plex to my new server, I first needed to choose an 28In order to migrate Plex to my new server, I first needed to choose an
31appropriate operating system (OS) and install it on the machine. Given 29appropriate operating system (OS) and install it on the machine. Given that I
32that I have encountered numerous issues installing other Linux 30have encountered numerous issues installing other Linux distributions properly
33distributions properly with Nvidia graphics, I chose [Ubuntu 31with Nvidia graphics, I chose [Ubuntu
34Server](https://ubuntu.com/download/server). 32Server](https://ubuntu.com/download/server).
35 33
36The first step is to create a bootable USB with Ubuntu Server. This is 34The first step is to create a bootable USB with Ubuntu Server. This is easy with
37easy with [Etcher](https://www.balena.io/etcher/), an app that runs on 35[Etcher](https://www.balena.io/etcher/), an app that runs on many different
38many different platforms. Just download the Ubuntu Server 36platforms. Just download the Ubuntu Server `.iso` image, launch Etcher, and
39`.iso` image, launch Etcher, and install the 37install the `.iso` on the USB.
40`.iso` on the USB.
41 38
42Once the USB is created, insert it into my server, reboot, and click 39Once the USB is created, insert it into my server, reboot, and click `Esc` (or
43`Esc` (or any of the `F1-12` keys) until the BIOS 40any of the `F1-12` keys) until the BIOS menu appears. Finally, launch the USB
44menu appears. Finally, launch the USB boot drive. 41boot drive.
45 42
46## Booting with Nvidia 43## Booting with Nvidia
47 44
48In order to install Ubuntu Server with an Nvidia Graphics card (and no 45In order to install Ubuntu Server with an Nvidia Graphics card (and no
49integrated graphics on this device for some reason), you\'ll have to 46integrated graphics on this device for some reason), you'll have to configure
50configure the boot menu to allow different graphics drivers to be 47the boot menu to allow different graphics drivers to be loaded.
51loaded.
52 48
53When booting from the USB, the machine will launch the initial 49When booting from the USB, the machine will launch the initial installation
54installation menu. From this menu, type `e` to view the 50menu. From this menu, type `e` to view the default command options that come
55default command options that come with the device - it\'s a good idea to 51with the device - it's a good idea to take a photo of this screen, so you can
56take a photo of this screen, so you can enter these commands on the next 52enter these commands on the next screen (along with adding support for Nvidia).
57screen (along with adding support for Nvidia).
58 53
59Finally, type `Ctrl + C` to enter the command line. From this 54Finally, type `Ctrl + C` to enter the command line. From this command line,
60command line, enter the commands found on the `e` screen. 55enter the commands found on the `e` screen. *Remember to add `nomodeset` to the
61\*Remember to add `nomodeset` to the `linux ...` 56`linux ...` line so that your Nvidia device will display the installation
62line so that your Nvidia device will display the installation screens 57screens properly!*
63properly!\*
64 58
65Here\'s an example of the commands I pulled from the `e` 59Here's an example of the commands I pulled from the `e` screen and entered on
66screen and entered on the command line. 60the command line.
67 61
68```sh 62```sh
69setparams 'Install Ubuntu Server' 63setparams 'Install Ubuntu Server'
@@ -79,12 +73,11 @@ boot
79![Ubuntu Server Installation 73![Ubuntu Server Installation
8002](https://img.cleberg.net/blog/20220308-plex-media-server-migration/ubuntu_server_installation_02.png) 7402](https://img.cleberg.net/blog/20220308-plex-media-server-migration/ubuntu_server_installation_02.png)
81 75
82Once the machine is rebooted, enter the `e` screen again and 76Once the machine is rebooted, enter the `e` screen again and add `nomodeset` to
83add `nomodeset` to the `linux ...` line again and 77the `linux ...` line again and press `Ctrl + X` to save the boot options.
84press `Ctrl + X` to save the boot options.
85 78
86The machine is now fully installed and can properly display on an 79The machine is now fully installed and can properly display on an external
87external display using the Nvidia GPU. 80display using the Nvidia GPU.
88 81
89Always remember to update and upgrade on a new installation: 82Always remember to update and upgrade on a new installation:
90 83
@@ -94,33 +87,30 @@ sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
94 87
95# Phase 2: Migrate Plex Data & Devices 88# Phase 2: Migrate Plex Data & Devices
96 89
97This phase uses the great Plex article on migrations ([Move an 90This phase uses the great Plex article on migrations ([Move an Installation to
98Installation to Another 91Another
99System](https://support.plex.tv/articles/201370363-move-an-install-to-another-system/)) 92System](https://support.plex.tv/articles/201370363-move-an-install-to-another-system/))
100and adds a bit more information to help with commands and context. 93and adds a bit more information to help with commands and context.
101 94
102## Terminology 95## Terminology
103 96
104**Source:\*** The original server that is being replaced.\ 97**Source:** The original server that is being replaced.\
105**Destination:\*** The new server.\ 98**Destination:** The new server.\
106**Client:\*** Any application that can be used to modify settings for 99**Client:** Any application that can be used to modify settings for both
107both source/destination. 100source/destination.
108 101
109## Step 01: \[Client\] Update Settings 102## Step 01: [Client] Update Settings
110 103
111Open up a Plex app and *disable* the `Account` \> 104Open up a Plex app and *disable* the `Account` > `Library` > `Empty trash
112`Library` \> 105automatically after every scan` preference for the source server.
113`Empty trash automatically after every scan` preference for
114the source server.
115 106
116## Step 02: \[Destination\] Install Plex 107## Step 02: [Destination] Install Plex
117 108
118Open up the [Plex Media Server download 109Open up the [Plex Media Server download
119page](https://www.plex.tv/media-server-downloads/) and copy the link for 110page](https://www.plex.tv/media-server-downloads/) and copy the link for the
120the appropriate platform. 111appropriate platform.
121 112
122Execute the following commands on the destination server to install 113Execute the following commands on the destination server to install Plex:
123Plex:
124 114
125```sh 115```sh
126wget <url> 116wget <url>
@@ -128,48 +118,45 @@ sudo dpkg -i <filename>
128sudo systemctl stop plexmediaserver.service 118sudo systemctl stop plexmediaserver.service
129``` 119```
130 120
131## Step 03: \[Source\] Stop Plex & Migrate Data 121## Step 03: [Source] Stop Plex & Migrate Data
132 122
133First, stop the Plex service so that no data is created or modified 123First, stop the Plex service so that no data is created or modified during the
134during the migration. 124migration.
135 125
136```sh 126```sh
137sudo systemctl stop plexmediaserver.service 127sudo systemctl stop plexmediaserver.service
138``` 128```
139 129
140Next, copy the data to the new server. To find where the Plex data 130Next, copy the data to the new server. To find where the Plex data directory is
141directory is located, Plex has another excellent article available: 131located, Plex has another excellent article available: [Where is the Plex Media
142[Where is the Plex Media Server data directory 132Server data directory
143located?](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/). 133located?](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/).
144 134
145There are many ways to copy the data to the new server and will largely 135There are many ways to copy the data to the new server and will largely depend
146depend on the size of the folder being copied. Personally, my data 136on the size of the folder being copied. Personally, my data folder was ~23GB
147folder was \~23GB and I opted to simply use the `scp` command 137and I opted to simply use the `scp` command to copy the files over SSH.
148to copy the files over SSH.
149 138
150This process was throttled by the old server\'s slow HDD and ports and 139This process was throttled by the old server's slow HDD and ports and took
151took approximately 90 minutes to complete. In comparison, moving the 140approximately 90 minutes to complete. In comparison, moving the data from the
152data from the new server\'s `home/user/` directory to the 141new server's `home/user/` directory to the `/var/.../Plex Media Server`
153`/var/.../Plex Media Server` directory took 2-3 minutes. 142directory took 2-3 minutes.
154 143
155```sh 144```sh
156scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'" 145scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'"
157``` 146```
158 147
159## Step 04: \[Destination\] Update File Permissions 148## Step 04: [Destination] Update File Permissions
160 149
161In case you move the data directory to a common area on the new server, 150In case you move the data directory to a common area on the new server, it will
162it will have to be moved to the proper location before Plex can function 151have to be moved to the proper location before Plex can function properly:
163properly:
164 152
165```sh 153```sh
166mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/ 154mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/
167``` 155```
168 156
169To ensure permissions were retained properly, the server will need to 157To ensure permissions were retained properly, the server will need to show that
170show that all files and folders in the data directory are owned by 158all files and folders in the data directory are owned by `plex:plex` (or
171`plex:plex` (or whichever user is running the Plex 159whichever user is running the Plex application).
172application).
173 160
174```sh 161```sh
175sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" 162sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"
@@ -182,43 +169,40 @@ sudo systemctl start plexmediaserver.service
182sudo systemctl status plexmediaserver.service 169sudo systemctl status plexmediaserver.service
183``` 170```
184 171
185## Step 05: \[Client\] Update Libraries & Metadata 172## Step 05: [Client] Update Libraries & Metadata
186 173
187The first step - now that the new server is up and running - is to sign 174The first step - now that the new server is up and running - is to sign out of
188out of the client and sign back in. Once this is done, update any 175the client and sign back in. Once this is done, update any library locations, if
189library locations, if necessary. This was unnecessary in my case since I 176necessary. This was unnecessary in my case since I simply moved my storage
190simply moved my storage drives from the source server to the destination 177drives from the source server to the destination server.
191server.
192 178
193Next, perform the following actions in the client: 179Next, perform the following actions in the client:
194 180
1951. On the left sidebar, click `More` \> Three-Dot Menu \> 1811. On the left sidebar, click `More` > Three-Dot Menu > `Scan Library Files`
196 `Scan Library Files` 1822. *Enable* the `Account` > `Library` > `Empty trash automatically after every
1972. *Enable* the `Account` \> `Library` \> 183 scan` preference for the source server.
198 `Empty trash automatically after every scan` preference 1843. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
199 for the source server. 185 `Empty Trash`
2003. On the left sidebar, click `More` \> Three-Dot Menu \> 1864. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
201 `Manage Server` \> `Empty Trash` 187 `Clean Bundles`
2024. On the left sidebar, click `More` \> Three-Dot Menu \> 1885. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
203 `Manage Server` \> `Clean Bundles` 189 `Optimize Database`
2045. On the left sidebar, click `More` \> Three-Dot Menu \>
205 `Manage Server` \> `Optimize Database`
206 190
207Finally, double-check the Remote Access settings to make sure no changes 191Finally, double-check the Remote Access settings to make sure no changes have
208have caused issues with accessing the server from outside the network. 192caused issues with accessing the server from outside the network.
209 193
210In my case, I use a single port forwarding rule in my router and needed 194In my case, I use a single port forwarding rule in my router and needed to
211to update the Local LAN IP Address to the new server IP address. 195update the Local LAN IP Address to the new server IP address.
212 196
213![Router port 197![Router port
214forwarding](https://img.cleberg.net/blog/20220308-plex-media-server-migration/port_forwarding.png) 198forwarding](https://img.cleberg.net/blog/20220308-plex-media-server-migration/port_forwarding.png)
215 199
216# Phase 3: Configure GPU Transcoding 200# Phase 3: Configure GPU Transcoding
217 201
218The final piece to the migration is enabling hardware transcoding so 202The final piece to the migration is enabling hardware transcoding so that Plex
219that Plex can fully utilize the new Nvidia GPU available in the server. 203can fully utilize the new Nvidia GPU available in the server. The first step is
220The first step is to install Nvidia graphics drivers. This process may 204to install Nvidia graphics drivers. This process may take a few minutes, but the
221take a few minutes, but the commands are pretty simple: 205commands are pretty simple:
222 206
223```sh 207```sh
224sudo add-apt-repository ppa:graphics-drivers/ppa 208sudo add-apt-repository ppa:graphics-drivers/ppa
content/blog/2022-03-23-cloudflare-dns-api.md +18 −23
@@ -7,15 +7,14 @@ draft = false
7 7
8# DDNS: Dynamic DNS 8# DDNS: Dynamic DNS
9 9
10If you\'re hosting a service from a location with dynamic DNS (where 10If you're hosting a service from a location with dynamic DNS (where your IP may
11your IP may change at any time), you must have a solution to update the 11change at any time), you must have a solution to update the DNS so that you can
12DNS so that you can access your service even when the IP of the server 12access your service even when the IP of the server changes.
13changes.
14 13
15The process below uses the [Cloudflare API](https://api.cloudflare.com/) 14The process below uses the [Cloudflare API](https://api.cloudflare.com/) to
16to update DNS `A` and `AAAA` records with the 15update DNS `A` and `AAAA` records with the server's current IP. If you use
17server\'s current IP. If you use another DNS provider, you will have to 16another DNS provider, you will have to find a way to update your DNS (or find a
18find a way to update your DNS (or find a way to get a static IP). 17way to get a static IP).
19 18
20First, install `jq` since we will use it in the next script: 19First, install `jq` since we will use it in the next script:
21 20
@@ -23,18 +22,16 @@ First, install `jq` since we will use it in the next script:
23sudo apt install jq 22sudo apt install jq
24``` 23```
25 24
26Next, create a location for your DDNS update scripts and open the first 25Next, create a location for your DDNS update scripts and open the first script:
27script:
28 26
29```sh 27```sh
30mkdir ~/ddns 28mkdir ~/ddns
31nano ~/ddns/update.sh 29nano ~/ddns/update.sh
32``` 30```
33 31
34The following `update.sh` script will take all of your 32The following `update.sh` script will take all of your domains and subdomains
35domains and subdomains and check Cloudflare to see if the current 33and check Cloudflare to see if the current `A` and `AAAA` records match your
36`A` and `AAAA` records match your server\'s IP 34server's IP address. If not, it will update the records.
37address. If not, it will update the records.
38 35
39```sh 36```sh
40# file: update.sh 37# file: update.sh
@@ -60,17 +57,16 @@ do
60done 57done
61``` 58```
62 59
63Next, open up the `ddns.sh` script. Paste the following into 60Next, open up the `ddns.sh` script. Paste the following into the script and
64the script and update the `api_token` and `email` 61update the `api_token` and `email` variables.
65variables.
66 62
67```sh 63```sh
68nano ~/ddns/ddns.sh 64nano ~/ddns/ddns.sh
69``` 65```
70 66
71**Note**: If you want your DNS records to be proxied through Cloudflare, 67**Note**: If you want your DNS records to be proxied through Cloudflare, find
72find and update the following snippet: `"proxied":false}"` to 68and update the following snippet: `"proxied":false}"` to say `true` instead of
73say `true` instead of `false`. 69`false`.
74 70
75```sh 71```sh
76# file: ddns.sh 72# file: ddns.sh
@@ -180,9 +176,8 @@ You can test the script by running it manually:
180./update.sh 176./update.sh
181``` 177```
182 178
183To make sure the scripts run automatically, add it to the 179To make sure the scripts run automatically, add it to the `cron` file so that it
184`cron` file so that it will run on a schedule. To do this, 180will run on a schedule. To do this, open the cron file:
185open the cron file:
186 181
187```sh 182```sh
188crontab -e 183crontab -e
content/blog/2022-03-23-nextcloud-on-ubuntu.md +27 −35
@@ -7,8 +7,8 @@ draft = false
7 7
8# What is Nextcloud? 8# What is Nextcloud?
9 9
10[Nextcloud](https://nextcloud.com/) is a self-hosted solution for 10[Nextcloud](https://nextcloud.com/) is a self-hosted solution for storage,
11storage, communications, editing, calendar, contacts, and more. 11communications, editing, calendar, contacts, and more.
12 12
13This tutorial assumes that you have an Ubuntu server and a domain name 13This tutorial assumes that you have an Ubuntu server and a domain name
14configured to point toward the server. 14configured to point toward the server.
@@ -25,16 +25,14 @@ sudo apt install php7.4-gmp php7.4-bcmath php-imagick php7.4-xml php7.4-zip
25 25
26# Set Up MySQL 26# Set Up MySQL
27 27
28Next, you will need to log in to MySQL as the `root` user of 28Next, you will need to log in to MySQL as the `root` user of the machine.
29the machine.
30 29
31```sh 30```sh
32sudo mysql -uroot -p 31sudo mysql -uroot -p
33``` 32```
34 33
35Once you\'ve logged in, you must create a new user so that Nextcloud can 34Once you've logged in, you must create a new user so that Nextcloud can manage
36manage the database. You will also create a `nextcloud` 35the database. You will also create a `nextcloud` database and assign privileges:
37database and assign privileges:
38 36
39``` sql 37``` sql
40CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; 38CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
@@ -47,14 +45,12 @@ quit;
47# Download & Install Nextcloud 45# Download & Install Nextcloud
48 46
49To download Nextcloud, go the [Nextcloud downloads 47To download Nextcloud, go the [Nextcloud downloads
50page](https://nextcloud.com/install/#instructions-server), click on 48page](https://nextcloud.com/install/#instructions-server), click on `Archive
51`Archive File` and right-click the big blue button to copy 49File` and right-click the big blue button to copy the link.
52the link.
53 50
54Then, go to your server and enter the following commands to download, 51Then, go to your server and enter the following commands to download, unzip, and
55unzip, and move the files to your destination directory. This example 52move the files to your destination directory. This example uses `example.com` as
56uses `example.com` as the destination, but you can put it 53the destination, but you can put it wherever you want to server your files from.
57wherever you want to server your files from.
58 54
59```sh 55```sh
60wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip 56wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip
@@ -65,9 +61,9 @@ sudo cp -r nextcloud /var/www/example.com
65 61
66# Configure the Apache Web Server 62# Configure the Apache Web Server
67 63
68Now that the database is set up and Nextcloud is installed, you need to 64Now that the database is set up and Nextcloud is installed, you need to set up
69set up the Apache configuration files to tell the server how to handle 65the Apache configuration files to tell the server how to handle requests for
70requests for `example.com/nextcloud`. 66`example.com/nextcloud`.
71 67
72First, open the following file in the editor: 68First, open the following file in the editor:
73 69
@@ -75,8 +71,8 @@ First, open the following file in the editor:
75sudo nano /etc/apache2/sites-available/nextcloud.conf 71sudo nano /etc/apache2/sites-available/nextcloud.conf
76``` 72```
77 73
78Once the editor is open, paste the following information in. Then, save 74Once the editor is open, paste the following information in. Then, save and
79and close the file. 75close the file.
80 76
81``` config 77``` config
82<VirtualHost *:80> 78<VirtualHost *:80>
@@ -111,16 +107,15 @@ Next, enable the Apache mods required by Nextcloud:
111sudo a2enmod rewrite headers env dir mime 107sudo a2enmod rewrite headers env dir mime
112``` 108```
113 109
114Finally, restart Apache. If any errors arise, you must solve those 110Finally, restart Apache. If any errors arise, you must solve those before
115before continuing. 111continuing.
116 112
117```sh 113```sh
118sudo systemctl restart apache2 114sudo systemctl restart apache2
119``` 115```
120 116
121For the app to work, you must have the correct file permissions on your 117For the app to work, you must have the correct file permissions on your
122`nextcloud` directory. Set the owner to be 118`nextcloud` directory. Set the owner to be `www-data`:
123`www-data`:
124 119
125```sh 120```sh
126sudo chown -R www-data:www-data /var/www/example.com/nextcloud/ 121sudo chown -R www-data:www-data /var/www/example.com/nextcloud/
@@ -129,17 +124,15 @@ sudo chown -R www-data:www-data /var/www/example.com/nextcloud/
129# DNS 124# DNS
130 125
131If you do not have a static IP address, you will need to update your DNS 126If you do not have a static IP address, you will need to update your DNS
132settings (at your DNS provider) whenever your dynamic IP address 127settings (at your DNS provider) whenever your dynamic IP address changes.
133changes.
134 128
135For an example on how I do that with Cloudflare, see my other post: 129For an example on how I do that with Cloudflare, see my other post: [Updating
136[Updating Dynamic DNS with Cloudflare 130Dynamic DNS with Cloudflare API](../updating-dynamic-dns-with-cloudflare-api/)
137API](../updating-dynamic-dns-with-cloudflare-api/)
138 131
139# Certbot 132# Certbot
140 133
141If you want to serve Nextcloud from HTTPS rather than plain HTTP, use 134If you want to serve Nextcloud from HTTPS rather than plain HTTP, use the
142the following commands to issue Let\'s Encrypt SSL certificates: 135following commands to issue Let's Encrypt SSL certificates:
143 136
144```sh 137```sh
145sudo apt install snapd 138sudo apt install snapd
@@ -152,12 +145,11 @@ sudo certbot --apache
152 145
153# Results 146# Results
154 147
155Voilà! You\'re all done and should be able to access Nextcloud from your 148Voilà! You're all done and should be able to access Nextcloud from your domain
156domain or IP address. 149or IP address.
157 150
158See the screenshots below for the dashboard and a settings page on my 151See the screenshots below for the dashboard and a settings page on my instance
159instance of Nextcloud, using the `Breeze Dark` theme I 152of Nextcloud, using the `Breeze Dark` theme I installed from the Apps page.
160installed from the Apps page.
161 153
162![Nextcloud 154![Nextcloud
163Dashboard](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_dashboard.png) 155Dashboard](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_dashboard.png)
content/blog/2022-03-24-server-hardening.md +209 −211
@@ -7,11 +7,10 @@ draft = false
7 7
8# Post Updates 8# Post Updates
9 9
10> After reviewing this post today (2022-10-04), I noticed quite a few 10> After reviewing this post today (2022-10-04), I noticed quite a few gaps in my
11> gaps in my write-up and wanted to add a few things, even though this 11> write-up and wanted to add a few things, even though this blog is really just
12> blog is really just a retrospective and knowledge dump for myself. I 12> a retrospective and knowledge dump for myself. I left things intact and simply
13> left things intact and simply crossed them out (~~like this~~) for 13> crossed them out (~~like this~~) for posterity.
14> posterity.
15 14
16# Planning Data Flows & Security 15# Planning Data Flows & Security
17 16
@@ -31,104 +30,97 @@ draft = false
31 30
32## Thought Process 31## Thought Process
33 32
34To serve content from your home server and harden your security posture, 33To serve content from your home server and harden your security posture, you
35you have to think about the transport of data from `server` 34have to think about the transport of data from `server` to `client`.
36to `client`. 35
37 36Let's start with the actual server itself. Think about the following:
38Let\'s start with the actual server itself. Think about the following: 37
39 38- Do I have a firewall enabled? Do I need to update this to allow new ports or
40- Do I have a firewall enabled? Do I need to update this to allow new 39 IPs?
41 ports or IPs? 40- Do I have an IPS/IDS that may prevent outside traffic?
42- Do I have an IPS/IDS that may prevent outside traffic? 41- Do I have any other security software installed?
43- Do I have any other security software installed? 42- Are the services hosted inside Docker containers, behind a reverse proxy, or
44- Are the services hosted inside Docker containers, behind a reverse 43 virtualized? If so, are they configured to allow outside traffic?
45 proxy, or virtualized? If so, are they configured to allow outside 44
46 traffic? 45Once the data leaves the server, where does it go? In my case, it goes to a
47 46managed switch. In this case, I asked the following:
48Once the data leaves the server, where does it go? In my case, it goes 47
49to a managed switch. In this case, I asked the following: 48- What configurations is the switch using?
50 49- Am I using VLANs?
51- What configurations is the switch using? 50 - Yes, I am using 802.1Q VLANs.
52- Am I using VLANs? 51- Are the VLANs configured properly?
53 - Yes, I am using 802.1Q VLANs. 52 - Yes, as shown in the Switch section below, I have a separate VLAN to allow
54- Are the VLANs configured properly? 53 outside traffic to and from the server alone. No other devices, except for
55 - Yes, as shown in the Switch section below, I have a separate 54 a service port, and in that VLAN.
56 VLAN to allow outside traffic to and from the server alone. No 55
57 other devices, except for a service port, and in that VLAN. 56At this point, the data has been processed through the switch. Where does it go
58 57next? In my case, it's pretty simple: it goes to the router/modem device.
59At this point, the data has been processed through the switch. Where 58
60does it go next? In my case, it\'s pretty simple: it goes to the 59- Does my ISP block any ports that I need?
61router/modem device. 60 - This is an important step that a lot of people run into when self-hosting
62 61 at home. Use an online port-checker tool for your IP or call your ISP if
63- Does my ISP block any ports that I need? 62 you think ports are blocked.
64 - This is an important step that a lot of people run into when 63- Is there a router firewall?
65 self-hosting at home. Use an online port-checker tool for your 64 - Yes, I checked that it's configured to allow the ports I need to run my
66 IP or call your ISP if you think ports are blocked. 65 services publicly. Common web servers and reverse proxies require ports 80
67- Is there a router firewall? 66 and 443, but other services like media servers or games can require unique
68 - Yes, I checked that it\'s configured to allow the ports I need 67 ports, so be sure to check the documentation for your service(s).
69 to run my services publicly. Common web servers and reverse 68- Are there any other settings affecting inbound/outbound traffic?
70 proxies require ports 80 and 443, but other services like media 69 - Schedules or access blocks
71 servers or games can require unique ports, so be sure to check 70 - Static Routing
72 the documentation for your service(s). 71 - QoS
73- Are there any other settings affecting inbound/outbound traffic? 72 - Port Forwarding
74 - Schedules or access blocks 73 - DMZ Hosting
75 - Static Routing 74 - Remote Management (this can sometimes mess with services that also require
76 - QoS 75 the use of ports 80 and 443)
77 - Port Forwarding 76
78 - DMZ Hosting 77Once the data leaves my router, it goes to the upstream ISP and can be accessed
79 - Remote Management (this can sometimes mess with services that 78publicly.
80 also require the use of ports 80 and 443)
81
82Once the data leaves my router, it goes to the upstream ISP and can be
83accessed publicly.
84 79
85### Server 80### Server
86 81
87+The services I run on my server are installed straight into the OS, 82+The services I run on my server are installed straight into the OS, without any
88without any use of Docker or VMs, so I don\'t need any extra application 83use of Docker or VMs, so I don't need any extra application configuration to
89configuration to make them accessible to the outside world.+ 84make them accessible to the outside world.+
90 85
91As of 2022-10-04, the paragraph above is no longer true as I now run a 86As of 2022-10-04, the paragraph above is no longer true as I now run a reverse
92reverse proxy with Nginx and host many services inside Docker. However, 87proxy with Nginx and host many services inside Docker. However, it doesn't
93it doesn\'t change anything regarding this post as I still just need to 88change anything regarding this post as I still just need to open ports 80 & 443
94open ports 80 & 443 and create the necessary website configuration 89and create the necessary website configuration files.
95files. 90
96 91When creating new services - either installed directly on bare metal or within
97When creating new services - either installed directly on bare metal or 92something like Docker - I ensure that I read through the documentation
98within something like Docker - I ensure that I read through the 93thoroughly to understand a few key things: - What network activities should this
99documentation thoroughly to understand a few key things: - What network 94app perform (if any)? Using which ports and protocols? - Does this app require
100activities should this app perform (if any)? Using which ports and 95any commands/services to be run as `root`? - Does this app log errors,
101protocols? - Does this app require any commands/services to be run as 96authentication failures/successes, or anything else that would be useful for an
102`root`? - Does this app log errors, authentication
103failures/successes, or anything else that would be useful for an
104investigation? 97investigation?
105 98
106For extra security, I use limit all incoming connections to SSH 99For extra security, I use limit all incoming connections to SSH connections
107connections through my server firewall (`ufw`) and disable 100through my server firewall (`ufw`) and disable common SSH settings. After all of
108common SSH settings. After all of that, I use `fail2ban` as a 101that, I use `fail2ban` as a preventative measure against brute-force login
109preventative measure against brute-force login attempts. 102attempts.
110 103
111As another piece of security, you can randomize your SSH port to ensure 104As another piece of security, you can randomize your SSH port to ensure that
112that random scanners or attackers can\'t easily try to force their way 105random scanners or attackers can't easily try to force their way into your
113into your network. For example, you can edit the port rules in your 106network. For example, you can edit the port rules in your server to block all
114server to block all connection requests to port `22` but 107connection requests to port `22` but forward all remote connections from port
115forward all remote connections from port `12345` to your 108`12345` to your server's port `22`. Then you just need to SSH to your network
116server\'s port `22`. Then you just need to SSH to your 109via your randomized port.
117network via your randomized port.
118 110
119## `ufw` 111## `ufw`
120 112
121To see how to configure `ufw`, see my other post: [Secure 113To see how to configure `ufw`, see my other post: [Secure Your Network with the
122Your Network with the Uncomplicated 114Uncomplicated
123Firewall](../secure-your-network-with-the-uncomplicated-firewall/). 115Firewall](../secure-your-network-with-the-uncomplicated-firewall/).
124 116
125The general notion with an on-device firewall is that you want to deny 117The general notion with an on-device firewall is that you want to deny all
126all incoming connections by default and then selectively open certain 118incoming connections by default and then selectively open certain ports for
127ports for services or users that you know need access. 119services or users that you know need access.
128 120
129If you know that you will only be logging into this server from a 121If you know that you will only be logging into this server from a certain set or
130certain set or list of IPs, you can always set the firewall to only 122list of IPs, you can always set the firewall to only allow connections to port
131allow connections to port 22 from those IPs. 12322 from those IPs.
132 124
133For a quick start to only allow SSH connections to the server, use this: 125For a quick start to only allow SSH connections to the server, use this:
134 126
@@ -145,31 +137,30 @@ sudo ufw enable
145 137
1461. Using SSH Keys 1381. Using SSH Keys
147 139
148 First, make sure you have an SSH keypair generated on the device(s) 140 First, make sure you have an SSH keypair generated on the device(s) that
149 that you\'ll be using to log in to the server. If you don\'t have an 141 you'll be using to log in to the server. If you don't have an SSH key, run
150 SSH key, run this command: 142 this command:
151 143
152 ```sh 144 ```sh
153 ssh-keygen 145 ssh-keygen
154 ``` 146 ```
155 147
156 Now that we have an SSH key, copy it to the server with the 148 Now that we have an SSH key, copy it to the server with the following
157 following command, which will ask for the user\'s password before 149 command, which will ask for the user's password before accepting the key:
158 accepting the key:
159 150
160 ```sh 151 ```sh
161 ssh-copy-id my_user@my_server 152 ssh-copy-id my_user@my_server
162 ``` 153 ```
163 154
164 If you have multiple keys, you\'ll need to specify which to use. 155 If you have multiple keys, you'll need to specify which to use. After it's
165 After it\'s complete, `ssh` back into the server as that 156 complete, `ssh` back into the server as that user and make sure it doesn't
166 user and make sure it doesn\'t ask for a password. 157 ask for a password.
167 158
1682. Disable Password & Root Authentication 1592. Disable Password & Root Authentication
169 160
170 Now that we can access the server without a password, we will 161 Now that we can access the server without a password, we will disable
171 disable password authentication and disable anyone from using 162 password authentication and disable anyone from using `ssh` to login as
172 `ssh` to login as `root`. 163 `root`.
173 164
174 To do this, open the `sshd_config` file: 165 To do this, open the `sshd_config` file:
175 166
@@ -177,9 +168,9 @@ sudo ufw enable
177 sudo nano /etc/ssh/sshd_config 168 sudo nano /etc/ssh/sshd_config
178 ``` 169 ```
179 170
180 You\'ll need to update the parameters to the values below. If one of 171 You'll need to update the parameters to the values below. If one of these
181 these rules is commented-out or doesn\'t exist, create the rule at 172 rules is commented-out or doesn't exist, create the rule at the bottom of
182 the bottom of the file. 173 the file.
183 174
184 ``` config 175 ``` config
185 PermitRootLogin no 176 PermitRootLogin no
@@ -193,36 +184,33 @@ sudo ufw enable
193 sudo systemctl restart sshd.service 184 sudo systemctl restart sshd.service
194 ``` 185 ```
195 186
196 To test that everything\'s working so far, open ANOTHER terminal and 187 To test that everything's working so far, open ANOTHER terminal and try
197 try logging in as `root` over SSH. It is very important 188 logging in as `root` over SSH. It is very important that you keep your
198 that you keep your current SSH session open and test with an 189 current SSH session open and test with an additional session, or you will
199 additional session, or you will lock yourself out at some point and 190 lock yourself out at some point and will need to use a recovery method
200 will need to use a recovery method (e.g., hooking monitor up to home 191 (e.g., hooking monitor up to home server) to get yourself back in.
201 server) to get yourself back in.
202 192
2033. Enable MFA for `ssh` 1933. Enable MFA for `ssh`
204 194
205 This part is optional, but I highly recommend it. So far, we\'ve 195 This part is optional, but I highly recommend it. So far, we've ensured
206 ensured that no one can log into our user on the server without 196 that no one can log into our user on the server without using our secret
207 using our secret key, and we\'ve ensured that no one can log in 197 key, and we've ensured that no one can log in remotely as `root`. Next, you
208 remotely as `root`. Next, you can enable MFA 198 can enable MFA authentication for `ssh` connections.
209 authentication for `ssh` connections.
210 199
211 This process involves editing a couple files and installing an MFA 200 This process involves editing a couple files and installing an MFA package,
212 package, so I will not include all the details in this post. To see 201 so I will not include all the details in this post. To see how to configure
213 how to configure MFA for `ssh`, see my other post: 202 MFA for `ssh`, see my other post: [Enabling MFA for
214 [Enabling MFA for SSH](../enable-totp-mfa-for-ssh/). 203 SSH](../enable-totp-mfa-for-ssh/).
215 204
216 ![SSH 205 ![SSH
217 MFA](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/ssh_mfa.png) 206 MFA](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/ssh_mfa.png)
218 207
219## `fail2ban` 208## `fail2ban`
220 209
221I haven\'t written a post on how I use `fail2ban`, but it\'s 210I haven't written a post on how I use `fail2ban`, but it's quite simple. I use
222quite simple. I use the default `sshd` jail, but you can 211the default `sshd` jail, but you can always create new jails for respective
223always create new jails for respective applications or ports. For 212applications or ports. For example, if you use Nginx as your web server, you can
224example, if you use Nginx as your web server, you can use the 213use the `nginx-http-auth` jail.
225`nginx-http-auth` jail.
226 214
227In order to get it up and running, use the following commands: 215In order to get it up and running, use the following commands:
228 216
@@ -232,122 +220,132 @@ sudo fail2ban-client start sshd
232sudo fail2ban-client status sshd 220sudo fail2ban-client status sshd
233``` 221```
234 222
235This should be used as a last-resort defense and shouldn\'t be a 223This should be used as a last-resort defense and shouldn't be a replacement for
236replacement for the security measures mentioned above. 224the security measures mentioned above.
237 225
238![fail2ban](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/fail2ban.png) 226![fail2ban](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/fail2ban.png)
239 227
240# Switch 228# Switch
241 229
242Between the router and any local devices is my managed switch, which is 230Between the router and any local devices is my managed switch, which is used to
243used to create VLANs. The example below shows how I would isolate the 231create VLANs. The example below shows how I would isolate the VLANs if I were
244VLANs if I were starting to host a single service at home. 232starting to host a single service at home.
245 233
246## 802.1Q VLAN Configuration 234## 802.1Q VLAN Configuration
247 235
248In this configuration, port 8 is the public server that needs to be 236In this configuration, port 8 is the public server that needs to be accessed
249accessed from the outside. Port 23 is my \'dedicated service port\' for 237from the outside. Port 23 is my 'dedicated service port' for this server. In
250this server. In order to SSH to this server, I need to plug my laptop 238order to SSH to this server, I need to plug my laptop into port 23 or else I
251into port 23 or else I cannot SSH. Otherwise, I\'d need to hook up a 239cannot SSH. Otherwise, I'd need to hook up a monitor and keyboard directly to
252monitor and keyboard directly to the server to manage it. 240the server to manage it.
253 241
254 VLAN ID VLAN Name Member Ports Tagged Ports Untagged Ports 242|
255 --------- ----------- -------------- -------------- ---------------- 243
256 1 Default 1-24 1-24 244| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports |
257 2 Server 1,8,23 1,8,23 245|---------|-----------|--------------|--------------|----------------|
246| 1 | Default | 1-24 | 1-24 | |
247| 2 | Server | 1,8,23 | 1,8,23 | |
258 248
259## 802.1Q VLAN PVID Setting 249## 802.1Q VLAN PVID Setting
260 250
261Once the VLAN is created, I simply add the `VLAN ID` of 251Once the VLAN is created, I simply add the `VLAN ID` of `2` as the `PVID` for
262`2` as the `PVID` for any related ports (in this 252any related ports (in this case, see that ports `8` and `23` have a PVID of
263case, see that ports `8` and `23` have a PVID of
264`2`). 253`2`).
265 254
266 Port PVID 255| Port | PVID |
267 ------ ------ 256|------|------|
268 1 1 257| 1 | 1 |
269 2 1 258| 2 | 1 |
270 3 1 259| 3 | 1 |
271 4 1 260| 4 | 1 |
272 5 1 261| 5 | 1 |
273 6 1 262| 6 | 1 |
274 7 1 263| 7 | 1 |
275 8 2 264| 8 | 2 |
276 9 1 265| 9 | 1 |
277 10 1 266| 10 | 1 |
278 11 1 267| 11 | 1 |
279 12 1 268| 12 | 1 |
280 13 1 269| 13 | 1 |
281 14 1 270| 14 | 1 |
282 15 1 271| 15 | 1 |
283 16 1 272| 16 | 1 |
284 17 1 273| 17 | 1 |
285 18 1 274| 18 | 1 |
286 19 1 275| 19 | 1 |
287 20 1 276| 20 | 1 |
288 21 1 277| 21 | 1 |
289 22 1 278| 22 | 1 |
290 23 2 279| 23 | 2 |
291 24 1 280| 24 | 1 |
292 281
293# Router 282# Router
294 283
295On my router, the configuration was as easy as opening the firewall 284On my router, the configuration was as easy as opening the firewall settings and
296settings and unblocking the ports I needed for my services (e.g., 285unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL,
297HTTP/S, Plex, SSH, MySQL, etc.). 286etc.).
298 287
299+Since I\'m relying on an ISP-provided modem/router combo for now (not 288*Since I'm relying on an ISP-provided modem/router combo for now (not by
300by choice), I do not use any other advanced settings on my router that 289choice), I do not use any other advanced settings on my router that would
301would inhibit any valid traffic to these services.+ 290inhibit any valid traffic to these services.*
302 291
303The paragraph above regarding the ISP-owned router is no longer accurate 292The paragraph above regarding the ISP-owned router is no longer accurate as I
304as I now use the Ubiquiti Unifi Dream Machine Pro as my router. Within 293now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I
305this router, I enabled port forwarding/firewall rules, segregate the 294enabled port forwarding/firewall rules, segregate the network based on the
306network based on the device, and enable traffic restrictions (e.g., 295device, and enable traffic restrictions (e.g., silently drop traffic from
307silently drop traffic from certain countries and threat categories). 296certain countries and threat categories).
308 297
309If you have the option with your ISP, I recommend using a personal 298If you have the option with your ISP, I recommend using a personal router with
310router with software that you are familiar with so that you can explore 299software that you are familiar with so that you can explore all the options
311all the options available to you. 300available to you.
312 301
313# Physical Security 302# Physical Security
314 303
315One large piece of self-hosting that people generally don\'t discuss 304One large piece of self-hosting that people generally don't discuss online is
316online is physical security. However, physical security is very 305physical security. However, physical security is very important for everyone who
317important for everyone who hosts a server like this. Exactly *how* 306hosts a server like this. Exactly *how* important it is depends on the server
318important it is depends on the server use/purpose. 307use/purpose.
319 308
320If you self-host customer applications that hold protected data (HIPAA, 309If you self-host customer applications that hold protected data (HIPAA, GDPR,
321GDPR, COPPA, etc.), then physical security is extremely important and 310COPPA, etc.), then physical security is extremely important and cannot be
322cannot be ignored. If you simply host a blog and some hobby sites, then 311ignored. If you simply host a blog and some hobby sites, then it's a relatively
323it\'s a relatively minor consideration, but one you still need to think 312minor consideration, but one you still need to think about.
324about.
325 313
326## Location 314## Location
327 315
328The first consideration is quite simple: location. - Is the server 316The first consideration is quite simple: location.
329within a property you own or housed on someone else\'s property? - Is it 317
330nearby (in your house, in your work office, in your neighbor\'s garage, 318- Is the server within a property you own or housed on someone else's property?
331in a storage unit, etc.)? - Do you have 24/7 access to the server? - Are 319- Is it nearby (in your house, in your work office, in your neighbor's garage,
332there climate considerations, such as humidity, fires, tornadoes, 320 in a storage unit, etc.)?
333monsoons? - Do you have emergency equipment nearby in case of emergency? 321- Do you have 24/7 access to the server?
322- Are there climate considerations, such as humidity, fires, tornadoes,
323 monsoons?
324- Do you have emergency equipment nearby in case of emergency?
334 325
335## Hardware Ownership 326## Hardware Ownership
336 327
337Secondly, consider the hardware itself: - Do you own the server in its 328Secondly, consider the hardware itself:
338entirety? - Are any other users able to access the server, even if your 329
339data/space is segregated? - If you\'re utilizing a third party, do they 330- Do you own the server in its entirety?
340have any documentation to show responsibility? This could be a SOC 1/2/3 331- Are any other users able to access the server, even if your data/space is
341report, ISO compliance report, internal security/safety documentation. 332 segregated?
333- If you're utilizing a third party, do they have any documentation to show
334 responsibility? This could be a SOC 1/2/3 report, ISO compliance report,
335 internal security/safety documentation.
342 336
343## Physical Controls 337## Physical Controls
344 338
345Regardless of who owns the hardware, ensure that there are adequate 339Regardless of who owns the hardware, ensure that there are adequate safeguards
346safeguards in place, if necessary. These usually don\'t apply to small 340in place, if necessary. These usually don't apply to small home servers and are
347home servers and are usually covered already if you\'re utilizing a 341usually covered already if you're utilizing a third party.
348third party. 342
343These can include:
349 344
350These can include: - Server bezel locks - Server room locks - physical, 345- Server bezel locks
351digital, or biometric authentication - Security cameras - Raised 346- Server room locks - physical, digital, or biometric authentication
352floors/lowered ceilings with proper guards/gates in-place within the 347- Security cameras
353floors or ceilings - Security personnel - Log sheets and/or guest badges 348- Raised floors/lowered ceilings with proper guards/gates in-place within the
349 floors or ceilings
350- Security personnel
351- Log sheets and/or guest badges
content/blog/2022-03-26-ssh-mfa.md +40 −43
@@ -1,35 +1,33 @@
1+++ 1+++
2date = 2022-03-26 2date = 2022-03-26
3title = "Enablt TOTP MFA for SSH" 3title = "Enable TOTP MFA for SSH"
4description = "" 4description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Why Do I Need MFA for SSH? 8# Why Do I Need MFA for SSH?
9 9
10If you are a sysadmin of a server anywhere (that includes at home!), you 10If you are a sysadmin of a server anywhere (that includes at home!), you may
11may want an added layer of protection against intruders. This is not a 11want an added layer of protection against intruders. This is not a replacement
12replacement for other security measures, such as: 12for other security measures, such as:
13 13
14- Disable root SSH 14- Disable root SSH
15- Disable SSH password authentication 15- Disable SSH password authentication
16- Allow only certain users to login via SSH 16- Allow only certain users to login via SSH
17- Allow SSH only from certain IPs 17- Allow SSH only from certain IPs
18 18
19However, MFA can be added as an additional security measure to ensure 19However, MFA can be added as an additional security measure to ensure that your
20that your server is protected. This is especially important if you need 20server is protected. This is especially important if you need to allow password
21to allow password authentication for SSH. 21authentication for SSH.
22 22
23For more guidance on server security measures, see my other post: 23For more guidance on server security measures, see my other post: [Hardening a
24[Hardening a Public-Facing Home 24Public-Facing Home Server](../hardening-a-public-facing-home-server/).
25Server](../hardening-a-public-facing-home-server/).
26 25
27# Install MFA PAM Module 26# Install MFA PAM Module
28 27
29PAM, which stands for Pluggable Authentication Module, is an 28PAM, which stands for Pluggable Authentication Module, is an authentication
30authentication infrastructure used on Linux systems to authenticate a 29infrastructure used on Linux systems to authenticate a user. In order to use
31user. In order to use this technology, let\'s install the 30this technology, let's install the `libpam-google-authenticator` package:
32`libpam-google-authenticator` package:
33 31
34```sh 32```sh
35sudo apt-get update 33sudo apt-get update
@@ -43,16 +41,16 @@ sudo apt-get install libpam-google-authenticator
43 41
44## Interactive Method 42## Interactive Method
45 43
46Once the package is installed, initialize it and following the 44Once the package is installed, initialize it and following the interactive
47interactive prompts to generate your OTP or TOTP: 45prompts to generate your OTP or TOTP:
48 46
49```sh 47```sh
50google-authenticator 48google-authenticator
51``` 49```
52 50
53If you are not sure how to answer, read the prompts carefully and think 51If you are not sure how to answer, read the prompts carefully and think about
54about having to how each situation would affect your normal login 52having to how each situation would affect your normal login attempts. If you are
55attempts. If you are still not sure, use my default responses below. 53still not sure, use my default responses below.
56 54
57``` txt 55``` txt
58OUTPUT 56OUTPUT
@@ -60,9 +58,9 @@ OUTPUT
60Do you want authentication tokens to be time-based (y/n) y 58Do you want authentication tokens to be time-based (y/n) y
61``` 59```
62 60
63At this point, use an authenticator app somewhere one of your devices to 61At this point, use an authenticator app somewhere one of your devices to scan
64scan the QR code. Any future login attempts after our upcoming 62the QR code. Any future login attempts after our upcoming configuration changes
65configuration changes will require that TOTP. 63will require that TOTP.
66 64
67``` txt 65``` txt
68OUTPUT 66OUTPUT
@@ -104,9 +102,9 @@ Do you want to enable rate-limiting? (y/n) y
104 102
105## Non-Interactive Method 103## Non-Interactive Method
106 104
107If you need to do this quickly, know your responses to the prompts, or 105If you need to do this quickly, know your responses to the prompts, or are
108are setting this up for numerous users, the non-interactive method can 106setting this up for numerous users, the non-interactive method can be much
109be much faster: 107faster:
110 108
111```sh 109```sh
112google-authenticator -t -d -f -r 3 -R 30 -w 3 110google-authenticator -t -d -f -r 3 -R 30 -w 3
@@ -136,23 +134,23 @@ google-authenticator [<options>]
136 -e, --emergency-codes=N Number of emergency codes to generate 134 -e, --emergency-codes=N Number of emergency codes to generate
137``` 135```
138 136
139This fully configures the authenticator, saves it to a file, and then 137This fully configures the authenticator, saves it to a file, and then outputs
140outputs the secret key, QR code, and recovery codes. (If you add the 138the secret key, QR code, and recovery codes. (If you add the flag `-q`, then
141flag `-q`, then there won\'t be any output). If you use this 139there won't be any output). If you use this command in an automated fashion,
142command in an automated fashion, make sure your script captures the 140make sure your script captures the secret key and/or recovery codes and makes
143secret key and/or recovery codes and makes them available to the user. 141them available to the user.
144 142
145# PAM Configuration Settings 143# PAM Configuration Settings
146 144
147Once you\'ve enabled the T/OTP and have it saved to an MFA app on your 145Once you've enabled the T/OTP and have it saved to an MFA app on your phone or
148phone or other device, open the PAM `sshd` file: 146other device, open the PAM `sshd` file:
149 147
150```sh 148```sh
151sudo nano /etc/pam.d/sshd 149sudo nano /etc/pam.d/sshd
152``` 150```
153 151
154You need to do two things in this file. First, add the following lines 152You need to do two things in this file. First, add the following lines to the
155to the bottom of the file: 153bottom of the file:
156 154
157``` config 155``` config
158auth required pam_google_authenticator.so nullok 156auth required pam_google_authenticator.so nullok
@@ -161,8 +159,8 @@ auth required pam_permit.so
161 159
162Second, comment-out the following line near the top of the file. 160Second, comment-out the following line near the top of the file.
163 161
164If you leave this line uncommented, every SSH login attempt will ask for 162If you leave this line uncommented, every SSH login attempt will ask for the
165the following three authentication factors: 163following three authentication factors:
166 164
1671. Publickey 1651. Publickey
1682. Password 1662. Password
@@ -180,9 +178,8 @@ Finally, edit the `sshd_config` file again:
180sudo nano /etc/ssh/sshd_config 178sudo nano /etc/ssh/sshd_config
181``` 179```
182 180
183You\'ll need to change `ChallengeResponseAuthentication` to 181You'll need to change `ChallengeResponseAuthentication` to yes and add the
184yes and add the `AuthenticationMethods` line to the bottom of 182`AuthenticationMethods` line to the bottom of the file.
185the file.
186 183
187``` config 184``` config
188ChallengeResponseAuthentication yes 185ChallengeResponseAuthentication yes
content/blog/2022-04-02-nginx-reverse-proxy.md +83 −92
@@ -7,36 +7,34 @@ draft = false
7 7
8# What is a Reverse Proxy? 8# What is a Reverse Proxy?
9 9
10A reverse proxy is a server that is placed between local servers or 10A reverse proxy is a server that is placed between local servers or services and
11services and clients/users (e.g., the internet). The reverse proxy 11clients/users (e.g., the internet). The reverse proxy intercepts all requests
12intercepts all requests from clients at the network edge and uses its 12from clients at the network edge and uses its configuration files to determine
13configuration files to determine where each request should be sent. 13where each request should be sent.
14 14
15## A Brief Example 15## A Brief Example
16 16
17For example, let\'s say that I run three servers in my home: 17For example, let's say that I run three servers in my home:
18 18
19- Server~01~ (`example.com`) 19- Server01 (`example.com`)
20- Server~02~ (`service01.example.com`) 20- Server02 (`service01.example.com`)
21- Server~03~ (`service02.example.com`) 21- Server03 (`service02.example.com`)
22 22
23I also run a reverse proxy in my home that intercepts all public 23I also run a reverse proxy in my home that intercepts all public traffic:
24traffic:
25 24
26- Reverse Proxy 25- Reverse Proxy
27 26
28Assume that I have a domain name (`example.com`) that allows 27Assume that I have a domain name (`example.com`) that allows clients to request
29clients to request websites or services from my home servers. 28websites or services from my home servers.
30 29
31In this case, the reverse proxy will intercept all traffic from 30In this case, the reverse proxy will intercept all traffic from `example.com`
32`example.com` that enters my network and determine if the 31that enters my network and determine if the client is requesting valid data,
33client is requesting valid data, based on my configuration. 32based on my configuration.
34 33
35If the user is requesting `example.com` and my configuration 34If the user is requesting `example.com` and my configuration files say that
36files say that Server~01~ holds that data, Nginx will send the user to 35Server~01~ holds that data, Nginx will send the user to Server~01~. If I were to
37Server~01~. If I were to change the configuration so that 36change the configuration so that `example.com` is routed to Server~02~, that
38`example.com` is routed to Server~02~, that same user would 37same user would be sent to Server~02~ instead.
39be sent to Server~02~ instead.
40 38
41``` txt 39``` txt
42┌──────┐ ┌───────────┐ 40┌──────┐ ┌───────────┐
@@ -52,62 +50,61 @@ be sent to Server~02~ instead.
52 50
53# Reverse Proxy Options 51# Reverse Proxy Options
54 52
55There are a lot of options when it comes to reverse proxy servers, so 53There are a lot of options when it comes to reverse proxy servers, so I'm just
56I\'m just going to list a few of the options I\'ve heard recommended 54going to list a few of the options I've heard recommended over the last few
57over the last few years: 55years:
58 56
59- [Nginx](https://nginx.com) 57- [Nginx](https://nginx.com)
60- [Caddy](https://caddyserver.com) 58- [Caddy](https://caddyserver.com)
61- [Traefik](https://traefik.io/) 59- [Traefik](https://traefik.io/)
62- [HAProxy](https://www.haproxy.org/) 60- [HAProxy](https://www.haproxy.org/)
63- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid) 61- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid)
64 62
65In this post, we will be using Nginx as our reverse proxy, running on 63In this post, we will be using Nginx as our reverse proxy, running on Ubuntu
66Ubuntu Server 20.04.4 LTS. 64Server 20.04.4 LTS.
67 65
68# Nginx Reverse Proxy Example 66# Nginx Reverse Proxy Example
69 67
70## Local Applications 68## Local Applications
71 69
72You may be like me and have a lot of applications running on your local 70You may be like me and have a lot of applications running on your local network
73network that you\'d like to expose publicly with a domain. 71that you'd like to expose publicly with a domain.
74 72
75In my case, I have services running in multiple Docker containers within 73In my case, I have services running in multiple Docker containers within a
76a single server and want a way to visit those services from anywhere 74single server and want a way to visit those services from anywhere with a URL.
77with a URL. For example, on my local network, [Dashy](https://dashy.to) 75For example, on my local network, [Dashy](https://dashy.to) runs through port
78runs through port 4000 (`localhost:4000`) and [Uptime 764000 (`localhost:4000`) and [Uptime
79Kuma](https://github.com/louislam/uptime-kuma) runs through port 3001 77Kuma](https://github.com/louislam/uptime-kuma) runs through port 3001
80(`localhost:3001`). 78(`localhost:3001`).
81 79
82In order to expose these services to the public, I will need to do the 80In order to expose these services to the public, I will need to do the
83following: 81following:
84 82
851. Set up DNS records for a domain or subdomain (one per service) to 831. Set up DNS records for a domain or subdomain (one per service) to point
86 point toward the IP address of the server. 84 toward the IP address of the server.
872. Open up the server network\'s HTTP and HTTPS ports (80 & 443) so 852. Open up the server network's HTTP and HTTPS ports (80 & 443) so that the
88 that the reverse proxy can accept traffic and determine where to 86 reverse proxy can accept traffic and determine where to send it.
89 send it. 873. Install the reverse proxy software.
903. Install the reverse proxy software. 884. Configure the reverse proxy to recognize which service should get traffic
914. Configure the reverse proxy to recognize which service should get 89 from any of the domains or subdomains.
92 traffic from any of the domains or subdomains.
93 90
94## Step 1: DNS Configuration 91## Step 1: DNS Configuration
95 92
96To start, update your DNS configuration so that you have an 93To start, update your DNS configuration so that you have an `A` record for each
97`A` record for each domain or subdomain. 94domain or subdomain.
98 95
99The `A` records should point toward the public IP address of 96The `A` records should point toward the public IP address of the server. If you
100the server. If you don\'t know the public IP address, log in to the 97don't know the public IP address, log in to the server and run the following
101server and run the following command: 98command:
102 99
103```sh 100```sh
104curl ifconfig.co 101curl ifconfig.co
105``` 102```
106 103
107In the DNS example below, `xxx.xxx.xxx.xxx` is the public IP 104In the DNS example below, `xxx.xxx.xxx.xxx` is the public IP address of the
108address of the server. 105server.
109 106
110``` config 107```conf
111example.com A xxx.xxx.xxx.xxx 108example.com A xxx.xxx.xxx.xxx
112uptime.example.com A xxx.xxx.xxx.xxx 109uptime.example.com A xxx.xxx.xxx.xxx
113dashy.example.com A xxx.xxx.xxx.xxx 110dashy.example.com A xxx.xxx.xxx.xxx
@@ -115,33 +112,30 @@ www CNAME example.com
115``` 112```
116 113
117Finally, ensure the DNS has propagated correctly with [DNS 114Finally, ensure the DNS has propagated correctly with [DNS
118Checker](https://dnschecker.org) by entering your domains or subdomains 115Checker](https://dnschecker.org) by entering your domains or subdomains in the
119in the search box and ensuring the results are showing the correct IP 116search box and ensuring the results are showing the correct IP address.
120address.
121 117
122## Step 2: Open Network Ports 118## Step 2: Open Network Ports
123 119
124This step will be different depending on which router you have in your 120This step will be different depending on which router you have in your home. If
125home. If you\'re not sure, try to visit 121you're not sure, try to visit [192.168.1.1](http://192.168.1.1) in your
126[192.168.1.1](http://192.168.1.1) in your browser. Login credentials are 122browser. Login credentials are usually written on a sticker somewhere on your
127usually written on a sticker somewhere on your modem/router. 123modem/router.
128 124
129Once you\'re able to log in to your router, find the Port Forwarding 125Once you're able to log in to your router, find the Port Forwarding settings.
130settings. You will need to forward ports `80` and 126You will need to forward ports `80` and `443` to whichever machine is running
131`443` to whichever machine is running the reverse proxy. 127the reverse proxy.
132 128
133In my case, the table below shows the port-forwarding rules I\'ve 129In my case, the table below shows the port-forwarding rules I've created. In
134created. In this table, `xxx.xxx.xxx.xxx` is the local device 130this table, `xxx.xxx.xxx.xxx` is the local device IP of the reverse proxy
135IP of the reverse proxy server, it will probably be an IP between 131server, it will probably be an IP between `192.168.1.1` and `192.168.1.255`.
136`192.168.1.1` and `192.168.1.255`.
137 132
138 NAME FROM PORT DEST PORT/IP ENABLED 133| NAME | FROM PORT | DEST PORT/IP | ENABLED |
139 ------- ------ ------ ----------------- --------- 134|-------|-----------|-----------------|---------|
140 HTTP ​\*\* 80 xxx.xxx.xxx.xxx TRUE 135| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE |
141 HTTPS ​\*\* 443 xxx.xxx.xxx.xxx TRUE 136| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE |
142 137
143Once configured, these rules will direct all web traffic to your reverse 138Once configured, these rules will direct all web traffic to your reverse proxy.
144proxy.
145 139
146## Step 3: Nginx Installation 140## Step 3: Nginx Installation
147 141
@@ -151,12 +145,11 @@ To install Nginx, simply run the following command:
151sudo apt install nginx 145sudo apt install nginx
152``` 146```
153 147
154If you have a firewall enabled, open up ports `80` and 148If you have a firewall enabled, open up ports `80` and `443` on your server so
155`443` on your server so that Nginx can accept web traffic 149that Nginx can accept web traffic from the router.
156from the router.
157 150
158For example, if you want to use `ufw` for web traffic and 151For example, if you want to use `ufw` for web traffic and SSH, run the following
159SSH, run the following commands: 152commands:
160 153
161```sh 154```sh
162sudo ufw allow 'Nginx Full' 155sudo ufw allow 'Nginx Full'
@@ -166,14 +159,12 @@ sudo ufw enable
166 159
167## Step 4: Nginx Configuration 160## Step 4: Nginx Configuration
168 161
169Now that we have domains pointing toward the server, the only step left 162Now that we have domains pointing toward the server, the only step left is to
170is to configure the reverse proxy to direct traffic from domains to 163configure the reverse proxy to direct traffic from domains to local services.
171local services.
172 164
173To start, you\'ll need to create a configuration file for each domain in 165To start, you'll need to create a configuration file for each domain in
174`/etc/nginx/sites-available/`. They will look identical 166`/etc/nginx/sites-available/`. They will look identical except for the
175except for the `server_name` variable and the 167`server_name` variable and the `proxy_pass` port.
176`proxy_pass` port.
177 168
178Dashy: 169Dashy:
179 170
@@ -209,8 +200,8 @@ server {
209} 200}
210``` 201```
211 202
212Once the configuration files are created, you will need to enable them 203Once the configuration files are created, you will need to enable them with the
213with the `symlink` command: 204`symlink` command:
214 205
215```sh 206```sh
216sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/ 207sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/
@@ -220,12 +211,12 @@ Voilà! Your local services should now be available through their URLs.
220 211
221# HTTPS with Certbot 212# HTTPS with Certbot
222 213
223If you\'ve followed along, you\'ll notice that your services are only 214If you've followed along, you'll notice that your services are only available
224available via HTTP (not HTTPS). 215via HTTP (not HTTPS).
225 216
226If you want to enable HTTPS for your new domains, you will need to 217If you want to enable HTTPS for your new domains, you will need to generate
227generate SSL/TLS certificates for them. The easiest way to generate 218SSL/TLS certificates for them. The easiest way to generate certificates on Nginx
228certificates on Nginx is [Certbot](https://certbot.eff.org): 219is [Certbot](https://certbot.eff.org):
229 220
230```sh 221```sh
231sudo apt install snapd; sudo snap install core; sudo snap refresh core 222sudo apt install snapd; sudo snap install core; sudo snap refresh core
content/blog/2022-04-09-pinetime.md +78 −84
@@ -9,48 +9,46 @@ draft = false
9 9
10## Overview 10## Overview
11 11
12The [PineTime](https://www.pine64.org/pinetime/) is an open-source 12The [PineTime](https://www.pine64.org/pinetime/) is an open-source smartwatch,
13smartwatch, created by [PINE64](https://www.pine64.org). Originally 13created by [PINE64](https://www.pine64.org). Originally announced in September
14announced in September 2019, this ARM-based watch is a fantastic option 142019, this ARM-based watch is a fantastic option for users who want the benefits
15for users who want the benefits of a modern smartwatch with the backing 15of a modern smartwatch with the backing of open-source components and software.
16of open-source components and software.
17 16
18## Product Specifications 17## Product Specifications
19 18
20I won\'t dive into too many details that you can find on [the product 19I won't dive into too many details that you can find on [the product
21page](https://www.pine64.org/pinetime/), but I wanted to point out the 20page](https://www.pine64.org/pinetime/), but I wanted to point out the prices
22prices for each watch and the primary functions: 21for each watch and the primary functions:
23 22
241. Price: 231. Price:
25 24
26 - \$26.99 (Sealed) 25 - $26.99 (Sealed)
27 - \$24.99 (Dev Kit) 26 - $24.99 (Dev Kit)
28 - \$51.98 (One Sealed + One Dev Kit) 27 - $51.98 (One Sealed + One Dev Kit)
29 28
302. Primary Functionality: 292. Primary Functionality:
31 30
32 - Clock (+ Smartphone Sync) 31 - Clock (+ Smartphone Sync)
33 - Pedometer 32 - Pedometer
34 - Heart Rate Monitor 33 - Heart Rate Monitor
35 - Sleep Monitor 34 - Sleep Monitor
36 - Calories burned 35 - Calories burned
37 - Messaging 36 - Messaging
38 - Smartphone Notifications 37 - Smartphone Notifications
39 - Media Controls 38 - Media Controls
40 39
41# Unboxing 40# Unboxing
42 41
43Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and 42Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and was
44was delivered on 2022-03-23. With the current delays on shipping times 43delivered on 2022-03-23. With the current delays on shipping times around the
45around the world (and the semiconductor shortage), a month for delivery 44world (and the semiconductor shortage), a month for delivery from China seems
46from China seems reasonable to me. 45reasonable to me.
47 46
48The packaging is simple, and the watch comes with instructions, 47The packaging is simple, and the watch comes with instructions, technical
49technical information, the watch, and a charger (it does not include a 48information, the watch, and a charger (it does not include a USB wall adapter).
50USB wall adapter).
51 49
52The watch itself was able to turn on immediately when I pulled it out of 50The watch itself was able to turn on immediately when I pulled it out of the
53the box, but the battery was depleted and required charging right away. 51box, but the battery was depleted and required charging right away.
54 52
55![PineTime Box 53![PineTime Box
56Contents](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime_box_contents.png) 54Contents](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime_box_contents.png)
@@ -59,62 +57,60 @@ Contents](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime_bo
59 57
60## Watch OS: InfiniTime 58## Watch OS: InfiniTime
61 59
62While turning on the watch for the first time, some of the main design 60While turning on the watch for the first time, some of the main design choices
63choices you can see in the watch OS, 61you can see in the watch OS,
64[InfiniTime](https://wiki.pine64.org/wiki/InfiniTime), are: 62[InfiniTime](https://wiki.pine64.org/wiki/InfiniTime), are:
65 63
66- A square bezel, not too thin against the sides of the watch. 64- A square bezel, not too thin against the sides of the watch.
67- A simple, rubber band. 65- A simple, rubber band.
68- Basic font and screen pixel design. 66- Basic font and screen pixel design.
69- Swipe gestures to access other screens. 67- Swipe gestures to access other screens.
70 68
71![PineTime 69![PineTime
72Screens](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime.png) 70Screens](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime.png)
73 71
74The OS itself is fantastic in terms of functionality for me. It does 72The OS itself is fantastic in terms of functionality for me. It does exactly
75exactly what a smartwatch should do - track time, steps, heart rates, 73what a smartwatch should do - track time, steps, heart rates, and connect to
76and connect to another smart device, without being overly burdensome to 74another smart device, without being overly burdensome to the user.
77the user.
78 75
79My only gripe so far is that it\'s *really* difficult to swipe to 76My only gripe so far is that it's *really* difficult to swipe to different
80different screens, such as pulling down the notification tray. I\'m not 77screens, such as pulling down the notification tray. I'm not sure if this is an
81sure if this is an OS or hardware issue, but it makes it quite hard to 78OS or hardware issue, but it makes it quite hard to quickly move around the
82quickly move around the screens. 79screens.
83 80
84However, my absolute favorite design choice is that the button the side 81However, my absolute favorite design choice is that the button the side turns
85turns the screen on and off and tilting/waving my wrist doesn\'t 82the screen on and off and tilting/waving my wrist doesn't accidentally turn on
86accidentally turn on the screen. With other watches, I absolutely hated 83the screen. With other watches, I absolutely hated not being able to turn off
87not being able to turn off the raise-to-wake or wave features (i.e., 84the raise-to-wake or wave features (i.e., blinding myself while wearing a watch
88blinding myself while wearing a watch at night because I moved my arm). 85at night because I moved my arm).
89 86
90## iOS App: InfiniLink 87## iOS App: InfiniLink
91 88
92Since I am using iOS as my primary mobile device OS, I am using the 89Since I am using iOS as my primary mobile device OS, I am using the
93[InfiniLink](https://github.com/xan-m/InfiniLink) app to connect my 90[InfiniLink](https://github.com/xan-m/InfiniLink) app to connect my watch.
94watch.
95 91
96This app provides the following for PineTime owners: 92This app provides the following for PineTime owners:
97 93
98- Firmware updates 94- Firmware updates
99- Steps 95- Steps
100- Charts 96- Charts
101- Notifications 97- Notifications
102 98
103I mashed up a few screenshots to show off the home page, menu, firmware 99I mashed up a few screenshots to show off the home page, menu, firmware update,
104update, and notification test screens: 100and notification test screens:
105 101
106![InfiniLink 102![InfiniLink
107Home](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_home.png) 103Home](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_home.png)
108 104
109Another big feature of InfiniLink is the ability to track pedometer 105Another big feature of InfiniLink is the ability to track pedometer steps in a
110steps in a collection of beautiful graphs, with the option to change 106collection of beautiful graphs, with the option to change your step goal and add
111your step goal and add in manual steps. 107in manual steps.
112 108
113![InfiniLink 109![InfiniLink
114Steps](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_steps.png) 110Steps](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_steps.png)
115 111
116Finally, there are charts to display the battery percentage and heart 112Finally, there are charts to display the battery percentage and heart rates over
117rates over time. This area also comes with an option to clear data. 113time. This area also comes with an option to clear data.
118 114
119![InfiniLink 115![InfiniLink
120Charts](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_charts.png) 116Charts](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_charts.png)
@@ -123,36 +119,34 @@ Charts](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_ch
123 119
124## Pros 120## Pros
125 121
126After wearing my watch for a few weeks, I have mostly positive thoughts 122After wearing my watch for a few weeks, I have mostly positive thoughts about
127about the watch so far. In the past, I have owned smartwatches by 123the watch so far. In the past, I have owned smartwatches by FitBit, Fossil,
128FitBit, Fossil, Apple, etc. - **but I prefer the PineTime over all of 124Apple, etc. - **but I prefer the PineTime over all of those watches**.
129those watches**.
130 125
131The PineTime strips out all the unnecessary features and performs the 126The PineTime strips out all the unnecessary features and performs the functions
132functions that it provides effectively and efficiently. 127that it provides effectively and efficiently.
133 128
134The battery life is amazing on this device. By default, the watch seems 129The battery life is amazing on this device. By default, the watch seems to last
135to last anywhere from a few days to a week before dying. 130anywhere from a few days to a week before dying.
136 131
137And of course, it\'s open source and backed by some of the most 132And of course, it's open source and backed by some of the most dedicated
138dedicated enthusiasts and developers I\'ve seen. Watching the Matrix 133enthusiasts and developers I've seen. Watching the Matrix channel, forums, and
139channel, forums, and website have been exciting to see. 134website have been exciting to see.
140 135
141## Cons 136## Cons
142 137
143If I had to complain about anything, it would simply be the small bugs 138If I had to complain about anything, it would simply be the small bugs in some
144in some features that can be contributed to the companion apps more than 139features that can be contributed to the companion apps more than the watch
145the watch itself. 140itself.
146 141
147A regular user would want native notification support out-of-the-box, 142A regular user would want native notification support out-of-the-box, which is
148which is the biggest item not working for me at the moment. 143the biggest item not working for me at the moment.
149 144
150My only other complaint is that the battery indicator on the watch 145My only other complaint is that the battery indicator on the watch doesn't seem
151doesn\'t seem accurate when it\'s nearing depletion - it seems that 146accurate when it's nearing depletion - it seems that there's a bit of battery
152there\'s a bit of battery life left and then my watch is dead very 147life left and then my watch is dead very suddenly after. This could just be me
153suddenly after. This could just be me misinterpreting the battery level 148misinterpreting the battery level icons, but it has fooled me a few times into
154icons, but it has fooled me a few times into thinking I had more battery 149thinking I had more battery left than I actually did.
155left than I actually did.
156 150
157Other than those small items, I really do love this watch and am glad I 151Other than those small items, I really do love this watch and am glad I replaced
158replaced my Apple Watch with the PineTime. 152my Apple Watch with the PineTime.
content/blog/2022-06-01-ditching-cloudflare.md +52 −58
@@ -7,89 +7,83 @@ draft = false
7 7
8# Registrar 8# Registrar
9 9
10After spending a year or so using Cloudflare for DNS only - no proxying 10After spending a year or so using Cloudflare for DNS only - no proxying or
11or applications - I spent the last few months using Cloudflare Tunnels 11applications - I spent the last few months using Cloudflare Tunnels and
12and Cloudflare Access to protect my self-hosted websites and 12Cloudflare Access to protect my self-hosted websites and applications via their
13applications via their proxy traffic model. 13proxy traffic model.
14 14
15However, I have never liked using Cloudflare due to their increasingly 15However, I have never liked using Cloudflare due to their increasingly large
16large share of control over web traffic, as well as their business model 16share of control over web traffic, as well as their business model of being a
17of being a MITM for all of your traffic. 17MITM for all of your traffic.
18 18
19So, as of today, I have switched over to [Njalla](https://njal.la) as my 19So, as of today, I have switched over to [Njalla](https://njal.la) as my
20registrar and DNS manager. I was able to easily transfer my domains over 20registrar and DNS manager. I was able to easily transfer my domains over
21rapidly, with only one domain taking more than 15-30 minutes to 21rapidly, with only one domain taking more than 15-30 minutes to propagate.
22propagate.
23 22
24+I do still have two domains sitting at Cloudflare for the moment while 23+I do still have two domains sitting at Cloudflare for the moment while I decide
25I decide if they\'re worth the higher rates (one domain is 30€ and the 24if they're worth the higher rates (one domain is 30€ and the other is 45€).+
26other is 45€).+
27 25
28> **Update (2022.06.03)**: I ended up transferring my final two domains 26> **Update (2022.06.03)**: I ended up transferring my final two domains over to
29> over to Njalla, clearing my Cloudflare account of personal data, and 27> Njalla, clearing my Cloudflare account of personal data, and deleting the
30> deleting the Cloudflare account entirely. *I actually feel relieved to 28> Cloudflare account entirely. *I actually feel relieved to have moved on to a
31> have moved on to a provider I trust.* 29> provider I trust.*
32 30
33# DNS 31# DNS
34 32
35As noted above, I\'m using Njalla exclusively for DNS configurations on 33As noted above, I'm using Njalla exclusively for DNS configurations on my
36my domains. 34domains.
37 35
38However, the transfer process was not ideal. As soon as the domains 36However, the transfer process was not ideal. As soon as the domains transferred
39transferred over, I switched the nameservers from Cloudflare to Njalla 37over, I switched the nameservers from Cloudflare to Njalla and lost most of the
40and lost most of the associated DNS records. So, the majority of the 38associated DNS records. So, the majority of the time spent during the migration
41time spent during the migration was simply re-typing all the DNS records 39was simply re-typing all the DNS records back in one-by-one.
42back in one-by-one.
43 40
44This would be much simpler if I were able to edit the plain-text format 41This would be much simpler if I were able to edit the plain-text format of the
45of the DNS configuration. I was able to do that at a past registrar 42DNS configuration. I was able to do that at a past registrar (perhaps it was
46(perhaps it was [Gandi.net](https://gandi.net/)?) and it made life a lot 43[Gandi.net](https://gandi.net/)?) and it made life a lot easier.
47easier.
48 44
49## Dynamic DNS Updates 45## Dynamic DNS Updates
50 46
51I have built an easy Python script to run (or set-up in 47I have built an easy Python script to run (or set-up in `cron` to run
52`cron` to run automatically) that will check my server\'s 48automatically) that will check my server's IPv4 and IPv6, compare it to Njalla,
53IPv4 and IPv6, compare it to Njalla, and update the DNS records if they 49and update the DNS records if they don't match. You can see the full script and
54don\'t match. You can see the full script and process in my other post: 50process in my other post: [Updating Dynamic DNS with Njalla
55[Updating Dynamic DNS with Njalla API](../njalla-dns-api/). 51API](../njalla-dns-api/).
56 52
57I haven\'t used this other method, but I do know that you can create 53I haven't used this other method, but I do know that you can create `Dynamic`
58`Dynamic` DNS records with Njalla that [work for updating 54DNS records with Njalla that [work for updating dynamic
59dynamic subdomains](https://njal.la/docs/ddns/). 55subdomains](https://njal.la/docs/ddns/).
60 56
61## Njalla\'s DNS Tool 57## Njalla's DNS Tool
62 58
63One neat upside to Njalla is that they have a [DNS lookup 59One neat upside to Njalla is that they have a [DNS lookup
64tool](https://check.njal.la/dns/) that provides a lot of great 60tool](https://check.njal.la/dns/) that provides a lot of great information for
65information for those of you (AKA: me) who hate using the 61those of you (AKA: me) who hate using the `dig` command.
66`dig` command.
67 62
68This was very useful for monitoring a couple of my transferred domains 63This was very useful for monitoring a couple of my transferred domains to see
69to see when the changes in nameservers, records, and DNSSEC went into 64when the changes in nameservers, records, and DNSSEC went into effect.
70effect.
71 65
72# Tunnel 66# Tunnel
73 67
74Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on 68Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on
75Cloudflare\'s servers) and allowed me to mask the private IP address of 69Cloudflare's servers) and allowed me to mask the private IP address of the
76the server hosting my various websites and apps. 70server hosting my various websites and apps.
77 71
78However, as I was moving away from Cloudflare, I was not able to find a 72However, as I was moving away from Cloudflare, I was not able to find a suitable
79suitable replacement that was both inexpensive and simple. So, I simply 73replacement that was both inexpensive and simple. So, I simply went back to
80went back to hosting [my own reverse proxy with 74hosting [my own reverse proxy with
81Nginx](file:///blog/set-up-nginx-reverse-proxy/). With the recent 75Nginx](file:///blog/set-up-nginx-reverse-proxy/). With the recent additions of
82additions of Unifi hardware in my server/network rack, I am much more 76Unifi hardware in my server/network rack, I am much more protected against spam
83protected against spam and malicious attacks at the network edge than I 77and malicious attacks at the network edge than I was before I switched to
84was before I switched to Cloudflare. 78Cloudflare.
85 79
86# Access 80# Access
87 81
88Cloudflare Access, another app I used in combination with Cloudflare 82Cloudflare Access, another app I used in combination with Cloudflare Tunnel,
89Tunnel, provided an authentication screen that required you to enter 83provided an authentication screen that required you to enter valid credentials
90valid credentials before Cloudflare would forward you to the actual 84before Cloudflare would forward you to the actual website or app (if the
91website or app (if the website/app has their own authentication, you\'d 85website/app has their own authentication, you'd then have to authenticate a
92then have to authenticate a second time). 86second time).
93 87
94I did not replace this service with anything since I only host a handful 88I did not replace this service with anything since I only host a handful of
95of non-sensitive apps that don\'t require duplicate authentication. 89non-sensitive apps that don't require duplicate authentication.
content/blog/2022-06-07-self-hosting-freshrss.md +75 −92
@@ -7,46 +7,43 @@ draft = false
7 7
8# Why RSS? 8# Why RSS?
9 9
10After noticing that I have collected 50+ blogs as bookmarks, I decided 10After noticing that I have collected 50+ blogs as bookmarks, I decided to
11to migrate back to using RSS feeds to stay up-to-date with my favorite 11migrate back to using RSS feeds to stay up-to-date with my favorite websites.
12websites. Using RSS allows me to read all of these posts in a single app 12Using RSS allows me to read all of these posts in a single app (on both mobile &
13(on both mobile & desktop) and allows me to be notified when new posts 13desktop) and allows me to be notified when new posts are available.
14are available.
15 14
16However, I ran into one issue: syncing subscriptions and read/unread 15However, I ran into one issue: syncing subscriptions and read/unread posts
17posts across devices. Since I want to be able to easily read on both 16across devices. Since I want to be able to easily read on both mobile and
18mobile and desktop, I decided to look for a self-hosted RSS solution. 17desktop, I decided to look for a self-hosted RSS solution.
19 18
20Thus, I found [FreshRSS](https://www.freshrss.org/) and was able to 19Thus, I found [FreshRSS](https://www.freshrss.org/) and was able to successfully
21successfully install it on my server in about 30 minutes. 20install it on my server in about 30 minutes.
22 21
23# Documentation 22# Documentation
24 23
25While it\'s certainly not robust, the [FreshRSS 24While it's certainly not robust, the [FreshRSS
26documentation](https://freshrss.github.io/FreshRSS/) is helpful for 25documentation](https://freshrss.github.io/FreshRSS/) is helpful for figuring out
27figuring out basic information about the service. 26basic information about the service.
28 27
29However, I wanted to install this service as a Docker container and 28However, I wanted to install this service as a Docker container and stumbled
30stumbled across the [Docker 29across the [Docker
31README](https://github.com/FreshRSS/FreshRSS/tree/edge/Docker) within 30README](https://github.com/FreshRSS/FreshRSS/tree/edge/Docker) within the GitHub
32the GitHub repository. 31repository.
33 32
34This README was the documentation I actually needed. However, as you\'ll 33This README was the documentation I actually needed. However, as you'll see
35see below, I still had to manually edit one file 34below, I still had to manually edit one file (`config.php`) to access the API
36(`config.php`) to access the API externally via my RSS apps. 35externally via my RSS apps.
37 36
38# Installation 37# Installation
39 38
40## DNS 39## DNS
41 40
42The first step, as required by any external web service, was assigning a 41The first step, as required by any external web service, was assigning a domain
43domain name to use. I chose to use a subdomain, like 42name to use. I chose to use a subdomain, like `rss.example.com`.
44`rss.example.com`.
45 43
46To assign this, I created an `A` record in my DNS settings 44To assign this, I created an `A` record in my DNS settings with the IPv4 address
47with the IPv4 address of the server and an `AAAA` record with 45of the server and an `AAAA` record with the IPv6 address of the server. Note:
48the IPv6 address of the server. Note: assigning an IPv6 46assigning an IPv6 (`AAAA`) record is optional, but I like to enable IPV6 for my
49(`AAAA`) record is optional, but I like to enable IPV6 for my
50services. 47services.
51 48
52``` config 49``` config
@@ -56,15 +53,13 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx
56 53
57## Docker 54## Docker
58 55
59I initially tried to set up a `docker-compose.yml` file with 56I initially tried to set up a `docker-compose.yml` file with a `.env` file
60a `.env` file because I prefer to have a file I can look back 57because I prefer to have a file I can look back at later to see how I initially
61at later to see how I initially started the container, but it simply 58started the container, but it simply wouldn't work for me. I'm not sure why,
62wouldn\'t work for me. I\'m not sure why, but I assume I wasn\'t telling 59but I assume I wasn't telling `docker-compose` where the `.env` file was.
63`docker-compose` where the `.env` file was.
64 60
65Regardless, I chose to simply run the service with 61Regardless, I chose to simply run the service with `docker run`. See the
66`docker run`. See the following command for my 62following command for my `docker run` configuration:
67`docker run` configuration:
68 63
69```sh 64```sh
70sudo docker run -d --restart unless-stopped --log-opt max-size=10m \ 65sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
@@ -77,32 +72,29 @@ sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
77 freshrss/freshrss 72 freshrss/freshrss
78``` 73```
79 74
80This started the container successfully and allowed me to visit the 75This started the container successfully and allowed me to visit the FreshRSS
81FreshRSS instance at `localhost:8080`. 76instance at `localhost:8080`.
82 77
83## Fresh RSS Set-Up 78## Fresh RSS Set-Up
84 79
85I **HIGHLY\*** suggest that you set up your user account prior to 80I **HIGHLY** suggest that you set up your user account prior to exposing this
86exposing this service to the public. It\'s unlikely that someone is 81service to the public. It's unlikely that someone is trying to access the exact
87trying to access the exact domain or IP/port you\'re assigning here, but 82domain or IP/port you're assigning here, but as soon as you expose this
88as soon as you expose this service, the first person to open the URL 83service, the first person to open the URL will be able to create the admin user.
89will be able to create the admin user.
90 84
91In order to set up your FreshRSS service, open the 85In order to set up your FreshRSS service, open the `localhost:8080` URL in your
92`localhost:8080` URL in your browser (you may need to use a 86browser (you may need to use a local IP instead of `localhost` if you're
93local IP instead of `localhost` if you\'re accessing the page 87accessing the page from a different machine on the network - e.g.,
94from a different machine on the network - e.g.,
95`192.168.1.20:8080`). 88`192.168.1.20:8080`).
96 89
97Once the page loads, set up your default user with a strong username and 90Once the page loads, set up your default user with a strong username and
98password. You may also choose to configure other settings prior to 91password. You may also choose to configure other settings prior to exposing this
99exposing this service. 92service.
100 93
101## Nginx Reverse-Proxy 94## Nginx Reverse-Proxy
102 95
103In order to access this service outside my home, I needed to set up a 96In order to access this service outside my home, I needed to set up a
104reverse-proxy to connect `localhost:8080` to 97reverse-proxy to connect `localhost:8080` to `rss.example.com`.
105`rss.example.com`.
106 98
107First, I created a new Nginx configuration file: 99First, I created a new Nginx configuration file:
108 100
@@ -143,8 +135,7 @@ server {
143} 135}
144``` 136```
145 137
146Finally, restart Nginx and you will be able to access your service via 138Finally, restart Nginx and you will be able to access your service via HTTP:
147HTTP:
148 139
149```sh 140```sh
150sudo systemctl restart nginx.service 141sudo systemctl restart nginx.service
@@ -152,51 +143,46 @@ sudo systemctl restart nginx.service
152 143
153## HTTPS 144## HTTPS
154 145
155However, I don\'t want to access my RSS feeds via HTTP. I want it 146However, I don't want to access my RSS feeds via HTTP. I want it available only
156available only via HTTPS. In order to do this, I ran the 147via HTTPS. In order to do this, I ran the [certbot](https://certbot.eff.org/)
157[certbot](https://certbot.eff.org/) program to generate SSL certificates 148program to generate SSL certificates for me:
158for me:
159 149
160```sh 150```sh
161sudo certbot --nginx 151sudo certbot --nginx
162``` 152```
163 153
164This process will automatically generate an SSL certificate for you and 154This process will automatically generate an SSL certificate for you and modify
165modify the Nginx configuration file to include a redirect from HTTP to 155the Nginx configuration file to include a redirect from HTTP to HTTPS.
166HTTPS.
167 156
168# Post-Installation Fixes 157# Post-Installation Fixes
169 158
170At this point, we have a functional FreshRSS website, available from 159At this point, we have a functional FreshRSS website, available from anywhere
171anywhere and secured with HTTPS. However, attempting to connect this 160and secured with HTTPS. However, attempting to connect this service to an RSS
172service to an RSS app resulted in many errors regarding unavailable URLs 161app resulted in many errors regarding unavailable URLs and incorrect
173and incorrect credentials. 162credentials.
174 163
175## API Set-Up 164## API Set-Up
176 165
177First, you need to open your user profile in FreshRSS 166First, you need to open your user profile in FreshRSS (`Settings` > `Profile`)
178(`Settings` \> `Profile`) and set an API password 167and set an API password in the field at the bottom. This is the password you
179in the field at the bottom. This is the password you will need to 168will need to provide to your RSS apps.
180provide to your RSS apps.
181 169
182Once that is set and saved, click the link below the API password field 170Once that is set and saved, click the link below the API password field to open
183to open the API check tool. It should look something like 171the API check tool. It should look something like `https://localhost:8080/api/`
184`https://localhost:8080/api/` or 172or `https://rss.example.com/api/`.
185`https://rss.example.com/api/`.
186 173
187Within this page, you *should* see your correct external URL and 174Within this page, you *should* see your correct external URL and "PASS" at the
188\"PASS\" at the bottom of each API type. This would mean everything is 175bottom of each API type. This would mean everything is set up correctly, and you
189set up correctly, and you can now move on and login to any RSS apps that 176can now move on and login to any RSS apps that support self-hosted options.
190support self-hosted options.
191 177
192In my case, the URL showed an internal URL and I had a warning that the 178In my case, the URL showed an internal URL and I had a warning that the
193`base_url` variable may be misconfigured. If this is the 179`base_url` variable may be misconfigured. If this is the case, see the next
194case, see the next section for a fix. 180section for a fix.
195 181
196## Base URL Fix 182## Base URL Fix
197 183
198In order to fix the `base_url` for the API, I opened up my 184In order to fix the `base_url` for the API, I opened up my docker container with
199docker container with the following command: 185the following command:
200 186
201```sh 187```sh
202sudo docker exec -it freshrss bash 188sudo docker exec -it freshrss bash
@@ -209,17 +195,15 @@ apt-get update
209apt-get install nano 195apt-get install nano
210``` 196```
211 197
212Finally, open up `config.php` in the `data` 198Finally, open up `config.php` in the `data` directory:
213directory:
214 199
215```sh 200```sh
216nano data/config.php 201nano data/config.php
217``` 202```
218 203
219Within `config.php`, you will need to update the 204Within `config.php`, you will need to update the `base_url` variable and update
220`base_url` variable and update it to match your external URL. 205it to match your external URL. In my case, I simply commented-out the incorrect
221In my case, I simply commented-out the incorrect URL with 206URL with `//` and added the correct one on a new line:
222`//` and added the correct one on a new line:
223 207
224``` php 208``` php
225<?php 209<?php
@@ -232,9 +216,8 @@ In my case, I simply commented-out the incorrect URL with
232> 216>
233``` 217```
234 218
235You can now exit the file with `Ctrl + x`, press 219You can now exit the file with `Ctrl + x`, press `y` to save the file, and then
236`y` to save the file, and then click `Enter` to 220click `Enter` to keep the same file name.
237keep the same file name.
238 221
239Finally, just exit out of the docker container: 222Finally, just exit out of the docker container:
240 223
@@ -248,8 +231,8 @@ Next, just restart the container:
248sudo docker restart freshrss 231sudo docker restart freshrss
249``` 232```
250 233
251Voilà! Your API check should now \"PASS\" and you should be able to use 234Voilà! Your API check should now "PASS" and you should be able to use one of
252one of the API URLs in your RSS apps. 235the API URLs in your RSS apps.
253 236
254In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop 237In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop and
255and phone. 238phone.
content/blog/2022-06-16-terminal-lifestyle.md +113 −126
@@ -7,165 +7,155 @@ draft = false
7 7
8# Text-Based Simplicity 8# Text-Based Simplicity
9 9
10I\'ve detailed my views on web-based minimalism and related topics in 10I've detailed my views on web-based minimalism and related topics in other
11other posts throughout the years; e.g., JavaScript/CSS bloat slowing 11posts throughout the years; e.g., JavaScript/CSS bloat slowing down websites
12down websites that are essentially a text document. However, I have 12that are essentially a text document. However, I have never really expanded
13never really expanded beyond talking about the web and describing how I 13beyond talking about the web and describing how I focus on minimizing
14focus on minimizing distractions in other digital environments. 14distractions in other digital environments.
15 15
16This post is going to set the baseline for how I *try* to live my 16This post is going to set the baseline for how I *try* to live my digital life.
17digital life. It does not necessarily get into my physical life, which 17It does not necessarily get into my physical life, which is often harder to
18is often harder to control and contain all the noise in our modern 18control and contain all the noise in our modern world.
19world. 19
20 20While there are new things to do every day in our digital world, I find that
21While there are new things to do every day in our digital world, I find 21keeping a core set of values and interests can ground you and keep you mindful
22that keeping a core set of values and interests can ground you and keep 22of *why* you are participating in the digital world. For example, if - at your
23you mindful of *why* you are participating in the digital world. For 23core - you have no interest in what strangers think about random topics, it
24example, if - at your core - you have no interest in what strangers 24would be unwise to start participating in social media. However, I am someone
25think about random topics, it would be unwise to start participating in 25who has been dragged in by effective advertising to participate in communities
26social media. However, I am someone who has been dragged in by effective 26that I realize I do not care for.
27advertising to participate in communities that I realize I do not care 27
28for. 28I won't dive much further into explaining the philosophy of all this, but I
29 29will link a few helpful articles that may pique your interest if you're in
30I won\'t dive much further into explaining the philosophy of all this, 30search of more meaningful experiences:
31but I will link a few helpful articles that may pique your interest if 31
32you\'re in search of more meaningful experiences: 32- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness)
33 33- [Minimalism](https://en.wikipedia.org/wiki/Minimalism)
34- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness) 34- [Stoicism](https://en.wikipedia.org/wiki/Stoicism)
35- [Minimalism](https://en.wikipedia.org/wiki/Minimalism)
36- [Stoicism](https://en.wikipedia.org/wiki/Stoicism)
37 35
38# Living Life in the Terminal 36# Living Life in the Terminal
39 37
40My personal approach to reducing digital distractions and increasing my 38My personal approach to reducing digital distractions and increasing my focus on
41focus on the task at hand is to use a terminal for as much as I possibly 39the task at hand is to use a terminal for as much as I possibly can.
42can.
43 40
44Most days, this means that I have a few tabs open constantly in my 41Most days, this means that I have a few tabs open constantly in my terminal:
45terminal:
46 42
471. A web browser 431. A web browser
482. A chat client 442. A chat client
493. An email client 453. An email client
504. An RSS feed reader 464. An RSS feed reader
515. A local shell for navigating my computer\'s files 475. A local shell for navigating my computer's files
526. A remote shell for managing servers and other machines 486. A remote shell for managing servers and other machines
53 49
54Beyond this, I rarely open other tabs or GUI applications, unless 50Beyond this, I rarely open other tabs or GUI applications, unless absolutely
55absolutely necessary. If you look, you may be surprised what can be 51necessary. If you look, you may be surprised what can be accomplished in the
56accomplished in the terminal. 52terminal.
57 53
58For example, I have moved my music and entertainment downloads to the 54For example, I have moved my music and entertainment downloads to the terminal,
59terminal, along with my device VPN connections. I am exploring options 55along with my device VPN connections. I am exploring options for moving my RSS
60for moving my RSS subscriptions to something like 56subscriptions to something like [Newsboat](https://newsboat.org/), so that I can
61[Newsboat](https://newsboat.org/), so that I can read my daily articles 57read my daily articles without all the fuss.
62without all the fuss.
63 58
64Now that we have some examples out of the way, let\'s dive into the 59Now that we have some examples out of the way, let's dive into the specifics.
65specifics.
66 60
67## Browsing the Web 61## Browsing the Web
68 62
69I\'m going to start off with a hard topic for those who prefer to live 63I'm going to start off with a hard topic for those who prefer to live in the
70in the terminal: web browsing. This task is made hard mostly by websites 64terminal: web browsing. This task is made hard mostly by websites and web apps
71and web apps that require JavaScript to run. The other difficult part is 65that require JavaScript to run. The other difficult part is that if you're
72that if you\'re using a text-based browser, that means images won\'t 66using a text-based browser, that means images won't load (hopefully that's
73load (hopefully that\'s obvious). 67obvious).
74 68
75I am using [Lynx](https://lynx.invisible-island.net), a text-based 69I am using [Lynx](https://lynx.invisible-island.net), a text-based browser that
76browser that runs quickly and easily in the terminal. Lynx allows me to 70runs quickly and easily in the terminal. Lynx allows me to browser most websites
77browser most websites by simply typing `g` and then typing in 71by simply typing `g` and then typing in the URL I want.
78the URL I want.
79 72
80![Lynx](https://img.cleberg.net/blog/20220616-terminal-lifestyle/lynx.png) 73![Lynx](https://img.cleberg.net/blog/20220616-terminal-lifestyle/lynx.png)
81 74
82If you need a search engine while in Lynx, I recommend [DuckDuckGo 75If you need a search engine while in Lynx, I recommend [DuckDuckGo
83(Lite)](https://lite.duckduckgo.com/lite/), which allows you to search 76(Lite)](https://lite.duckduckgo.com/lite/), which allows you to search the web
84the web using their text-only interface. 77using their text-only interface.
85 78
86![DuckDuckGo 79![DuckDuckGo
87!Lite](https://img.cleberg.net/blog/20220616-terminal-lifestyle/ddg.png) 80!Lite](https://img.cleberg.net/blog/20220616-terminal-lifestyle/ddg.png)
88 81
89Eventually, you will run into websites that don\'t work (or are just too 82Eventually, you will run into websites that don't work (or are just too ugly
90ugly and messy) in a text-only mode, and you\'ll be forced to switch 83and messy) in a text-only mode, and you'll be forced to switch over to a GUI
91over to a GUI browser to look at that site. Personally, I don\'t mind 84browser to look at that site. Personally, I don't mind this as it doesn't
92this as it doesn\'t happen as often as I thought it would. 85happen as often as I thought it would.
93 86
94The only time I need to do this is when I want to browse an 87The only time I need to do this is when I want to browse an image/video-focused
95image/video-focused webpage or if I need to log in to a site, and it 88webpage or if I need to log in to a site, and it doesn't support a text-only
96doesn\'t support a text-only login page. For example, I am able to 89login page. For example, I am able to easily log in to
97easily log in to [Sourcehut](https://sr.ht) in lynx. 90[Sourcehut](https://sr.ht) in lynx.
98 91
99## Chatting with Friends 92## Chatting with Friends
100 93
101After web browsing activities, my main form of terminal communication is 94After web browsing activities, my main form of terminal communication is Matrix.
102Matrix. I use the [gomuks](https://docs.mau.fi/gomuks/) client 95I use the [gomuks](https://docs.mau.fi/gomuks/) client currently.
103currently.
104 96
105This was incredibly easy to install on macOS (but I will need to see if 97This was incredibly easy to install on macOS (but I will need to see if it'll
106it\'ll be just as easy on Linux when my new laptop arrives): 98be just as easy on Linux when my new laptop arrives):
107 99
108```sh 100```sh
109brew install gomuks 101brew install gomuks
110``` 102```
111 103
112Once you launch gomuks, it will sync and require your username and 104Once you launch gomuks, it will sync and require your username and password to
113password to login. After doing so, the only problem I ran into was 105login. After doing so, the only problem I ran into was verifying my gomuks
114verifying my gomuks client so that I could participate in rooms with 106client so that I could participate in rooms with E2EE.
115E2EE.
116 107
117Finally, I was able to verify the session by opening the Element desktop 108Finally, I was able to verify the session by opening the Element desktop app (I
118app (I assume you can do this in the browser and mobile app too, but 109assume you can do this in the browser and mobile app too, but I'm not sure) and
119I\'m not sure) and manually verifying myself with this process: 110manually verifying myself with this process:
120 111
1211. Open the Element desktop app 1121. Open the Element desktop app
1222. Open a room I was a member of 1132. Open a room I was a member of
1233. Open the `Room Info` pane 1143. Open the `Room Info` pane
1244. Open the `People` menu and search for myself 1154. Open the `People` menu and search for myself
1255. Click on my profile name 1165. Click on my profile name
1266. Click on the session link under the `Security` section 1176. Click on the session link under the `Security` section and follow the prompts
127 and follow the prompts to manually verify the session 118 to manually verify the session
128 119
129Overall, I like gomuks and am able to enjoy all the features I was using 120Overall, I like gomuks and am able to enjoy all the features I was using in
130in Element. The only hiccup I have occurred is manually downloading 121Element. The only hiccup I have occurred is manually downloading images to view
131images to view them, which can be annoying. 122them, which can be annoying.
132 123
133![gomuks](https://img.cleberg.net/blog/20220616-terminal-lifestyle/gomuks.png) 124![gomuks](https://img.cleberg.net/blog/20220616-terminal-lifestyle/gomuks.png)
134 125
135## Email 126## Email
136 127
137Moving email to the terminal has been the hardest of the tasks for me. 128Moving email to the terminal has been the hardest of the tasks for me. Unlike
138Unlike web browsing, where I can simply decide to not look at a website 129web browsing, where I can simply decide to not look at a website that does not
139that does not work in the terminal, I cannot simply ignore emails sent 130work in the terminal, I cannot simply ignore emails sent to me.
140to me.
141 131
142Personally, I am experimenting with [neomutt](https://neomutt.org/) as a 132Personally, I am experimenting with [neomutt](https://neomutt.org/) as a
143potential email client. 133potential email client.
144 134
145However, this requires a **TON\*** of configuration and tweaking to get 135However, this requires a **TON** of configuration and tweaking to get right.
146right. Even when I was able to set up neomutt, configure my email 136Even when I was able to set up neomutt, configure my email account, and
147account, and customize a few personal preferences, a lot of emails still 137customize a few personal preferences, a lot of emails still do not display
148do not display correctly (mostly due to HTML and images). 138correctly (mostly due to HTML and images).
149 139
150I won\'t get into the details of configuring `neomutt`; I 140I won't get into the details of configuring `neomutt`; I mostly followed this
151mostly followed this blog post: [Email in the Terminal: Configuring 141blog post: [Email in the Terminal: Configuring
152Neomutt](https://gideonwolfe.com/posts/workflow/neomutt/intro/). 142Neomutt](https://gideonwolfe.com/posts/workflow/neomutt/intro/).
153 143
154Finally, I have yet to figure out how to connect my GPG keys to 144Finally, I have yet to figure out how to connect my GPG keys to `neomutt`, but
155`neomutt`, but that\'s a problem for another day. 145that's a problem for another day.
156 146
157## RSS Feed Reader 147## RSS Feed Reader
158 148
159I have just started using [Newsboat](https://newsboat.org/) to read 149I have just started using [Newsboat](https://newsboat.org/) to read articles in
160articles in my terminal and have found quick success with it. 150my terminal and have found quick success with it.
161 151
162I\'ll show you a quick screenshot first: 152I'll show you a quick screenshot first:
163 153
164![Newsboat](https://img.cleberg.net/blog/20220616-terminal-lifestyle/newsboat.png) 154![Newsboat](https://img.cleberg.net/blog/20220616-terminal-lifestyle/newsboat.png)
165 155
166The configuration was super easy for this app; I simply installed the 156The configuration was super easy for this app; I simply installed the app,
167app, created a file for URLs, and imported my OPML subscriptions that I 157created a file for URLs, and imported my OPML subscriptions that I had exported
168had exported out of my old feed reader: 158out of my old feed reader:
169 159
170```sh 160```sh
171brew install newsboat 161brew install newsboat
@@ -181,13 +171,12 @@ newsboat -i=my_subscriptions.opml
181 171
182## Writing & Programming 172## Writing & Programming
183 173
184Unfortunately, the weak link in my terminal-based environment right now 174Unfortunately, the weak link in my terminal-based environment right now is my
185is my grasp of the possibilities of editing files within a shell. 175grasp of the possibilities of editing files within a shell.
186 176
187I am used to the easy extensions found in VSCodium and Kate, so I am 177I am used to the easy extensions found in VSCodium and Kate, so I am slowly
188slowly learning how to mold the default editing tools to my needs. 178learning how to mold the default editing tools to my needs. Currently, this
189Currently, this means I am using `nano` with the following 179means I am using `nano` with the following configuration:
190configuration:
191 180
192``` config 181``` config
193set breaklonglines 182set breaklonglines
@@ -199,18 +188,16 @@ set fill 80
199``` 188```
200 189
201This configuration allows nano to automatically hard-wrap lines at 80 190This configuration allows nano to automatically hard-wrap lines at 80
202characters, autoindent the wrapped lines (if the previous line was 191characters, autoindent the wrapped lines (if the previous line was indented),
203indented), use 2 spaces per tab, and display line numbers within each 192use 2 spaces per tab, and display line numbers within each file I open.
204file I open. 193
205 194I am currently looking to see if `vim` or `emacs` would be more useful for my
206I am currently looking to see if `vim` or `emacs` 195current needs, but I'm not in any rush, so I don't expect to find an answer
207would be more useful for my current needs, but I\'m not in any rush, so 196anytime soon.
208I don\'t expect to find an answer anytime soon. 197
209 198With my current life demands, I am not programming at the moment and have not
210With my current life demands, I am not programming at the moment and 199explored the best terminal set-up for programming. However, I have seen many
211have not explored the best terminal set-up for programming. However, I 200peers find success configuring `vim` and `emacs`, so that's where I will start
212have seen many peers find success configuring `vim` and 201when I pick my projects back up.
213`emacs`, so that\'s where I will start when I pick my
214projects back up.
215 202
216![nano](https://img.cleberg.net/blog/20220616-terminal-lifestyle/nano.png) 203![nano](https://img.cleberg.net/blog/20220616-terminal-lifestyle/nano.png)
content/blog/2022-06-22-daily-poetry.md +51 −59
@@ -7,9 +7,8 @@ draft = false
7 7
8# Source Code 8# Source Code
9 9
10I don\'t want to bury the lede here, so if you\'d like to see the full 10I don't want to bury the lede here, so if you'd like to see the full source
11source code I use to email myself plaintext poems daily, visit the 11code I use to email myself plaintext poems daily, visit the repository:
12repository:
13[daily-poem.git](https://git.cleberg.net/?p=daily-poem.git;a=summary). 12[daily-poem.git](https://git.cleberg.net/?p=daily-poem.git;a=summary).
14 13
15# My Daily Dose of Poetry 14# My Daily Dose of Poetry
@@ -17,36 +16,35 @@ repository:
17Most of my programming projects are small, random projects that are made 16Most of my programming projects are small, random projects that are made
18strictly to fix some small problem I have or enhance my quality of life. 17strictly to fix some small problem I have or enhance my quality of life.
19 18
20In this case, I was looking for a simply and easy way to get a daily 19In this case, I was looking for a simply and easy way to get a daily dose of
21dose of literature or poetry to read in the mornings. 20literature or poetry to read in the mornings.
22 21
23However, I don\'t want to sign up for a random mailing list on just any 22However, I don't want to sign up for a random mailing list on just any website.
24website. I also don\'t want to have to work to find the reading content 23I also don't want to have to work to find the reading content each morning, as
25each morning, as I know I would simply give up and stop reading daily. 24I know I would simply give up and stop reading daily.
26 25
27Thus, I found a way to deliver poetry to myself in plain-text format, on 26Thus, I found a way to deliver poetry to myself in plain-text format, on a daily
28a daily basis, and scheduled to deliver automatically. 27basis, and scheduled to deliver automatically.
29 28
30# Prerequisites 29# Prerequisites
31 30
32This solution uses Python and email, so the following process requires 31This solution uses Python and email, so the following process requires the
33the following to be installed: 32following to be installed:
34 33
351. An SMTP server, which can be as easy as installing 341. An SMTP server, which can be as easy as installing `mailutils` if you're on
36 `mailutils` if you\'re on a Debian-based distro. 35 a Debian-based distro.
372. Python (& pip!) 362. Python (& pip!)
383. The following Python packages: `email`, 373. The following Python packages: `email`, `smtplib`, `json`, and `requests`
39 `smtplib`, `json`, and `requests`
40 38
41# Breaking Down the Logic 39# Breaking Down the Logic
42 40
43I want to break down the logic for this program, as it\'s quite simple 41I want to break down the logic for this program, as it's quite simple and
44and informational. 42informational.
45 43
46## Required Packages 44## Required Packages
47 45
48This program starts with a simple import of the required packages, so I 46This program starts with a simple import of the required packages, so I wanted
49wanted to explain why each package is used: 47to explain why each package is used:
50 48
51``` python 49``` python
52from email.mime.text import MIMEText # Required for translating MIMEText 50from email.mime.text import MIMEText # Required for translating MIMEText
@@ -57,9 +55,9 @@ import requests # Required to send out a request to the API
57 55
58## Sending the API Request 56## Sending the API Request
59 57
60Next, we need to actually send the API request. In my case, I\'m calling 58Next, we need to actually send the API request. In my case, I'm calling a
61a random poem from the entire API. If you want, you can call specific 59random poem from the entire API. If you want, you can call specific poems or
62poems or authors from this API. 60authors from this API.
63 61
64``` python 62``` python
65json_data = requests.get('https://poetrydb.org/random').json() 63json_data = requests.get('https://poetrydb.org/random').json()
@@ -97,24 +95,22 @@ This gives us the following result in JSON:
97 95
98## Parsing the API Results 96## Parsing the API Results
99 97
100In order to parse this into a readable format, we need to use the 98In order to parse this into a readable format, we need to use the `json` package
101`json` package and extract the fields we want. In the example 99and extract the fields we want. In the example below, I am grabbing every field
102below, I am grabbing every field presented by the API. 100presented by the API.
103 101
104For the actual poem content, we need to loop over each line in the 102For the actual poem content, we need to loop over each line in the `lines`
105`lines` variable since each line is a separate string by 103variable since each line is a separate string by default.
106default.
107 104
108> You *could* also extract the title or author and make another call out 105> You *could* also extract the title or author and make another call out to the
109> to the API to avoid having to build the plaintext poem with a loop, 106> API to avoid having to build the plaintext poem with a loop, but it just
110> but it just doesn\'t make sense to me to send multiple requests when 107> doesn't make sense to me to send multiple requests when we can create a
111> we can create a simple loop on our local machine to work with the data 108> simple loop on our local machine to work with the data we already have.
112> we already have.
113> 109>
114> For 110> For
115> [example](https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text), 111> [example](https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text),
116> look at the raw data response of this link to see the poem\'s lines 112> look at the raw data response of this link to see the poem's lines returned
117> returned in plaintext. 113> in plaintext.
118 114
119``` python 115``` python
120title = json_data[0]['title'] 116title = json_data[0]['title']
@@ -127,21 +123,20 @@ for line in json_data[0]['lines']:
127 123
128## Composing the Email 124## Composing the Email
129 125
130Now that I have all the data I need, I just need to compose it into a 126Now that I have all the data I need, I just need to compose it into a message
131message and prepare the message metadata. 127and prepare the message metadata.
132 128
133For my daily email, I want to see the title of the poem first, followed 129For my daily email, I want to see the title of the poem first, followed by the
134by the author, then a blank line, and finally the full poem. This code 130author, then a blank line, and finally the full poem. This code snippet combines
135snippet combines that data and packages it into a MIMEText container, 131that data and packages it into a MIMEText container, ready to be emailed.
136ready to be emailed.
137 132
138``` python 133``` python
139msg_body = title + "\n" + author + "\n\n" + lines 134msg_body = title + "\n" + author + "\n\n" + lines
140msg = MIMEText(msg_body) 135msg = MIMEText(msg_body)
141``` 136```
142 137
143Before we send the email, we need to prepare the metadata (subject, 138Before we send the email, we need to prepare the metadata (subject, from, to,
144from, to, etc.): 139etc.):
145 140
146``` python 141``` python
147sender_email = 'example@server.local' 142sender_email = 'example@server.local'
@@ -153,10 +148,9 @@ msg['To'] = recipient_email
153 148
154## Sending the Email 149## Sending the Email
155 150
156Now that I have everything ready to be emailed, the last step is to 151Now that I have everything ready to be emailed, the last step is to simply
157simply connect to an SMTP server and send the email out to the 152connect to an SMTP server and send the email out to the recipients. In my case,
158recipients. In my case, I installed `mailutils` on Ubuntu and 153I installed `mailutils` on Ubuntu and let my SMTP server be `localhost`.
159let my SMTP server be `localhost`.
160 154
161``` python 155``` python
162smtp_server = 'localhost' 156smtp_server = 'localhost'
@@ -167,9 +161,8 @@ s.quit()
167 161
168# The Result! 162# The Result!
169 163
170Instead of including a screenshot, I\'ve copied the contents of the 164Instead of including a screenshot, I've copied the contents of the email that
171email that was delivered to my inbox below since I set this process up 165was delivered to my inbox below since I set this process up in plaintext format.
172in plaintext format.
173 166
174``` txt 167``` txt
175Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC) 168Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
@@ -201,18 +194,17 @@ Some, wise in show, more fools indeed than they.
201 194
202# Scheduling the Daily Email 195# Scheduling the Daily Email
203 196
204Last, but not least, is scheduling this Python script with 197Last, but not least, is scheduling this Python script with `crontab`. To
205`crontab`. To schedule a script to run daily, you can add it 198schedule a script to run daily, you can add it to the `crontab` file. To do
206to the `crontab` file. To do this, open `crontab` 199this, open `crontab` in editing mode:
207in editing mode:
208 200
209```sh 201```sh
210crontab -e 202crontab -e
211``` 203```
212 204
213In the file, simply paste the following snippet at the bottom of the 205In the file, simply paste the following snippet at the bottom of the file and
214file and ensure that the file path is correctly pointing to wherever you 206ensure that the file path is correctly pointing to wherever you saved your
215saved your Python script: 207Python script:
216 208
217``` config 209``` config
2180 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py 2100 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py
content/blog/2022-06-24-fedora-i3.md +34 −35
@@ -15,20 +15,19 @@ world of Linux again.
15My decision to leave macOS really came down to just a few important 15My decision to leave macOS really came down to just a few important
16things: 16things:
17 17
18- Apple Security (Gatekeeper) restricting me from running any software 18- Apple Security (Gatekeeper) restricting me from running any software I want.
19 I want. Even if you disable Gatekeeper and allow software to bypass 19 Even if you disable Gatekeeper and allow software to bypass the rest of the
20 the rest of the device installation security, you still have to 20 device installation security, you still have to repeat that process every time
21 repeat that process every time the allowed software is updated. 21 the allowed software is updated.
22- macOS sends out nearly constant connections, pings, telemetry, etc. 22- macOS sends out nearly constant connections, pings, telemetry, etc. to a
23 to a myriad of mysterious Apple services. I\'m not even going to 23 myriad of mysterious Apple services. I'm not even going to dive into how many
24 dive into how many macOS apps have constant telemetry on, as well. 24 macOS apps have constant telemetry on, as well.
25- Lastly, I just *really* missed the customization and freedom that 25- Lastly, I just *really* missed the customization and freedom that comes with
26 comes with Linux. Being able to switch to entirely new kernel, OS, 26 Linux. Being able to switch to entirely new kernel, OS, or desktop within
27 or desktop within minutes is a freedom I took for granted when I 27 minutes is a freedom I took for granted when I switched to macOS.
28 switched to macOS. 28
29 29Now that I've covered macOS, I'm going to move on to more exciting
30Now that I\'ve covered macOS, I\'m going to move on to more exciting 30topics: my personal choice of OS, DE, and various customizations I'm
31topics: my personal choice of OS, DE, and various customizations I\'m
32using. 31using.
33 32
34# Fedora 33# Fedora
@@ -37,8 +36,8 @@ After trying a ton of distros (I think I booted and tested around 20-25
37distros), I finally landed on [Fedora Linux](https://getfedora.org/). I 36distros), I finally landed on [Fedora Linux](https://getfedora.org/). I
38have quite a bit of experience with Fedora and enjoy the 37have quite a bit of experience with Fedora and enjoy the
39`dnf` package manager. Fedora allows me to keep up-to-date 38`dnf` package manager. Fedora allows me to keep up-to-date
40with recent software (I\'m looking at you, Debian), but still provides a 39with recent software (I'm looking at you, Debian), but still provides a
41level of stability you don\'t find in every distro. 40level of stability you don't find in every distro.
42 41
43In a very close second place was Arch Linux, as well as its spin-off: 42In a very close second place was Arch Linux, as well as its spin-off:
44Garuda Linux (Garuda w/ sway is *beautiful*). Arch is great for 43Garuda Linux (Garuda w/ sway is *beautiful*). Arch is great for
@@ -47,8 +46,8 @@ had the time to properly sit down and learn the methodology behind their
47packaging systems. 46packaging systems.
48 47
49Basically, everything else I tested was unacceptable in at least one way 48Basically, everything else I tested was unacceptable in at least one way
50or another. Void (`glibc`) was great, but doesn\'t support 49or another. Void (`glibc`) was great, but doesn't support
51all the software I need. Slackware worked well as a tui, but I wasn\'t 50all the software I need. Slackware worked well as a tui, but I wasn't
52skilled enough to get a tiling window manager (WM) working on it. 51skilled enough to get a tiling window manager (WM) working on it.
53 52
54## i3 53## i3
@@ -57,7 +56,7 @@ One of the reasons I settled on Fedora is that it comes with an official
57i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of 56i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of
58the biggest things I wanted to do as soon as I adopted Linux again. 57the biggest things I wanted to do as soon as I adopted Linux again.
59 58
60I will probably set up a dotfile repository soon, so that I don\'t lose 59I will probably set up a dotfile repository soon, so that I don't lose
61any of my configurations, but nothing big has been configured thus far. 60any of my configurations, but nothing big has been configured thus far.
62 61
63The two main things I have updated in i3wm are natural scrolling and 62The two main things I have updated in i3wm are natural scrolling and
@@ -123,37 +122,37 @@ binding my brightness keys to the `brightnessctl` program.
123 122
124 My config for this menu bar is basically just the default settings 123 My config for this menu bar is basically just the default settings
125 with modified colors and an added battery block to quickly show me 124 with modified colors and an added battery block to quickly show me
126 the machine\'s battery info. 125 the machine's battery info.
127 126
1284. `alacritty` 1274. `alacritty`
129 128
130 Not much to say on this part yet, as I haven\'t configured it much, 129 Not much to say on this part yet, as I haven't configured it much,
131 but I installed `alacritty` as my default terminal, and I 130 but I installed `alacritty` as my default terminal, and I
132 am using `zsh` and the shell. 131 am using `zsh` and the shell.
133 132
134# Software Choices 133# Software Choices
135 134
136Again, I\'m not going to say much that I haven\'t said yet in other blog 135Again, I'm not going to say much that I haven't said yet in other blog
137posts, so I\'ll just do a quick rundown of the apps I installed 136posts, so I'll just do a quick rundown of the apps I installed
138immediately after I set up the environment. 137immediately after I set up the environment.
139 138
140Flatpak Apps: 139Flatpak Apps:
141 140
142- Cryptomator 141- Cryptomator
143- pCloud 142- pCloud
144- Signal 143- Signal
145 144
146Fedora Packages: 145Fedora Packages:
147 146
148- gomuks 147- gomuks
149- neomutt 148- neomutt
150- neofetch 149- neofetch
151- Firefox 150- Firefox
152 - uBlock Origin 151 - uBlock Origin
153 - Bitwarden 152 - Bitwarden
154 - Stylus 153 - Stylus
155 - Privacy Redirect 154 - Privacy Redirect
156 155
157Other: 156Other:
158 157
159- exiftool 158- exiftool
content/blog/2022-07-01-git-server.md +151 −182
@@ -7,60 +7,54 @@ draft = false
7 7
8# My Approach to Self-Hosting Git 8# My Approach to Self-Hosting Git
9 9
10I have often tried to self-host my Git repositories, but have always 10I have often tried to self-host my Git repositories, but have always fallen
11fallen short when I tried to find a suitable web interface to show on 11short when I tried to find a suitable web interface to show on the front-end.
12the front-end. 12
13 13After a few years, I have finally found a combination of methods that allow me
14After a few years, I have finally found a combination of methods that 14to easily self-host my projects, view them on the web, and access them from
15allow me to easily self-host my projects, view them on the web, and 15anywhere.
16access them from anywhere. 16
17 17Before I dive into the details, I want to state a high-level summary of my
18Before I dive into the details, I want to state a high-level summary of 18self-hosted Git approach:
19my self-hosted Git approach: 19
20 20- This method uses the `ssh://` (read & write) and `git://` (read-only)
21- This method uses the `ssh://` (read & write) and 21 protocols for push and pull access.
22 `git://` (read-only) protocols for push and pull access. 22 - For the `git://` protocol, I create a `git-daemon-export-ok` file in any
23 - For the `git://` protocol, I create a 23 repository that I want to be cloneable by anyone.
24 `git-daemon-export-ok` file in any repository that I 24 - The web interface I am using (`cgit`) allows simple HTTP cloning by default.
25 want to be cloneable by anyone. 25 I do not disable this setting as I want beginners to be able to clone one of
26 - The web interface I am using (`cgit`) allows simple 26 my repositories even if they don't know the proper method.
27 HTTP cloning by default. I do not disable this setting as I want 27- I am not enabling Smart HTTPS for any repositories. Updates to repositories
28 beginners to be able to clone one of my repositories even if 28 must be pushed via SSH.
29 they don\'t know the proper method. 29- Beyond the actual repository management, I am using `cgit` for the front-end
30- I am not enabling Smart HTTPS for any repositories. Updates to 30 web interface.
31 repositories must be pushed via SSH. 31 - If you use the `scan-path=<path>` configuration in the `cgitrc`
32- Beyond the actual repository management, I am using 32 configuration file to automatically find repositories, you can't exclude a
33 `cgit` for the front-end web interface. 33 repository from `cgit` if it's stored within the path that `cgit` reads. To
34 - If you use the `scan-path=<path>` configuration in 34 host private repositories, you'd need to set up another directory that
35 the `cgitrc` configuration file to automatically find 35 `cgit` can't read.
36 repositories, you can\'t exclude a repository from
37 `cgit` if it\'s stored within the path that
38 `cgit` reads. To host private repositories, you\'d
39 need to set up another directory that `cgit` can\'t
40 read.
41 36
42# Assumptions 37# Assumptions
43 38
44For the purposes of this walkthrough, I am assuming you have a URL 39For the purposes of this walkthrough, I am assuming you have a URL
45(`git.example.com`) or IP address 40(`git.example.com`) or IP address (`207.84.26.991`) addressed to the server that
46(`207.84.26.991`) addressed to the server that you will be 41you will be using to host your git repositories.
47using to host your git repositories.
48 42
49# Adding a Git User 43# Adding a Git User
50 44
51In order to use the SSH method associated with git, we will need to add 45In order to use the SSH method associated with git, we will need to add a user
52a user named `git`. If you have used the SSH method for other 46named `git`. If you have used the SSH method for other git hosting sites, you
53git hosting sites, you are probably used to the following syntax: 47are probably used to the following syntax:
54 48
55```sh 49```sh
56git clone [user@]server:project.git 50git clone [user@]server:project.git
57``` 51```
58 52
59The syntax above is an `scp`-like syntax for using SSH on the 53The syntax above is an `scp`-like syntax for using SSH on the `git` user on the
60`git` user on the server to access your repository. 54server to access your repository.
61 55
62Let\'s delete any remnants of an old `git` user, if any, and 56Let's delete any remnants of an old `git` user, if any, and create the new user
63create the new user account: 57account:
64 58
65```sh 59```sh
66sudo deluser --remove-home git 60sudo deluser --remove-home git
@@ -69,21 +63,19 @@ sudo adduser git
69 63
70## Import Your SSH Keys to the Git User 64## Import Your SSH Keys to the Git User
71 65
72Once the `git` user is created, you will need to copy your 66Once the `git` user is created, you will need to copy your public SSH key on
73public SSH key on your local development machine to the `git` 67your local development machine to the `git` user on the server.
74user on the server.
75 68
76If you don\'t have an SSH key yet, create one with this command: 69If you don't have an SSH key yet, create one with this command:
77 70
78```sh 71```sh
79ssh-keygen 72ssh-keygen
80``` 73```
81 74
82Once you create the key pair, the public should be saved to 75Once you create the key pair, the public should be saved to `~/.ssh/id_rsa.pub`.
83`~/.ssh/id_rsa.pub`.
84 76
85If your server still has password-based authentication available, you 77If your server still has password-based authentication available, you can copy
86can copy it over to your user\'s home directory like this: 78it over to your user's home directory like this:
87 79
88```sh 80```sh
89ssh-copy-id git@server 81ssh-copy-id git@server
@@ -95,8 +87,8 @@ Otherwise, copy it over to any user that you can access.
95scp ~/.ssh/id_rsa.pub your_user@your_server: 87scp ~/.ssh/id_rsa.pub your_user@your_server:
96``` 88```
97 89
98Once on the server, you will need to copy the contents into the 90Once on the server, you will need to copy the contents into the `git` user's
99`git` user\'s `authorized_keys` file: 91`authorized_keys` file:
100 92
101```sh 93```sh
102cat id_rsa.pub > /home/git/.ssh/authorized_keys 94cat id_rsa.pub > /home/git/.ssh/authorized_keys
@@ -104,16 +96,15 @@ cat id_rsa.pub > /home/git/.ssh/authorized_keys
104 96
105## (Optional) Disable Password-Based SSH 97## (Optional) Disable Password-Based SSH
106 98
107If you want to lock down your server and ensure that no one can 99If you want to lock down your server and ensure that no one can authenticate in
108authenticate in via SSH with a password, you will need to edit your SSH 100via SSH with a password, you will need to edit your SSH configuration.
109configuration.
110 101
111```sh 102```sh
112sudo nano /etc/ssh/sshd_config 103sudo nano /etc/ssh/sshd_config
113``` 104```
114 105
115Within this file, find the following settings and set them to the values 106Within this file, find the following settings and set them to the values I am
116I am showing below: 107showing below:
117 108
118``` conf 109``` conf
119PermitRootLogin no 110PermitRootLogin no
@@ -121,19 +112,17 @@ PasswordAuthentication no
121AuthenticationMethods publickey 112AuthenticationMethods publickey
122``` 113```
123 114
124You may have other Authentication Methods required in your personal 115You may have other Authentication Methods required in your personal set-up, so
125set-up, so the key here is just to ensure that 116the key here is just to ensure that `AuthenticationMethods` does not allow
126`AuthenticationMethods` does not allow passwords. 117passwords.
127 118
128### Setting up the Base Directory 119### Setting up the Base Directory
129 120
130Now that we have set up a `git` user to handle all transport 121Now that we have set up a `git` user to handle all transport methods, we need to
131methods, we need to set up the directory that we will be using as our 122set up the directory that we will be using as our base of all repositories.
132base of all repositories.
133 123
134In my case, I am using `/git` as my source folder. To create 124In my case, I am using `/git` as my source folder. To create this folder and
135this folder and assign it to the user we created, execute the following 125assign it to the user we created, execute the following commands:
136commands:
137 126
138```sh 127```sh
139sudo mkdir /git 128sudo mkdir /git
@@ -142,15 +131,15 @@ sudo chown -R git:git /git
142 131
143### Creating a Test Repository 132### Creating a Test Repository
144 133
145On your server, switch over to the `git` user in order to 134On your server, switch over to the `git` user in order to start managing git
146start managing git files. 135files.
147 136
148```sh 137```sh
149su git 138su git
150``` 139```
151 140
152Once logged-in as the `git` user, go to your base directory 141Once logged-in as the `git` user, go to your base directory and create a test
153and create a test repository. 142repository.
154 143
155```sh 144```sh
156cd /git 145cd /git
@@ -158,9 +147,9 @@ mkdir test.git && cd test.git
158git init --bare 147git init --bare
159``` 148```
160 149
161If you want to make this repo viewable/cloneable to the public via the 150If you want to make this repo viewable/cloneable to the public via the `git://`
162`git://` protocol, you need to create a 151protocol, you need to create a `git-daemon-export-ok` file inside the
163`git-daemon-export-ok` file inside the repository. 152repository.
164 153
165```sh 154```sh
166touch git-daemon-export-ok 155touch git-daemon-export-ok
@@ -168,34 +157,33 @@ touch git-daemon-export-ok
168 157
169# Change the Login Shell for `git` 158# Change the Login Shell for `git`
170 159
171To make sure that the `git` user is only used for git 160To make sure that the `git` user is only used for git operations and nothing
172operations and nothing else, you need to change the user\'s login shell. 161else, you need to change the user's login shell. To do this, simply use the
173To do this, simply use the `chsh` command: 162`chsh` command:
174 163
175```sh 164```sh
176sudo chsh git 165sudo chsh git
177``` 166```
178 167
179The interactive prompt will ask which shell you want the 168The interactive prompt will ask which shell you want the `git` user to use. You
180`git` user to use. You must use the following value: 169must use the following value:
181 170
182```sh 171```sh
183/usr/bin/git-shell 172/usr/bin/git-shell
184``` 173```
185 174
186Once done, no one will be able to SSH to the `git` user or 175Once done, no one will be able to SSH to the `git` user or execute commands
187execute commands other than the standard git commands. 176other than the standard git commands.
188 177
189# Opening the Firewall 178# Opening the Firewall
190 179
191Don\'t forget to open up ports on the device firewall and network 180Don't forget to open up ports on the device firewall and network firewall if
192firewall if you want to access these repositories publicly. If you\'re 181you want to access these repositories publicly. If you're using default ports,
193using default ports, forward ports `22` (ssh) and 182forward ports `22` (ssh) and `9418` (git) from your router to your server's IP
194`9418` (git) from your router to your server\'s IP address. 183address.
195 184
196If your server also has a firewall, ensure that the firewall allows the 185If your server also has a firewall, ensure that the firewall allows the same
197same ports that are forwarded from the router. For example, if you use 186ports that are forwarded from the router. For example, if you use `ufw`:
198`ufw`:
199 187
200```sh 188```sh
201sudo ufw allow 22 189sudo ufw allow 22
@@ -204,12 +192,12 @@ sudo ufw allow 9418
204 192
205## Non-Standard SSH Ports 193## Non-Standard SSH Ports
206 194
207If you use a non-standard port for SSH, such as `9876`, you 195If you use a non-standard port for SSH, such as `9876`, you will need to create
208will need to create an SSH configuration file on your local development 196an SSH configuration file on your local development machine in order to connect
209machine in order to connect to your server\'s git repositories. 197to your server's git repositories.
210 198
211To do this, you\'ll need to define your custom port on your client 199To do this, you'll need to define your custom port on your client machine in
212machine in your `~/.ssh/config` file: 200your `~/.ssh/config` file:
213 201
214```sh 202```sh
215nano ~/.ssh/config 203nano ~/.ssh/config
@@ -227,11 +215,11 @@ Host git.example.com
227 215
228There are two main syntaxes you can use to manage git over SSH: 216There are two main syntaxes you can use to manage git over SSH:
229 217
230- `git clone [user@]server:project.git` 218- `git clone [user@]server:project.git`
231- `git clone ssh://[user@]server/project.git` 219- `git clone ssh://[user@]server/project.git`
232 220
233I prefer the first, which is an `scp`-like syntax. To test 221I prefer the first, which is an `scp`-like syntax. To test it, try to clone the
234it, try to clone the test repository you set up on the server: 222test repository you set up on the server:
235 223
236```sh 224```sh
237git clone git@git.example.com:/git/test.git 225git clone git@git.example.com:/git/test.git
@@ -239,9 +227,8 @@ git clone git@git.example.com:/git/test.git
239 227
240# Enabling Read-Only Access 228# Enabling Read-Only Access
241 229
242If you want people to be able to clone any repository where you\'ve 230If you want people to be able to clone any repository where you've placed a
243placed a `git-daemon-export-ok` file, you will need to start 231`git-daemon-export-ok` file, you will need to start the git daemon.
244the git daemon.
245 232
246To do this on a system with `systemd`, create a service file: 233To do this on a system with `systemd`, create a service file:
247 234
@@ -279,8 +266,7 @@ sudo systemctl enable git-daemon.service
279sudo systemctl start git-daemon.service 266sudo systemctl start git-daemon.service
280``` 267```
281 268
282To clone read-only via the `git://` protocol, you can use the 269To clone read-only via the `git://` protocol, you can use the following syntax:
283following syntax:
284 270
285```sh 271```sh
286git clone git://git.example.com/test.git 272git clone git://git.example.com/test.git
@@ -291,9 +277,9 @@ git clone git://git.example.com/test.git
291At this point, we have a working git server that works with both SSH and 277At this point, we have a working git server that works with both SSH and
292read-only access. 278read-only access.
293 279
294For each of the repositories I had hosted a different provider, I 280For each of the repositories I had hosted a different provider, I executed the
295executed the following commands in order to place a copy on my server as 281following commands in order to place a copy on my server as my new source of
296my new source of truth: 282truth:
297 283
298Server: 284Server:
299 285
@@ -316,23 +302,20 @@ git push
316 302
317# Optional Web View: `cgit` 303# Optional Web View: `cgit`
318 304
319If you want a web viewer for your repositories, you can use various 305If you want a web viewer for your repositories, you can use various tools, such
320tools, such as `gitweb`, `cgit`, or 306as `gitweb`, `cgit`, or `klaus`. I chose `cgit` due to its simple interface and
321`klaus`. I chose `cgit` due to its simple 307fairly easy set-up (compared to others). Not to mention that the [Linux kernel
322interface and fairly easy set-up (compared to others). Not to mention 308uses `cgit`](https://git.kernel.org/).
323that the [Linux kernel uses `cgit`](https://git.kernel.org/).
324 309
325## Docker Compose 310## Docker Compose
326 311
327Instead of using my previous method of using a `docker run` 312Instead of using my previous method of using a `docker run` command, I've
328command, I\'ve updated this section to use `docker-compose` 313updated this section to use `docker-compose` instead for an easier installation
329instead for an easier installation and simpler management and 314and simpler management and configuration.
330configuration.
331 315
332In order to use Docker Compose, you will set up a 316In order to use Docker Compose, you will set up a `docker-compose.yml` file to
333`docker-compose.yml` file to automatically connect resources 317automatically connect resources like the repositories, `cgitrc`, and various
334like the repositories, `cgitrc`, and various files or folders 318files or folders to the `cgit` container you're creating:
335to the `cgit` container you\'re creating:
336 319
337```sh 320```sh
338mkdir ~/cgit && cd ~/cgit 321mkdir ~/cgit && cd ~/cgit
@@ -363,17 +346,16 @@ Then, just start the container:
363sudo docker-compose up -d 346sudo docker-compose up -d
364``` 347```
365 348
366Once it\'s finished installing, you can access the site at 349Once it's finished installing, you can access the site at `<SERVER_IP>:8763` or
367`<SERVER_IP>:8763` or use a reverse-proxy service to forward 350use a reverse-proxy service to forward `cgit` to a URL, such as
368`cgit` to a URL, such as `git.example.com`. See 351`git.example.com`. See the next section for more details on reverse proxying a
369the next section for more details on reverse proxying a URL to a local 352URL to a local port.
370port.
371 353
372## Nginx Reverse Proxy 354## Nginx Reverse Proxy
373 355
374I am using Nginx as my reverse proxy so that the `cgit` 356I am using Nginx as my reverse proxy so that the `cgit` Docker container can use
375Docker container can use `git.example.com` as its URL. To do 357`git.example.com` as its URL. To do so, I simply created the following
376so, I simply created the following configuration file: 358configuration file:
377 359
378```sh 360```sh
379sudo nano /etc/nginx/sites-available/git.example.com 361sudo nano /etc/nginx/sites-available/git.example.com
@@ -422,29 +404,26 @@ sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/
422sudo systemctl restart nginx.service 404sudo systemctl restart nginx.service
423``` 405```
424 406
425As we can see below, my site at `git.example.com` is 407As we can see below, my site at `git.example.com` is available and running:
426available and running:
427 408
428## Settings Up Git Details 409## Settings Up Git Details
429 410
430Once you have `cgit` running, you can add some small details, 411Once you have `cgit` running, you can add some small details, such as repository
431such as repository owners and descriptions by editing the following 412owners and descriptions by editing the following files within each repository.
432files within each repository.
433 413
434Alternatively, you can use the `cgitrc` file to edit these 414Alternatively, you can use the `cgitrc` file to edit these details if you only
435details if you only care to edit them for the purpose of seeing them on 415care to edit them for the purpose of seeing them on your website.
436your website.
437 416
438The `description` file within the repository on your server 417The `description` file within the repository on your server will display the
439will display the description online. 418description online.
440 419
441```sh 420```sh
442cd /git/example.git 421cd /git/example.git
443nano description 422nano description
444``` 423```
445 424
446You can add a `[gitweb]` block to the `config` 425You can add a `[gitweb]` block to the `config` file in order to display the
447file in order to display the owner of the repository. 426owner of the repository.
448 427
449```sh 428```sh
450cd /git/example.git 429cd /git/example.git
@@ -456,21 +435,20 @@ nano config
456 owner = "YourName" 435 owner = "YourName"
457``` 436```
458 437
459Note that you can ignore the configuration within each repository and 438Note that you can ignore the configuration within each repository and simply set
460simply set up this information in the `cgitrc` file, if you 439up this information in the `cgitrc` file, if you want to do it that way.
461want to do it that way.
462 440
463## Editing `cgit` 441## Editing `cgit`
464 442
465In order to edit certain items within `cgit`, you need to 443In order to edit certain items within `cgit`, you need to edit the `cgitrc`
466edit the `cgitrc` file. 444file.
467 445
468```sh 446```sh
469nano ~/cgit/cgitrc 447nano ~/cgit/cgitrc
470``` 448```
471 449
472Below is an example configuration for `cgitrc`. You can find 450Below is an example configuration for `cgitrc`. You can find all the
473all the configuration options within the \[configuration manual\] 451configuration options within the [configuration manual]
474(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>). 452(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>).
475 453
476``` conf 454``` conf
@@ -549,17 +527,14 @@ repo.desc=An example repository!
549 527
550## Final Fixes: Syntax Highlighting & README Rendering 528## Final Fixes: Syntax Highlighting & README Rendering
551 529
552After completing my initial install and playing around with it for a few 530After completing my initial install and playing around with it for a few days, I
553days, I noticed two issues: 531noticed two issues:
554 532
5551. Syntax highlighting did not work when viewing the source code within 5331. Syntax highlighting did not work when viewing the source code within a file.
556 a file. 5342. The `about` tab within a repository was not rendered to HTML.
5572. The `about` tab within a repository was not rendered to
558 HTML.
559 535
560The following process fixes these issues. To start, let\'s go to the 536The following process fixes these issues. To start, let's go to the `cgit`
561`cgit` directory where we were editing our configuration file 537directory where we were editing our configuration file earlier.
562earlier.
563 538
564```sh 539```sh
565cd ~/cgit 540cd ~/cgit
@@ -589,15 +564,13 @@ curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html
589chmod 755 md2html 564chmod 755 md2html
590``` 565```
591 566
592If you need other filters or html-converters found within [the cgit 567If you need other filters or html-converters found within [the cgit project
593project files](https://git.zx2c4.com/cgit/tree/filters), repeat the 568files](https://git.zx2c4.com/cgit/tree/filters), repeat the `curl` and `chmod`
594`curl` and `chmod` process above for whichever 569process above for whichever files you need.
595files you need.
596 570
597However, formatting will not work quite yet since the Docker cgit 571However, formatting will not work quite yet since the Docker cgit container
598container we\'re using doesn\'t have the formatting package installed. 572we're using doesn't have the formatting package installed. You can install
599You can install this easily by install Python 3+ and the 573this easily by install Python 3+ and the `pygments` package:
600`pygments` package:
601 574
602```sh 575```sh
603# Enter the container's command line 576# Enter the container's command line
@@ -613,13 +586,11 @@ pip3 install markdown pygments && \
613exit 586exit
614``` 587```
615 588
616**You will need to enter the cgit docker container and re-run these 589**You will need to enter the cgit docker container and re-run these `yum`
617`yum` commands every time you kill and restart the 590commands every time you kill and restart the container!**
618container!**
619 591
620If not done already, we need to add the following variables to our 592If not done already, we need to add the following variables to our `cgitrc` file
621`cgitrc` file in order for `cgit` to know where 593in order for `cgit` to know where our filtering files are:
622our filtering files are:
623 594
624``` conf 595``` conf
625# Highlight source code with python pygments-based highlighter 596# Highlight source code with python pygments-based highlighter
@@ -630,26 +601,24 @@ source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
630about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh 601about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
631``` 602```
632 603
633Now you should see that syntax highlighting and README rendering to the 604Now you should see that syntax highlighting and README rendering to the `about`
634`about` tab is fixed. 605tab is fixed.
635 606
636## Theming 607## Theming
637 608
638I won\'t go into much detail in this section, but you can fully theme 609I won't go into much detail in this section, but you can fully theme your
639your installation of `cgit` since you have access to the 610installation of `cgit` since you have access to the `cgit.css` file in your web
640`cgit.css` file in your web root. This is another file you 611root. This is another file you can add as a volume to the `docker-compose.yml`
641can add as a volume to the `docker-compose.yml` file if you 612file if you want to edit this without entering the container's command line.
642want to edit this without entering the container\'s command line.
643 613
644### :warning: Remember to Back Up Your Data! 614### :warning: Remember to Back Up Your Data!
645 615
646The last thing to note is that running services on your own equipment 616The last thing to note is that running services on your own equipment means that
647means that you\'re assuming a level of risk that exists regarding data 617you're assuming a level of risk that exists regarding data loss, catastrophes,
648loss, catastrophes, etc. In order to reduce the impact of any such 618etc. In order to reduce the impact of any such occurrence, I suggest backing up
649occurrence, I suggest backing up your data regularly. 619your data regularly.
650 620
651Backups can be automated via `cron`, by hooking your base 621Backups can be automated via `cron`, by hooking your base directory up to a
652directory up to a cloud provider, or even setting up hooks to push all 622cloud provider, or even setting up hooks to push all repository info to git
653repository info to git mirrors on other git hosts. Whatever the method, 623mirrors on other git hosts. Whatever the method, make sure that your data
654make sure that your data doesn\'t vanish in the event that your drives 624doesn't vanish in the event that your drives or servers fail.
655or servers fail.
content/blog/2022-07-14-gnupg.md +126 −140
@@ -7,33 +7,31 @@ draft = false
7 7
8# The History of GPG 8# The History of GPG
9 9
10[GNU Privacy Guard](https://gnupg.org/), also known as GnuPG and GPG, is 10[GNU Privacy Guard](https://gnupg.org/), also known as GnuPG and GPG, is a free
11a free (\"free\" as in both speech and beer) software that fully 11("free" as in both speech and beer) software that fully implements the OpenPGP
12implements the OpenPGP Message Format documented in [RFC 12Message Format documented in [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880).
134880](https://www.rfc-editor.org/rfc/rfc4880).
14 13
15I won\'t go in-depth on the full history of the software in this post, 14I won't go in-depth on the full history of the software in this post, but it is
16but it is important to understand that GPG is not the same as PGP 15important to understand that GPG is not the same as PGP (Pretty Good Privacy),
17(Pretty Good Privacy), which is a different implementation of RFC 4880. 16which is a different implementation of RFC 4880. However, GPG was designed to
18However, GPG was designed to interoperate with PGP. 17interoperate with PGP.
19 18
20GPG was originally developed in the late 1990s by [Werner 19GPG was originally developed in the late 1990s by [Werner
21Koch](https://en.wikipedia.org/wiki/Werner_Koch) and has historically 20Koch](https://en.wikipedia.org/wiki/Werner_Koch) and has historically been
22been funded generously by the German government. 21funded generously by the German government.
23 22
24Now that we have all the high-level info out of the way, let\'s dive 23Now that we have all the high-level info out of the way, let's dive into the
25into the different aspects of GPG and its uses. 24different aspects of GPG and its uses.
26 25
27# Encryption Algorithms 26# Encryption Algorithms
28 27
29GPG supports a wide range of different encryption algorithms, including 28GPG supports a wide range of different encryption algorithms, including
30public-key, cipher, hash, and compression algorithms. The support for 29public-key, cipher, hash, and compression algorithms. The support for these
31these algorithms has grown since the adoption of the Libgcrypt library 30algorithms has grown since the adoption of the Libgcrypt library in the 2.x
32in the 2.x versions of GPG. 31versions of GPG.
33 32
34As you will be able to see below in an example of a full key generation 33As you will be able to see below in an example of a full key generation with the
35with the GPG command line tool, GPG recommends the following algorithms 34GPG command line tool, GPG recommends the following algorithms to new users:
36to new users:
37 35
38```sh 36```sh
39Please select what kind of key you want: 37Please select what kind of key you want:
@@ -45,77 +43,71 @@ Please select what kind of key you want:
45 (10) ECC (sign only) 43 (10) ECC (sign only)
46``` 44```
47 45
48I am not doing an in-depth explanation here in order to keep the focus 46I am not doing an in-depth explanation here in order to keep the focus on GPG
49on GPG and not encryption algorithms. If you want a deep dive into 47and not encryption algorithms. If you want a deep dive into cryptography or
50cryptography or encryption algorithms, please read my other posts: 48encryption algorithms, please read my other posts:
51 49
52- [AES Encryption](../aes-encryption/) (2018) 50- [AES Encryption](../aes-encryption/) (2018)
53- [Cryptography Basics](../cryptography-basics/) (2020) 51- [Cryptography Basics](../cryptography-basics/) (2020)
54 52
55## Vulnerabilities 53## Vulnerabilities
56 54
57As of 2022-07-14, there are a few different vulnerabilities associated 55As of 2022-07-14, there are a few different vulnerabilities associated with GPG
58with GPG or the libraries it uses: 56or the libraries it uses:
59 57
60- GPG versions 1.0.2--1.2.3 contains a bug where \"as soon as one 58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one
61 (GPG-generated) ElGamal signature of an arbitrary message is 59 (GPG-generated) ElGamal signature of an arbitrary message is released, one can
62 released, one can recover the signer\'s private key in less than a 60 recover the signer's private key in less than a second on a PC."
63 second on a PC.\" 61 ([Source](https://www.di.ens.fr/~pnguyen/pub_Ng04.htm))
64 ([Source](https://www.di.ens.fr/~pnguyen/pub_Ng04.htm)) 62- GPG versions prior to 1.4.2.1 contain a false positive signature verification
65- GPG versions prior to 1.4.2.1 contain a false positive signature 63 bug.
66 verification bug. 64 ([Source](https://lists.gnupg.%20org/pipermail/gnupg-announce/2006q1/000211.html))
67 ([Source](https://lists.gnupg.%20org/pipermail/gnupg-announce/2006q1/000211.html)) 65- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned data. (
68- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned 66 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html))
69 data. ( 67- Libgcrypt, a library used by GPG, contained a bug which enabled full key
70 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html)) 68 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG
71- Libgcrypt, a library used by GPG, contained a bug which enabled full 69 update in 2017. ([Source](https://lwn.net/Articles/727179/))
72 key recovery for RSA-1024 and some RSA-2048 keys. This was resolved 70- The [ROCA Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability)
73 in a GPG update in 2017. 71 affects RSA keys generated by YubiKey 4 tokens.
74 ([Source](https://lwn.net/Articles/727179/)) 72 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf))
75- The [ROCA 73- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows an
76 Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability) 74 attacker to spoof digital signatures.
77 affects RSA keys generated by YubiKey 4 tokens. 75 ([Source](https://arstechnica.%20com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/))
78 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf)) 76- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow,
79- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows 77 fixed in Libgcrypt 1.9.1
80 an attacker to spoof digital signatures. 78 ([Source](https://web.archive.%20org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/))
81 ([Source](https://arstechnica.%20com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/))
82- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer
83 overflow, fixed in Libgcrypt 1.9.1
84 ([Source](https://web.archive.%20org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/))
85 79
86### Platforms 80### Platforms
87 81
88Originally developed as a command-line program for \*nix systems, GPG 82Originally developed as a command-line program for *nix systems, GPG now has a
89now has a wealth of front-end applications and libraries available for 83wealth of front-end applications and libraries available for end-users. However,
90end-users. However, the most recommended programs remain the same: 84the most recommended programs remain the same:
91 85
92- [GnuPG](https://gnupg.org) for Linux (depending on distro) 86- [GnuPG](https://gnupg.org) for Linux (depending on distro)
93- [Gpg4win](https://gpg4win.org) for Windows 87- [Gpg4win](https://gpg4win.org) for Windows
94- [GPGTools](https://gpgtools.org) for macOS 88- [GPGTools](https://gpgtools.org) for macOS
95 89
96# Creating a Key Pair 90# Creating a Key Pair
97 91
98In order to create a GPG key pair, a user would first need to install 92In order to create a GPG key pair, a user would first need to install GPG on
99GPG on their system. If we\'re assuming that the user is on Fedora 93their system. If we're assuming that the user is on Fedora Linux, they would
100Linux, they would execute the following: 94execute the following:
101 95
102```sh 96```sh
103sudo dnf install gpg 97sudo dnf install gpg
104``` 98```
105 99
106Once installed, a user can create a new key pair with the following 100Once installed, a user can create a new key pair with the following command(s):
107command(s):
108 101
109```sh 102```sh
110gpg --full-generate-key 103gpg --full-generate-key
111``` 104```
112 105
113GPG will walk the user through an interactive setup that asks for an 106GPG will walk the user through an interactive setup that asks for an algorithm
114algorithm preference, expiration date, name, and email to associate with 107preference, expiration date, name, and email to associate with this key.
115this key.
116 108
117See the following example key set-up for a default key generation using 109See the following example key set-up for a default key generation using the
118the GnuPG command-line interface: 110GnuPG command-line interface:
119 111
120```sh 112```sh
121gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc. 113gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc.
@@ -178,66 +170,63 @@ interface.
178 170
179As noted in RFC 4880, the general functions of OpenPGP are as follows: 171As noted in RFC 4880, the general functions of OpenPGP are as follows:
180 172
181- digital signatures 173- digital signatures
182- encryption 174- encryption
183- compression 175- compression
184- Radix-64 conversion 176- Radix-64 conversion
185- key management and certificate services 177- key management and certificate services
186 178
187From this, you can probably gather that the main use of GPG is for 179From this, you can probably gather that the main use of GPG is for encrypting
188encrypting data and/or signing the data with a key. The purpose of 180data and/or signing the data with a key. The purpose of encrypting data with GPG
189encrypting data with GPG is to ensure that no one except the intended 181is to ensure that no one except the intended recipient(s) can access the data.
190recipient(s) can access the data.
191 182
192Let\'s explore some specific GPG use-cases. 183Let's explore some specific GPG use-cases.
193 184
194## Email 185## Email
195 186
196One of the more popular uses of GPG is to sign and/or encrypt emails. 187One of the more popular uses of GPG is to sign and/or encrypt emails. With the
197With the use of a GPG keypair, you can encrypt a message, its subject, 188use of a GPG keypair, you can encrypt a message, its subject, and even the
198and even the attachments within. 189attachments within.
199 190
200The first process, regarding the signing of a message without any 191The first process, regarding the signing of a message without any encryption, is
201encryption, is generally used to provide assurance that an email is 192generally used to provide assurance that an email is truly coming from the
202truly coming from the sender that the message claims. When I send an 193sender that the message claims. When I send an email, and it's signed with my
203email, and it\'s signed with my public key, the recipient(s) of the 194public key, the recipient(s) of the message can verify that the message was
204message can verify that the message was signed with my personal key. 195signed with my personal key.
205 196
206The second process, regarding the actual encryption of the message and 197The second process, regarding the actual encryption of the message and its
207its contents, works by using a combination of the sender\'s keys and the 198contents, works by using a combination of the sender's keys and the
208recipient\'s keys. This process may vary slightly by implementation, but 199recipient's keys. This process may vary slightly by implementation, but it most
209it most commonly uses asymmetric cryptography, also known as public-key 200commonly uses asymmetric cryptography, also known as public-key cryptography. In
210cryptography. In this version of encryption, the sender\'s private key 201this version of encryption, the sender's private key to sign the message and a
211to sign the message and a combination of the sender\'s keys and the 202combination of the sender's keys and the recipient's public key to encrypt the
212recipient\'s public key to encrypt the message. 203message.
213 204
214If two people each have their own private keys and exchange their public 205If two people each have their own private keys and exchange their public keys,
215keys, they can send encrypted messages back and forth with GPG. This is 206they can send encrypted messages back and forth with GPG. This is also possible
216also possible with symmetric cryptography, but the process differs since 207with symmetric cryptography, but the process differs since there are no key
217there are no key pairs. 208pairs.
218 209
219Implementation of email encryption varies greatly between email clients, 210Implementation of email encryption varies greatly between email clients, so you
220so you will need to reference your email client\'s documentation to 211will need to reference your email client's documentation to ensure you are
221ensure you are setting it up correctly for that specific client. 212setting it up correctly for that specific client.
222 213
223## File Encryption 214## File Encryption
224 215
225As noted in the section above regarding emails, GPG enables users to be 216As noted in the section above regarding emails, GPG enables users to be able to
226able to send a message to each other if they are both set-up with GPG 217send a message to each other if they are both set-up with GPG keys. In this
227keys. In this example, I am going to show how a user could send a file 218example, I am going to show how a user could send a file called
228called `example_file.txt` to another user via the 219`example_file.txt` to another user via the recipient's email.
229recipient\'s email.
230 220
231The sender would find the file they want to send and execute the 221The sender would find the file they want to send and execute the following
232following command: 222command:
233 223
234```sh 224```sh
235gpg --encrypt --output example_file.txt.gpg --recipient \ 225gpg --encrypt --output example_file.txt.gpg --recipient \
236recipient@example.com example_file.txt 226recipient@example.com example_file.txt
237``` 227```
238 228
239Once received, the recipient can decrypt the file with the following 229Once received, the recipient can decrypt the file with the following command:
240command:
241 230
242```sh 231```sh
243gpg --decrypt --output example_file.txt example_file.txt.gpg 232gpg --decrypt --output example_file.txt example_file.txt.gpg
@@ -245,29 +234,28 @@ gpg --decrypt --output example_file.txt example_file.txt.gpg
245 234
246## Ownership Signatures 235## Ownership Signatures
247 236
248One important aspect of GPG, especially for developers, is the ability 237One important aspect of GPG, especially for developers, is the ability to sign
249to sign data without encrypting it. For example, developers often sign 238data without encrypting it. For example, developers often sign code changes when
250code changes when they commit the changes back to a central repository, 239they commit the changes back to a central repository, in order to display
251in order to display ownership of who made the changes. This allows other 240ownership of who made the changes. This allows other users to look at a code
252users to look at a code change and determine that the change was valid. 241change and determine that the change was valid.
253 242
254In order to do this using [Git](https://git-scm.com), the developer 243In order to do this using [Git](https://git-scm.com), the developer simply needs
255simply needs to alter the `git commit` command to include the 244to alter the `git commit` command to include the `-S` flag. Here's an example:
256`-S` flag. Here\'s an example:
257 245
258```sh 246```sh
259git commit -S -m "my commit message" 247git commit -S -m "my commit message"
260``` 248```
261 249
262As an expansion of the example above, Git users can configure their 250As an expansion of the example above, Git users can configure their environment
263environment with a default key to use by adding their GPG signature: 251with a default key to use by adding their GPG signature:
264 252
265```sh 253```sh
266git config --global user.signingkey XXXXXXXXXXXXXXXX 254git config --global user.signingkey XXXXXXXXXXXXXXXX
267``` 255```
268 256
269If you\'re not sure what your signature is, you can find it titled 257If you're not sure what your signature is, you can find it titled `sig` in the
270`sig` in the output of this command: 258output of this command:
271 259
272```sh 260```sh
273gpg --list-signatures 261gpg --list-signatures
@@ -275,12 +263,11 @@ gpg --list-signatures
275 263
276## File Integrity 264## File Integrity
277 265
278When a person generates a signature for data, they are allowing users 266When a person generates a signature for data, they are allowing users the
279the ability to verify the signature on that data in the future to ensure 267ability to verify the signature on that data in the future to ensure the data
280the data has not been corrupted. This is most common with software 268has not been corrupted. This is most common with software applications hosted on
281applications hosted on the internet - developers provide signatures so 269the internet - developers provide signatures so that users can verify a website
282that users can verify a website was not hijacked and download links 270was not hijacked and download links replaced with dangerous software.
283replaced with dangerous software.
284 271
285In order to verify signed data, a user needs to have: 272In order to verify signed data, a user needs to have:
286 273
@@ -288,9 +275,8 @@ In order to verify signed data, a user needs to have:
2882. A signature file 2752. A signature file
2893. The public GPG key of the signer 2763. The public GPG key of the signer
290 277
291Once the signer\'s public key is imported on the user\'s system, and 278Once the signer's public key is imported on the user's system, and they have
292they have the data and signature, they can verify the data with the 279the data and signature, they can verify the data with the following commands:
293following commands:
294 280
295```sh 281```sh
296# If the signature is attached to the data 282# If the signature is attached to the data
@@ -302,13 +288,13 @@ gpg --verify [signature-file] [original-file]
302 288
303### Finding Public Keys 289### Finding Public Keys
304 290
305In order to use GPG with others, a user needs to know the other user(s) 291In order to use GPG with others, a user needs to know the other user(s) keys.
306keys. This is easy to do if the user knows the other user(s) in person, 292This is easy to do if the user knows the other user(s) in person, but may be
307but may be hard if the relationship is strictly digital. Luckily, there 293hard if the relationship is strictly digital. Luckily, there are a few options.
308are a few options. The first option is to look at a user\'s web page or 294The first option is to look at a user's web page or social pages if they have
309social pages if they have them. 295them.
310 296
311Otherwise, the best option is to use a keyserver, such as: 297Otherwise, the best option is to use a keyserver, such as:
312 298
313- [pgp.mit.edu](https://pgp.mit.edu) 299- [pgp.mit.edu](https://pgp.mit.edu)
314- [keys.openpgp.org](https://keys.openpgp.org) 300- [keys.openpgp.org](https://keys.openpgp.org)
content/blog/2022-07-25-curseradio.md +36 −42
@@ -8,62 +8,56 @@ draft = false
8# Overview 8# Overview
9 9
10While exploring some interesting Linux applications, I stumbled across 10While exploring some interesting Linux applications, I stumbled across
11[curseradio](https://github.com/chronitis/curseradio), a command-line 11[curseradio](https://github.com/chronitis/curseradio), a command-line radio
12radio player based on Python. 12player based on Python.
13 13
14This application is fantastic and incredibly easy to install, so I 14This application is fantastic and incredibly easy to install, so I wanted to
15wanted to dedicate a post today to this app. Let\'s look at the features 15dedicate a post today to this app. Let's look at the features within the app
16within the app and then walk through the installation process I took to 16and then walk through the installation process I took to get `curseradio`
17get `curseradio` working. 17working.
18 18
19# Features 19# Features
20 20
21![curseradio](https://img.cleberg.net/blog/20220725-curseradio/curseradio.png) 21![curseradio](https://img.cleberg.net/blog/20220725-curseradio/curseradio.png)
22 22
23The radio player itself is quite minimal. As you can see in the 23The radio player itself is quite minimal. As you can see in the screenshot
24screenshot above, it contains a simple plaintext list of all available 24above, it contains a simple plaintext list of all available categories, which
25categories, which can be broken down further and further. In addition, 25can be broken down further and further. In addition, radio shows are available
26radio shows are available for listening, alongside regular radio 26for listening, alongside regular radio stations.
27stations.
28 27
29For example, the `Sports` \> `Pro Basketball` \> 28For example, the `Sports` > `Pro Basketball` > `Shows` category contains a
30`Shows` category contains a number of specific shows related 29number of specific shows related to Professional Basketball.
31to Professional Basketball.
32 30
33Aside from being able to play any of the listed stations/shows, you can 31Aside from being able to play any of the listed stations/shows, you can make a
34make a channel your favorite by pressing `f`. It will now 32channel your favorite by pressing `f`. It will now show up at the top of the
35show up at the top of the radio player in the `Favourites` 33radio player in the `Favourites` category.
36category.
37 34
38## Commands/Shortcuts 35## Commands/Shortcuts
39 36
40 Key(s) Command 37| Key(s) | Command |
41 ------------ --------------------------------- 38|------------|---------------------------------|
42 ↑, ↓ navigate 39| ↑, ↓ | navigate |
43 PgUp, PgDn navigate quickly 40| PgUp, PgDn | navigate quickly |
44 Home, End to top/bottom 41| Home, End | to top/bottom |
45 Enter open/close folders, play stream 42| Enter | open/close folders, play stream |
46 k stop playing stream 43| k | stop playing stream |
47 q quit 44| q | quit |
48 f toggle favourite 45| f | toggle favourite |
49 46
50# Installation 47# Installation
51 48
52## Dependencies 49## Dependencies
53 50
54Before installing `curseradio`, a handful of system and 51Before installing `curseradio`, a handful of system and Python packages are
55Python packages are required. To get started, install 52required. To get started, install `python3`, `pip3`, and `mpv` on your system.
56`python3`, `pip3`, and `mpv` on your 53In this example, I'm using Fedora Linux, which uses the `dnf` package manager.
57system. In this example, I\'m using Fedora Linux, which uses the 54You may need to adjust this if you're using a different system.
58`dnf` package manager. You may need to adjust this if you\'re
59using a different system.
60 55
61```sh 56```sh
62sudo dnf install python3 pip3 mpv 57sudo dnf install python3 pip3 mpv
63``` 58```
64 59
65Next, use `pip3` to install `requests`, 60Next, use `pip3` to install `requests`, `xdg`, and `lxml`:
66`xdg`, and `lxml`:
67 61
68```sh 62```sh
69pip3 install requests xdg lxml 63pip3 install requests xdg lxml
@@ -71,23 +65,23 @@ pip3 install requests xdg lxml
71 65
72## Repository Source Installation 66## Repository Source Installation
73 67
74Once all the dependencies are installed, we can clone the source code 68Once all the dependencies are installed, we can clone the source code and enter
75and enter that directory: 69that directory:
76 70
77```sh 71```sh
78git clone https://github.com/chronitis/curseradio && cd curseradio 72git clone https://github.com/chronitis/curseradio && cd curseradio
79``` 73```
80 74
81Once you\'re within the `curseradio` directory, you can 75Once you're within the `curseradio` directory, you can install the application
82install the application with the provided `setup.py` script. 76with the provided `setup.py` script.
83 77
84```sh 78```sh
85sudo python3 setup.py install 79sudo python3 setup.py install
86``` 80```
87 81
88In my case, I ran into a few errors and needed to create the folders 82In my case, I ran into a few errors and needed to create the folders that
89that curseradio wanted to use for its installation. If you don\'t get 83curseradio wanted to use for its installation. If you don't get any errors, you
90any errors, you can skip this and run the app. 84can skip this and run the app.
91 85
92```sh 86```sh
93sudo mkdir /usr/local/lib/python3.10/ 87sudo mkdir /usr/local/lib/python3.10/
content/blog/2022-07-30-flac-to-opus.md +38 −42
@@ -11,59 +11,56 @@ I am currently rebuilding my music library from scratch so that I can
11effectively archive all the music I own in the [FLAC file 11effectively archive all the music I own in the [FLAC file
12format](https://en.wikipedia.org/wiki/FLAC), a lossless audio codec. 12format](https://en.wikipedia.org/wiki/FLAC), a lossless audio codec.
13 13
14However, streaming FLAC files outside the home can be difficult due to 14However, streaming FLAC files outside the home can be difficult due to the size
15the size of the files, especially if you\'re using a weak connection. 15of the files, especially if you're using a weak connection.
16 16
17So, in order to archive the music in a lossless format and still be able 17So, in order to archive the music in a lossless format and still be able to
18to stream it easily, I opted to create a copy of my FLAC files in the 18stream it easily, I opted to create a copy of my FLAC files in the [Opus audio
19[Opus audio codec](https://en.wikipedia.org/wiki/Opus_(audio_format)). 19codec](https://en.wikipedia.org/wiki/Opus_(audio_format)). This allows me to
20This allows me to archive a quality, lossless version of the music and 20archive a quality, lossless version of the music and then point my streaming
21then point my streaming service to the smaller, stream-ready version. 21service to the smaller, stream-ready version.
22 22
23## Dependencies 23## Dependencies
24 24
25The process I follow utilizes the `opus-tools` package in 25The process I follow utilizes the `opus-tools` package in Ubuntu. Before
26Ubuntu. Before proceeding, install the package: 26proceeding, install the package:
27 27
28```sh 28```sh
29sudo apt install opus-tools 29sudo apt install opus-tools
30``` 30```
31 31
32If you want to use a different conversion method, such as 32If you want to use a different conversion method, such as `ffmpeg` or `avconv`,
33`ffmpeg` or `avconv`, simply install that package 33simply install that package instead.
34instead.
35 34
36## Conversion Process 35## Conversion Process
37 36
38The script I\'m using is stored in my home directory, but feel free to 37The script I'm using is stored in my home directory, but feel free to create it
39create it wherever you want. It does not need to be in the same 38wherever you want. It does not need to be in the same directory as your music
40directory as your music files. 39files.
41 40
42```sh 41```sh
43cd ~ && nano transform.sh 42cd ~ && nano transform.sh
44``` 43```
45 44
46Once you have your new bash script opened in an editor, go ahead and 45Once you have your new bash script opened in an editor, go ahead and paste the
47paste the following logic into the script. 46following logic into the script.
48 47
49You **MUST** edit the following variables in order for it to work: 48You **MUST** edit the following variables in order for it to work:
50 49
51- `source`: The source directory where your FLAC files are 50- `source`: The source directory where your FLAC files are stored.
52 stored. 51- `dest`: The destination directory where you want the resulting Opus files to
53- `dest`: The destination directory where you want the 52 be stored.
54 resulting Opus files to be stored.
55 53
56You **MAY** want to edit the following variables to suit your needs: 54You **MAY** want to edit the following variables to suit your needs:
57 55
58- `filename`: If you are converting to a file format other 56- `filename`: If you are converting to a file format other than Opus, you'll
59 than Opus, you\'ll need to edit this so that your resulting files 57 need to edit this so that your resulting files have the correct filename
60 have the correct filename extension. 58 extension.
61- `reldir`: This variable can be edited to strip out more 59- `reldir`: This variable can be edited to strip out more leading directories in
62 leading directories in the file path. As you\'ll see later, I ignore 60 the file path. As you'll see later, I ignore this for now and simply clean it
63 this for now and simply clean it up afterward. 61 up afterward.
64- `opusenc`: This is the actual conversion process. You may 62- `opusenc`: This is the actual conversion process. You may want to edit the
65 want to edit the bitrate to suit your needs. I set mine at 128 but 63 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher.
66 some prefer 160 or higher.
67 64
68```sh 65```sh
69#!/bin/bash 66#!/bin/bash
@@ -129,8 +126,8 @@ opusenc --vbr --bitrate 128 --date "$DATE" \
129done 126done
130``` 127```
131 128
132Once you\'re done, simply save the file and exit your editor. Don\'t 129Once you're done, simply save the file and exit your editor. Don't forget to
133forget to enable execution of the script: 130enable execution of the script:
134 131
135```sh 132```sh
136chmod +x transform.sh 133chmod +x transform.sh
@@ -142,17 +139,16 @@ Finally, you may now run the script:
142./transform.sh 139./transform.sh
143``` 140```
144 141
145If you used `opusenc`, you\'ll see the conversions happen 142If you used `opusenc`, you'll see the conversions happen within the terminal as
146within the terminal as it progresses. You will also see variables 143it progresses. You will also see variables printed if you uncommented any of the
147printed if you uncommented any of the bash script\'s comments. 144bash script's comments.
148 145
149## Cleanup 146## Cleanup
150 147
151As I noted above, I didn\'t customize my `reldir` variable in 148As I noted above, I didn't customize my `reldir` variable in the script, which
152the script, which caused my output directory to be 149caused my output directory to be `/mnt/music/library/archives` instead of
153`/mnt/music/library/archives` instead of 150`/mnt/music/library`. So, I moved the output up one level and deleted the
154`/mnt/music/library`. So, I moved the output up one level and 151accidental directory.
155deleted the accidental directory.
156 152
157```sh 153```sh
158cd /mnt/music/library 154cd /mnt/music/library
@@ -162,8 +158,8 @@ rm -rf archives
162 158
163## Check the Resulting Size 159## Check the Resulting Size
164 160
165If you want to see what kind of file size savings you\'ve gained, you 161If you want to see what kind of file size savings you've gained, you can always
166can always use the `du` command to check: 162use the `du` command to check:
167 163
168```sh 164```sh
169cd /mnt/music 165cd /mnt/music
content/blog/2022-07-31-bash-it.md +66 −72
@@ -8,30 +8,30 @@ draft = false
8# Bash 8# Bash
9 9
10For those who are not familiar, 10For those who are not familiar,
11[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is a Unix shell 11[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is a Unix shell that is
12that is used as the default login shell for most Linux distributions. 12used as the default login shell for most Linux distributions. This shell and
13This shell and command processor should be familiar if you\'ve used 13command processor should be familiar if you've used Linux (or older version of
14Linux (or older version of macOS) before. 14macOS) before.
15 15
16However, bash is not the only option. There are numerous other shells 16However, bash is not the only option. There are numerous other shells that
17that exist. Here are some popular examples: 17exist. Here are some popular examples:
18 18
19- [zsh](https://en.wikipedia.org/wiki/Z_shell) 19- [zsh](https://en.wikipedia.org/wiki/Z_shell)
20- [fish](https://en.wikipedia.org/wiki/Fish_(Unix_shell)) 20- [fish](https://en.wikipedia.org/wiki/Fish_(Unix_shell))
21- [oksh](https://github.com/ibara/oksh) 21- [oksh](https://github.com/ibara/oksh)
22- [mksh](https://wiki.gentoo.org/wiki/Mksh) 22- [mksh](https://wiki.gentoo.org/wiki/Mksh)
23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell) 23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell)
24 24
25While each shell has its differences, bash is POSIX compliant and the 25While each shell has its differences, bash is POSIX compliant and the default
26default for many Linux users. Because of this, I am going to explore a 26for many Linux users. Because of this, I am going to explore a program called
27program called `bash-it` below that helps bash users increase 27`bash-it` below that helps bash users increase the utility of their shell
28the utility of their shell without installing a completely new shell. 28without installing a completely new shell.
29 29
30## Installation 30## Installation
31 31
32First, if bash is not already installed on your system, you can 32First, if bash is not already installed on your system, you can [download bash
33[download bash from GNU](https://www.gnu.org/software/bash/) or use your 33from GNU](https://www.gnu.org/software/bash/) or use your package manager to
34package manager to install it. 34install it.
35 35
36For example, this is how you can install bash on Fedora Linux: 36For example, this is how you can install bash on Fedora Linux:
37 37
@@ -39,29 +39,29 @@ For example, this is how you can install bash on Fedora Linux:
39sudo dnf install bash 39sudo dnf install bash
40``` 40```
41 41
42If you are not using bash as your default shell, use the 42If you are not using bash as your default shell, use the `chsh` command to
43`chsh` command to change your shell: 43change your shell:
44 44
45```sh 45```sh
46chsh 46chsh
47``` 47```
48 48
49You should see a prompt like the one below. If the brackets 49You should see a prompt like the one below. If the brackets (`[]`) contain
50(`[]`) contain `bash` already, you\'re done, and 50`bash` already, you're done, and you can simply continue by hitting the Enter
51you can simply continue by hitting the Enter key. 51key.
52 52
53If the brackets contain another shell path (e.g. 53If the brackets contain another shell path (e.g. `/usr/bin/zsh`), enter the path
54`/usr/bin/zsh`), enter the path to the bash program on your 54to the bash program on your system (it's most likely located at
55system (it\'s most likely located at `/usr/bin/bash`). 55`/usr/bin/bash`).
56 56
57```sh 57```sh
58Changing shell for <user>. 58Changing shell for <user>.
59New shell [/usr/bin/bash]: 59New shell [/usr/bin/bash]:
60``` 60```
61 61
62You must log out or restart the machine in order for the login shell to 62You must log out or restart the machine in order for the login shell to be
63be refreshed. You can do it now or wait until you\'re finished 63refreshed. You can do it now or wait until you're finished customizing the
64customizing the shell. 64shell.
65 65
66```sh 66```sh
67sudo reboot now 67sudo reboot now
@@ -69,30 +69,28 @@ sudo reboot now
69 69
70# Bash-it 70# Bash-it
71 71
72As noted on the [Bash-it](https://github.com/Bash-it/bash-it) 72As noted on the [Bash-it](https://github.com/Bash-it/bash-it) repository:
73repository:
74 73
75> Bash-it is a collection of community Bash commands and scripts for 74> Bash-it is a collection of community Bash commands and scripts for Bash 3.2+.
76> Bash 3.2+. (And a shameless ripoff of oh-my-zsh 😃) 75> (And a shameless ripoff of oh-my-zsh 😃)
77 76
78Bash-it makes it easy to install plugins, set up aliases for common 77Bash-it makes it easy to install plugins, set up aliases for common commands,
79commands, and easily change the visual theme of your shell. 78and easily change the visual theme of your shell.
80 79
81## Installation 80## Installation
82 81
83To install the framework, simply copy the repository files and use the 82To install the framework, simply copy the repository files and use the
84`install.sh` script provided. If you want, you can (and 83`install.sh` script provided. If you want, you can (and should!) inspect the
85should!) inspect the contents of the installation script before you run 84contents of the installation script before you run it.
86it.
87 85
88```sh 86```sh
89git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it 87git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it
90~/.bash_it/install.sh 88~/.bash_it/install.sh
91``` 89```
92 90
93If you didn\'t restart your session after making bash the default, and 91If you didn't restart your session after making bash the default, and are
94are currently working within another shell, be sure to enter a bash 92currently working within another shell, be sure to enter a bash session before
95session before using `bash-it`: 93using `bash-it`:
96 94
97```sh 95```sh
98bash 96bash
@@ -101,16 +99,16 @@ bash
101## Aliases 99## Aliases
102 100
103Bash-it contains a number of aliases for common commands to help improve 101Bash-it contains a number of aliases for common commands to help improve
104efficiency in the terminal. To list all available options, use the 102efficiency in the terminal. To list all available options, use the following
105following command: 103command:
106 104
107```sh 105```sh
108bash-it show aliases 106bash-it show aliases
109``` 107```
110 108
111This will provide you a list that looks like the following text block. 109This will provide you a list that looks like the following text block. Within
112Within this screen, you will be able to see all available options and 110this screen, you will be able to see all available options and which ones are
113which ones are currently enabled. 111currently enabled.
114 112
115``` txt 113``` txt
116Alias Enabled? Description 114Alias Enabled? Description
@@ -141,9 +139,8 @@ bash-it disable alias <alias name> [alias name]... -or- $ bash-it disable alias
141 139
142## Plugins 140## Plugins
143 141
144Similar to aliases, plugins are available with bash-it. You can find a 142Similar to aliases, plugins are available with bash-it. You can find a complete
145complete list of plugins in the same way as aliases. Simply execute the 143list of plugins in the same way as aliases. Simply execute the following:
146following:
147 144
148```sh 145```sh
149bash-it show plugins 146bash-it show plugins
@@ -188,9 +185,8 @@ To list all themes:
188ls ~/.bash_it/themes/ 185ls ~/.bash_it/themes/
189``` 186```
190 187
191To use a new theme, you\'ll need to edit `.bashrc` and alter 188To use a new theme, you'll need to edit `.bashrc` and alter the `BASH_IT_THEME`
192the `BASH_IT_THEME` variable to your desired theme. For 189variable to your desired theme. For example, I am using the `zork` theme.
193example, I am using the `zork` theme.
194 190
195```sh 191```sh
196nano ~/.bashrc 192nano ~/.bashrc
@@ -200,23 +196,22 @@ nano ~/.bashrc
200export BASH_IT_THEME='zork' 196export BASH_IT_THEME='zork'
201``` 197```
202 198
203Once you save your changes, you just need to exit your terminal and 199Once you save your changes, you just need to exit your terminal and create a new
204create a new one in order to see your changes to the 200one in order to see your changes to the `.bashrc` file. You can also `source`
205`.bashrc` file. You can also `source` the file to 201the file to see changes, but I recommend starting a completely new shell
206see changes, but I recommend starting a completely new shell instead. 202instead.
207 203
208### ble.sh 204### ble.sh
209 205
210One big feature I was missing in Bash that both `zsh` and 206One big feature I was missing in Bash that both `zsh` and `fish` have is an
211`fish` have is an autosuggestion feature. To explain: as you 207autosuggestion feature. To explain: as you type, an autosuggestion feature in
212type, an autosuggestion feature in the shell will offer suggestions in a 208the shell will offer suggestions in a lighter font color beyond the characters
213lighter font color beyond the characters already typed. Once you see the 209already typed. Once you see the command you want, you can click the right arrow
214command you want, you can click the right arrow and have the shell 210and have the shell auto-complete that line for you.
215auto-complete that line for you.
216 211
217Luckily, the [Bash Line Editor](https://github.com/akinomyoga/ble.sh) 212Luckily, the [Bash Line Editor](https://github.com/akinomyoga/ble.sh) (ble.sh)
218(ble.sh) exists! This program provides a wonderful autosuggestions 213exists! This program provides a wonderful autosuggestions feature perfectly,
219feature perfectly, among other features that I haven\'t tested yet. 214among other features that I haven't tested yet.
220 215
221In order to install ble.sh, execute the following: 216In order to install ble.sh, execute the following:
222 217
@@ -226,17 +221,16 @@ make -C ble.sh install PREFIX=~/.local
226echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc 221echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
227``` 222```
228 223
229Again, exit the terminal and open a new one in order to see the 224Again, exit the terminal and open a new one in order to see the newly-configured
230newly-configured shell. 225shell.
231 226
232# Restart the Session 227# Restart the Session
233 228
234Finally, as mentioned above, you\'ll need to restart the session to 229Finally, as mentioned above, you'll need to restart the session to ensure that
235ensure that your user is using bash by default. 230your user is using bash by default.
236 231
237You will also need to exit and re-open a shell (e.g., terminal or 232You will also need to exit and re-open a shell (e.g., terminal or terminal tab)
238terminal tab) any time you make changes to the `.bashrc` 233any time you make changes to the `.bashrc` file.
239file.
240 234
241```sh 235```sh
242sudo reboot now 236sudo reboot now
content/blog/2022-08-31-privacy-com-changes.md +54 −61
@@ -7,93 +7,86 @@ draft = false
7 7
8# Privacy.com Changes Their Terms 8# Privacy.com Changes Their Terms
9 9
10Recently, Privacy.com reached out to their customers regarding a change 10Recently, Privacy.com reached out to their customers regarding a change in their
11in their terms of use. Further, all customers are required to agree to 11terms of use. Further, all customers are required to agree to the changes in
12the changes in order to continue using their accounts. 12order to continue using their accounts.
13 13
14[You can view the new cardholder agreement 14[You can view the new cardholder agreement
15here](https://privacy.com/commercial-cardholder-agreement). 15here](https://privacy.com/commercial-cardholder-agreement).
16 16
17When you log in, you\'ll be greeted with a pop-up window asking you to 17When you log in, you'll be greeted with a pop-up window asking you to review
18review and agree to the new terms of use. You will also not be able to 18and agree to the new terms of use. You will also not be able to open any new
19open any new cards until the terms are agreed to. 19cards until the terms are agreed to.
20 20
21## Changing from a \"Prepaid Debit\" Model to a \"Charge Card\" Model 21## Changing from a "Prepaid Debit" Model to a "Charge Card" Model
22 22
23The actual content of the changes is interesting. While the historical 23The actual content of the changes is interesting. While the historical model of
24model of using Privacy.com was akin to prepaid debit cards, the new 24using Privacy.com was akin to prepaid debit cards, the new model is very similar
25model is very similar to a credit card (they use the term \"charge 25to a credit card (they use the term "charge card").
26card\").
27 26
28I have used Privacy.com for 1-2 years, and the process was always that 27I have used Privacy.com for 1-2 years, and the process was always that you would
29you would create a single-use or merchant-locked card. This card could 28create a single-use or merchant-locked card. This card could be used for any
30be used for any dollar limit you set and would immediately draw the 29dollar limit you set and would immediately draw the funds from whatever funding
31funds from whatever funding source you connected, e.g. PayPal account or 30source you connected, e.g. PayPal account or a bank account.
32a bank account.
33 31
34The benefit this service provides with a premium account is masking the 32The benefit this service provides with a premium account is masking the merchant
35merchant names from your funding source. If you have a concern that your 33names from your funding source. If you have a concern that your bank account
36bank account uses merchant data from your account, you could direct all 34uses merchant data from your account, you could direct all charges through
37charges through Privacy.com and set the merchant as one of their pre-set 35Privacy.com and set the merchant as one of their pre-set options, such as
38options, such as \"Smiley\'s Corner Store\" or \"NSA Gift Shop.\" 36"Smiley's Corner Store" or "NSA Gift Shop."
39 37
40The new model still works with a bank account as a funding source, but 38The new model still works with a bank account as a funding source, but the model
41the model is changed so that you get a \"line of credit\" set according 39is changed so that you get a "line of credit" set according to a 14-day
42to a 14-day billing cycle. It seems that Privacy.com will now allow 40billing cycle. It seems that Privacy.com will now allow charges to be incurred
43charges to be incurred without being immediately paid. 41without being immediately paid.
44 42
45## Daily Payments and Available Credit 43## Daily Payments and Available Credit
46 44
47Instead of paying as charges are incurred, you must make a \"Daily 45Instead of paying as charges are incurred, you must make a "Daily Payment" and
48Payment\" and your \"Available Credit\" will be locked until you make 46your "Available Credit" will be locked until you make that payment. There are
49that payment. There are also \"End of Billing Cycle Payments\" that are 47also "End of Billing Cycle Payments" that are assigned a due date.
50assigned a due date.
51 48
52Further, Privacy.com will decline charges that would cause you to exceed 49Further, Privacy.com will decline charges that would cause you to exceed your
53your Available Credit or Credit Limit. 50Available Credit or Credit Limit.
54 51
55One particular interesting section states the following: 52One particular interesting section states the following:
56 53
57> YOUR OBLIGATION TO PAY US BACK FOR ALL CARD TRANSACTIONS AND OTHER 54> YOUR OBLIGATION TO PAY US BACK FOR ALL CARD TRANSACTIONS AND OTHER OBLIGATIONS
58> OBLIGATIONS YOU INCUR IS SECURED BY THE SECURED ACCOUNT. IF YOU DO NOT 55> YOU INCUR IS SECURED BY THE SECURED ACCOUNT. IF YOU DO NOT PAY US BACK FOR ANY
59> PAY US BACK FOR ANY AMOUNT YOU OWE US WHEN YOUR PAYMENTS ARE DUE, WE 56> AMOUNT YOU OWE US WHEN YOUR PAYMENTS ARE DUE, WE WILL EXERCISE OUR INTEREST
60> WILL EXERCISE OUR INTEREST AND DEBIT THE SECURED ACCOUNT, AND YOU WILL 57> AND DEBIT THE SECURED ACCOUNT, AND YOU WILL LOSE THE MONEY IN THE SECURED
61> LOSE THE MONEY IN THE SECURED ACCOUNT. SEE SECTION 8: SECURITY 58> ACCOUNT. SEE SECTION 8: SECURITY AGREEMENT FOR MORE INFORMATION.
62> AGREEMENT FOR MORE INFORMATION.
63 59
64## Personal Information 60## Personal Information
65 61
66Now that Privacy.com is more of a financial institution, they are 62Now that Privacy.com is more of a financial institution, they are obligated to
67obligated to comply with the [know your 63comply with the [know your
68customer](https://en.wikipedia.org/wiki/Know_your_customer) 64customer](https://en.wikipedia.org/wiki/Know_your_customer) guidelines/laws.
69guidelines/laws.
70 65
71I did not proceed with the change to my Privacy.com account, but I have 66I did not proceed with the change to my Privacy.com account, but I have heard
72heard from some peers that the changes require more personal information 67from some peers that the changes require more personal information to be
73to be submitted, such as SSN. I am not aware of all new personal 68submitted, such as SSN. I am not aware of all new personal information required
74information required or if the funding source is now required to only be 69or if the funding source is now required to only be a bank account.
75a bank account.
76 70
77## Fees 71## Fees
78 72
79Luckily, the fees section did not change much. The subscription fees for 73Luckily, the fees section did not change much. The subscription fees for a
80a premium account are still the only fees. 74premium account are still the only fees.
81 75
82# My Thoughts 76# My Thoughts
83 77
84Personally, I wiped my personal information from my account and then 78Personally, I wiped my personal information from my account and then permanently
85permanently deleted it when I heard about these changes. I have no 79deleted it when I heard about these changes. I have no interest in yet another
86interest in yet another method of credit lending offered by private 80method of credit lending offered by private companies. While I accepted that
87companies. While I accepted that they would have access to my bank 81they would have access to my bank account information for the purposes of paying
88account information for the purposes of paying off my prepaid debit 82off my prepaid debit payments, I have no interest in incurring charges that will
89payments, I have no interest in incurring charges that will need to be 83need to be paid back at a later date. I also have no interest in submitting
90paid back at a later date. I also have no interest in submitting
91personal information to Privacy.com. 84personal information to Privacy.com.
92 85
93This type of change toward a \"buy it now, pay us later\" model is 86This type of change toward a "buy it now, pay us later" model is concerning,
94concerning, and I will be watching Privacy.com to see if they further 87and I will be watching Privacy.com to see if they further their interests in the
95their interests in the credit model as time goes on. 88credit model as time goes on.
96 89
97Could we see them start charging interest, fees, etc.? I\'m not sure, 90Could we see them start charging interest, fees, etc.? I'm not sure, but this
98but this change does not inspire confidence in their mission as a 91change does not inspire confidence in their mission as a privacy-focused
99privacy-focused company. 92company.
content/blog/2022-09-17-serenity-os.md +41 −47
@@ -7,39 +7,37 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10[SerenityOS](https://serenityos.org) is a unique operating system (OS) 10[SerenityOS](https://serenityos.org) is a unique operating system (OS) that I
11that I have seen pop up in my news feed a few times over the last few 11have seen pop up in my news feed a few times over the last few years, but I have
12years, but I have never had time to test it out until now. 12never had time to test it out until now.
13 13
14Testing out this system brought back fond memories of yellowed, 14Testing out this system brought back fond memories of yellowed,
15modem-screeching, 100-pound computers that brought so many fond memories 15modem-screeching, 100-pound computers that brought so many fond memories to my
16to my youth. 16youth.
17 17
18Per their website: 18Per their website:
19 19
20> A graphical Unix-like operating system for desktop computers! 20> A graphical Unix-like operating system for desktop computers!
21> 21>
22> SerenityOS is a love letter to \'90s user interfaces with a custom 22> SerenityOS is a love letter to '90s user interfaces with a custom Unix-like
23> Unix-like core. It flatters with sincerity by stealing beautiful ideas 23> core. It flatters with sincerity by stealing beautiful ideas from various
24> from various other systems. 24> other systems.
25> 25>
26> Roughly speaking, the goal is a marriage between the aesthetic of 26> Roughly speaking, the goal is a marriage between the aesthetic of late-1990s
27> late-1990s productivity software and the power-user accessibility of 27> productivity software and the power-user accessibility of late-2000s *nix.
28> late-2000s \*nix.
29> 28>
30> This is a system by us, for us, based on the things we like. 29> This is a system by us, for us, based on the things we like.
31 30
32# Building 31# Building
33 32
34Your first question may be \"Where\'s the iso?\" and the answer is... 33Your first question may be "Where's the iso?" and the answer is... there are
35there are none. SerenityOS does not provide pre-built images for 34none. SerenityOS does not provide pre-built images for testing. You must build
36testing. You must build the images yourself. This seems intentionally to 35the images yourself. This seems intentionally to limit participation to only
37limit participation to only those who are truly interested enough to 36those who are truly interested enough to learn how to build the OS.
38learn how to build the OS.
39 37
40## Clone 38## Clone
41 39
42In order to get started, you\'ll need to clone the source repository: 40In order to get started, you'll need to clone the source repository:
43 41
44```sh 42```sh
45git clone https://github.com/SerenityOS/serenity && cd serenity 43git clone https://github.com/SerenityOS/serenity && cd serenity
@@ -50,23 +48,21 @@ git clone https://github.com/SerenityOS/serenity && cd serenity
50Note that I followed the [Build 48Note that I followed the [Build
51Instructions](https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md) 49Instructions](https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md)
52in the SerenityOS repository as of commit 50in the SerenityOS repository as of commit
53`660d2b53b1206e868d5470eee80b5e62d7e30da7`. Things may have 51`660d2b53b1206e868d5470eee80b5e62d7e30da7`. Things may have changed since my
54changed since my installation, and you should double-check the 52installation, and you should double-check the instructions first.
55instructions first.
56 53
57Regardless, I want to repeat my steps here to illustrate any errors or 54Regardless, I want to repeat my steps here to illustrate any errors or differing
58differing commands I needed to run in order to build and run SerenityOS. 55commands I needed to run in order to build and run SerenityOS.
59 56
60Since I am running Fedora, I needed to install these packages in order 57Since I am running Fedora, I needed to install these packages in order to build
61to build the OS images: 58the OS images:
62 59
63```sh 60```sh
64sudo dnf install texinfo binutils-devel curl cmake mpfr-devel libmpc-devel gmp-devel e2fsprogs ninja-build patch ccache rsync @"C Development Tools and Libraries" @Virtualization 61sudo dnf install texinfo binutils-devel curl cmake mpfr-devel libmpc-devel gmp-devel e2fsprogs ninja-build patch ccache rsync @"C Development Tools and Libraries" @Virtualization
65``` 62```
66 63
67Next, make sure you\'re inside the `serenity` directory 64Next, make sure you're inside the `serenity` directory created earlier during
68created earlier during the git cloning process and process to build the 65the git cloning process and process to build the toolchain:
69toolchain:
70 66
71```sh 67```sh
72Meta/serenity.sh rebuild-toolchain 68Meta/serenity.sh rebuild-toolchain
@@ -78,45 +74,43 @@ Once the toolchain is built, you can Build and run the OS!
78Meta/serenity.sh run 74Meta/serenity.sh run
79``` 75```
80 76
81After this process is completed, the image should run automatically and 77After this process is completed, the image should run automatically and launch.
82launch.
83 78
84# Issues 79# Issues
85 80
86I played around in SerenityOS for an hour or two in order to see what I 81I played around in SerenityOS for an hour or two in order to see what I could do
87could do and had a lot of fun with it. The only issue I ran into was a 82and had a lot of fun with it. The only issue I ran into was a lack of working
88lack of working internet. I didn\'t try very hard, but I could tell that 83internet. I didn't try very hard, but I could tell that the main network link
89the main network link wasn\'t connecting to my Fedora host properly. 84wasn't connecting to my Fedora host properly.
90 85
91# Screenshots 86# Screenshots
92 87
93The initial launch of the image displays the SerenityOS desktop, with a 88The initial launch of the image displays the SerenityOS desktop, with a simple
94simple terminal already launched: 89terminal already launched:
95 90
96![SerenityOS 91![SerenityOS
97Terminal](https://img.cleberg.net/blog/20220917-serenityos/initial_launch.png) 92Terminal](https://img.cleberg.net/blog/20220917-serenityos/initial_launch.png)
98 93
99Here you can see the Fire application (literally just shows fire 94Here you can see the Fire application (literally just shows fire burning), a
100burning), a browser with the local Serenity Browser page loaded, and a 95browser with the local Serenity Browser page loaded, and a text editor.
101text editor.
102 96
103![SerenityOS 97![SerenityOS
104Fire](https://img.cleberg.net/blog/20220917-serenityos/basic_apps.png) 98Fire](https://img.cleberg.net/blog/20220917-serenityos/basic_apps.png)
105 99
106I also poked around the system utilities and found most tools you\'d 100I also poked around the system utilities and found most tools you'd expect to
107expect to find within a standard desktop. 101find within a standard desktop.
108 102
109![SerenityOS System 103![SerenityOS System
110Monitor](https://img.cleberg.net/blog/20220917-serenityos/system_monitor.png) 104Monitor](https://img.cleberg.net/blog/20220917-serenityos/system_monitor.png)
111 105
112Lastly, I noted that the default desktop contains numerous pre-defined 106Lastly, I noted that the default desktop contains numerous pre-defined themes to
113themes to choose from. This is a small piece, but it\'s actually 107choose from. This is a small piece, but it's actually wonderful to see desktop
114wonderful to see desktop developers consider theming directly out of the 108developers consider theming directly out of the box rather than using an
115box rather than using an addon-based mentality. 109addon-based mentality.
116 110
117![SerenityOS 111![SerenityOS
118Themes](https://img.cleberg.net/blog/20220917-serenityos/themes.png) 112Themes](https://img.cleberg.net/blog/20220917-serenityos/themes.png)
119 113
120I didn\'t take a screenshot of the other pre-installed games, but I did 114I didn't take a screenshot of the other pre-installed games, but I did spend
121spend nearly 30 minutes playing Solitaire before remembering that I was 115nearly 30 minutes playing Solitaire before remembering that I was supposed to be
122supposed to be writing a post about the OS. 116writing a post about the OS.
content/blog/2022-09-21-graphene-os.md +53 −62
@@ -7,27 +7,24 @@ draft = false
7 7
8# Introduction 8# Introduction
9 9
10After using iOS for a couple of years, I finally took the plunge and 10After using iOS for a couple of years, I finally took the plunge and purchased a
11purchased a Pixel 6 Pro in order to test and use \[GrapheneOS\] 11Pixel 6 Pro in order to test and use [GrapheneOS] (<https://grapheneos.org>).
12(<https://grapheneos.org>).
13 12
14The installation process was rather quick once you have the tools and 13The installation process was rather quick once you have the tools and files you
15files you need. Overall, it can be done in just a few minutes. 14need. Overall, it can be done in just a few minutes.
16 15
17# Gathering Tools & Files 16# Gathering Tools & Files
18 17
19## Android Tools 18## Android Tools
20 19
21First, in order to interact with the device, we will need the [Android 20First, in order to interact with the device, we will need the [Android platform
22platform 21tools](https://developer.android.com/studio/releases/platform-tools.html). Find
23tools](https://developer.android.com/studio/releases/platform-tools.html). 22the Linux download and save the ZIP folder to your preferred location.
24Find the Linux download and save the ZIP folder to your preferred
25location.
26 23
27Once we\'ve downloaded the files, we will need to unzip them, enter the 24Once we've downloaded the files, we will need to unzip them, enter the
28directory, and move the necessary executables to a central location, 25directory, and move the necessary executables to a central location, such as
29such as `/usr/bin/`. For this installation, we only need the 26`/usr/bin/`. For this installation, we only need the `fastboot` and `adb`
30`fastboot` and `adb` executables. 27executables.
31 28
32```sh 29```sh
33cd ~/Downloads 30cd ~/Downloads
@@ -42,11 +39,11 @@ sudo mv adb /usr/bin
42 39
43## GrapheneOS Files 40## GrapheneOS Files
44 41
45Next, we need the [GrapheneOS files](https://grapheneos.org/releases) 42Next, we need the [GrapheneOS files](https://grapheneos.org/releases) for our
46for our device and model. For example, the Pixel 6 Pro is codenamed 43device and model. For example, the Pixel 6 Pro is codenamed `raven` on the
47`raven` on the release page. 44release page.
48 45
49Once we have the links, let\'s download them to our working directory: 46Once we have the links, let's download them to our working directory:
50 47
51```sh 48```sh
52curl -O https://releases.grapheneos.org/factory.pub 49curl -O https://releases.grapheneos.org/factory.pub
@@ -56,9 +53,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
56 53
571. Validate Integrity 541. Validate Integrity
58 55
59 In order to validate the integrity of the downloaded files, we will 56 In order to validate the integrity of the downloaded files, we will need the
60 need the `signify` package and Graphene\'s 57 `signify` package and Graphene's `factory.pub` file.
61 `factory.pub` file.
62 58
63 ```sh 59 ```sh
64 sudo dnf install signify 60 sudo dnf install signify
@@ -68,8 +64,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
68 curl -O https://releases.grapheneos.org/factory.pub 64 curl -O https://releases.grapheneos.org/factory.pub
69 ``` 65 ```
70 66
71 Then we can validate the files and ensure that no data was corrupted 67 Then we can validate the files and ensure that no data was corrupted or
72 or modified before it was saved to our device. 68 modified before it was saved to our device.
73 69
74 ```sh 70 ```sh
75 signify -Cqp factory.pub -x raven-factory-2022091400.zip.sig && echo verified 71 signify -Cqp factory.pub -x raven-factory-2022091400.zip.sig && echo verified
@@ -77,8 +73,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
77 73
782. Unzip Files 742. Unzip Files
79 75
80 Once the files are verified, we can unzip the Graphene image and 76 Once the files are verified, we can unzip the Graphene image and enter the
81 enter the directory: 77 directory:
82 78
83 ```sh 79 ```sh
84 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400 80 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400
@@ -88,35 +84,34 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
88 84
89## Enable Developer Debugging & OEM Unlock 85## Enable Developer Debugging & OEM Unlock
90 86
91Before we can actually flash anything to the phone, we will need to 87Before we can actually flash anything to the phone, we will need to enable OEM
92enable OEM Unlocking, as well as either USB Debugging or Wireless 88Unlocking, as well as either USB Debugging or Wireless Debugging, depending on
93Debugging, depending on which method we will be using. 89which method we will be using.
94 90
95To start, enable developer mode by going to `Settings` \> 91To start, enable developer mode by going to `Settings` > `About` and tapping
96`About` and tapping `Build Number` seven (7) 92`Build Number` seven (7) times. You may need to enter your PIN to enable this
97times. You may need to enter your PIN to enable this mode. 93mode.
98 94
99Once developer mode is enabled, go to `Settings` \> 95Once developer mode is enabled, go to `Settings` > `System` > `Devloper
100`System` \> `Devloper Options` and enable OEM 96Options` and enable OEM Unlocking, as well as USB or Wireless Debugging. In my
101Unlocking, as well as USB or Wireless Debugging. In my case, I chose USB 97case, I chose USB Debugging and performed all actions via USB cable.
102Debugging and performed all actions via USB cable.
103 98
104Once these options are enabled, plug the phone into the computer and 99Once these options are enabled, plug the phone into the computer and execute the
105execute the following command: 100following command:
106 101
107```sh 102```sh
108adb devices 103adb devices
109``` 104```
110 105
111If an unauthorized error occurs, make sure the USB mode on the phone is 106If an unauthorized error occurs, make sure the USB mode on the phone is changed
112changed from charging to something like \"File Transfer\" or \"PTP.\" 107from charging to something like "File Transfer" or "PTP." You can find the
113You can find the USB mode in the notification tray. 108USB mode in the notification tray.
114 109
115## Reboot Device 110## Reboot Device
116 111
117Once we have found the device via `adb`, we can either boot 112Once we have found the device via `adb`, we can either boot into the bootloader
118into the bootloader interface by holding the volume down button while 113interface by holding the volume down button while the phone reboots or by
119the phone reboots or by executing the following command: 114executing the following command:
120 115
121```sh 116```sh
122adb reboot bootloader 117adb reboot bootloader
@@ -124,17 +119,14 @@ adb reboot bootloader
124 119
125## Unlock the Bootloader 120## Unlock the Bootloader
126 121
127The phone will reboot and load the bootloader screen upon startup. At 122The phone will reboot and load the bootloader screen upon startup. At this
128this point, we are ready to start the actual flashing of GrapheneOS onto 123point, we are ready to start the actual flashing of GrapheneOS onto the device.
129the device.
130 124
131**NOTE**: In my situation, I needed to use `sudo` with every 125**NOTE**: In my situation, I needed to use `sudo` with every `fastboot` command,
132`fastboot` command, but not with `adb` commands. I 126but not with `adb` commands. I am not sure if this is standard or a Fedora
133am not sure if this is standard or a Fedora quirk, but I\'m documenting 127quirk, but I'm documenting my commands verbatim in this post.
134my commands verbatim in this post.
135 128
136First, we start by unlocking the bootloader so that we can load other 129First, we start by unlocking the bootloader so that we can load other ROMs:
137ROMs:
138 130
139```sh 131```sh
140sudo fastboot flashing unlock 132sudo fastboot flashing unlock
@@ -142,24 +134,23 @@ sudo fastboot flashing unlock
142 134
143## Flashing Factory Images 135## Flashing Factory Images
144 136
145Once the phone is unlocked, we can flash it with the 137Once the phone is unlocked, we can flash it with the `flash-all.sh` script found
146`flash-all.sh` script found inside the 138inside the `raven-factory-2022091400` folder we entered earlier:
147`raven-factory-2022091400` folder we entered earlier:
148 139
149```sh 140```sh
150sudo ./flash-all.sh 141sudo ./flash-all.sh
151``` 142```
152 143
153This process should take a few minutes and will print informational 144This process should take a few minutes and will print informational messages as
154messages as things progress. Avoid doing anything on the phone while 145things progress. Avoid doing anything on the phone while this process is
155this process is operating. 146operating.
156 147
157## Lock the Bootloader 148## Lock the Bootloader
158 149
159If everything was successful, the phone should reboot a few times and 150If everything was successful, the phone should reboot a few times and finally
160finally land back on the bootloader screen. At this point, we can 151land back on the bootloader screen. At this point, we can re-lock the bootloader
161re-lock the bootloader to enable full verified boot and protect the 152to enable full verified boot and protect the device from unwanted flashing or
162device from unwanted flashing or erasure of data. 153erasure of data.
163 154
164```sh 155```sh
165sudo fastboot flashing lock 156sudo fastboot flashing lock
content/blog/2022-10-04-mtp-linux.md +23 −26
@@ -5,31 +5,30 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8I recently ran into trouble attempting to mount my GrapheneOS phone to 8I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop
9my laptop running Fedora Linux via the [Media Transfer 9running Fedora Linux via the [Media Transfer
10Protocol](https://en.wikipedia.org/wiki/Media_transfer_protocol) (MTP) 10Protocol](https://en.wikipedia.org/wiki/Media_transfer_protocol) (MTP) and
11and discovered a simple and effective solution. 11discovered a simple and effective solution.
12 12
13# Use a USB 3.0 Port 13# Use a USB 3.0 Port
14 14
15First, ensure that the device was plugged in to the laptop through a USB 15First, ensure that the device was plugged in to the laptop through a USB 3.0
163.0 port, if possible. From a brief glance online, it seems that USB 2.0 16port, if possible. From a brief glance online, it seems that USB 2.0 ports may
17ports may cause issues with dropped connections over MTP. This is purely 17cause issues with dropped connections over MTP. This is purely anecdotal since I
18anecdotal since I don\'t have any evidence to link showing that USB 2.0 18don't have any evidence to link showing that USB 2.0 causes issues, but I can
19causes issues, but I can confirm that switching to a USB 3.0 port seemed 19confirm that switching to a USB 3.0 port seemed to cut out most of my issues.
20to cut out most of my issues.
21 20
22# Switch USB Preferences to MTP 21# Switch USB Preferences to MTP
23 22
24Secondly, you need to ensure that the phone\'s USB preferences/mode is 23Secondly, you need to ensure that the phone's USB preferences/mode is changed
25changed to MTP or File Transfer once the phone is plugged in. Other 24to MTP or File Transfer once the phone is plugged in. Other modes will not allow
26modes will not allow you to access the phone\'s file system. 25you to access the phone's file system.
27 26
28# Install `jmtpfs` 27# Install `jmtpfs`
29 28
30Next, I used the `jmtpfs` package to mount my phone to my 29Next, I used the `jmtpfs` package to mount my phone to my laptop. There are
31laptop. There are other packages that exist, but this one worked 30other packages that exist, but this one worked perfectly for me. On Fedora
32perfectly for me. On Fedora Linux, you can install it like this: 31Linux, you can install it like this:
33 32
34```sh 33```sh
35sudo dnf install jmtpfs -y 34sudo dnf install jmtpfs -y
@@ -37,19 +36,18 @@ sudo dnf install jmtpfs -y
37 36
38# Create a Mount Point 37# Create a Mount Point
39 38
40Once you have the package installed, you just need to create a folder 39Once you have the package installed, you just need to create a folder for the
41for the device to use as a mount point. In my case, I used 40device to use as a mount point. In my case, I used `/mnt/pixel`:
42`/mnt/pixel`:
43 41
44```sh 42```sh
45sudo mkdir /mnt/pixel 43sudo mkdir /mnt/pixel
46sudo chown -R $USER:$USER /mnt/pixel 44sudo chown -R $USER:$USER /mnt/pixel
47``` 45```
48 46
49# Mount & Access the Phone\'s File System 47# Mount & Access the Phone's File System
50 48
51Finally, plug-in and mount the device, and you should be able to see all 49Finally, plug-in and mount the device, and you should be able to see all storage
52storage (internal and external) inside your new folder! 50(internal and external) inside your new folder!
53 51
54```sh 52```sh
55jmtpfs /mnt/pixel 53jmtpfs /mnt/pixel
@@ -62,16 +60,15 @@ Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
62Android device detected, assigning default bug flags 60Android device detected, assigning default bug flags
63``` 61```
64 62
65Now you are mounted and can do anything you\'d like with the device\'s 63Now you are mounted and can do anything you'd like with the device's files:
66files:
67 64
68```sh 65```sh
69cd /mnt/pixel 66cd /mnt/pixel
70ls -lha 67ls -lha
71``` 68```
72 69
73From here, you will be able to see any internal or external storage 70From here, you will be able to see any internal or external storage available on
74available on the device: 71the device:
75 72
76```sh 73```sh
77total 0 74total 0
content/blog/2022-10-04-syncthing.md +93 −103
@@ -7,26 +7,25 @@ draft = false
7 7
8# An Overview of Syncthing 8# An Overview of Syncthing
9 9
10If you\'ve been looking around the self-hosted cloud storage space for a 10If you've been looking around the self-hosted cloud storage space for a while,
11while, you\'ve undoubtedly run into someone suggesting 11you've undoubtedly run into someone suggesting
12[Syncthing](https://syncthing.net) as an option. However, it is an 12[Syncthing](https://syncthing.net) as an option. However, it is an unusual
13unusual alternative for those users out there who are used to having a 13alternative for those users out there who are used to having a centralized cloud
14centralized cloud server that serves as the \"controller\" of the data 14server that serves as the "controller" of the data and interacts with clients
15and interacts with clients on devices to fetch files. 15on devices to fetch files.
16 16
17This post is a walkthrough of the Syncthing software, how I set up my 17This post is a walkthrough of the Syncthing software, how I set up my personal
18personal storage, and some pros and cons of using the software. 18storage, and some pros and cons of using the software.
19 19
20# Installing Syncthing 20# Installing Syncthing
21 21
22To install Syncthing, visit the 22To install Syncthing, visit the [Downloads](https://syncthing.net/downloads/)
23[Downloads](https://syncthing.net/downloads/) page or install via your 23page or install via your device's package manager.
24device\'s package manager.
25 24
26## Server & Desktop 25## Server & Desktop
27 26
28You can install Syncthing on servers and desktops via the Downloads page 27You can install Syncthing on servers and desktops via the Downloads page linked
29linked above or via the command-line. 28above or via the command-line.
30 29
31For Debian-based distros: 30For Debian-based distros:
32 31
@@ -43,37 +42,36 @@ sudo dnf install syncthing
43## Mobile 42## Mobile
44 43
45Syncthing for Android is available on 44Syncthing for Android is available on
46[F-Droid](https://f-droid.org/packages/com.nutomic.syncthingandroid/) 45[F-Droid](https://f-droid.org/packages/com.nutomic.syncthingandroid/) and
47and [Google 46[Google
48Play](https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid). 47Play](https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid).
49Syncthing does not have an official iOS client, but there is a 48Syncthing does not have an official iOS client, but there is a third-party
50third-party client called [Möbius 49client called [Möbius
51Sync](https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216). 50Sync](https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216).
52 51
53# How Does Syncthing Work? 52# How Does Syncthing Work?
54 53
55To start, I wanted to include the main marketing blurb from their 54To start, I wanted to include the main marketing blurb from their website:
56website:
57 55
58> Syncthing is a continuous file synchronization program. It 56> Syncthing is a continuous file synchronization program. It synchronizes files
59> synchronizes files between two or more computers in real time, safely 57> between two or more computers in real time, safely protected from prying eyes.
60> protected from prying eyes. Your data is your data alone, and you 58> Your data is your data alone, and you deserve to choose where it is stored,
61> deserve to choose where it is stored, whether it is shared with some 59> whether it is shared with some third party, and how it's transmitted over the
62> third party, and how it\'s transmitted over the internet. 60> internet.
63 61
64Let\'s break this apart and add in some other details to help explain 62Let's break this apart and add in some other details to help explain what
65what exactly Syncthing does in order to sync files between devices. 63exactly Syncthing does in order to sync files between devices.
66 64
67## Local Syncthing Server(s) 65## Local Syncthing Server(s)
68 66
69Syncthing syncs files between multiple devices by creating a local 67Syncthing syncs files between multiple devices by creating a local server on
70server on each device. These local servers handle a few different 68each device. These local servers handle a few different things, such as watching
71things, such as watching files and directories for changes, hosting an 69files and directories for changes, hosting an administrative GUI website, and
72administrative GUI website, and authenticating with connected devices. 70authenticating with connected devices.
73 71
74You can also start, stop, and restart the Syncthing server via the 72You can also start, stop, and restart the Syncthing server via the command-line
75command-line or web dashboard. If you\'re running Syncthing on a device 73or web dashboard. If you're running Syncthing on a device with `systemd`, you
76with `systemd`, you can use the following commands: 74can use the following commands:
77 75
78```sh 76```sh
79sudo systemctl start syncthing@username.service 77sudo systemctl start syncthing@username.service
@@ -83,97 +81,89 @@ sudo systemctl stop syncthing@username.service
83 81
84## Syncthing Dashboard 82## Syncthing Dashboard
85 83
86This biggest part of Syncthing is the admin GUI website that runs on 84This biggest part of Syncthing is the admin GUI website that runs on each device
87each device (note that mobile devices will use the Syncthing app rather 85(note that mobile devices will use the Syncthing app rather than the web GUI).
88than the web GUI). The admin GUI is available through the web browser on 86The admin GUI is available through the web browser on the local device that is
89the local device that is running Syncthing - simply go to 87running Syncthing - simply go to `http://localhost:8384` or
90`http://localhost:8384` or 88`http://127.0.0.1:8384`. This web page is the place where you will change
91`http://127.0.0.1:8384`. This web page is the place where you 89settings, add/modify synced files, and add/modify connected devices.
92will change settings, add/modify synced files, and add/modify connected
93devices.
94 90
95Here\'s an example web GUI dashboard: 91Here's an example web GUI dashboard:
96 92
97![Syncthing 93![Syncthing
98Dashboard](https://img.cleberg.net/blog/20221020-syncthing/syncthing_gui.png) 94Dashboard](https://img.cleberg.net/blog/20221020-syncthing/syncthing_gui.png)
99 95
100## Remote Devices 96## Remote Devices
101 97
102A cloud storage solution wouldn\'t be very useful if you aren\'t able to 98A cloud storage solution wouldn't be very useful if you aren't able to share
103share data among various devices. Syncthing does this by sharing Device 99data among various devices. Syncthing does this by sharing Device IDs to connect
104IDs to connect servers, and then by manually sharing Folders with 100servers, and then by manually sharing Folders with devices that have been
105devices that have been connected. 101connected.
106 102
107For instance, if you have a laptop running Syncthing and then install 103For instance, if you have a laptop running Syncthing and then install the
108the Syncthing mobile app on a phone, you could scan the laptop\'s QR 104Syncthing mobile app on a phone, you could scan the laptop's QR code for Device
109code for Device ID and then accept the authentication on the laptop\'s 105ID and then accept the authentication on the laptop's dashboard. Next, you can
110dashboard. Next, you can use either device to select a folder for 106use either device to select a folder for sharing and dictating which device
111sharing and dictating which device should send, receive, or both. 107should send, receive, or both.
112 108
113When you connect devices, you can set one device as an \"Introducer,\" 109When you connect devices, you can set one device as an "Introducer," which can
114which can add devices from the introducer to the device list, for 110add devices from the introducer to the device list, for mutually shared folders.
115mutually shared folders. You can also configure Auto Accept, 111You can also configure Auto Accept, compression, rate limits, and more settings
116compression, rate limits, and more settings per device. 112per device.
117 113
118# My Personal Cloud Storage Set-up 114# My Personal Cloud Storage Set-up
119 115
120Personally, I use a model similar to a traditional cloud storage 116Personally, I use a model similar to a traditional cloud storage service. I have
121service. I have a \"centralized\" server running 24/7 that acts as an 117a "centralized" server running 24/7 that acts as an Introducer for my
122Introducer for my Syncthing network. I think of this as my main storage 118Syncthing network. I think of this as my main storage and all other devices as
123and all other devices as tertiary client devices. I will likely add 119tertiary client devices. I will likely add additional servers as backups as time
124additional servers as backups as time goes on so that I don\'t have to 120goes on so that I don't have to rely on my laptop or phone as the only backups.
125rely on my laptop or phone as the only backups.
126 121
127Currently, I have one desktop and one mobile device connected to the 122Currently, I have one desktop and one mobile device connected to the network,
128network, both running intermittently as they are not powered-on 24/7. 123both running intermittently as they are not powered-on 24/7.
129 124
130The initial set-up of the software was easy enough, but data transfer 125The initial set-up of the software was easy enough, but data transfer rates were
131rates were incredibly slow for me due to the Wi-Fi. Instead, I plugged 126incredibly slow for me due to the Wi-Fi. Instead, I plugged my laptop into the
132my laptop into the ethernet network that my server is on and manually 127ethernet network that my server is on and manually copied my folders over to the
133copied my folders over to the server with `scp`. Once 128server with `scp`. Once complete, Syncthing validated that all files were there
134complete, Syncthing validated that all files were there and not missing, 129and not missing, and it did not need to transfer any data through the WAN.
135and it did not need to transfer any data through the WAN.
136 130
137As slow as the transfer was going, this probably saved me a few days of 131As slow as the transfer was going, this probably saved me a few days of waiting
138waiting for my \~100GB sync. 132for my ~100GB sync.
139 133
140# Pros & Cons 134# Pros & Cons
141 135
142I\'ve put together a short list of pros and cons for Syncthing. I 136I've put together a short list of pros and cons for Syncthing. I thought about
143thought about my experiences with Nextcloud, WebDAV, proprietary 137my experiences with Nextcloud, WebDAV, proprietary services (Google Drive,
144services (Google Drive, iCloud, etc.), and privacy-focused cloud 138iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.).
145solutions (pCloud, Tresorit, etc.).
146 139
147**Pros:** 140**Pros:**
148 141
149- I\'ve faced no data loss at all through my two-month trial run. 142- I've faced no data loss at all through my two-month trial run.
150- No third-parties store your data on their servers. 143- No third-parties store your data on their servers.
151- You have full control over your data and can take your data and 144- You have full control over your data and can take your data and leave at any
152 leave at any time. 145 time.
153- It\'s possible to encrypt client-side easily with software like 146- It's possible to encrypt client-side easily with software like Cryptomator.
154 Cryptomator. 147- No proprietary clients or mounted volumes, just plain files and folders.
155- No proprietary clients or mounted volumes, just plain files and
156 folders.
157 148
158**Cons:** 149**Cons:**
159 150
160- The learning curve is steeper than traditional cloud services and is 151- The learning curve is steeper than traditional cloud services and is focused
161 focused on a technical audience. 152 on a technical audience.
162- If a device needs to modify files in a Folder, the devices will need 153- If a device needs to modify files in a Folder, the devices will need to sync
163 to sync ALL files from the folder, which may be large. To avoid size 154 ALL files from the folder, which may be large. To avoid size restraints, split
164 restraints, split large folders into smaller folders for syncing. 155 large folders into smaller folders for syncing.
165- Syncing can be slow due to the clients/servers initially connecting 156- Syncing can be slow due to the clients/servers initially connecting or
166 or re-connecting after sleeping. 157 re-connecting after sleeping.
167- Multiple personal devices are required and require the user to own 158- Multiple personal devices are required and require the user to own or rent
168 or rent them as no third-party servers are involved in the storage 159 them as no third-party servers are involved in the storage of data.
169 of data. 160
170 161Overall, I've had a great experience with Syncthing so far. I've had no data
171Overall, I\'ve had a great experience with Syncthing so far. I\'ve had 162loss, syncing has been quick and easy when changes are made to files, device
172no data loss, syncing has been quick and easy when changes are made to 163connections are reliable, and I love the freedom of controlling the clients and
173files, device connections are reliable, and I love the freedom of 164servers as I choose.
174controlling the clients and servers as I choose. 165
175 166Not to mention that I appreciate that I - or someone else - could pull the
176Not to mention that I appreciate that I - or someone else - could pull 167Syncthing [source code](https://github.com/syncthing) and continue
177the Syncthing [source code](https://github.com/syncthing) and continue 168development/support if the Syncthing Foundation decides to stop developing the
178development/support if the Syncthing Foundation decides to stop 169software or sells the business.
179developing the software or sells the business.
content/blog/2022-10-22-alpine-linux.md +96 −110
@@ -7,80 +7,73 @@ draft = false
7 7
8# Alpine Linux 8# Alpine Linux
9 9
10[Alpine Linux](https://alpinelinux.org) is a very small distro, built on 10[Alpine Linux](https://alpinelinux.org) is a very small distro, built on musl
11musl libc and busybox. It uses ash as the default shell, OpenRC as the 11libc and busybox. It uses ash as the default shell, OpenRC as the init system,
12init system, and apk as the package manager. According to their website, 12and apk as the package manager. According to their website, an Alpine container
13an Alpine container \"requires no more than 8 MB and a minimal 13"requires no more than 8 MB and a minimal installation to disk requires around
14installation to disk requires around 130 MB of storage.\" An actual bare 14130 MB of storage." An actual bare metal machine is recommended to have 100 MB
15metal machine is recommended to have 100 MB of RAM and 0-700 MB of 15of RAM and 0-700 MB of storage space.
16storage space. 16
17 17Historically, I've used Ubuntu's minimal installation image as my server OS
18Historically, I\'ve used Ubuntu\'s minimal installation image as my 18for the last five years. Ubuntu worked well and helped as my original server
19server OS for the last five years. Ubuntu worked well and helped as my 19contained an nVidia GPU and no onboard graphics, so quite a few distros won't
20original server contained an nVidia GPU and no onboard graphics, so 20boot or install without a lot of tinkering.
21quite a few distros won\'t boot or install without a lot of tinkering. 21
22 22Alpine has given me a huge increase in performance across my Docker apps and
23Alpine has given me a huge increase in performance across my Docker apps 23Nginx websites. CPU load for the new server I'm using to test Alpine hovers
24and Nginx websites. CPU load for the new server I\'m using to test 24around 0-5% on average with an Intel(R) Core(TM) i3-6100 CPU @ 3.70GHz.
25Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100 25
26CPU @ 3.70GHz. 26The only services I haven't moved over to Alpine are Plex Media Server and
27 27Syncthing, which may increase CPU load quite a bit depending on how many streams
28The only services I haven\'t moved over to Alpine are Plex Media Server 28are running.
29and Syncthing, which may increase CPU load quite a bit depending on how
30many streams are running.
31 29
32## Installation 30## Installation
33 31
34In terms of installation, Alpine has an incredibly useful 32In terms of installation, Alpine has an incredibly useful
35[wiki](https://wiki.alpinelinux.org/wiki/Installation) that will guide a 33[wiki](https://wiki.alpinelinux.org/wiki/Installation) that will guide a user
36user throughout the installation and post-installation processes, as 34throughout the installation and post-installation processes, as well as various
37well as various other articles and guides. 35other articles and guides.
38 36
39To install Alpine, find an appropriate [image to 37To install Alpine, find an appropriate [image to
40download](https://alpinelinux.org/downloads/) and flash it to a USB 38download](https://alpinelinux.org/downloads/) and flash it to a USB using
41using software such as Rufus or Etcher. I opted to use the Standard 39software such as Rufus or Etcher. I opted to use the Standard image for my
42image for my x86~64~ architecture. 40x86~64~ architecture.
43 41
44Once the USB is ready, plug it into the machine and reboot. Note that 42Once the USB is ready, plug it into the machine and reboot. Note that you may
45you may have to use a key such as `Esc` or `F1-12` 43have to use a key such as `Esc` or `F1-12` to access the boot menu. The Alpine
46to access the boot menu. The Alpine Linux terminal will load quickly and 44Linux terminal will load quickly and for a login.
47for a login.
48 45
49To log in to the installation image, use the `root` account; 46To log in to the installation image, use the `root` account; there is no
50there is no password. Once logged-in, execute the setup command: 47password. Once logged-in, execute the setup command:
51 48
52```sh 49```sh
53setup-alpine 50setup-alpine
54``` 51```
55 52
56The setup script will ask a series of questions to configure the system. 53The setup script will ask a series of questions to configure the system. Be sure
57Be sure to answer carefully or else you may have to re-configure the 54to answer carefully or else you may have to re-configure the system after boot.
58system after boot. 55
59 56- Keyboard Layout (Local keyboard language and usage mode, e.g., us and variant
60- Keyboard Layout (Local keyboard language and usage mode, e.g., us 57 of us-nodeadkeys.)
61 and variant of us-nodeadkeys.) 58- Hostname (The name for the computer.)
62- Hostname (The name for the computer.) 59- Network (For example, automatic IP address discovery with the "DHCP"
63- Network (For example, automatic IP address discovery with the 60 protocol.)
64 \"DHCP\" protocol.) 61- DNS Servers (Domain Name Servers to query. For privacy reasons, it is NOT
65- DNS Servers (Domain Name Servers to query. For privacy reasons, it 62 recommended to route every local request to servers like Google's 8.8.8.8.)
66 is NOT recommended to route every local request to servers like 63- Timezone
67 Google\'s 8.8.8.8 .) 64- Proxy (Proxy server to use for accessing the web. Use "none" for direct
68- Timezone 65 connections to the internet.)
69- Proxy (Proxy server to use for accessing the web. Use \"none\" for 66- Mirror (From where to download packages. Choose the organization you trust
70 direct connections to the internet.) 67 giving your usage patterns to.)
71- Mirror (From where to download packages. Choose the organization you 68- SSH (Secure SHell remote access server. "Openssh" is part of the default
72 trust giving your usage patterns to.) 69 install image. Use "none" to disable remote login, e.g. on laptops.)
73- SSH (Secure SHell remote access server. \"Openssh\" is part of the 70- NTP (Network Time Protocol client used for keeping the system clock in sync
74 default install image. Use \"none\" to disable remote login, e.g. on 71 with a time-server. Package "chrony" is part of the default install image.)
75 laptops.) 72- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as
76- NTP (Network Time Protocol client used for keeping the system clock 73 described above.)
77 in sync with a time-server. Package \"chrony\" is part of the 74
78 default install image.) 75Once the setup script is finished, be sure to reboot the machine and remove the
79- Disk Mode (Select between diskless (disk=\"none\"), \"data\" or 76USB device.
80 \"sys\", as described above.)
81
82Once the setup script is finished, be sure to reboot the machine and
83remove the USB device.
84 77
85```sh 78```sh
86reboot 79reboot
@@ -89,14 +82,12 @@ reboot
89## Post-Installation 82## Post-Installation
90 83
91There are many things you can do once your Alpine Linux system is up and 84There are many things you can do once your Alpine Linux system is up and
92running, and it largely depends on what you\'ll use the machine for. 85running, and it largely depends on what you'll use the machine for. I'm going
93I\'m going to walk through my personal post-installation setup for my 86to walk through my personal post-installation setup for my web server.
94web server.
95 87
961. Upgrade the System 881. Upgrade the System
97 89
98 First, login as `root` in order to update and upgrade the 90 First, login as `root` in order to update and upgrade the system:
99 system:
100 91
101 ```sh 92 ```sh
102 apk -U upgrade 93 apk -U upgrade
@@ -104,9 +95,9 @@ web server.
104 95
1052. Adding a User 962. Adding a User
106 97
107 I needed to add a user so that I don\'t need to log in as root. Note 98 I needed to add a user so that I don't need to log in as root. Note that if
108 that if you\'re used to using the `sudo` command, you 99 you're used to using the `sudo` command, you will now need to use the
109 will now need to use the `doas` command on Alpine Linux. 100 `doas` command on Alpine Linux.
110 101
111 ```sh 102 ```sh
112 apk add doas 103 apk add doas
@@ -122,15 +113,14 @@ web server.
122 113
1233. Enable Community Packages 1143. Enable Community Packages
124 115
125 In order to install more common packages that aren\'t found in the 116 In order to install more common packages that aren't found in the `main`
126 `main` repository, you will need to enable the 117 repository, you will need to enable the `community` repository:
127 `community` repository:
128 118
129 ```sh 119 ```sh
130 doas nano /etc/apk/repositories 120 doas nano /etc/apk/repositories
131 ``` 121 ```
132 122
133 Uncomment the community line for whichever version of Alpine you\'re 123 Uncomment the community line for whichever version of Alpine you're
134 running: 124 running:
135 125
136 ```sh 126 ```sh
@@ -144,9 +134,9 @@ web server.
144 134
1454. Install Required Packages 1354. Install Required Packages
146 136
147 Now that the community packages are available, you can install any 137 Now that the community packages are available, you can install any packages
148 packages you need. In my case, I installed the web server packages I 138 you need. In my case, I installed the web server packages I need for my
149 need for my services: 139 services:
150 140
151 ```sh 141 ```sh
152 doas apk add nano nginx docker docker-compose ufw 142 doas apk add nano nginx docker docker-compose ufw
@@ -154,15 +144,15 @@ web server.
154 144
1555. SSH 1455. SSH
156 146
157 If you didn\'t install OpenSSH as part of the installation, you can 147 If you didn't install OpenSSH as part of the installation, you can do so
158 do so now: 148 now:
159 149
160 ```sh 150 ```sh
161 doas apk add openssh 151 doas apk add openssh
162 ``` 152 ```
163 153
164 Next, either create a new key or copy your SSH key to the server 154 Next, either create a new key or copy your SSH key to the server from your
165 from your current machines: 155 current machines:
166 156
167 ```sh 157 ```sh
168 # Create a new key 158 # Create a new key
@@ -178,9 +168,9 @@ web server.
178 168
1796. Firewall 1696. Firewall
180 170
181 Lastly, I installed `ufw` above as my firewall. To set 171 Lastly, I installed `ufw` above as my firewall. To set up, default to deny
182 up, default to deny incoming and allow outgoing connections. Then 172 incoming and allow outgoing connections. Then selectively allow other ports
183 selectively allow other ports or apps as needed. 173 or apps as needed.
184 174
185 ```sh 175 ```sh
186 doas ufw default deny incoming 176 doas ufw default deny incoming
@@ -192,8 +182,8 @@ web server.
192 182
1937. Change Hostname 1837. Change Hostname
194 184
195 If you don\'t like the hostname set during installation, you just 185 If you don't like the hostname set during installation, you just need to
196 need to edit two files. First, edit the simple hostname file: 186 edit two files. First, edit the simple hostname file:
197 187
198 ```sh 188 ```sh
199 doas nano /etc/hostname 189 doas nano /etc/hostname
@@ -216,8 +206,8 @@ web server.
216 206
217# Nginx Web Server 207# Nginx Web Server
218 208
219To set up my web server, I simply created the `www` user and 209To set up my web server, I simply created the `www` user and created the
220created the necessary files. 210necessary files.
221 211
222```sh 212```sh
223doas adduser -D -g 'www' www 213doas adduser -D -g 'www' www
@@ -227,17 +217,17 @@ doas chown -R www:www /var/lib/nginx/
227doas chown -R www:www /www 217doas chown -R www:www /www
228``` 218```
229 219
230If you\'re running a simple webroot, you can alter the main 220If you're running a simple webroot, you can alter the main `nginx.conf` file.
231`nginx.conf` file. Otherwise, you can drop configuration 221Otherwise, you can drop configuration files in the following directory. You
232files in the following directory. You don\'t need to enable or symlink 222don't need to enable or symlink the configuration file like you do in other
233the configuration file like you do in other systems. 223systems.
234 224
235```sh 225```sh
236doas nano /etc/nginx/http.d/example_website.conf 226doas nano /etc/nginx/http.d/example_website.conf
237``` 227```
238 228
239Once the configuration is set and pointed at the `/www` 229Once the configuration is set and pointed at the `/www` directory to serve
240directory to serve files, enable the Nginx service: 230files, enable the Nginx service:
241 231
242```sh 232```sh
243# Note that 'default' must be included or Nginx will not start on boot 233# Note that 'default' must be included or Nginx will not start on boot
@@ -246,19 +236,16 @@ doas rc-update add nginx default
246 236
247# Docker Containers 237# Docker Containers
248 238
249Docker works exactly the same as other systems. Either execute a 239Docker works exactly the same as other systems. Either execute a `docker run`
250`docker run` command or create a 240command or create a `docker-compose.yml` file and do `docker-compose up -d`.
251`docker-compose.yml` file and do
252`docker-compose up -d`.
253 241
254# Git Server 242# Git Server
255 243
256I went in-depth on how to self-host a git server in another post: 244I went in-depth on how to self-host a git server in another post: [Self-Hosting
257[Self-Hosting a Personal Git Server](../git-server/). 245a Personal Git Server](../git-server/).
258 246
259However, there are a few differences with Alpine. First note that in 247However, there are a few differences with Alpine. First note that in order to
260order to change the `git` user\'s shell, you must do a few 248change the `git` user's shell, you must do a few things a little different:
261things a little different:
262 249
263```sh 250```sh
264doas apk add libuser 251doas apk add libuser
@@ -270,12 +257,11 @@ doas lchsh git
270 257
271# Thoughts on Alpine 258# Thoughts on Alpine
272 259
273So far, I love Alpine Linux. I have no complaints about anything at this 260So far, I love Alpine Linux. I have no complaints about anything at this point,
274point, but I\'m not completely finished with the migration yet. Once 261but I'm not completely finished with the migration yet. Once I'm able to
275I\'m able to upgrade my hardware to a rack-mounted server, I will 262upgrade my hardware to a rack-mounted server, I will migrate Plex and Syncthing
276migrate Plex and Syncthing over to Alpine as well - possibly putting 263over to Alpine as well - possibly putting Plex into a container or VM.
277Plex into a container or VM.
278 264
279The performance is stellar, the `apk` package manager is 265The performance is stellar, the `apk` package manager is seamless, and system
280seamless, and system administration tasks are effortless. My only regret 266administration tasks are effortless. My only regret is that I didn't install
281is that I didn\'t install Alpine sooner. 267Alpine sooner.
content/blog/2022-10-30-linux-display-manager.md +20 −25
@@ -8,18 +8,16 @@ draft = false
8# Display Manager Services 8# Display Manager Services
9 9
10In order to change the [display 10In order to change the [display
11manager](https://en.wikipedia.org/wiki/Display_manager) on Void Linux - 11manager](https://en.wikipedia.org/wiki/Display_manager) on Void Linux - or any
12or any other Linux distro - you need to identify the currently enabled 12other Linux distro - you need to identify the currently enabled display manager.
13display manager.
14 13
15## Disabling the Current Display Manager 14## Disabling the Current Display Manager
16 15
17Void Linux only has one ISO available for download with a pre-built 16Void Linux only has one ISO available for download with a pre-built display
18display manager at the time of this post: the XFCE ISO. If you\'ve 17manager at the time of this post: the XFCE ISO. If you've installed this
19installed this version, the pre-assigned display manager is 18version, the pre-assigned display manager is `lxdm`. If you installed another
20`lxdm`. If you installed another display manager, replace 19display manager, replace `lxdm` in the following command with the display
21`lxdm` in the following command with the display manager you 20manager you have installed.
22have installed.
23 21
24To disable `lxdm`, simply remove the service symlink: 22To disable `lxdm`, simply remove the service symlink:
25 23
@@ -29,9 +27,8 @@ sudo rm /var/service/lxdm
29 27
30## Enabling a New Display Manager 28## Enabling a New Display Manager
31 29
32If you want to enable a new display manager, you can do so after 30If you want to enable a new display manager, you can do so after `lxdm` is
33`lxdm` is disabled. Make sure to replace 31disabled. Make sure to replace `<new_display_manager>` with your new DM, such as
34`<new_display_manager>` with your new DM, such as
35`gdm`, `xdm`, etc. 32`gdm`, `xdm`, etc.
36 33
37```sh 34```sh
@@ -41,8 +38,8 @@ sudo ln -s /etc/sv/<new_display_manager> /var/service
41# Set Up `.xinitrc` 38# Set Up `.xinitrc`
42 39
43Depending on your setup, you may need to create a few X files, such as 40Depending on your setup, you may need to create a few X files, such as
44`~/.xinitrc`. For my personal set-up, I created this file to 41`~/.xinitrc`. For my personal set-up, I created this file to launch the i3wm as
45launch the i3wm as my desktop. 42my desktop.
46 43
47```sh 44```sh
48nano ~/.xinitrc 45nano ~/.xinitrc
@@ -54,21 +51,20 @@ nano ~/.xinitrc
54exec i3 51exec i3
55``` 52```
56 53
57If you run a desktop other than i3, simply replace `i3` with 54If you run a desktop other than i3, simply replace `i3` with the shell command
58the shell command that launches that desktop. 55that launches that desktop.
59 56
60# Set Up Your Shell Profile 57# Set Up Your Shell Profile
61 58
62Finally, in order to automatically launch an X session upon login, you 59Finally, in order to automatically launch an X session upon login, you will need
63will need to edit the `.bash_profile` (bash) or 60to edit the `.bash_profile` (bash) or `.zprofile` (zsh) files for your shell:
64`.zprofile` (zsh) files for your shell:
65 61
66```sh 62```sh
67nano ~/.zprofile 63nano ~/.zprofile
68``` 64```
69 65
70Add the following snippet to the end of the shell profile file. This 66Add the following snippet to the end of the shell profile file. This will
71will execute the `startx` command upon login. 67execute the `startx` command upon login.
72 68
73```sh 69```sh
74if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then 70if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
@@ -76,7 +72,6 @@ if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
76fi 72fi
77``` 73```
78 74
79Alternatively, you can ignore this step and simply choose to manually 75Alternatively, you can ignore this step and simply choose to manually execute
80execute `startx` upon login. This can be useful if you have 76`startx` upon login. This can be useful if you have issues with your desktop or
81issues with your desktop or like to manually launch different desktops 77like to manually launch different desktops by choice.
82by choice.
content/blog/2022-11-07-self-hosting-matrix.md +43 −52
@@ -7,21 +7,21 @@ draft = false
7 7
8# Synpase 8# Synpase
9 9
10If you\'re reading this, you likely know that 10If you're reading this, you likely know that
11[Synapse](https://github.com/matrix-org/synapse/) is a popular 11[Synapse](https://github.com/matrix-org/synapse/) is a popular
12[Matrix](https://matrix.org/) home server software that allows users to 12[Matrix](https://matrix.org/) home server software that allows users to run
13run their own Matrix home server. 13their own Matrix home server.
14 14
15This post is a short guide describing how I was able to get Synapse 15This post is a short guide describing how I was able to get Synapse working in a
16working in a minimally-usable state on Alpine Linux. 16minimally-usable state on Alpine Linux.
17 17
18# Installation Process 18# Installation Process
19 19
20## Dependencies 20## Dependencies
21 21
22First, since there is no Alpine-specific package for Synapse, we need to 22First, since there is no Alpine-specific package for Synapse, we need to ensure
23ensure that Alpine has the required dependencies for the Python-based 23that Alpine has the required dependencies for the Python-based installation
24installation method. 24method.
25 25
26```sh 26```sh
27doas apk -U update 27doas apk -U update
@@ -41,10 +41,9 @@ pip install matrix-synapse
41 41
42## Running Synapse 42## Running Synapse
43 43
44Once installed, running Synapse is easy. Simply execute the following 44Once installed, running Synapse is easy. Simply execute the following command,
45command, replacing `example.com` with the domain name that 45replacing `example.com` with the domain name that will be used with this home
46will be used with this home server. This will generate the configuration 46server. This will generate the configuration files needed to run the server.
47files needed to run the server.
48 47
49```sh 48```sh
50python -m synapse.app.homeserver \ 49python -m synapse.app.homeserver \
@@ -62,16 +61,14 @@ synctl start
62 61
63## Configuring Synapse 62## Configuring Synapse
64 63
65To make any change to Synapse, we need to edit the `YAML` 64To make any change to Synapse, we need to edit the `YAML` configuration file:
66configuration file:
67 65
68```sh 66```sh
69nano ~/synapse/homeserver.yaml 67nano ~/synapse/homeserver.yaml
70``` 68```
71 69
72For now, we just need to ensure the `server_name` is 70For now, we just need to ensure the `server_name` is accurate. However, there
73accurate. However, there are a lot of other configuration options found 71are a lot of other configuration options found in the [Configuring
74in the [Configuring
75Synapse](https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html) 72Synapse](https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html)
76documentation that can be enabled/disabled at any point. 73documentation that can be enabled/disabled at any point.
77 74
@@ -87,9 +84,9 @@ synctl restart
87 84
88## Nginx Reverse-Proxy 85## Nginx Reverse-Proxy
89 86
90To ensure that Synapse is reachable from the public, we need to connect 87To ensure that Synapse is reachable from the public, we need to connect our
91our domain to the Synapse server. In my case, I use a Nginx 88domain to the Synapse server. In my case, I use a Nginx reverse-proxy for this
92reverse-proxy for this purpose. 89purpose.
93 90
94To use Nginx, we need to create a reverse-proxy configuration file: 91To use Nginx, we need to create a reverse-proxy configuration file:
95 92
@@ -97,9 +94,8 @@ To use Nginx, we need to create a reverse-proxy configuration file:
97doas nano /etc/nginx/http.d/example.com.conf 94doas nano /etc/nginx/http.d/example.com.conf
98``` 95```
99 96
100If you already have TLS certificates for this domain 97If you already have TLS certificates for this domain (`example.com`), you can
101(`example.com`), you can simply use the SSL configuration and 98simply use the SSL configuration and point toward your TLS certificates.
102point toward your TLS certificates.
103 99
104``` conf 100``` conf
105server { 101server {
@@ -143,10 +139,9 @@ server {
143``` 139```
144 140
145If you need to generate TLS certificates (I recommend 141If you need to generate TLS certificates (I recommend
146[Certbot](https://certbot.eff.org/)), you\'ll need a more minimal Nginx 142[Certbot](https://certbot.eff.org/)), you'll need a more minimal Nginx conf
147conf file before you can use the TLS-enabled example above. Instead, use 143file before you can use the TLS-enabled example above. Instead, use this
148this configuration file during the Certbot certificate generation 144configuration file during the Certbot certificate generation process:
149process:
150 145
151``` conf 146``` conf
152server { 147server {
@@ -158,20 +153,19 @@ server {
158} 153}
159``` 154```
160 155
161Once you\'re done editing the Nginx conf file, restart Nginx: 156Once you're done editing the Nginx conf file, restart Nginx:
162 157
163```sh 158```sh
164doas rc-service nginx restart 159doas rc-service nginx restart
165``` 160```
166 161
167If you still need to generate TLS certificates, run `certbot` 162If you still need to generate TLS certificates, run `certbot` now and obtain the
168now and obtain the certificates. Certbot will ask if you want to use a 163certificates. Certbot will ask if you want to use a webroot or spin up a
169webroot or spin up a temporary web server. I **highly\*** recommend 164temporary web server. I **highly** recommend using the temporary web server due
170using the temporary web server due to the many issues with using a 165to the many issues with using a webroot.
171webroot.
172 166
173You will need to stop Nginx in order to user the temporary web server 167You will need to stop Nginx in order to user the temporary web server option
174option with Certbot: 168with Certbot:
175 169
176```sh 170```sh
177# Stop Nginx so certbot can spin up a temp webserver for cert generation 171# Stop Nginx so certbot can spin up a temp webserver for cert generation
@@ -182,13 +176,13 @@ doas rc-service nginx start
182 176
183## Open Firewall & Router Ports 177## Open Firewall & Router Ports
184 178
185If you use a firewall on the server, open the `8448` port for 179If you use a firewall on the server, open the `8448` port for discovery and
186discovery and federation, as well as the normal web server ports if 180federation, as well as the normal web server ports if you're using a reverse
187you\'re using a reverse proxy. If you want additional services, such as 181proxy. If you want additional services, such as voice calls, you will need to
188voice calls, you will need to read the Synapse documentation to see 182read the Synapse documentation to see which ports need to be opened for those
189which ports need to be opened for those features. 183features.
190 184
191Here\'s an example of the Universal Firewall (UFW) software: 185Here's an example of the Universal Firewall (UFW) software:
192 186
193```sh 187```sh
194# Matrix port 188# Matrix port
@@ -197,15 +191,13 @@ doas ufw allow 8448
197doas ufw allow "Nginx Full" 191doas ufw allow "Nginx Full"
198``` 192```
199 193
200Remember to forward any Synapse ports, such as `8448`, 194Remember to forward any Synapse ports, such as `8448`, `80`, and `443`, in your
201`80`, and `443`, in your Router from the internet 195Router from the internet to your server's IP address.
202to your server\'s IP address.
203 196
204## Adding Matrix Users 197## Adding Matrix Users
205 198
206Finally, if you didn\'t enable public registration in the 199Finally, if you didn't enable public registration in the `homeserver.yaml`
207`homeserver.yaml` file, you can manually create users via the 200file, you can manually create users via the command-line:
208command-line:
209 201
210```sh 202```sh
211cd ~/synapse 203cd ~/synapse
@@ -213,9 +205,8 @@ register_new_matrix_user -c homeserver.yaml
213``` 205```
214 206
215Remember that the format for federated Matrix usernames is 207Remember that the format for federated Matrix usernames is
216`@username:example.com` when logging in to client 208`@username:example.com` when logging in to client applications.
217applications.
218 209
219Once Synapse is running, and you have a username, you are ready to log 210Once Synapse is running, and you have a username, you are ready to log in to a
220in to a Matrix client and start sending messages, joining rooms, and 211Matrix client and start sending messages, joining rooms, and utilizing your very
221utilizing your very own Matrix server. 212own Matrix server.
content/blog/2022-11-11-nginx-tmp-errors.md +17 −20
@@ -5,15 +5,14 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8*This is a brief post so that I personally remember the solution as it 8*This is a brief post so that I personally remember the solution as it has
9has occurred multiple times for me.* 9occurred multiple times for me.*
10 10
11# The Problem 11# The Problem
12 12
13After migrating to a new server OS, I started receiving quite a few 13After migrating to a new server OS, I started receiving quite a few permission
14permission errors like the one below. These popped up for various 14errors like the one below. These popped up for various different websites I'm
15different websites I\'m serving via Nginx on this server, but did not 15serving via Nginx on this server, but did not prevent the website from loading.
16prevent the website from loading.
17 16
18I found the errors in the standard log file: 17I found the errors in the standard log file:
19 18
@@ -25,20 +24,18 @@ cat /var/log/nginx/error.log
252022/11/11 11:30:34 [crit] 8970#8970: *10 open() "/var/lib/nginx/tmp/proxy/3/00/0000000003" failed (13: Permission denied) while reading upstream, client: 169.150.203.10, server: cyberchef.example.com, request: "GET /assets/main.css HTTP/2.0", upstream: "http://127.0.0.1:8111/assets/main.css", host: "cyberchef.example.com", referrer: "https://cyberchef.example.com/" 242022/11/11 11:30:34 [crit] 8970#8970: *10 open() "/var/lib/nginx/tmp/proxy/3/00/0000000003" failed (13: Permission denied) while reading upstream, client: 169.150.203.10, server: cyberchef.example.com, request: "GET /assets/main.css HTTP/2.0", upstream: "http://127.0.0.1:8111/assets/main.css", host: "cyberchef.example.com", referrer: "https://cyberchef.example.com/"
26``` 25```
27 26
28You can see that the error is `13: Permission denied` and it 27You can see that the error is `13: Permission denied` and it occurs in the
29occurs in the `/var/lib/nginx/tmp/` directory. In my case, I 28`/var/lib/nginx/tmp/` directory. In my case, I had thousands of errors where
30had thousands of errors where Nginx was denied permission to read/write 29Nginx was denied permission to read/write files in this directory.
31files in this directory.
32 30
33So how do I fix it? 31So how do I fix it?
34 32
35# The Solution 33# The Solution
36 34
37In order to resolve the issue, I had to ensure the 35In order to resolve the issue, I had to ensure the `/var/lib/nginx` directory is
38`/var/lib/nginx` directory is owned by Nginx. Mine was owned 36owned by Nginx. Mine was owned by the `www` user and Nginx was not able to read
39by the `www` user and Nginx was not able to read or write 37or write files within that directory. This prevented Nginx from caching
40files within that directory. This prevented Nginx from caching temporary 38temporary files.
41files.
42 39
43```sh 40```sh
44# Alpine Linux 41# Alpine Linux
@@ -48,9 +45,9 @@ doas chown -R nginx:nginx /var/lib/nginx
48sudo chown -R nginx:nginx /var/lib/nginx 45sudo chown -R nginx:nginx /var/lib/nginx
49``` 46```
50 47
51You *may* also be able to change the `proxy_temp_path` in 48You *may* also be able to change the `proxy_temp_path` in your Nginx config, but
52your Nginx config, but I did not try this. Here\'s a suggestion I found 49I did not try this. Here's a suggestion I found online that may work if the
53online that may work if the above solution does not: 50above solution does not:
54 51
55```sh 52```sh
56nano /etc/nginx/http.d/example.com.conf 53nano /etc/nginx/http.d/example.com.conf
@@ -68,8 +65,8 @@ server {
68} 65}
69``` 66```
70 67
71Finally, restart Nginx and your server should be able to cache temporary 68Finally, restart Nginx and your server should be able to cache temporary files
72files again. 69again.
73 70
74```sh 71```sh
75# Alpine Linux (OpenRC) 72# Alpine Linux (OpenRC)
content/blog/2022-11-27-server-build.md +85 −90
@@ -7,142 +7,137 @@ draft = false
7 7
8# The Dilemma 8# The Dilemma
9 9
10For years, I have been using desktops and a Raspberry Pi as the backbone 10For years, I have been using desktops and a Raspberry Pi as the backbone of my
11of my homelab. I have always wanted to move toward a single dedicated 11homelab. I have always wanted to move toward a single dedicated server that
12server that could handle all of my tasks, but was often put off by the 12could handle all of my tasks, but was often put off by the complexity of the
13complexity of the choices (and financial roadblocks at some times). 13choices (and financial roadblocks at some times).
14 14
15However, after purchasing a small server rack this past year, I have 15However, after purchasing a small server rack this past year, I have been
16been researching to see what kind of rack-mounted server I could buy. I 16researching to see what kind of rack-mounted server I could buy. I initially
17initially bought a Dell R720XD loaded up with everything I could ever 17bought a Dell R720XD loaded up with everything I could ever want in a server -
18want in a server - but I did not care for it. It was far too loud, and 18but I did not care for it. It was far too loud, and the age of the CPU/RAM was
19the age of the CPU/RAM was something I wanted to improve upon. 19something I wanted to improve upon.
20 20
21After returning the R720XD, I decided that I wanted to build my own 21After returning the R720XD, I decided that I wanted to build my own server with
22server with modern, consumer-grade PC components. This time, I am very 22modern, consumer-grade PC components. This time, I am very happy with the
23happy with the results of my server. 23results of my server.
24 24
25# Components 25# Components
26 26
27I\'ll start by listing all the components I used for this server build: 27I'll start by listing all the components I used for this server build:
28 28
29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount 29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount
30 Case](https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825) 30 Case](https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825)
31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550) 31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550)
32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics 32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics
33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that 33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that support
34 support onboard graphics. 34 onboard graphics.
35- **RAM**: 64GB RAM (2x32GB) *Max of 128GB RAM on this motherboard* 35- **RAM**: 64GB RAM (2x32GB) *Max of 128GB RAM on this motherboard*
36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD 36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD
37- **HDD Bay**: 37- **HDD Bay**:
38 - 10TB WD White *(shucked, moved from previous server)* 38 - 10TB WD White *(shucked, moved from previous server)*
39 - 8TB WD White *(shucked, moved from previous server)* 39 - 8TB WD White *(shucked, moved from previous server)*
40 - 2 x 8TB WD Red Plus *(Black Friday lined up perfectly with this 40 - 2 x 8TB WD Red Plus *(Black Friday lined up perfectly with this build,
41 build, so I grabbed two of these)* 41 so I grabbed two of these)*
42- **PSU**: Corsair RM850 PSU 42- **PSU**: Corsair RM850 PSU
43- **Extras**: 43- **Extras**:
44 - Corsair TM3Q Thermal Paste 44 - Corsair TM3Q Thermal Paste
45 - Noctua 120mm fan *(replacement for front case fan)* 45 - Noctua 120mm fan *(replacement for front case fan)*
46 - 2 x Noctua 80mm fans *(replacement for rear case fans)* 46 - 2 x Noctua 80mm fans *(replacement for rear case fans)*
47 - CableMatters 6Gbps SATA Cables 47 - CableMatters 6Gbps SATA Cables
48 48
49# Building the Server 49# Building the Server
50 50
51This took quite a while for me to build (in my opinion of time), 51This took quite a while for me to build (in my opinion of time), totaling around
52totaling around 3 hours from start to finish. The case has some peculiar 523 hours from start to finish. The case has some peculiar construction, so you
53construction, so you have to completely remove the ODD & HDD cages to 53have to completely remove the ODD & HDD cages to install the motherboard and
54install the motherboard and other components first. 54other components first.
55 55
56Now, I\'ve never built a computer of any kind before, so I was quite 56Now, I've never built a computer of any kind before, so I was quite nervous.
57nervous. Personally, the only challenging part was getting the CPU 57Personally, the only challenging part was getting the CPU cooler to screw into
58cooler to screw into the motherboard without sliding the thermal paste 58the motherboard without sliding the thermal paste around too much underneath.
59around too much underneath. I\'m still not entirely sure if I did a 59I'm still not entirely sure if I did a great job of it, but nothing's broken
60great job of it, but nothing\'s broken yet. 60yet.
61 61
62The main components were all fine and simple. However, installing the 62The main components were all fine and simple. However, installing the hard
63hard drives is slightly tedious as I need to power off the server and 63drives is slightly tedious as I need to power off the server and completely
64completely unscrew the HDD cage to install or remove any drives. 64unscrew the HDD cage to install or remove any drives. Additionally, the drives
65Additionally, the drives are screwed directly into the metal cage with 65are screwed directly into the metal cage with small screws, which are quite a
66small screws, which are quite a bit different from the HDD trays I\'m 66bit different from the HDD trays I'm used to in other machines.
67used to in other machines.
68 67
69Seeing that the cases with hot-swap bays were 3-4x the price, I\'m okay 68Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay dealing
70dealing with the tedium of removing the cage to install new drives. 69with the tedium of removing the cage to install new drives.
71 70
72# Software 71# Software
73 72
74I\'m not going to dive into the software as I have done so in other 73I'm not going to dive into the software as I have done so in other recent
75recent posts. However, I wanted to note that I am using Alpine Linux on 74posts. However, I wanted to note that I am using Alpine Linux on this server and
76this server and hosting most services inside Docker. No virtual machines 75hosting most services inside Docker. No virtual machines (VMs) and very few
77(VMs) and very few bare-metal services. 76bare-metal services.
78 77
79# The Results 78# The Results
80 79
81How did my build turn out? Well, after migrating my other servers and 80How did my build turn out? Well, after migrating my other servers and their
82their services over, I found that my server is blazing fast. The 81services over, I found that my server is blazing fast. The heaviest of my
83heaviest of my applications, Plex, is handled with ease. Even 4k 82applications, Plex, is handled with ease. Even 4k streaming seems to be
84streaming seems to be effortless. 83effortless.
85 84
86I am very happy with the results and will likely continue to improve on 85I am very happy with the results and will likely continue to improve on this
87this server as the years go by rather than buying another used server 86server as the years go by rather than buying another used server online.
88online.
89 87
90## Mistakes I Made 88## Mistakes I Made
91 89
92This post wouldn\'t be complete unless I wrote about the mistakes I made 90This post wouldn't be complete unless I wrote about the mistakes I made while
93while building. The only real mistake I made beyond a \"whoops I dropped 91building. The only real mistake I made beyond a "whoops I dropped a screw"
94a screw\" related to airflow and fan direction. 92related to airflow and fan direction.
95 93
96While installing the two new hard drives that showed up on 2022-11-30 94While installing the two new hard drives that showed up on 2022-11-30 and
97and getting ready to install the case in my rack, I noticed that the 95getting ready to install the case in my rack, I noticed that the hard drive
98hard drive temperatures were quite high. 96temperatures were quite high.
99 97
100I used the `smartctl` command for each of my drives 98I used the `smartctl` command for each of my drives (`/dev/sda` through
101(`/dev/sda` through `/dev/sdd`): 99`/dev/sdd`):
102 100
103```sh 101```sh
104doas smartctl -a /dev/sda | grep Temperature_Celsius 102doas smartctl -a /dev/sda | grep Temperature_Celsius
105``` 103```
106 104
107The results were unusual - all four drives were idling at \~44-46 105The results were unusual - all four drives were idling at ~44-46 degrees
108degrees Celsius. The only drive that was cooler was my 10TB drive, which 106Celsius. The only drive that was cooler was my 10TB drive, which was at 38
109was at 38 degrees Celsius. I noted that this 10TB drive was also closest 107degrees Celsius. I noted that this 10TB drive was also closest to the case fan.
110to the case fan.
111 108
112```sh 109```sh
113ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 110ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
114# /dev/sda 111# /dev/sda
115194 Temperature_Celsius 0x0002 147 147 000 Old_age Always - 44 (Min/Max 22/46) 112194 Temperature_Celsius 0x0002 147 147 000 Old_age Always - 44 (Min/Max 22/46)
116# /dev/sdb 113# /dev/sdb
117194 Temperature_Celsius 0x0002 141 141 000 Old_age Always - 46 (Min/Max 21/48) 114194 Temperature_Celsius 0x0002 141 141 000 Old_age Always - 46 (Min/Max 21/48)
118# /dev/sdc 115# /dev/sdc
119194 Temperature_Celsius 0x0002 144 144 000 Old_age Always - 45 (Min/Max 19/61) 116194 Temperature_Celsius 0x0002 144 144 000 Old_age Always - 45 (Min/Max 19/61)
120# /dev/sdd 117# /dev/sdd
121194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56) 118194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56)
122``` 119```
123 120
124After looking to see if I could fit more fans into the case, I noticed 121After looking to see if I could fit more fans into the case, I noticed that the
125that the 120mm fan used for intake from the front of the case was 122120mm fan used for intake from the front of the case was actually pushing air
126actually pushing air out of the case by mistake. This fan sits right in 123out of the case by mistake. This fan sits right in front of the hard drive bay.
127front of the hard drive bay.
128 124
129Once I flipped the fan around to act as an intake fan, the temperatures 125Once I flipped the fan around to act as an intake fan, the temperatures dropped
130dropped immediately! They are now idling at \~31-33 degrees Celsius. A 126immediately! They are now idling at ~31-33 degrees Celsius. A single fan
131single fan spinning the wrong way caused my drives to idle 10-15 degrees 127spinning the wrong way caused my drives to idle 10-15 degrees higher than they
132higher than they should have. 128should have.
133 129
134```sh 130```sh
135ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 131ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
136# /dev/sda 132# /dev/sda
137194 Temperature_Celsius 0x0002 209 209 000 Old_age Always - 31 (Min/Max 14/56) 133194 Temperature_Celsius 0x0002 209 209 000 Old_age Always - 31 (Min/Max 14/56)
138# /dev/sdb 134# /dev/sdb
139194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 19/61) 135194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 19/61)
140# /dev/sdc 136# /dev/sdc
141194 Temperature_Celsius 0x0002 203 203 000 Old_age Always - 32 (Min/Max 21/48) 137194 Temperature_Celsius 0x0002 203 203 000 Old_age Always - 32 (Min/Max 21/48)
142# /dev/sdd 138# /dev/sdd
143194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46) 139194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46)
144``` 140```
145 141
146This was a silly error to make, but I\'m glad I found it today before I 142This was a silly error to make, but I'm glad I found it today before I screwed
147screwed the case into the rack and made things a lot more tedious to 143the case into the rack and made things a lot more tedious to fix.
148fix.
content/blog/2022-11-29-nginx-referrer-ban-list.md +25 −26
@@ -7,9 +7,9 @@ draft = false
7 7
8# Creating the Ban List 8# Creating the Ban List
9 9
10In order to ban list referral domains or websites with Nginx, you need 10In order to ban list referral domains or websites with Nginx, you need to create
11to create a ban list file. The file below will accept regexes for 11a ban list file. The file below will accept regexes for different domains or
12different domains or websites you wish to block. 12websites you wish to block.
13 13
14First, create the file in your nginx directory: 14First, create the file in your nginx directory:
15 15
@@ -17,8 +17,8 @@ First, create the file in your nginx directory:
17doas nano /etc/nginx/banlist.conf 17doas nano /etc/nginx/banlist.conf
18``` 18```
19 19
20Next, paste the following contents in and fill out the regexes with 20Next, paste the following contents in and fill out the regexes with whichever
21whichever domains you\'re blocking. 21domains you're blocking.
22 22
23``` conf 23``` conf
24# /etc/nginx/banlist.conf 24# /etc/nginx/banlist.conf
@@ -35,15 +35,15 @@ map $http_referer $bad_referer {
35 35
36# Configuring Nginx 36# Configuring Nginx
37 37
38In order for the ban list to work, Nginx needs to know it exists and how 38In order for the ban list to work, Nginx needs to know it exists and how to
39to handle it. For this, edit the `nginx.conf` file. 39handle it. For this, edit the `nginx.conf` file.
40 40
41```sh 41```sh
42doas nano /etc/nginx/nginx.conf 42doas nano /etc/nginx/nginx.conf
43``` 43```
44 44
45Within this file, find the `http` block and add your ban list 45Within this file, find the `http` block and add your ban list file location to
46file location to the end of the block. 46the end of the block.
47 47
48``` conf 48``` conf
49# /etc/nginx/nginx.conf 49# /etc/nginx/nginx.conf
@@ -58,24 +58,23 @@ http {
58 58
59# Enabling the Ban List 59# Enabling the Ban List
60 60
61Finally, we need to take action when a bad referral site is found. To do 61Finally, we need to take action when a bad referral site is found. To do so,
62so, edit the configuration file for your website. For example, I have 62edit the configuration file for your website. For example, I have all website
63all website configuration files in the `http.d` directory. 63configuration files in the `http.d` directory. You may have them in the
64You may have them in the `sites-available` directory on some 64`sites-available` directory on some distributions.
65distributions.
66 65
67```sh 66```sh
68doas nano /etc/nginx/http.d/example.com.conf 67doas nano /etc/nginx/http.d/example.com.conf
69``` 68```
70 69
71Within each website\'s configuration file, edit the `server` 70Within each website's configuration file, edit the `server` blocks that are
72blocks that are listening to ports 80 and 443 and create a check for the 71listening to ports 80 and 443 and create a check for the `$bad_referrer`
73`$bad_referrer` variable we created in the ban list file. 72variable we created in the ban list file.
74 73
75If a matching site is found, you can return any [HTTP Status 74If a matching site is found, you can return any [HTTP Status
76Code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) you want. 75Code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) you want. Code
77Code 403 (Forbidden) is logical in this case since you are preventing a 76403 (Forbidden) is logical in this case since you are preventing a client
78client connection due to a banned domain. 77connection due to a banned domain.
79 78
80``` conf 79``` conf
81server { 80server {
@@ -100,8 +99,8 @@ doas rc-service nginx restart
100 99
101# Testing Results 100# Testing Results
102 101
103In order to test the results, let\'s curl the contents of our site. To 102In order to test the results, let's curl the contents of our site. To start,
104start, I\'ll curl the site normally: 103I'll curl the site normally:
105 104
106```sh 105```sh
107curl https://cleberg.net 106curl https://cleberg.net
@@ -113,15 +112,15 @@ The HTML contents of the page come back successfully:
113<!doctype html>...</html> 112<!doctype html>...</html>
114``` 113```
115 114
116Next, let\'s include a banned referrer: 115Next, let's include a banned referrer:
117 116
118```sh 117```sh
119curl --referer https://news.ycombinator.com https://cleberg.net 118curl --referer https://news.ycombinator.com https://cleberg.net
120``` 119```
121 120
122This time, I\'m met with a 403 Forbidden response page. That means we 121This time, I'm met with a 403 Forbidden response page. That means we are
123are successful and any clients being referred from a banned domain will 122successful and any clients being referred from a banned domain will be met with
124be met with this same response code. 123this same response code.
125 124
126``` html 125``` html
127<html> 126<html>
content/blog/2022-12-01-nginx-compression.md +33 −37
@@ -7,24 +7,23 @@ draft = false
7 7
8# Text Compression 8# Text Compression
9 9
10Text compression allows a web server to serve text-based resources 10Text compression allows a web server to serve text-based resources faster than
11faster than uncompressed data. This can speed up things like First 11uncompressed data. This can speed up things like First Contentful Paint, Tie to
12Contentful Paint, Tie to Interactive, and Speed Index. 12Interactive, and Speed Index.
13 13
14# Enable Nginx Compression with gzip 14# Enable Nginx Compression with gzip
15 15
16In order to enable text compression on Nginx, we need to enable it 16In order to enable text compression on Nginx, we need to enable it within the
17within the configuration file: 17configuration file:
18 18
19```sh 19```sh
20nano /etc/nginx/nginx.conf 20nano /etc/nginx/nginx.conf
21``` 21```
22 22
23Within the `http` block, find the section that shows 23Within the `http` block, find the section that shows something like the block
24something like the block below. This is the default gzip configuration I 24below. This is the default gzip configuration I found in my `nginx.conf` file on
25found in my `nginx.conf` file on Alpine Linux 3.17. Yours may 25Alpine Linux 3.17. Yours may look slightly different, just make sure that
26look slightly different, just make sure that you\'re not creating any 26you're not creating any duplicate gzip options.
27duplicate gzip options.
28 27
29``` conf 28``` conf
30# Enable gzipping of responses. 29# Enable gzipping of responses.
@@ -48,33 +47,30 @@ gzip_disable "MSIE [1-6]";
48 47
49# Explanations of ngx~httpgzipmodule~ Options 48# Explanations of ngx~httpgzipmodule~ Options
50 49
51Each of the lines above enables a different aspect of the gzip response 50Each of the lines above enables a different aspect of the gzip response for
52for Nginx. Here are the full explanations: 51Nginx. Here are the full explanations:
53 52
54- `gzip` -- Enables or disables gzipping of responses. 53- `gzip` -- Enables or disables gzipping of responses.
55- `gzip_vary` -- Enables or disables inserting the \"Vary: 54- `gzip_vary` -- Enables or disables inserting the "Vary: Accept-Encoding"
56 Accept-Encoding\" response header field if the directives gzip, 55 response header field if the directives gzip, gzip~static~, or gunzip are
57 gzip~static~, or gunzip are active. 56 active.
58- `gzip_min_length` -- Sets the minimum length of a 57- `gzip_min_length` -- Sets the minimum length of a response that will be
59 response that will be gzipped. The length is determined only from 58 gzipped. The length is determined only from the "Content-Length" response
60 the \"Content-Length\" response header field. 59 header field.
61- `gzip_proxied` -- Enables or disables gzipping of 60- `gzip_proxied` -- Enables or disables gzipping of responses for proxied
62 responses for proxied requests depending on the request and 61 requests depending on the request and response. The fact that the request is
63 response. The fact that the request is proxied is determined by the 62 proxied is determined by the presence of the "Via" request header field.
64 presence of the \"Via\" request header field. 63- `gzip_types` -- Enables gzipping of responses for the specified MIME types in
65- `gzip_types` -- Enables gzipping of responses for the 64 addition to "text/html". The special value "*" matches any MIME type
66 specified MIME types in addition to \"text/html\". The special value 65 (0.8.29). Responses with the "text/html" type are always compressed.
67 "\*" matches any MIME type (0.8.29). Responses with the 66- `gzip_disable` -- Disables gzipping of responses for requests with
68 \"text/html\" type are always compressed. 67 "User-Agent" header fields matching any of the specified regular
69- `gzip_disable` -- Disables gzipping of responses for 68 expressions.
70 requests with \"User-Agent\" header fields matching any of the 69 - The special mask "msie6" (0.7.12) corresponds to the regular expression
71 specified regular expressions. 70 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE
72 - The special mask \"msie6\" (0.7.12) corresponds to the regular 71 6.0; ... SV1" is excluded from this mask.
73 expression \"MSIE \[4-6\].\", but works faster. Starting from
74 version 0.8.11, \"MSIE 6.0; ... SV1\" is excluded from this
75 mask.
76 72
77More information on these directives and their options can be found on 73More information on these directives and their options can be found on the
78the [Module 74[Module
79ngx~httpgzipmodule~](https://nginx.org/en/docs/http/ngx_http_gzip_module.html) 75ngx~httpgzipmodule~](https://nginx.org/en/docs/http/ngx_http_gzip_module.html)
80page in Nginx\'s documentation. 76page in Nginx's documentation.
content/blog/2022-12-07-nginx-wildcard-redirect.md +29 −33
@@ -7,18 +7,18 @@ draft = false
7 7
8# Problem 8# Problem
9 9
10I recently migrated domains and replaced the old webpage with a simple 10I recently migrated domains and replaced the old webpage with a simple info page
11info page with instructions to users on how to edit their bookmarks and 11with instructions to users on how to edit their bookmarks and URLs to get to the
12URLs to get to the page they were seeking. 12page they were seeking.
13 13
14This was not ideal as it left the work up to the user and may have 14This was not ideal as it left the work up to the user and may have caused
15caused friction for users who accessed my RSS feed. 15friction for users who accessed my RSS feed.
16 16
17# Solution 17# Solution
18 18
19Instead, I finally found a solution that allows me to redirect both 19Instead, I finally found a solution that allows me to redirect both subdomains
20subdomains AND trailing content. For example, both of these URLs now 20AND trailing content. For example, both of these URLs now redirect properly
21redirect properly using the logic I\'ll explain below: 21using the logic I'll explain below:
22 22
23``` txt 23``` txt
24# Example 1 - Simple base domain redirect with trailing content 24# Example 1 - Simple base domain redirect with trailing content
@@ -34,15 +34,15 @@ Go ahead, try the URLs if you want to test them.
34 34
35## Nginx Config 35## Nginx Config
36 36
37To make this possible. I needed to configure a proper redirect scheme in 37To make this possible. I needed to configure a proper redirect scheme in my
38my Nginx configuration. 38Nginx configuration.
39 39
40```sh 40```sh
41doas nano /etc/nginx/http.d/domain1.conf 41doas nano /etc/nginx/http.d/domain1.conf
42``` 42```
43 43
44Within this file, I had one block configured to redirect HTTP requests 44Within this file, I had one block configured to redirect HTTP requests to HTTPS
45to HTTPS for the base domain and all subdomains. 45for the base domain and all subdomains.
46 46
47``` conf 47``` conf
48server { 48server {
@@ -62,10 +62,9 @@ server {
62} 62}
63``` 63```
64 64
65For the base domain, I have another `server` block dedicated 65For the base domain, I have another `server` block dedicated to redirecting all
66to redirecting all base domain requests. You can see that the 66base domain requests. You can see that the `rewrite` line is instructing Nginx
67`rewrite` line is instructing Nginx to gather all trailing 67to gather all trailing content and append it to the new `domain2.com` URL.
68content and append it to the new `domain2.com` URL.
69 68
70``` conf 69``` conf
71server { 70server {
@@ -81,19 +80,16 @@ server {
81} 80}
82``` 81```
83 82
84Finally, the tricky part is figuring out how to tell Nginx to redirect 83Finally, the tricky part is figuring out how to tell Nginx to redirect while
85while keeping both a subdomain and trailing content intact. I found that 84keeping both a subdomain and trailing content intact. I found that the easiest
86the easiest way to do this is to give it a `server` block of 85way to do this is to give it a `server` block of its own.
87its own.
88 86
89Within this block, we need to do some regex on the 87Within this block, we need to do some regex on the `server_name` line before we
90`server_name` line before we can rewrite anything. This 88can rewrite anything. This creates a variable called `subdomain`.
91creates a variable called `subdomain`.
92 89
93Once the server gets to the `rewrite` line, it pulls the 90Once the server gets to the `rewrite` line, it pulls the `subdomain` variable
94`subdomain` variable from above and uses it on the new 91from above and uses it on the new `domain2.com` domain before appending the
95`domain2.com` domain before appending the trailing content 92trailing content (`$request_uri`).
96(`$request_uri`).
97 93
98``` conf 94``` conf
99server { 95server {
@@ -109,15 +105,15 @@ server {
109} 105}
110``` 106```
111 107
112That\'s all there is to it. With this, I simply restarted Nginx and 108That's all there is to it. With this, I simply restarted Nginx and watched the
113watched the redirections work in-action. 109redirections work in-action.
114 110
115```sh 111```sh
116doas rc-service nginx restart 112doas rc-service nginx restart
117``` 113```
118 114
119Looking back on it, I wish I had done this sooner. Who knows how many 115Looking back on it, I wish I had done this sooner. Who knows how many people
120people went looking for my sites or bookmarks and gave up when they saw 116went looking for my sites or bookmarks and gave up when they saw the redirect
121the redirect instructions page. 117instructions page.
122 118
123Oh well, it\'s done now. Live and learn. 119Oh well, it's done now. Live and learn.
content/blog/2022-12-17-st.md +26 −30
@@ -7,17 +7,15 @@ draft = false
7 7
8# st 8# st
9 9
10[st](https://st.suckless.org) standards for Simple Terminal, a simple 10[st](https://st.suckless.org) standards for Simple Terminal, a simple terminal
11terminal implementation for X made by the 11implementation for X made by the [suckless](https://suckless.org) team.
12[suckless](https://suckless.org) team.
13 12
14This post walks through the dependencies needed and process to build and 13This post walks through the dependencies needed and process to build and install
15install `st` on Fedora Workstation. 14`st` on Fedora Workstation.
16 15
17## Obtain Files 16## Obtain Files
18 17
19To start, obtain the source files for `st` via 18To start, obtain the source files for `st` via `git clone`.
20`git clone`.
21 19
22```sh 20```sh
23mkdir ~/suckless && cd ~/suckless 21mkdir ~/suckless && cd ~/suckless
@@ -26,8 +24,8 @@ git clone https://git.suckless.org/st && cd st
26 24
27## Dependencies 25## Dependencies
28 26
29Once you have the files and are in the `st` directory, ensure 27Once you have the files and are in the `st` directory, ensure the following
30the following packages are installed. 28packages are installed.
31 29
32```sh 30```sh
33sudo dnf update && sudo dnf upgrade 31sudo dnf update && sudo dnf upgrade
@@ -42,13 +40,12 @@ Before building, ensure that you read the README file.
42cat README 40cat README
43``` 41```
44 42
45Once you\'ve read the instructions, open the `config.mk` file 43Once you've read the instructions, open the `config.mk` file and ensure it
46and ensure it matches your setup. If you\'re not sure, leave the default 44matches your setup. If you're not sure, leave the default options within the
47options within the file. 45file.
48 46
49Finally, you can build `st` with the following command. 47Finally, you can build `st` with the following command. Ensure you run as root
50Ensure you run as root (e.g., `sudo`) or else you may not end 48(e.g., `sudo`) or else you may not end up with a usable application file.
51up with a usable application file.
52 49
53```sh 50```sh
54sudo make clean install 51sudo make clean install
@@ -56,39 +53,38 @@ sudo make clean install
56 53
57## Customization (Patches) 54## Customization (Patches)
58 55
59Note that customizing `st` requires you to modify the source 56Note that customizing `st` requires you to modify the source files or to
60files or to download one of the [available 57download one of the [available patches](https://st.suckless.org/patches/) for
61patches](https://st.suckless.org/patches/) for suckless.org. 58suckless.org.
62 59
63If you\'ve already installed `st` and want to customize or 60If you've already installed `st` and want to customize or install a patch,
64install a patch, start by uninstalling the current program. 61start by uninstalling the current program.
65 62
66```sh 63```sh
67cd ~/suckless/st 64cd ~/suckless/st
68sudo make uninstall 65sudo make uninstall
69``` 66```
70 67
71Next, grab the `<path>.diff` file from the page of the patch 68Next, grab the `<path>.diff` file from the page of the patch you chose. For
72you chose. For example, I will be using the 69example, I will be using the
73[defaultfontsize](https://st.suckless.org/patches/defaultfontsize/) 70[defaultfontsize](https://st.suckless.org/patches/defaultfontsize/) patch in the
74patch in the below example. 71below example.
75 72
76```sh 73```sh
77wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff 74wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff
78``` 75```
79 76
80Once the file is downloaded inside the `st` folder, apply the 77Once the file is downloaded inside the `st` folder, apply the patch and
81patch and re-install the program. You may need to install the 78re-install the program. You may need to install the `patch` command if you
82`patch` command if you don\'t have it installed already (you 79don't have it installed already (you should have installed it above).
83should have installed it above).
84 80
85```sh 81```sh
86patch -i st-defaultfontsize-20210225-4ef0cbd.diff 82patch -i st-defaultfontsize-20210225-4ef0cbd.diff
87sudo make clean install 83sudo make clean install
88``` 84```
89 85
90Once installed, you can use the default font size patch to launch 86Once installed, you can use the default font size patch to launch `st` with any
91`st` with any font size you wish: 87font size you wish:
92 88
93```sh 89```sh
94st -z 16 90st -z 16
content/blog/2022-12-23-alpine-desktop.md +45 −52
@@ -5,33 +5,31 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Isn't Alpine Linux for Servers?
8 9
9# Isn\'t Alpine Linux for Servers? 10This is a question I see a lot when people are presented with an example of
11Alpine Linux running as a desktop OS.
10 12
11This is a question I see a lot when people are presented with an example 13While Alpine is small, fast, and minimal, that doesn't stop it from functioning
12of Alpine Linux running as a desktop OS. 14at a productive level for desktop users.
13 15
14While Alpine is small, fast, and minimal, that doesn\'t stop it from 16This post is documentation of how I installed and modified Alpine Linux to
15functioning at a productive level for desktop users. 17become my daily desktop OS.
16
17This post is documentation of how I installed and modified Alpine Linux
18to become my daily desktop OS.
19 18
20# Installation 19# Installation
21 20
22Note that I cover the installation of Alpine Linux in my other post, so 21Note that I cover the installation of Alpine Linux in my other post, so I won't
23I won\'t repeat it here: [Alpine Linux: My New Server 22repeat it here: [Alpine Linux: My New Server OS](../alpine-linux/).
24OS](../alpine-linux/).
25 23
26Basically, get a bootable USB or whatever you prefer with Alpine on it, 24Basically, get a bootable USB or whatever you prefer with Alpine on it, boot the
27boot the ISO, and run the setup script. 25ISO, and run the setup script.
28 26
29```sh 27```sh
30setup-alpine 28setup-alpine
31``` 29```
32 30
33Once you have gone through all the options and installer finishes 31Once you have gone through all the options and installer finishes without
34without errors, reboot. 32errors, reboot.
35 33
36```sh 34```sh
37reboot 35reboot
@@ -40,9 +38,9 @@ reboot
40# Initial Setup 38# Initial Setup
41 39
42Once Alpine is installed and the machine has rebooted, login is as root 40Once Alpine is installed and the machine has rebooted, login is as root
43initially or `su` to root once you log in as your user. From 41initially or `su` to root once you log in as your user. From here, you should
44here, you should start by updating and upgrading the system in case the 42start by updating and upgrading the system in case the ISO was not fully
45ISO was not fully up-to-date. 43up-to-date.
46 44
47```sh 45```sh
48# Update and upgrade system 46# Update and upgrade system
@@ -52,8 +50,8 @@ apk -U update && apk -U upgrade
52apk add nano 50apk add nano
53``` 51```
54 52
55You need to uncomment the `community` repository for your 53You need to uncomment the `community` repository for your version of Alpine
56version of Alpine Linux. 54Linux.
57 55
58For v3.17, the `repositories` file should look like this: 56For v3.17, the `repositories` file should look like this:
59 57
@@ -80,11 +78,11 @@ adduser $USER wheel
80 78
81# Window Manager (Desktop) 79# Window Manager (Desktop)
82 80
83The [Sway installation guide](https://wiki.alpinelinux.org/wiki/Sway) 81The [Sway installation guide](https://wiki.alpinelinux.org/wiki/Sway) has
84has everything you need to get Sway working on Alpine. 82everything you need to get Sway working on Alpine.
85 83
86However, I\'ll include a brief list of the commands I ran and their 84However, I'll include a brief list of the commands I ran and their purpose for
87purpose for posterity here. 85posterity here.
88 86
89```sh 87```sh
90# Add eudev and set it up 88# Add eudev and set it up
@@ -126,11 +124,10 @@ apk add \ # Install optional dependencies:
126``` 124```
127 125
128Once you have the packages installed and set-up, you need to export the 126Once you have the packages installed and set-up, you need to export the
129`XDG_RUNTIME_DIR` upon login. To do this, edit your 127`XDG_RUNTIME_DIR` upon login. To do this, edit your `.profile` file.
130`.profile` file.
131 128
132If you use another shell, such as `zsh`, you need to edit 129If you use another shell, such as `zsh`, you need to edit that shell's profile
133that shell\'s profile (e.g., `~/.zprofile`)! 130(e.g., `~/.zprofile`)!
134 131
135```sh 132```sh
136nano ~/.profile 133nano ~/.profile
@@ -148,7 +145,7 @@ if test -z "${XDG_RUNTIME_DIR}"; then
148fi 145fi
149``` 146```
150 147
151Once that\'s complete, you can launch Sway manually. 148Once that's complete, you can launch Sway manually.
152 149
153```sh 150```sh
154dbus-run-session -- sway 151dbus-run-session -- sway
@@ -156,8 +153,7 @@ dbus-run-session -- sway
156 153
157## Personal Touches 154## Personal Touches
158 155
159I also added the following packages, per my personal preferences and 156I also added the following packages, per my personal preferences and situation.
160situation.
161 157
162```sh 158```sh
163doas apk add brightnessctl \ # Brightness controller 159doas apk add brightnessctl \ # Brightness controller
@@ -171,16 +167,16 @@ doas apk add brightnessctl \ # Brightness controller
171 gnupg # GPG key manager 167 gnupg # GPG key manager
172``` 168```
173 169
174From here, I use my Syncthing storage to pull all the configuration 170From here, I use my Syncthing storage to pull all the configuration files I
175files I stored from prior desktops, such as [my 171stored from prior desktops, such as [my
176dotfiles](https://git.sr.ht/~cmc/dotfiles). 172dotfiles](https://git.sr.ht/~cmc/dotfiles).
177 173
178# Resolving Issues 174# Resolving Issues
179 175
180## WiFi Issues 176## WiFi Issues
181 177
182I initially tried to set up my Wi-Fi the standard way with 178I initially tried to set up my Wi-Fi the standard way with `iwd`, but it didn't
183`iwd`, but it didn\'t work. 179work.
184 180
185Here is what I initially tried (I did all of this as `root`): 181Here is what I initially tried (I did all of this as `root`):
186 182
@@ -191,8 +187,7 @@ iwctl station wlan0 connect <SSID> # This will prompt for the password
191rc-update add iwd boot && rc-update add dbus boot 187rc-update add iwd boot && rc-update add dbus boot
192``` 188```
193 189
194Then, I added the Wi-Fi entry to the bottom of the networking interface 190Then, I added the Wi-Fi entry to the bottom of the networking interface file:
195file:
196 191
197```sh 192```sh
198nano /etc/network/interfaces 193nano /etc/network/interfaces
@@ -209,13 +204,11 @@ Finally, restart the networking service:
209rc-service networking restart 204rc-service networking restart
210``` 205```
211 206
212My Wi-Fi interface would receive an IP address from the router, but it 207My Wi-Fi interface would receive an IP address from the router, but it could not
213could not ping anything in the network. To solve the Wi-Fi issues, I 208ping anything in the network. To solve the Wi-Fi issues, I originally upgraded
214originally upgraded to Alpine\'s `edge` repositories, which 209to Alpine's `edge` repositories, which was unnecessary.
215was unnecessary.
216 210
217Really, the solution was to enable the 211Really, the solution was to enable the `NameResolvingService=resolvconf` in
218`NameResolvingService=resolvconf` in
219`/etc/iwd/main.conf`. 212`/etc/iwd/main.conf`.
220 213
221```sh 214```sh
@@ -232,8 +225,8 @@ Once I finished this process, my Wi-Fi is working flawlessly.
232 225
233## Sound Issues 226## Sound Issues
234 227
235Same as with the Wi-Fi, I had no sound and could not control the 228Same as with the Wi-Fi, I had no sound and could not control the mute/unmute or
236mute/unmute or volume buttons on my laptop. 229volume buttons on my laptop.
237 230
238To resolve this, I installed 231To resolve this, I installed
239[pipewire](https://wiki.alpinelinux.org/wiki/PipeWire). 232[pipewire](https://wiki.alpinelinux.org/wiki/PipeWire).
@@ -247,9 +240,9 @@ addgroup $USER video
247apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa 240apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa
248``` 241```
249 242
250Finally, I needed to add `/usr/libexec/pipewire-launcher` to 243Finally, I needed to add `/usr/libexec/pipewire-launcher` to my
251my `.config/sway/config` file so that Pipewire would run 244`.config/sway/config` file so that Pipewire would run every time I launched
252every time I launched sway. 245sway.
253 246
254```sh 247```sh
255nano ~/.config/sway/config 248nano ~/.config/sway/config
@@ -266,8 +259,8 @@ bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ to
266bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle 259bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle
267``` 260```
268 261
269Note that I do not use bluetooth or screen sharing, so I won\'t cover 262Note that I do not use bluetooth or screen sharing, so I won't cover those
270those options in this post. 263options in this post.
271 264
272Other than these issues, I have a working Alpine desktop. No other 265Other than these issues, I have a working Alpine desktop. No other complaints
273complaints thus far! 266thus far!
content/blog/2023-01-03-recent-website-changes.md +47 −51
@@ -7,80 +7,76 @@ draft = false
7 7
8# The State of This Website 8# The State of This Website
9 9
10Over the years, this website has changed URLs, styles, content focus, 10Over the years, this website has changed URLs, styles, content focus, and much
11and much more. However, it seems that I am never done, as I am yet again 11more. However, it seems that I am never done, as I am yet again changing this
12changing this page to fit my current needs and wants. 12page to fit my current needs and wants.
13 13
14While this site was already minimal (\~12kb), it contained a lot of 14While this site was already minimal (~12kb), it contained a lot of disorganized
15disorganized content and some poorly chosen color schemes. 15content and some poorly chosen color schemes.
16 16
17The recent updates attempt to fix these items while focusing on what I 17The recent updates attempt to fix these items while focusing on what I truly
18truly care about here: the content within each page. 18care about here: the content within each page.
19 19
20# Recent Changes 20# Recent Changes
21 21
22I\'ve made quite a few changes to the style of this website today, both 22I've made quite a few changes to the style of this website today, both in the
23in the CSS and in the HTML. 23CSS and in the HTML.
24 24
25Here are some of the key takeaways from today\'s changes: 25Here are some of the key takeaways from today's changes:
26 26
271. Reduce the width of the website from `60em` to 271. Reduce the width of the website from `60em` to `40em`.
28 `40em`. 282. Remove breadcrumb navigation and replaced with a simple "Return Home" link
292. Remove breadcrumb navigation and replaced with a simple \"Return 29 when visiting anything other than the homepage.
30 Home\" link when visiting anything other than the homepage. 303. Remove syntax highlighting from code blocks. CSS now loads from a single
313. Remove syntax highlighting from code blocks. CSS now loads from a 31 file.
32 single file. 324. Move blog posts on the homepage to the top, pushing tertiary content down.
334. Move blog posts on the homepage to the top, pushing tertiary content 335. Update font-family from `monospace` to `sans-serif` for readability.
34 down.
355. Update font-family from `monospace` to
36 `sans-serif` for readability.
37 34
38# Future Focus 35# Future Focus
39 36
40## Accessibility 37## Accessibility
41 38
42My main focus amidst all the changes this past year was accessibility. I 39My main focus amidst all the changes this past year was accessibility. I tried
43tried to improve the accessibility of all pages on this site as well as 40to improve the accessibility of all pages on this site as well as I know how.
44I know how. For example, I added aria labels to identify different 41For example, I added aria labels to identify different navigation menus in
45navigation menus in November. 42November.
46 43
47I want to continue this in 2023 and learn more about the accessibility 44I want to continue this in 2023 and learn more about the accessibility features
48features I can utilize to help those who may need them. 45I can utilize to help those who may need them.
49 46
50## Content First 47## Content First
51 48
52Beyond accessibility, I am making a concerted effort to bring the 49Beyond accessibility, I am making a concerted effort to bring the content of
53content of this site to the forefront and push the tertiary information 50this site to the forefront and push the tertiary information (e.g., About Me,
54(e.g., About Me, Services, etc.) down below the content. 51Services, etc.) down below the content.
55 52
56Further, I want to review and edit previous blog posts for grammar, 53Further, I want to review and edit previous blog posts for grammar, accuracy,
57accuracy, dead links, and more. Where necessary, I may even add a blurb 54dead links, and more. Where necessary, I may even add a blurb at the top of old
58at the top of old posts that are no longer accurate or helpful. 55posts that are no longer accurate or helpful.
59 56
60## Style 57## Style
61 58
62As always, I will be searching for ways to reduce distractions and bring 59As always, I will be searching for ways to reduce distractions and bring a
63a minimalistic approach to this site. While there are certainly more 60minimalistic approach to this site. While there are certainly more drastic
64drastic measures I could take, such as making this a [Shinobi 61measures I could take, such as making this a [Shinobi
65Website](https://shinobi.bt.ht) or a [No CSS 62Website](https://shinobi.bt.ht) or a [No CSS Website](https://nocss.club), I
66Website](https://nocss.club), I prefer to keep some modern features 63prefer to keep some modern features here.
67here.
68 64
69Two ideas have been floating around in my head, but I am not sure how I 65Two ideas have been floating around in my head, but I am not sure how I feel
70feel about these approaches yet: 66about these approaches yet:
71 67
721. Going all-in with Emacs org-mode and creating a script to 681. Going all-in with Emacs org-mode and creating a script to auto-publish all my
73 auto-publish all my blog posts from org-mode to plain HTML files and 69 blog posts from org-mode to plain HTML files and then letting my CSS style it
74 then letting my CSS style it after the fact. 70 after the fact.
752. Focus on publishing for Gemini or Gopher and then utilize a 712. Focus on publishing for Gemini or Gopher and then utilize a conversion
76 conversion program to translate the pages to HTML. 72 program to translate the pages to HTML.
77 73
78# Looking Back 74# Looking Back
79 75
80As I sit here and finalize the changes, as well as this post, I am happy 76As I sit here and finalize the changes, as well as this post, I am happy with
81with the current state of this website. It\'s certainly a long way from 77the current state of this website. It's certainly a long way from my first
82my first attempts (parallax background images, anyone?) and it\'s good 78attempts (parallax background images, anyone?) and it's good to see the
83to see the progress. 79progress.
84 80
85I can only hope and work hard to ensure that I make more meaningful 81I can only hope and work hard to ensure that I make more meaningful progress by
86progress by this time next year. 82this time next year.
content/blog/2023-01-05-mass-unlike-tumblr-posts.md +32 −39
@@ -7,27 +7,24 @@ draft = false
7 7
8# The Dilemma 8# The Dilemma
9 9
10The dilemma I had was pretty simple: I wanted to unlike all the posts I 10The dilemma I had was pretty simple: I wanted to unlike all the posts I have
11have liked on Tumblr so that I could follow a new focus on blogs and 11liked on Tumblr so that I could follow a new focus on blogs and start fresh.
12start fresh. Otherwise, Tumblr will keep recommending content based on 12Otherwise, Tumblr will keep recommending content based on your previous likes.
13your previous likes.
14 13
15# The Solution 14# The Solution
16 15
17I searched the web for a while and noted that most solutions referenced 16I searched the web for a while and noted that most solutions referenced Tumblr
18Tumblr setting and dashboard pages that no longer exist. Additionally, I 17setting and dashboard pages that no longer exist. Additionally, I did not want
19did not want to install a third party extension to do this, as some 18to install a third party extension to do this, as some suggested.
20suggested.
21 19
22Luckily, I used Javascript for a while a few years ago and figured it 20Luckily, I used Javascript for a while a few years ago and figured it would be
23would be easy enough to script a solution, as long as Tumblr had a 21easy enough to script a solution, as long as Tumblr had a system for the unlike
24system for the unlike buttons. 22buttons.
25 23
26## Identifying Unlike Buttons 24## Identifying Unlike Buttons
27 25
28Tumblr\'s unlike buttons are structured as you can see in the following 26Tumblr's unlike buttons are structured as you can see in the following code
29code block. All unlike buttons have an `aria-label` with a 27block. All unlike buttons have an `aria-label` with a value of `Unlike`.
30value of `Unlike`.
31 28
32``` html 29``` html
33<button class="TRX6J" aria-label="Unlike"> 30<button class="TRX6J" aria-label="Unlike">
@@ -43,28 +40,26 @@ value of `Unlike`.
43## Running a Script to Unlike All Likes 40## Running a Script to Unlike All Likes
44 41
45To run this script, you will need to load the [Likes \| 42To run this script, you will need to load the [Likes \|
46Tumblr](https://www.tumblr.com/likes) page while logged in to your 43Tumblr](https://www.tumblr.com/likes) page while logged in to your account.
47account.
48 44
49Further, be sure to scroll down to the bottom and force Tumblr to load 45Further, be sure to scroll down to the bottom and force Tumblr to load more
50more posts so that this script unlikes more posts at a time. 46posts so that this script unlikes more posts at a time.
51 47
52Once you are logged in and the page is loaded, open the Developer Tools 48Once you are logged in and the page is loaded, open the Developer Tools and be
53and be sure you\'re on the \"Console\" tab. It should look something 49sure you're on the "Console" tab. It should look something like this (this is
54like this (this is in Firefox, Chromium should be similar): 50in Firefox, Chromium should be similar):
55 51
56![Firefox Dev 52![Firefox Dev
57!Tools](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/dev_console.png) 53!Tools](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/dev_console.png)
58 54
59All you need to do is paste the following snippet into the dev console. 55All you need to do is paste the following snippet into the dev console. This
60This code will collect all unlike buttons (`elements`) and 56code will collect all unlike buttons (`elements`) and then click each button to
61then click each button to unlike it. 57unlike it.
62 58
63Optionally, you can comment-out the line 59Optionally, you can comment-out the line `elements[i].click();` and uncomment
64`elements[i].click();` and uncomment the 60the `console.log()` lines to simply print out information without performing any
65`console.log()` lines to simply print out information without 61actions. This can be useful to debug issues or confirm that the code below
66performing any actions. This can be useful to debug issues or confirm 62isn't doing anything you don't want it to.
67that the code below isn\'t doing anything you don\'t want it to.
68 63
69``` javascript 64``` javascript
70const elements = document.querySelectorAll('[aria-label="Unlike"]'); 65const elements = document.querySelectorAll('[aria-label="Unlike"]');
@@ -78,18 +73,16 @@ for (let i=0; i < elements.length; i++) {
78 73
79# Results 74# Results
80 75
81The results were quick for my situation, as it unliked \~200 posts 76The results were quick for my situation, as it unliked ~200 posts within 2-3
82within 2-3 seconds. I am not sure how this will perform on larger sets 77seconds. I am not sure how this will perform on larger sets of likes (or if
83of likes (or if Tumblr has a limit to unliking posts). 78Tumblr has a limit to unliking posts).
84 79
85You can see the below screenshot showing that I pasted the snippet into 80You can see the below screenshot showing that I pasted the snippet into the
86the console, pressed Enter, and then the posts are automatically 81console, pressed Enter, and then the posts are automatically unliked.
87unliked.
88 82
89![Script 83![Script
90!Results](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/script_results.png) 84!Results](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/script_results.png)
91 85
92Thinking about this further, I would bet that this would be fairly 86Thinking about this further, I would bet that this would be fairly simple to
93simple to package into a browser add-on so that users could install the 87package into a browser add-on so that users could install the add-on, go to
94add-on, go to their Likes page, and click a button to run the script. 88their Likes page, and click a button to run the script. Food for thought.
95Food for thought.
content/blog/2023-01-08-fedora-login-manager.md +12 −12
@@ -5,15 +5,15 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Fedora i3\'s Login Manager 8# Fedora i3's Login Manager
9 9
10Since I use the i3 spin of Fedora Workstation, I don\'t like to have a 10Since I use the i3 spin of Fedora Workstation, I don't like to have a login
11login manager installed by default. As of the current version of Fedora 11manager installed by default. As of the current version of Fedora i3, the
12i3, the default login manager is LightDM. 12default login manager is LightDM.
13 13
14If this is no longer the case, you can search for currently-installed 14If this is no longer the case, you can search for currently-installed packages
15packages with the following command and see if you can identify a 15with the following command and see if you can identify a different login
16different login manager. 16manager.
17 17
18```sh 18```sh
19sudo dnf list installed 19sudo dnf list installed
@@ -29,16 +29,16 @@ sudo dnf remove lightdm
29 29
30# Launching i3 Manually 30# Launching i3 Manually
31 31
32In order to launch i3 manually, you need to set up your X session 32In order to launch i3 manually, you need to set up your X session properly. To
33properly. To start, create or edit the `~/.xinitrc` file to 33start, create or edit the `~/.xinitrc` file to include the following at the
34include the following at the bottom. 34bottom.
35 35
36``` config 36``` config
37exec i3 37exec i3
38``` 38```
39 39
40Now, whenever you log in to the TTY, you can launch your desktop with 40Now, whenever you log in to the TTY, you can launch your desktop with the
41the following command. 41following command.
42 42
43```sh 43```sh
44startx 44startx
content/blog/2023-01-21-flatpak-symlinks.md +16 −20
@@ -7,45 +7,41 @@ draft = false
7 7
8# Running Flatpak Apps Should Be Faster 8# Running Flatpak Apps Should Be Faster
9 9
10If you\'re like me and use Flatpak for those pesky apps that cannot run 10If you're like me and use Flatpak for those pesky apps that cannot run on your
11on your system for one reason or another, you likely get annoyed with 11system for one reason or another, you likely get annoyed with opening a terminal
12opening a terminal and manually running the Flatpak app with the lengthy 12and manually running the Flatpak app with the lengthy `flatpak run ...` command.
13`flatpak run ...` command.
14 13
15In the past, I manually created aliases in my `.zshrc` file 14In the past, I manually created aliases in my `.zshrc` file for certain apps.
16for certain apps. For example, an alias would look like the example 15For example, an alias would look like the example below.
17below.
18 16
19This would allow me to run the command fast within the terminal, but it 17This would allow me to run the command fast within the terminal, but it
20wouldn\'t allow me to run it in an application launcher. 18wouldn't allow me to run it in an application launcher.
21 19
22```sh 20```sh
23# ~/.zshrc 21# ~/.zshrc
24alias librewolf = "flatpak run io.gitlab.librewolf-community" 22alias librewolf = "flatpak run io.gitlab.librewolf-community"
25``` 23```
26 24
27However, I now use a much faster and better method that integrates with 25However, I now use a much faster and better method that integrates with the
28the tiling WMs I use and their application launchers - 26tiling WMs I use and their application launchers - `dmenu` and `bemenu`.
29`dmenu` and `bemenu`.
30 27
31# Creating Symlinks for Flatpak Apps 28# Creating Symlinks for Flatpak Apps
32 29
33Let\'s use the example of Librewolf below. I can install the application 30Let's use the example of Librewolf below. I can install the application like
34like so: 31so:
35 32
36```sh 33```sh
37flatpak install flathub io.gitlab.librewolf-community 34flatpak install flathub io.gitlab.librewolf-community
38``` 35```
39 36
40Once installed, I can create a symlink to link the flatpak app to my new 37Once installed, I can create a symlink to link the flatpak app to my new symlink
41symlink in a location commonly included in your PATH. In this case, I 38in a location commonly included in your PATH. In this case, I chose `/usr/bin`.
42chose `/usr/bin`. You may need to choose a different location 39You may need to choose a different location if `/usr/bin` isn't in your PATH.
43if `/usr/bin` isn\'t in your PATH.
44 40
45```sh 41```sh
46ln -s /var/lib/flatpak/exports/bin/io.gitlab.librewolf-community /usr/bin/librewolf 42ln -s /var/lib/flatpak/exports/bin/io.gitlab.librewolf-community /usr/bin/librewolf
47``` 43```
48 44
49Once complete, you should be able to launch the app using the command 45Once complete, you should be able to launch the app using the command name you
50name you chose above in the symlink (`librewolf`) from a 46chose above in the symlink (`librewolf`) from a terminal or from your
51terminal or from your application launcher! 47application launcher!
content/blog/2023-01-23-random-wireguard.md +26 −28
@@ -7,18 +7,18 @@ draft = false
7 7
8# Mullvad Wireguard 8# Mullvad Wireguard
9 9
10If you\'re using an OS that does not support one of Mullvad\'s apps, 10If you're using an OS that does not support one of Mullvad's apps, you're
11you\'re likely using the Wireguard configuration files instead. 11likely using the Wireguard configuration files instead.
12 12
13If not, the first step is to visit Mullvad\'s [Wireguard configuration 13If not, the first step is to visit Mullvad's [Wireguard configuration
14files](https://mullvad.net/en/account/#/wireguard-config) page and 14files](https://mullvad.net/en/account/#/wireguard-config) page and download a
15download a ZIP of the configuration files you want to use. 15ZIP of the configuration files you want to use.
16 16
17Personally, I downloaded all configuration files across the world and 17Personally, I downloaded all configuration files across the world and chose my
18chose my connections using the script below. 18connections using the script below.
19 19
20Once the files are downloaded, unzip them and move them to your 20Once the files are downloaded, unzip them and move them to your preferred
21preferred location: 21location:
22 22
23```sh 23```sh
24cd Downloads 24cd Downloads
@@ -28,8 +28,8 @@ mkdir ~/mullvad && mv ~/Downloads/*.conf ~/mullvad/
28 28
29### Creating a Script to Connect to a Random Host 29### Creating a Script to Connect to a Random Host
30 30
31Once you have a folder of Wireguard configuration files from Mullvad, 31Once you have a folder of Wireguard configuration files from Mullvad, you can
32you can create a script to randomly connect to any one of the locations. 32create a script to randomly connect to any one of the locations.
33 33
34Start by creating a shell script - mine is called `vpn.sh`. 34Start by creating a shell script - mine is called `vpn.sh`.
35 35
@@ -37,10 +37,9 @@ Start by creating a shell script - mine is called `vpn.sh`.
37nano ~/vpn.sh 37nano ~/vpn.sh
38``` 38```
39 39
40Within this script, you can paste the following info. Note that I 40Within this script, you can paste the following info. Note that I specify `us-*`
41specify `us-*` in my script, which means that it will only 41in my script, which means that it will only consider US-based VPN locations. You
42consider US-based VPN locations. You can alter this or simply change it 42can alter this or simply change it `*` to consider all locations.
43`*` to consider all locations.
44 43
45```sh 44```sh
46#!/bin/sh 45#!/bin/sh
@@ -55,8 +54,8 @@ ls /home/$USER/mullvad/us-** |sort -R |tail -n 1 |while read file; do
55done 54done
56``` 55```
57 56
58Once you\'ve modified the script to your liking, add executable 57Once you've modified the script to your liking, add executable permissions and
59permissions and run the script: 58run the script:
60 59
61```sh 60```sh
62chmod +x ~/vpn.sh 61chmod +x ~/vpn.sh
@@ -76,21 +75,20 @@ Printing new IP info:
76You are connected to Mullvad (server country-city-wg-num). Your IP address is 12.345.678.99 75You are connected to Mullvad (server country-city-wg-num). Your IP address is 12.345.678.99
77``` 76```
78 77
79That\'s all there is to it. You can see your new location and IP via the 78That's all there is to it. You can see your new location and IP via the
80`printf` and `curl` commands included in the 79`printf` and `curl` commands included in the script.
81script.
82 80
83You can also go to the [Connection Check ​\| 81You can also go to the [Connection Check ​\|
84Mullvad](https://mullvad.net/en/check/) page to see if you are fully 82Mullvad](https://mullvad.net/en/check/) page to see if you are fully connected
85connected to Mullvad and if any leaks exist. 83to Mullvad and if any leaks exist.
86 84
87![Mullvad Connection 85![Mullvad Connection
88Check](https://img.cleberg.net/blog/20230123-random-mullvad-wireguard/mullvad_check.png) 86Check](https://img.cleberg.net/blog/20230123-random-mullvad-wireguard/mullvad_check.png)
89 87
90# Disconnecting from the Wireguard Connection 88# Disconnecting from the Wireguard Connection
91 89
92If you forget which connection you\'re using, you can execute the 90If you forget which connection you're using, you can execute the following
93following command to see where Wireguard is currently connected: 91command to see where Wireguard is currently connected:
94 92
95```sh 93```sh
96wg show 94wg show
@@ -99,15 +97,15 @@ wg show
99This command will show you the Wireguard interfaces and should output a 97This command will show you the Wireguard interfaces and should output a
100connection like so: `interface: us-lax-wg-104`. 98connection like so: `interface: us-lax-wg-104`.
101 99
102Once you have this, just disconnect using that files\' full path: 100Once you have this, just disconnect using that files' full path:
103 101
104```sh 102```sh
105wg-quick down /home/user/mullvad/us-lax-wg-104.conf 103wg-quick down /home/user/mullvad/us-lax-wg-104.conf
106``` 104```
107 105
108I have a TODO item on figuring out how to easily export an environment 106I have a TODO item on figuring out how to easily export an environment variable
109variable that contains the configuration file\'s full name, so that I 107that contains the configuration file's full name, so that I can just execute
110can just execute the following: 108the following:
111 109
112```sh 110```sh
113# Ideal situation if I can export the $file variable to the environment 111# Ideal situation if I can export the $file variable to the environment
content/blog/2023-01-28-self-hosting-wger.md +52 −58
@@ -7,53 +7,52 @@ draft = false
7 7
8# Wger: The Self-Hosted Workout Manager 8# Wger: The Self-Hosted Workout Manager
9 9
10[Wger Workout Manager](https://wger.de) is a fitness tracking tool for 10[Wger Workout Manager](https://wger.de) is a fitness tracking tool for those who
11those who enjoy self-hosting their data. You can also register an 11enjoy self-hosting their data. You can also register an account on their main
12account on their main website if you\'d prefer to try without 12website if you'd prefer to try without self-hosting.
13self-hosting.
14 13
15## Features 14## Features
16 15
17I didn\'t see a full listing of features anywhere, so I compiled this 16I didn't see a full listing of features anywhere, so I compiled this list of my
18list of my own after installing wger: 17own after installing wger:
19 18
201. Dashboard 191. Dashboard
21 20
22 - Dashboard view of Workout Schedule, Nutrition Plan, Weight 21 - Dashboard view of Workout Schedule, Nutrition Plan, Weight Graph, & last
23 Graph, & last 5 Weight Logs 22 5 Weight Logs
24 23
252. Training 242. Training
26 25
27 - Workout Log 26 - Workout Log
28 - Workout Schedule 27 - Workout Schedule
29 - Calendar (shows weight logs and Bad/Neutral/Good days) 28 - Calendar (shows weight logs and Bad/Neutral/Good days)
30 - Gallery (shows images you upload) 29 - Gallery (shows images you upload)
31 - Workout templates 30 - Workout templates
32 - Public templates 31 - Public templates
33 - Exercises 32 - Exercises
34 33
353. Nutrition 343. Nutrition
36 35
37 - Nutrition plans 36 - Nutrition plans
38 - BMI calculator 37 - BMI calculator
39 - Daily calories calculator 38 - Daily calories calculator
40 - Ingredient overview 39 - Ingredient overview
41 40
424. Body Weight 414. Body Weight
43 42
44 - Weight overview 43 - Weight overview
45 44
46## Documentation 45## Documentation
47 46
48In order to self-host wger, I opted to use the Docker version of the 47In order to self-host wger, I opted to use the Docker version of the
49application. You can read the README within the 48application. You can read the README within the
50[wger-project/docker](https://github.com/wger-project/docker) project on 49[wger-project/docker](https://github.com/wger-project/docker) project on GitHub
51GitHub for information and installation instructions. 50for information and installation instructions.
52 51
53## Installation 52## Installation
54 53
55To start the installation, I created a folder for wger and started 54To start the installation, I created a folder for wger and started creating the
56creating the three necessary files: 55three necessary files:
57 56
58```sh 57```sh
59mkdir ~/wger && mkdir ~/wger/config 58mkdir ~/wger && mkdir ~/wger/config
@@ -62,23 +61,20 @@ touch ~/wger/config/prod.env && \
62touch ~/wger/config/nginx.conf 61touch ~/wger/config/nginx.conf
63``` 62```
64 63
65Once you have the folders and files created, you will need to copy the 64Once you have the folders and files created, you will need to copy the contents
66contents of the `docker-compose.yml`, `prod.env`, 65of the `docker-compose.yml`, `prod.env`, and `nginx.conf` from the GitHub link
67and `nginx.conf` from the GitHub link above. 66above.
68 67
69A few notes to explain the changes I made to the default files: 68A few notes to explain the changes I made to the default files:
70 69
71- I updated the `ALLOW_REGISTRAION` variable in 70- I updated the `ALLOW_REGISTRAION` variable in `prod.env` to `False` after I
72 `prod.env` to `False` after I created an 71 created an account via my LAN connection, **before** I connected this app to a
73 account via my LAN connection, **before\*** I connected this app to 72 publicly-available domain.
74 a publicly-available domain. 73- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be equal to the public
75- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be 74 version of this app: `https://wger.example.com`.
76 equal to the public version of this app: 75- I updated the port within `docker-compose.yml`, within the `nginx` block. The
77 `https://wger.example.com`. 76 port I updated this to will be reflected in my nginx configuration file on the
78- I updated the port within `docker-compose.yml`, within 77 server (NOT the wger nginx.conf file).
79 the `nginx` block. The port I updated this to will be
80 reflected in my nginx configuration file on the server (NOT the wger
81 nginx.conf file).
82 78
83## Deploy 79## Deploy
84 80
@@ -89,17 +85,16 @@ container.
89docker-compose up -d 85docker-compose up -d
90``` 86```
91 87
92You can now visit the website on your LAN by going to 88You can now visit the website on your LAN by going to `localhost:YOUR_PORT` or
93`localhost:YOUR_PORT` or by the server\'s IP, if you\'re not 89by the server's IP, if you're not on the same machine that is running the
94on the same machine that is running the container. 90container.
95 91
96If you wish to connect this app to a public domain name, you\'ll need to 92If you wish to connect this app to a public domain name, you'll need to point
97point an `A` DNS record from the domain to your server\'s 93an `A` DNS record from the domain to your server's public IP. You'll then need
98public IP. You\'ll then need to create a configuration file for 94to create a configuration file for whichever web server or reverse proxy you're
99whichever web server or reverse proxy you\'re using. 95using.
100 96
101Wger\'s README suggests the following reverse proxy configuration for 97Wger's README suggests the following reverse proxy configuration for Nginx:
102Nginx:
103 98
104``` conf 99``` conf
105upstream wger { 100upstream wger {
@@ -132,20 +127,19 @@ server {
132 127
133# Thoughts on Wger 128# Thoughts on Wger
134 129
135I\'m still playing around with the app itself, but it seems to be a 130I'm still playing around with the app itself, but it seems to be a solid
136solid all-around workout manager, weight log, and food log. 131all-around workout manager, weight log, and food log.
137 132
138I like that the weight log graph is fluid and updates quickly. You can 133I like that the weight log graph is fluid and updates quickly. You can also
139also import or export data in CSV format if you\'d like to move your 134import or export data in CSV format if you'd like to move your data elsewhere.
140data elsewhere.
141 135
142The workout manager is slightly odd, as it requires you to enter sets 136The workout manager is slightly odd, as it requires you to enter sets and reps
143and reps for each exercise when you enter it into the plan. Then, when 137for each exercise when you enter it into the plan. Then, when you add a log
144you add a log entry for performing a workout, you then add what you 138entry for performing a workout, you then add what you actually performed, in
145actually performed, in terms of reps and weight. 139terms of reps and weight.
146 140
147I haven\'t tried the food log yet and I likely will not, at least for a 141I haven't tried the food log yet and I likely will not, at least for a while. I
148while. I have no need for a food log or calorie tracker at the moment. 142have no need for a food log or calorie tracker at the moment.
149 143
150## Screenshot Example 144## Screenshot Example
151 145
content/blog/2023-02-02-exploring-hare.md +65 −76
@@ -7,87 +7,80 @@ draft = false
7 7
8# A Quick Note 8# A Quick Note
9 9
10By no means am I a professional developer, so this post will be rather 10By no means am I a professional developer, so this post will be rather short. I
11short. I won\'t be going into depth on the specification or anything 11won't be going into depth on the specification or anything that technical.
12that technical.
13 12
14Instead, I will simply be talking about how I (a relatively basic 13Instead, I will simply be talking about how I (a relatively basic hobbyist
15hobbyist programmer) have been playing with Hare and what intrigues me 14programmer) have been playing with Hare and what intrigues me about the
16about the language. 15language.
17 16
18# Hare 17# Hare
19 18
20The [Hare](https://harelang.org) programming language is a 19The [Hare](https://harelang.org) programming language is a straightforward
21straightforward language that should look familiar if you\'ve ever 20language that should look familiar if you've ever programmed with C, Rust, or
22programmed with C, Rust, or other languages that aim to build software 21other languages that aim to build software at the system-level.
23at the system-level.
24 22
25The Hare homepage states the following: 23The Hare homepage states the following:
26 24
27> Hare is a systems programming language designed to be simple, stable, 25> Hare is a systems programming language designed to be simple, stable, and
28> and robust. Hare uses a static type system, manual memory management, 26> robust. Hare uses a static type system, manual memory management, and minimal
29> and minimal runtime. It is well-suited to writing operating systems, 27> runtime. It is well-suited to writing operating systems, system tools,
30> system tools, compilers, networking software, and other low-level, 28> compilers, networking software, and other low-level, high performance tasks.
31> high performance tasks.
32 29
33I have found this all to be true while playing with it for the first 30I have found this all to be true while playing with it for the first time today.
34time today. In the next few sections, I\'m going to walk through my 31In the next few sections, I'm going to walk through my installation and first
35installation and first program. 32program.
36 33
37## Installation 34## Installation
38 35
39I\'m currently running Alpine Linux on my Thinkpad, so the installation 36I'm currently running Alpine Linux on my Thinkpad, so the installation was
40was quite easy as there is a package for Hare in the `apk` 37quite easy as there is a package for Hare in the `apk` repositories.
41repositories.
42 38
43```sh 39```sh
44doas apk add hare hare-doc 40doas apk add hare hare-doc
45``` 41```
46 42
47However, I was able to install Hare from scratch on Fedora Linux a short 43However, I was able to install Hare from scratch on Fedora Linux a short while
48while ago, which was also very easy to do. If you need further 44ago, which was also very easy to do. If you need further instructions and Hare
49instructions and Hare doesn\'t have a package on your system, take a 45doesn't have a package on your system, take a look at the [Hare
50look at the [Hare Installation](https://harelang.org/installation/) 46Installation](https://harelang.org/installation/) page.
51page.
52 47
53## Creating a Test Project 48## Creating a Test Project
54 49
55In order to play with the language, I created 50In order to play with the language, I created
56[hare-test](https://git.sr.ht/~cmc/hare-projects) and will be putting 51[hare-test](https://git.sr.ht/~cmc/hare-projects) and will be putting any of my
57any of my Hare-related adventures in here. 52Hare-related adventures in here.
58 53
59> **Update:\*** I also created a simple Hare program for creating a file 54> **Update:** I also created a simple Hare program for creating a file from user
60> from user input: 55> input:
61> [files.ha](https://git.sr.ht/~cmc/hare-projects/tree/main/item/files/files.ha) 56> [files.ha](https://git.sr.ht/~cmc/hare-projects/tree/main/item/files/files.ha)
62 57
63Luckily, Hare doesn\'t require any complex set-up tools or build 58Luckily, Hare doesn't require any complex set-up tools or build environment.
64environment. Once you have Hare installed, you simply need to create a 59Once you have Hare installed, you simply need to create a file ending with `.ha`
65file ending with `.ha` and you can run a Hare program. 60and you can run a Hare program.
66 61
67I created a file called `rgb.ha` in order to test out the 62I created a file called `rgb.ha` in order to test out the random number
68random number generation and passing parameters between functions. 63generation and passing parameters between functions.
69 64
70```sh 65```sh
71nano rgb.ha 66nano rgb.ha
72``` 67```
73 68
74Within this file, I was able to easily import a few of the [standard 69Within this file, I was able to easily import a few of the [standard library
75library modules](https://harelang.org/tutorials/stdlib/): 70modules](https://harelang.org/tutorials/stdlib/): `fmt`, `math::random`, and
76`fmt`, `math::random`, and `datetime`. 71`datetime`.
77 72
78With these modules, I created two functions: 73With these modules, I created two functions:
79 74
801. `main`: This function calls the `generate_rgb` 751. `main`: This function calls the `generate_rgb` function and then prints out
81 function and then prints out the returned values. 76 the returned values.
822. `generate_rgb`: This function uses the current Unix epoch 772. `generate_rgb`: This function uses the current Unix epoch time to generate a
83 time to generate a pseudo-random value and uses this value to create 78 pseudo-random value and uses this value to create three more random values
84 three more random values between 0 and 255. These three numbers 79 between 0 and 255. These three numbers represent a color in RGB format.
85 represent a color in RGB format.
86 80
87> **Note**: Some syntax coloring may look odd, as Zola currently 81> **Note**: Some syntax coloring may look odd, as Zola currently doesn't have a
88> doesn\'t have a syntax highlighting theme for Hare. Instead, I\'m 82> syntax highlighting theme for Hare. Instead, I'm using the C theme, which may
89> using the C theme, which may not be exactly accurate when coloring the 83> not be exactly accurate when coloring the code below.
90> code below.
91 84
92```c 85```c
93use datetime; 86use datetime;
@@ -120,8 +113,7 @@ fn generate_rgb() []u64 = {
120 113
121## Running a Program 114## Running a Program
122 115
123Once you have a Hare file written and ready to run, you simply need to 116Once you have a Hare file written and ready to run, you simply need to run it:
124run it:
125 117
126```sh 118```sh
127hare run file.ha 119hare run file.ha
@@ -136,37 +128,34 @@ hare build -o example file.ha
136 128
137## Initial Thoughts 129## Initial Thoughts
138 130
1391. Documentation Improvements Would Help 1311. Documentation Improvements Would Help
140 132
141 While I was able to piece everything together eventually, the 133 While I was able to piece everything together eventually, the biggest
142 biggest downfall right now in Hare\'s documentation. For such a new 134 downfall right now in Hare's documentation. For such a new project, the
143 project, the documentation is in a great spot. However, bare 135 documentation is in a great spot. However, bare specifications don't help
144 specifications don\'t help as much as a brief examples section 136 as much as a brief examples section would.
145 would.
146 137
147 For example, it took me a while to figure out what the 138 For example, it took me a while to figure out what the `u64n` function was
148 `u64n` function was looking for. I could tell that it 139 looking for. I could tell that it took two parameters and the second was my
149 took two parameters and the second was my max value (255), but 140 max value (255), but couldn't figure out what the first value should be.
150 couldn\'t figure out what the first value should be. Eventually, I 141 Eventually, I inspected the `random.ha` file in the [Hare source
151 inspected the `random.ha` file in the [Hare source
152 code](https://git.sr.ht/~sircmpwn/hare/tree/master/item/math/random/random.ha) 142 code](https://git.sr.ht/~sircmpwn/hare/tree/master/item/math/random/random.ha)
153 and found the test suite that helped me discover that it needed an 143 and found the test suite that helped me discover that it needed an `init()`
154 `init()` value in the form of `&var`. 144 value in the form of `&var`.
155 145
1562. More Basic Modules 1462. More Basic Modules
157 147
158 This is another point that comes from Hare being new and awaiting 148 This is another point that comes from Hare being new and awaiting more
159 more contributions, but there are some basic functions that I would 149 contributions, but there are some basic functions that I would personally
160 personally enjoy seeing in Hare, such as one to convert decimal 150 enjoy seeing in Hare, such as one to convert decimal (base 10) values to
161 (base 10) values to hexadecimal (base 16). 151 hexadecimal (base 16).
162 152
163 If I\'m feeling comfortable with my math, I may work on the list of 153 If I'm feeling comfortable with my math, I may work on the list of
164 functions I want and see if any can make it into the Hare source 154 functions I want and see if any can make it into the Hare source code.
165 code.
166 155
1673. Overall Thoughts 1563. Overall Thoughts
168 157
169 Overall, I actually really enjoy Hare. It\'s not as tedious to get a 158 Overall, I actually really enjoy Hare. It's not as tedious to get a project
170 project up and running as Rust, but it\'s also simpler and more 159 up and running as Rust, but it's also simpler and more user-friendly than
171 user-friendly than learning C. I am going to continue playing with 160 learning C. I am going to continue playing with it and see if I can make
172 it and see if I can make anything of particular value. 161 anything of particular value.
content/blog/2023-05-22-burnout.md +25 −25
@@ -7,39 +7,39 @@ draft = false
7 7
8# RE: Burnout {#re-burnout-1} 8# RE: Burnout {#re-burnout-1}
9 9
10I recently read [Drew DeVault\'s post on 10I recently read [Drew DeVault's post on
11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html) 11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html) around the
12around the same time I was pulling out of a burnout rut myself earlier 12same time I was pulling out of a burnout rut myself earlier this month. Finally,
13this month. Finally, seeing the light at the end of my burnout tunnel 13seeing the light at the end of my burnout tunnel made me want to write my first
14made me want to write my first post back on this topic. 14post back on this topic.
15 15
16# Busy Seasons on Busy Seasons 16# Busy Seasons on Busy Seasons
17 17
18My career deals with busy seasons, generally driven by client demand. 18My career deals with busy seasons, generally driven by client demand. This last
19This last year, I dealt with a harsh busy season from Aug to Oct 2022 to 19year, I dealt with a harsh busy season from Aug to Oct 2022 to issue a few SOC
20issue a few SOC reports for the period ending 2022-09-30. Immediately 20reports for the period ending 2022-09-30. Immediately following that, I had to
21following that, I had to pivot and found another busy season from Oct to 21pivot and found another busy season from Oct to Jan for financial statement
22Jan for financial statement audits ending on 2022-12-31. Then again, 22audits ending on 2022-12-31. Then again, supporting other clients from Jan to
23supporting other clients from Jan to Mar 2023, followed by my current 23Mar 2023, followed by my current client workload aiming for SOC reports due on
24client workload aiming for SOC reports due on 2023-06-30. 242023-06-30.
25 25
26The result? A busy season that has lasted from August 2022 through 26The result? A busy season that has lasted from August 2022 through today. I will
27today. I will likely be rushing throughout the next month or two before 27likely be rushing throughout the next month or two before I have a brief break
28I have a brief break and need to focus on the 2023-09-30 SOC reports 28and need to focus on the 2023-09-30 SOC reports again. While auditing and
29again. While auditing and consulting always involve a busy season, this 29consulting always involve a busy season, this is the first time I've had one
30is the first time I\'ve had one last 9+ months without a break. 30last 9+ months without a break.
31 31
32While it\'s been tough, I have a handful of breaks pre-planned 32While it's been tough, I have a handful of breaks pre-planned throughout this
33throughout this next cycle and should be able to moderate the level of 33next cycle and should be able to moderate the level of commitment required for
34commitment required for each client. 34each client.
35 35
36# Refocusing 36# Refocusing
37 37
38Outside of work, I finally have time to work on hobbies such as this 38Outside of work, I finally have time to work on hobbies such as this website,
39website, programming, athletics, games, etc. 39programming, athletics, games, etc.
40 40
41You may have noticed my absence if you\'re in the same channels, forums, 41You may have noticed my absence if you're in the same channels, forums, and
42and rooms that I am, but I should finally be active again. 42rooms that I am, but I should finally be active again.
43 43
44I\'m hoping to break an item out of my backlog soon and start working on 44I'm hoping to break an item out of my backlog soon and start working on
45building a new project or hack around with a stale one. 45building a new project or hack around with a stale one.
content/blog/2023-06-08-goaccess-geoip.md +19 −21
@@ -7,22 +7,21 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10[GoAccess](https://goaccess.io/) is an open source real-time web log 10[GoAccess](https://goaccess.io/) is an open source real-time web log analyzer
11analyzer and interactive viewer that runs in a terminal in \*nix systems 11and interactive viewer that runs in a terminal in *nix systems or through your
12or through your browser. 12browser.
13 13
14# Installation 14# Installation
15 15
16To start, you\'ll need to install GoAccess for your OS. Here\'s an 16To start, you'll need to install GoAccess for your OS. Here's an example for
17example for Debian-based distros: 17Debian-based distros:
18 18
19```sh 19```sh
20sudo apt install goaccess 20sudo apt install goaccess
21``` 21```
22 22
23Next, find any number of the MaxMind GeoIP database files on GitHub or 23Next, find any number of the MaxMind GeoIP database files on GitHub or another
24another file hosting website. We\'re going to use P3TERX\'s version in 24file hosting website. We're going to use P3TERX's version in this example:
25this example:
26 25
27```sh 26```sh
28wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb 27wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb
@@ -32,16 +31,15 @@ Be sure to save this file in an easy to remember location!
32 31
33# Usage 32# Usage
34 33
35In order to utilize the full capabilities of GoAccess and MMDB, start 34In order to utilize the full capabilities of GoAccess and MMDB, start with the
36with the command template below and customize as necessary. This will 35command template below and customize as necessary. This will export an HTML view
37export an HTML view of the GoAccess dashboard, showing all relevant 36of the GoAccess dashboard, showing all relevant information related to that
38information related to that site\'s access log. You can also omit the 37site's access log. You can also omit the `-o output.html` parameter if you
39`-o output.html` parameter if you prefer to view the data 38prefer to view the data within the CLI instead of creating an HTML file.
40within the CLI instead of creating an HTML file.
41 39
42With the addition of the GeoIP Database parameter, section 40With the addition of the GeoIP Database parameter, section `16 - Geo Location`
43`16 - Geo Location` will be added with the various countries 41will be added with the various countries that are associated with the collected
44that are associated with the collected IP addresses. 42IP addresses.
45 43
46```sh 44```sh
47zcat /var/log/nginx/example.access.log.*.gz | goaccess \ 45zcat /var/log/nginx/example.access.log.*.gz | goaccess \
@@ -60,11 +58,11 @@ See below for an example of the HTML output:
60![GoAccess 58![GoAccess
61HTML](https://img.cleberg.net/blog/20230608-goaccess/goaccess-dashboard.png) 59HTML](https://img.cleberg.net/blog/20230608-goaccess/goaccess-dashboard.png)
62 60
63You can also see the GeoIP card created by the integration of the 61You can also see the GeoIP card created by the integration of the MaxMind
64MaxMind database information. 62database information.
65 63
66![GoAccess 64![GoAccess
67GeoIP](https://img.cleberg.net/blog/20230608-goaccess/goaccess-geoip.png) 65GeoIP](https://img.cleberg.net/blog/20230608-goaccess/goaccess-geoip.png)
68 66
69That\'s all there is to it! Informational data is provided in an 67That's all there is to it! Informational data is provided in an organized
70organized fashion with minimal effort. 68fashion with minimal effort.
content/blog/2023-06-08-self-hosting-baikal.md +47 −51
@@ -7,27 +7,26 @@ draft = false
7 7
8# What is Baikal? 8# What is Baikal?
9 9
10[Baikal](https://sabre.io/baikal/) is a lightweight CalDAV + CardDAV 10[Baikal](https://sabre.io/baikal/) is a lightweight CalDAV + CardDAV server that
11server that you can self-host on your own machine. While I have tried (& 11you can self-host on your own machine. While I have tried (& failed) to get this
12failed) to get this CalDAV + CardDAV server running before, it was quite 12CalDAV + CardDAV server running before, it was quite easy this time. Not really
13easy this time. Not really sure what I did differently this time, but 13sure what I did differently this time, but I'm documenting my process here to
14I\'m documenting my process here to ensure I don\'t forget. 14ensure I don't forget.
15 15
16# Installation 16# Installation
17 17
18First, create a folder on your server and open a 18First, create a folder on your server and open a `docker-compose.yml` file for
19`docker-compose.yml` file for editing: 19editing:
20 20
21```sh 21```sh
22mkdir baikal && cd baikal 22mkdir baikal && cd baikal
23nano docker-compose.yml 23nano docker-compose.yml
24``` 24```
25 25
26Within this file, you\'ll need to paste the information below. You can 26Within this file, you'll need to paste the information below. You can customize
27customize the `ports` section to use any port on your server 27the `ports` section to use any port on your server to pass through to port 80 in
28to pass through to port 80 in the container. You can also edit the 28the container. You can also edit the `volumes` section to use docker volumes
29`volumes` section to use docker volumes instead of local 29instead of local folders.
30folders.
31 30
32``` conf 31``` conf
33version: "2" 32version: "2"
@@ -42,8 +41,8 @@ services:
42 - ./data:/var/www/baikal/Specific 41 - ./data:/var/www/baikal/Specific
43``` 42```
44 43
45Once finished with editing, save and close the file. Then, launch the 44Once finished with editing, save and close the file. Then, launch the docker
46docker container: 45container:
47 46
48```sh 47```sh
49sudo docker-compose up -d 48sudo docker-compose up -d
@@ -51,42 +50,40 @@ sudo docker-compose up -d
51 50
52# Intial Setup 51# Intial Setup
53 52
54As long as no issues came up when starting the container, you should be 53As long as no issues came up when starting the container, you should be able to
55able to visit the server\'s set-up page at 54visit the server's set-up page at `http://<server_ip>:<port>`. The application
56`http://<server_ip>:<port>`. The application will ask you to 55will ask you to create an administrator account and choose the database type for
57create an administrator account and choose the database type for your 56your storage. Personally, I opted to use SQLite.
58storage. Personally, I opted to use SQLite.
59 57
60Make sure the administrator credentials are adequate to protect against 58Make sure the administrator credentials are adequate to protect against common
61common attacks. 59attacks.
62 60
63# Creating Users 61# Creating Users
64 62
65Once you\'ve set up the application, you will be greeted by the 63Once you've set up the application, you will be greeted by the Dashboard page,
66Dashboard page, which will show the version of the app, status of the 64which will show the version of the app, status of the admin/CalDAV/CardDAV
67admin/CalDAV/CardDAV services, and the number of users, calendars, 65services, and the number of users, calendars, events, address books, and
68events, address books, and contacts. 66contacts.
69 67
70![Baikal 68![Baikal
71Dashboard](https://img.cleberg.net/blog/20230608-baikal/baikal-dashboard.png) 69Dashboard](https://img.cleberg.net/blog/20230608-baikal/baikal-dashboard.png)
72 70
73To create a new user, navigate to the `Users and resources` 71To create a new user, navigate to the `Users and resources` page. This process
74page. This process is as simple as entering a username, password, and 72is as simple as entering a username, password, and email.
75email.
76 73
77Once a user has been created, you can create any number of calendars and 74Once a user has been created, you can create any number of calendars and address
78address books for user, as well as inspect their information. 75books for user, as well as inspect their information.
79 76
80# Setting Up a Public URL 77# Setting Up a Public URL
81 78
82Once your application is working locally, you can open access remotely 79Once your application is working locally, you can open access remotely via a URL
83via a URL by using a reverse-proxy like Nginx. 80by using a reverse-proxy like Nginx.
84 81
85As a prerequisite, you must own a domain name and set up DNS records to 82As a prerequisite, you must own a domain name and set up DNS records to point a
86point a domain name to the server hosting Baikal. 83domain name to the server hosting Baikal.
87 84
88Start by navigating to your web server\'s configuration directory and 85Start by navigating to your web server's configuration directory and create a
89create a new file for this application. 86new file for this application.
90 87
91```sh 88```sh
92cd /etc/nginx/sites-available/ 89cd /etc/nginx/sites-available/
@@ -94,7 +91,7 @@ nano dav
94``` 91```
95 92
96Within this file, paste in the configuration from below and change 93Within this file, paste in the configuration from below and change
97`dav.example.com` to match the URL you\'ll be using. 94`dav.example.com` to match the URL you'll be using.
98 95
99``` conf 96``` conf
100server { 97server {
@@ -128,33 +125,32 @@ server {
128} 125}
129``` 126```
130 127
131For Nginx on Ubuntu, you\'ll need to symlink the configuration file to 128For Nginx on Ubuntu, you'll need to symlink the configuration file to the
132the `sites-enabled` directory and then restart Nginx. 129`sites-enabled` directory and then restart Nginx.
133 130
134```sh 131```sh
135sudo ln -s /etc/nginx/sites-available/dav /etc/nginx/sites-enabled/dav 132sudo ln -s /etc/nginx/sites-available/dav /etc/nginx/sites-enabled/dav
136sudo systemctl restart nginx.service 133sudo systemctl restart nginx.service
137``` 134```
138 135
139At this point, the Baikal server should be available over the internet 136At this point, the Baikal server should be available over the internet at the
140at the URL configured above! 137URL configured above!
141 138
142# Configuring Clients 139# Configuring Clients
143 140
144Lastly, configuring clients and applications is essential to making sure 141Lastly, configuring clients and applications is essential to making sure the DAV
145the DAV server is being fully utilized. 142server is being fully utilized.
146 143
147You can also use the `Users and resources` page to inspect a 144You can also use the `Users and resources` page to inspect a user's personal
148user\'s personal link to their calendars and address books by clicking 145link to their calendars and address books by clicking the info (i) button. It
149the info (i) button. It will show a URI like 146will show a URI like `/dav.php/calendars/your-user/default/`.
150`/dav.php/calendars/your-user/default/`.
151 147
152However, I found that the following URL works for most applications: 148However, I found that the following URL works for most applications:
153`/dav.php/principals/your-user/`. 149`/dav.php/principals/your-user/`.
154 150
155I used the `principals` URL above for Thunderbird (calendar, 151I used the `principals` URL above for Thunderbird (calendar, tasks, and
156tasks, and contacts), as well as iOS (calendar, tasks, and contacts) and 152contacts), as well as iOS (calendar, tasks, and contacts) and everything works
157everything works flawlessly so far. 153flawlessly so far.
158 154
159Syncing is quick between the server and clients, and I haven\'t seen any 155Syncing is quick between the server and clients, and I haven't seen any
160disruptions in the service or data integrity. 156disruptions in the service or data integrity.
content/blog/2023-06-18-unifi-ip-blocklist.md +40 −48
@@ -7,82 +7,74 @@ draft = false
7 7
8# Identifying Abusive IPs 8# Identifying Abusive IPs
9 9
10If you\'re like me and use Unifi network equipment at the edge of the 10If you're like me and use Unifi network equipment at the edge of the network
11network you manage, you may know that Unifi is only somewhat decent at 11you manage, you may know that Unifi is only somewhat decent at identifying and
12identifying and blocking IPs that represent abusive or threat actors. 12blocking IPs that represent abusive or threat actors.
13 13
14While Unifi has a [threat 14While Unifi has a [threat
15management](https://help.ui.com/hc/en-us/articles/360006893234-UniFi-Gateway-Threat-Management) 15management](https://help.ui.com/hc/en-us/articles/360006893234-UniFi-Gateway-Threat-Management)
16tool inside their Network application, it can be lacking in 16tool inside their Network application, it can be lacking in functionality and
17functionality and identification. For example, I have my UDM Pro set to 17identification. For example, I have my UDM Pro set to identify and block almost
18identify and block almost all categories of threats available within the 18all categories of threats available within the Unifi settings. However, I
19Unifi settings. However, I regularly identify abusive actors on my web 19regularly identify abusive actors on my web server via the server logs.
20server via the server logs.
21 20
22In addition, I have identified IP addresses and subnets directly within 21In addition, I have identified IP addresses and subnets directly within Unifi's
23Unifi\'s logs that the UDM did not block for whatever reason. 22logs that the UDM did not block for whatever reason.
24 23
25This guide is meant to be another step in the process to manually block 24This guide is meant to be another step in the process to manually block abusive
26abusive IP addresses or subnets that you have identified but are not 25IP addresses or subnets that you have identified but are not being automatically
27being automatically blocked yet. 26blocked yet.
28 27
29# Create an IP Group Profile 28# Create an IP Group Profile
30 29
31To start, login to the Unifi machine\'s web GUI and navigate to the 30To start, login to the Unifi machine's web GUI and navigate to the Network app
32Network app \> Settings \> Profiles. 31> Settings > Profiles.
33 32
34Within this page, choose the `IP Groups` tab and click 33Within this page, choose the `IP Groups` tab and click `Create New`.
35`Create New`.
36 34
37![Network 35![Network
38Profiles](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/unifi_profiles.png) 36Profiles](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/unifi_profiles.png)
39 37
40Each IP Group profile can be used as one of three options: 38Each IP Group profile can be used as one of three options:
41 39
421. Port Group 401. Port Group
432. IPv4 Address/Subnet 412. IPv4 Address/Subnet
443. IPv6 Address/Subnet 423. IPv6 Address/Subnet
45 43
46In this example, I\'m creating an IPv4 Address/Subnet group and adding a 44In this example, I'm creating an IPv4 Address/Subnet group and adding a few
47few different IP addresses and a subnet. Once you\'ve added all IP 45different IP addresses and a subnet. Once you've added all IP addresses and
48addresses and subnets, click the `Apply` button that should 46subnets, click the `Apply` button that should appear at the bottom.
49appear at the bottom.
50 47
51![Network Profile 48![Network Profile
52IPs](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/abusive_ips.png) 49IPs](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/abusive_ips.png)
53 50
54At this point, the IPv4 Address/Subnet has been created but not yet 51At this point, the IPv4 Address/Subnet has been created but not yet used.
55used.
56 52
57# Drop IP Group Profile via the Unifi Firewall 53# Drop IP Group Profile via the Unifi Firewall
58 54
59To instruct the Unifi machine to block the profile we just created, we 55To instruct the Unifi machine to block the profile we just created, we need to
60need to navigate to the Network app \> Settings \> Firewall & Security. 56navigate to the Network app > Settings > Firewall & Security.
61 57
62Within this screen, find the Firewall Rules table and click 58Within this screen, find the Firewall Rules table and click `Create Entry`. This
63`Create Entry`. This entry should contain the following 59entry should contain the following settings:
64settings:
65 60
66- Type: `Internet In` 61- Type: `Internet In`
67- Description: `<Your Custom Rule>` 62- Description: `<Your Custom Rule>`
68- Rule Applied: `Before Predefined Rules` 63- Rule Applied: `Before Predefined Rules`
69- Action: `Drop` 64- Action: `Drop`
70- Source Type: `Port/IP Group` 65- Source Type: `Port/IP Group`
71- IPv4 Address Group: 66- IPv4 Address Group: `<Name of the Group Profile You Created Above>`
72 `<Name of the Group Profile You Created Above>`
73 67
74Customize the remaining configurations to your liking, and then save and 68Customize the remaining configurations to your liking, and then save and enable
75enable the firewall rule. 69the firewall rule.
76 70
77![Firewall 71![Firewall
78Rule](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/firewall_drop_rule.png) 72Rule](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/firewall_drop_rule.png)
79 73
80Once enabled, the Unifi machine will be able to drop all incoming 74Once enabled, the Unifi machine will be able to drop all incoming connections
81connections from the defined IP addresses and subnets within the created 75from the defined IP addresses and subnets within the created profile.
82profile.
83 76
84> As a personal aside to this topic, I\'m looking for a convenient way 77> As a personal aside to this topic, I'm looking for a convenient way to update
85> to update the firewall rules or profiles remotely (within the LAN) 78> the firewall rules or profiles remotely (within the LAN) from the web server
86> from the web server to accelerate this process. If you have an idea on 79> to accelerate this process. If you have an idea on how to automatically update
87> how to automatically update Unifi IP groups or firewall rules, let me 80> Unifi IP groups or firewall rules, let me know!
88> know!
content/blog/2023-06-20-audit-review-template.md +57 −62
@@ -7,75 +7,70 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10This post is a *very* brief overview on the basic process to review 10This post is a *very* brief overview on the basic process to review audit test
11audit test results, focusing on work done as part of a financial 11results, focusing on work done as part of a financial statement audit (FSA) or
12statement audit (FSA) or service organization controls (SOC) report. 12service organization controls (SOC) report.
13 13
14While there are numerous different things to review and look for - all 14While there are numerous different things to review and look for - all varying
15varying wildly depending on the report, client, and tester - this list 15wildly depending on the report, client, and tester - this list serves as a solid
16serves as a solid base foundation for a reviewer. 16base foundation for a reviewer.
17 17
18I have used this throughout my career as a starting point to my reviews, 18I have used this throughout my career as a starting point to my reviews, and it
19and it has worked wonders for creating a consistent and objective 19has worked wonders for creating a consistent and objective template to my
20template to my reviews. The goal is to keep this base high-level enough 20reviews. The goal is to keep this base high-level enough to be used on a wide
21to be used on a wide variety of engagements, while still ensuring that 21variety of engagements, while still ensuring that all key areas are covered.
22all key areas are covered.
23 22
24# Review Template 23# Review Template
25 24
261. [ ] Check all documents for spelling and grammar. 251. [ ] Check all documents for spelling and grammar.
272. [ ] Ensure all acronyms are fully explained upon first use. 262. [ ] Ensure all acronyms are fully explained upon first use.
283. [ ] For all people referenced, use their full names and job titles 273. [ ] For all people referenced, use their full names and job titles upon first
29 upon first use. 28 use.
304. [ ] All supporting documents must cross-reference to the lead sheet 294. [ ] All supporting documents must cross-reference to the lead sheet and
31 and vice-versa. 30 vice-versa.
325. [ ] Verify that the control has been adequately tested: 315. [ ] Verify that the control has been adequately tested:
33 - [ ] **Test of Design**: Did the tester obtain information 32 - [ ] **Test of Design**: Did the tester obtain information regarding how
34 regarding how the control should perform normally and abnormally 33 the control should perform normally and abnormally (e.g., emergency
35 (e.g., emergency scenarios)? 34 scenarios)?
36 - [ ] **Test of Operating Effectiveness**: Did the tester inquire, 35 - [ ] **Test of Operating Effectiveness**: Did the tester inquire, observe,
37 observe, inspect, or re-perform sufficient evidence to support 36 inspect, or re-perform sufficient evidence to support their conclusion
38 their conclusion over the control? Inquiry alone is not 37 over the control? Inquiry alone is not adequate!
39 adequate! 386. [ ] For any information used in the control, whether by the control operator
406. [ ] For any information used in the control, whether by the control 39 or by the tester, did the tester appropriately document the source (system or
41 operator or by the tester, did the tester appropriately document the 40 person), extraction method, parameters, and completeness and accuracy (C&A)?
42 source (system or person), extraction method, parameters, and 41 - [ ] For any reports, queries, etc. used in the extraction, did the tester
43 completeness and accuracy (C&A)? 42 include a copy and notate C&A considerations?
44 - [ ] For any reports, queries, etc. used in the extraction, did 437. [ ] Did the tester document the specific criteria that the control is being
45 the tester include a copy and notate C&A considerations? 44 tested against?
467. [ ] Did the tester document the specific criteria that the control 458. [ ] Did the tester notate in the supporting documents where each criterion
47 is being tested against? 46 was satisfied?
488. [ ] Did the tester notate in the supporting documents where each 479. [ ] If testing specific policies or procedures, are the documents adequate?
49 criterion was satisfied? 48 - [ ] e.g., a test to validate that a review of policy XYZ occurs
509. [ ] If testing specific policies or procedures, are the documents 49 periodically should also evaluate the sufficiency of the policy itself, if
51 adequate? 50 meant to cover the risk that such a policy does not exist and is not
52 - [ ] e.g., a test to validate that a review of policy XYZ occurs 51 reviewed.
53 periodically should also evaluate the sufficiency of the policy
54 itself, if meant to cover the risk that such a policy does not
55 exist and is not reviewed.
5610. [ ] Does the test cover the appropriate period under review? 5210. [ ] Does the test cover the appropriate period under review?
57 - [ ] If the test is meant to cover only a portion of the audit 53 - [ ] If the test is meant to cover only a portion of the audit period, do
58 period, do other controls exist to mitigate the risks that exist 54 other controls exist to mitigate the risks that exist for the remainder of
59 for the remainder of the period? 55 the period?
6011. [ ] For any computer-aided audit tools (CAATs) or other automation 5611. [ ] For any computer-aided audit tools (CAATs) or other automation
61 techniques used in the test, is the use of such tools explained and 57 techniques used in the test, is the use of such tools explained and
62 appropriately documented? 58 appropriately documented?
6312. [ ] If prior-period documentation exists, are there any missing 5912. [ ] If prior-period documentation exists, are there any missing pieces of
64 pieces of evidence that would further enhance the quality of the 60 evidence that would further enhance the quality of the test?
6113. [ ] Was any information discovered during the walkthrough or inquiry phase
62 that was not incorporated into the test?
6314. [ ] Are there new rules or expectations from your company's internal
64 guidance or your regulatory bodies that would affect the audit approach for
65 this control?
6615. [ ] Was an exception, finding, or deficiency identified as a result of this
65 test? 67 test?
6613. [ ] Was any information discovered during the walkthrough or inquiry 68 - [ ] Was the control deficient in design, operation, or both?
67 phase that was not incorporated into the test? 69 - [ ] What was the root cause of the finding?
6814. [ ] Are there new rules or expectations from your company\'s 70 - [ ] Does the finding indicate other findings or potential fraud?
69 internal guidance or your regulatory bodies that would affect the 71 - [ ] What's the severity and scope of the finding?
70 audit approach for this control? 72 - [ ] Do other controls exist as a form of compensation against the
7115. [ ] Was an exception, finding, or deficiency identified as a result 73 finding's severity, and do they mitigate the risk within the control
72 of this test? 74 objective?
73 - [ ] Was the control deficient in design, operation, or both? 75 - [ ] Does the finding exist at the end of the period, or was it resolved
74 - [ ] What was the root cause of the finding? 76 within the audit period?
75 - [ ] Does the finding indicate other findings or potential fraud?
76 - [ ] What\'s the severity and scope of the finding?
77 - [ ] Do other controls exist as a form of compensation against
78 the finding\'s severity, and do they mitigate the risk within
79 the control objective?
80 - [ ] Does the finding exist at the end of the period, or was it
81 resolved within the audit period?
content/blog/2023-06-23-byobu.md +13 −14
@@ -5,27 +5,26 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Byobu {#byobu-1} 8# Byobu
9 9
10[byobu](https://www.byobu.org) is a command-line tool that allows you to 10[byobu](https://www.byobu.org) is a command-line tool that allows you to use
11use numerous screens within a single terminal emulator instance. More 11numerous screens within a single terminal emulator instance. More specifically,
12specifically, it\'s a text based window manager, using either 12it's a text based window manager, using either `screen` or `tmux`.
13`screen` or `tmux`.
14 13
15This post is mostly just a self-reference as I explore byobu, so I may 14This post is mostly just a self-reference as I explore byobu, so I may come back
16come back later and update this post with more content. 15later and update this post with more content.
17 16
18## Screenshot 17## Screenshot
19 18
20Take a look below at my current multi-window set-up in byobu while I 19Take a look below at my current multi-window set-up in byobu while I write this
21write this blog post: 20blog post:
22 21
23![byobu](https://img.cleberg.net/blog/20230623-byobu/byobu.png) 22![byobu](https://img.cleberg.net/blog/20230623-byobu/byobu.png)
24 23
25### Keybindings 24### Keybindings
26 25
27You can open the help menu with either of the following commands; they 26You can open the help menu with either of the following commands; they will both
28will both open the same manpage: 27open the same manpage:
29 28
30```sh 29```sh
31byobu --help 30byobu --help
@@ -33,9 +32,9 @@ byobu --help
33man byobu 32man byobu
34``` 33```
35 34
36While the manpage contains a ton of information about the functionality 35While the manpage contains a ton of information about the functionality of byobu
37of byobu (such as status notifications, sessions, and windows), the 36(such as status notifications, sessions, and windows), the first location to
38first location to explore should be the keybindings section. 37explore should be the keybindings section.
39 38
40The keybindings are configured as follows: 39The keybindings are configured as follows:
41 40
content/blog/2023-06-23-self-hosting-convos.md +43 −51
@@ -7,36 +7,32 @@ draft = false
7 7
8# Convos 8# Convos
9 9
10[Convos](https://convos.chat/) is an always-online web client for IRC. 10[Convos](https://convos.chat/) is an always-online web client for IRC. It has a
11It has a few features that made it attractive to me as a self-hosted 11few features that made it attractive to me as a self-hosted option:
12option: 12
13 13- Extremely simple Docker Compose installation method.
14- Extremely simple Docker Compose installation method. 14- Runs in the background and monitors chats even while you're not logged in.
15- Runs in the background and monitors chats even while you\'re not 15- Neatly organized sidebar for conversation and client settings.
16 logged in. 16- Ability to connect to different hosts and create profiles for hosts.
17- Neatly organized sidebar for conversation and client settings. 17- By default, registration is closed to the public. You can enable public
18- Ability to connect to different hosts and create profiles for hosts. 18 registration on the Settings page or generate invitation links on the Users
19- By default, registration is closed to the public. You can enable 19 page.
20 public registration on the Settings page or generate invitation 20- Customization of the client theme, organization name and URL, admin email, and
21 links on the Users page. 21 video service.
22- Customization of the client theme, organization name and URL, admin
23 email, and video service.
24 22
25# Docker Installation 23# Docker Installation
26 24
27To install Convos, simply create a directory and a 25To install Convos, simply create a directory and a `docker-compose.yml` file:
28`docker-compose.yml` file:
29 26
30```sh 27```sh
31mkdir ~/convos && cd ~/convos 28mkdir ~/convos && cd ~/convos
32nano docker-compose.yml 29nano docker-compose.yml
33``` 30```
34 31
35With the `docker-compose.yml` file open, paste the 32With the `docker-compose.yml` file open, paste the configuration below into the
36configuration below into the file. You can customize the host port to be 33file. You can customize the host port to be something unique, such as
37something unique, such as `21897:3000`. You can also change 34`21897:3000`. You can also change the `data` folder to be a docker volume
38the `data` folder to be a docker volume instead, if you 35instead, if you prefer.
39prefer.
40 36
41``` config 37``` config
42version: '3' 38version: '3'
@@ -53,29 +49,27 @@ services:
53 restart: always 49 restart: always
54``` 50```
55 51
56Save the `docker-compose.yml` file and bring the container 52Save the `docker-compose.yml` file and bring the container up:
57up:
58 53
59```sh 54```sh
60sudo docker-compose up -d 55sudo docker-compose up -d
61``` 56```
62 57
63At this point, Convos is available at `<server_ip>:3000` but 58At this point, Convos is available at `<server_ip>:3000` but not available to
64not available to the public. 59the public.
65 60
66# Nginx Reverse Proxy 61# Nginx Reverse Proxy
67 62
68If you\'re using Nginx, you can create a configuration file for the 63If you're using Nginx, you can create a configuration file for the convos
69convos application. Start by opening the file: 64application. Start by opening the file:
70 65
71```sh 66```sh
72nano /etc/nginx/sites-available/convos 67nano /etc/nginx/sites-available/convos
73``` 68```
74 69
75Within the nginx configuration file, paste the following content and be 70Within the nginx configuration file, paste the following content and be sure to
76sure to update `convos.example.com` to match your domain and 71update `convos.example.com` to match your domain and `127.0.0.1:3000` to match
77`127.0.0.1:3000` to match the port you opened in the 72the port you opened in the `docker-compose.yml` file.
78`docker-compose.yml` file.
79 73
80``` config 74``` config
81# Host and port where convos is running 75# Host and port where convos is running
@@ -117,8 +111,8 @@ server {
117} 111}
118``` 112```
119 113
120Once the file is saved, link it to the `sites-enabled` 114Once the file is saved, link it to the `sites-enabled` directory and restart
121directory and restart Nginx. 115Nginx.
122 116
123```sh 117```sh
124sudo ln -s /etc/nginx/sites-available/convos /etc/nginx/sites-enabled/convos 118sudo ln -s /etc/nginx/sites-available/convos /etc/nginx/sites-enabled/convos
@@ -127,43 +121,41 @@ sudo systemctl restart nginx.service
127 121
128# Screenshots 122# Screenshots
129 123
130See the screenshots below for an example of the Convos homepage and an 124See the screenshots below for an example of the Convos homepage and an excerpt
131excerpt of the chat screen. 125of the chat screen.
132 126
133There are numerous themes to choose from; the theme shown in the images 127There are numerous themes to choose from; the theme shown in the images below is
134below is Dracula. 128Dracula.
135 129
136![Convos 130![Convos Home](https://img.cleberg.net/blog/20230623-convos/convos_home.png)
137Home](https://img.cleberg.net/blog/20230623-convos/convos_home.png)
138 131
139![Convos 132![Convos Chat](https://img.cleberg.net/blog/20230623-convos/convos_chat.png)
140Chat](https://img.cleberg.net/blog/20230623-convos/convos_chat.png)
141 133
142# Registering a Nickname 134# Registering a Nickname
143 135
144Hop into the server channel so that you can message NickServ. In the 136Hop into the server channel so that you can message NickServ. In the case of
145case of Convos, the default sever is libera.chat. Simply click the 137Convos, the default sever is libera.chat. Simply click the `libera` conversation
146`libera` conversation at the top of the sidebar to open it. 138at the top of the sidebar to open it. Once the chat is open, you can claim a
147Once the chat is open, you can claim a nickname by typing: 139nickname by typing:
148 140
149``` txt 141``` txt
150/nick <nick> 142/nick <nick>
151``` 143```
152 144
153If the nickname is available, and you\'d like to register the nickname 145If the nickname is available, and you'd like to register the nickname to
154to yourself, you\'ll need to type another command: 146yourself, you'll need to type another command:
155 147
156``` txt 148``` txt
157/msg NickServ REGISTER 149/msg NickServ REGISTER
158<password> <email> 150<password> <email>
159``` 151```
160 152
161On libera.chat, the server will send a confirmation email with a command 153On libera.chat, the server will send a confirmation email with a command that
162that you must message in IRC to verify registration of the nickname: 154you must message in IRC to verify registration of the nickname:
163 155
164``` txt 156``` txt
165/msg NickServ VERIFY REGISTER <nick> <verification_code> 157/msg NickServ VERIFY REGISTER <nick> <verification_code>
166``` 158```
167 159
168Once entered, the server should confirm registration of the nickname to 160Once entered, the server should confirm registration of the nickname to the
169the supplied email with the password specified. 161supplied email with the password specified.
content/blog/2023-06-28-backblaze-b2.md +66 −74
@@ -7,82 +7,77 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10Backblaze [B2 Cloud 10Backblaze [B2 Cloud Storage](https://www.backblaze.com/b2/cloud-storage.html) is
11Storage](https://www.backblaze.com/b2/cloud-storage.html) is an 11an inexpensive and reliable on-demand cloud storage and backup solution.
12inexpensive and reliable on-demand cloud storage and backup solution.
13 12
14The service starts at \$5/TB/month (\$0.005/GB/month) with a download 13The service starts at $5/TB/month ($0.005/GB/month) with a download rate of
15rate of \$0.01/GB/month. 14$0.01/GB/month.
16 15
17However, there are free tiers: 16However, there are free tiers:
18 17
19- The first 10 GB of storage is free. 18- The first 10 GB of storage is free.
20- The first 1 GB of data downloaded each day is free. 19- The first 1 GB of data downloaded each day is free.
21- Class A transactions are free. 20- Class A transactions are free.
22- The first 2500 Class B transactions each day are free. 21- The first 2500 Class B transactions each day are free.
23- The first 2500 Class C transactions each day are free. 22- The first 2500 Class C transactions each day are free.
24 23
25You can see which API calls fall into categories A, B, or C here: 24You can see which API calls fall into categories A, B, or C here: [Pricing
26[Pricing Organized by API 25Organized by API
27Calls](https://www.backblaze.com/b2/b2-transactions-price.html). 26Calls](https://www.backblaze.com/b2/b2-transactions-price.html).
28 27
29For someone like me, who wants an offsite backup of their server\'s 28For someone like me, who wants an offsite backup of their server's `/home/`
30`/home/` directory and various other server configs that fall 29directory and various other server configs that fall under 10 GB total,
31under 10 GB total, Backblaze is a great solution from a financial 30Backblaze is a great solution from a financial perspective.
32perspective.
33 31
34# Create An Account 32# Create An Account
35 33
36To start with Backblaze, you\'ll need to [create a free 34To start with Backblaze, you'll need to [create a free
37account](https://www.backblaze.com/b2/sign-up.html) - no payment method 35account](https://www.backblaze.com/b2/sign-up.html) - no payment method is
38is required to sign up. 36required to sign up.
39 37
40Once you have an account, you can test out the service with their web 38Once you have an account, you can test out the service with their web GUI, their
41GUI, their mobile app, or their CLI tool. I\'m going to use the CLI tool 39mobile app, or their CLI tool. I'm going to use the CLI tool below to test a
42below to test a file upload and then sync an entire directory to my 40file upload and then sync an entire directory to my Backblaze bucket.
43Backblaze bucket.
44 41
45# Create a Bucket 42# Create a Bucket
46 43
47Before you can start uploading, you need to create a bucket. If you\'re 44Before you can start uploading, you need to create a bucket. If you're familiar
48familiar with other object storage services, this will feel familiar. If 45with other object storage services, this will feel familiar. If not, it's
49not, it\'s pretty simple to create one. 46pretty simple to create one.
50 47
51As their webpage says: 48As their webpage says:
52 49
53> A bucket is a container that holds files that are uploaded into B2 50> A bucket is a container that holds files that are uploaded into B2 Cloud
54> Cloud Storage. The bucket name must be globally unique and must have a 51> Storage. The bucket name must be globally unique and must have a minimum of 6
55> minimum of 6 characters. A limit of 100 buckets may be created per 52> characters. A limit of 100 buckets may be created per account. An unlimited
56> account. An unlimited number of files may be uploaded into a bucket. 53> number of files may be uploaded into a bucket.
57 54
58Once you click the `Create a Bucket` button on their webpage 55Once you click the `Create a Bucket` button on their webpage or mobile app, you
59or mobile app, you need to provide the following: 56need to provide the following:
60 57
61- Bucket Unique Name 58- Bucket Unique Name
62- Files in Bucket are: `Private` or `Public` 59- Files in Bucket are: `Private` or `Public`
63- Default Encryption: `Disable` or `Enable` 60- Default Encryption: `Disable` or `Enable`
64- Object Lock: `Disable` or `Enable` 61- Object Lock: `Disable` or `Enable`
65 62
66For my bucket, I created a private bucket with encryption enabled and 63For my bucket, I created a private bucket with encryption enabled and object
67object lock disabled. 64lock disabled.
68 65
69Once your bucket is created, you can test the upload/download feature on 66Once your bucket is created, you can test the upload/download feature on their
70their web GUI or mobile app! At this point, you have a fully functional 67web GUI or mobile app! At this point, you have a fully functional bucket and
71bucket and account. 68account.
72 69
73# Linux CLI Tool 70# Linux CLI Tool
74 71
75## Installation 72## Installation
76 73
77To install the `b2` CLI tool, you\'ll need to download it 74To install the `b2` CLI tool, you'll need to download it from the [CLI
78from the [CLI 75Tools](https://www.backblaze.com/docs/cloud-storage-command-line-tools) page. I
79Tools](https://www.backblaze.com/docs/cloud-storage-command-line-tools) 76recommend copying the URL from the link that says `Linux` and using wget to
80page. I recommend copying the URL from the link that says 77download it, as shown below.
81`Linux` and using wget to download it, as shown below.
82 78
83Once downloaded, make the file executable and move it to a location on 79Once downloaded, make the file executable and move it to a location on your
84your `$PATH`, so that you can execute that command from 80`$PATH`, so that you can execute that command from anywhere on the machine.
85anywhere on the machine.
86 81
87```sh 82```sh
88wget <b2_cli_url> 83wget <b2_cli_url>
@@ -93,12 +88,10 @@ mv b2_linux /usr/bin/b2
93## Log In 88## Log In
94 89
95The first step after installation is to log in. To do this, execute the 90The first step after installation is to log in. To do this, execute the
96following command and provide your `<applicationKeyId>` and 91following command and provide your `<applicationKeyId>` and `<applicationKey>`.
97`<applicationKey>`.
98 92
99If you don\'t want to provide these values in the command itself, you 93If you don't want to provide these values in the command itself, you can simply
100can simply execute the base command and it will request them in an 94execute the base command and it will request them in an interactive prompt.
101interactive prompt.
102 95
103```sh 96```sh
104# if you want to provide the keys directly: 97# if you want to provide the keys directly:
@@ -110,9 +103,9 @@ b2 authorize-account
110 103
111## Upload a Test File 104## Upload a Test File
112 105
113In order to test the functionality of the CLI tool, I\'ll start by 106In order to test the functionality of the CLI tool, I'll start by uploading a
114uploading a single test file to the bucket I created above. We can do 107single test file to the bucket I created above. We can do this with the
115this with the `upload_file` function. 108`upload_file` function.
116 109
117The command is issued as follows: 110The command is issued as follows:
118 111
@@ -126,8 +119,8 @@ In my situation, I executed the following command with my username.
126b2 upload_file my_unique_bucket /home/<user>/test.md test.md 119b2 upload_file my_unique_bucket /home/<user>/test.md test.md
127``` 120```
128 121
129To confirm that the file was uploaded successfully, list the files in 122To confirm that the file was uploaded successfully, list the files in your
130your bucket: 123bucket:
131 124
132```sh 125```sh
133b2 ls <bucket_name> 126b2 ls <bucket_name>
@@ -139,9 +132,9 @@ test.md
139 132
140## Sync a Directory 133## Sync a Directory
141 134
142If you have numerous files, you can use the `sync` function 135If you have numerous files, you can use the `sync` function to perform
143to perform functionality similar to `rsync`, where you can 136functionality similar to `rsync`, where you can check what's in your bucket and
144check what\'s in your bucket and sync anything that is new or modified. 137sync anything that is new or modified.
145 138
146The command is issued as follows: 139The command is issued as follows:
147 140
@@ -149,8 +142,8 @@ The command is issued as follows:
149b2 sync <source file location> <B2 bucket destination> 142b2 sync <source file location> <B2 bucket destination>
150``` 143```
151 144
152In my case, I can sync my user\'s entire home directory to my bucket 145In my case, I can sync my user's entire home directory to my bucket without
153without specifying any of the files directly: 146specifying any of the files directly:
154 147
155```sh 148```sh
156b2 sync /home/<user>/ "b2://<bucketName>/home/<user>" 149b2 sync /home/<user>/ "b2://<bucketName>/home/<user>"
@@ -160,22 +153,21 @@ b2 sync /home/<user>/ "b2://<bucketName>/home/<user>"
160 153
161## Timing of Updates to the Web GUI 154## Timing of Updates to the Web GUI
162 155
163When performing actions over a bucket, there is a slight delay in the 156When performing actions over a bucket, there is a slight delay in the web GUI
164web GUI when inspecting a bucket or its file. Note that simple actions 157when inspecting a bucket or its file. Note that simple actions such as uploading
165such as uploading or deleting files may have a delay of a few minutes up 158or deleting files may have a delay of a few minutes up to 24 hours. In my
166to 24 hours. In my experience (\<10 GB and \~20,000 files), any actions 159experience (\<10 GB and ~20,000 files), any actions took only a few minutes to
167took only a few minutes to update across clients. 160update across clients.
168 161
169## Symlinks 162## Symlinks
170 163
171Note that symlinks are resolved by b2, so if you have a link from 164Note that symlinks are resolved by b2, so if you have a link from
172`/home/<user>/nas-storage` that symlinks out to a 165`/home/<user>/nas-storage` that symlinks out to a `/mnt/nas-storage` folder that
173`/mnt/nas-storage` folder that has 10TB of data, 166has 10TB of data, `b2` will resolve that link and start uploading all 10TB of
174`b2` will resolve that link and start uploading all 10TB of
175data linked within the folder. 167data linked within the folder.
176 168
177If you\'re not sure if you have any symlinks, a symlink will look like 169If you're not sure if you have any symlinks, a symlink will look like this
178this (note the `->` symbol): 170(note the `->` symbol):
179 171
180```sh 172```sh
181> ls -lha 173> ls -lha
content/blog/2023-06-30-self-hosting-voyager.md +24 −28
@@ -7,12 +7,12 @@ draft = false
7 7
8# Installation Guide 8# Installation Guide
9 9
10[Voyager](https://github.com/aeharding/voyager) is a mobile-first Lemmy 10[Voyager](https://github.com/aeharding/voyager) is a mobile-first Lemmy web
11web client, based on iOS design standards. It follows very closely to 11client, based on iOS design standards. It follows very closely to Apollo's
12Apollo\'s design. 12design.
13 13
14This post is a guide showing how I was able to build and launch my own 14This post is a guide showing how I was able to build and launch my own instance
15instance of Voyager via Docker Compose. 15of Voyager via Docker Compose.
16 16
17## Clone the Repository 17## Clone the Repository
18 18
@@ -25,26 +25,24 @@ cd voyager
25 25
26## Build the Image 26## Build the Image
27 27
28With this repository, you can build the image yourself without any 28With this repository, you can build the image yourself without any further
29further configuration. When complete, it\'ll give you the image ID for 29configuration. When complete, it'll give you the image ID for you to run.
30you to run.
31 30
32```sh 31```sh
33sudo docker build . 32sudo docker build .
34# Successfully built 5f00723cb5be 33# Successfully built 5f00723cb5be
35``` 34```
36 35
37With the image ID above, you can run the container and pass the 36With the image ID above, you can run the container and pass the requested port
38requested port `5314` through or use a custom port, if you 37`5314` through or use a custom port, if you wish.
39wish.
40 38
41You can also set the `CUSTOM_LEMMY_SERVERS` environment 39You can also set the `CUSTOM_LEMMY_SERVERS` environment variable if you want to
42variable if you want to add to the default suggested login servers. This 40add to the default suggested login servers. This must be set with a comma
43must be set with a comma separated list of suggested servers. The first 41separated list of suggested servers. The first instance in the list will be the
44instance in the list will be the default view for logged-out users. 42default view for logged-out users.
45 43
46I will be using a `docker-compose.yml` file to run this 44I will be using a `docker-compose.yml` file to run this container, instead of a
47container, instead of a `docker run` command. 45`docker run` command.
48 46
49```sh 47```sh
50nano docker-compose.yml 48nano docker-compose.yml
@@ -67,17 +65,16 @@ sudo docker-compose up -d
67``` 65```
68 66
69The web app will now be available at the following address: 67The web app will now be available at the following address:
70`<machine_ip>:<custom_port>`. If you are running it on your 68`<machine_ip>:<custom_port>`. If you are running it on your local device, try
71local device, try `localhost:<custom_port>`. 69`localhost:<custom_port>`.
72 70
73## Reverse Proxy 71## Reverse Proxy
74 72
75If you want to visit this app via an external URL or domain name, 73If you want to visit this app via an external URL or domain name, you'll need
76you\'ll need to set up a reverse proxy. The example below uses Nginx as 74to set up a reverse proxy. The example below uses Nginx as a reverse proxy.
77a reverse proxy.
78 75
79Simply create the configuration file, paste the contents below, save the 76Simply create the configuration file, paste the contents below, save the file,
80file, symlink the file, and restart Nginx. 77symlink the file, and restart Nginx.
81 78
82```sh 79```sh
83sudo nano /etc/nginx/sites-available/voyager 80sudo nano /etc/nginx/sites-available/voyager
@@ -120,8 +117,7 @@ sudo ln sudo ln -s /etc/nginx/sites-available/voyager /etc/nginx/sites-enabled/v
120sudo systemctl restart nginx.service 117sudo systemctl restart nginx.service
121``` 118```
122 119
123The site will now be available at the `server_name` you 120The site will now be available at the `server_name` you specified above!
124specified above!
125 121
126You can visit my instance at 122You can visit my instance at [voyager.cleberg.net](https://voyager.cleberg.net)
127[voyager.cleberg.net](https://voyager.cleberg.net) for an example. 123for an example.
content/blog/2023-07-12-wireguard-lan.md +29 −33
@@ -7,13 +7,13 @@ draft = false
7 7
8# Download Configuration Files from Mullvad 8# Download Configuration Files from Mullvad
9 9
10To begin, you\'ll need [Wireguard configuration files from 10To begin, you'll need [Wireguard configuration files from
11Mullvad](https://mullvad.net/account/wireguard-config). You can choose 11Mullvad](https://mullvad.net/account/wireguard-config). You can choose any of
12any of the options as you download them. For example, I enabled the kill 12the options as you download them. For example, I enabled the kill switch,
13switch, selected all countries, and selected a few content filters. 13selected all countries, and selected a few content filters.
14 14
15Once downloaded, unzip the files and move them to the Wireguard folder 15Once downloaded, unzip the files and move them to the Wireguard folder on your
16on your system. 16system.
17 17
18```sh 18```sh
19cd ~/Downloads 19cd ~/Downloads
@@ -40,41 +40,38 @@ AllowedIPs = <redacted>
40Endpoint = <redacted> 40Endpoint = <redacted>
41``` 41```
42 42
43> Note: If you didn\'t select the kill switch option, you won\'t see the 43> Note: If you didn't select the kill switch option, you won't see the
44> `PostUp` and `PreDown` lines. In this case, 44> `PostUp` and `PreDown` lines. In this case, you'll need to modify the script
45> you\'ll need to modify the script below to simply append those lines 45> below to simply append those lines to the `[Interface]` block.
46> to the `[Interface]` block.
47 46
48# Editing the Configuration Files 47# Editing the Configuration Files
49 48
50Once you have the files, you\'ll need to edit them and replace the 49Once you have the files, you'll need to edit them and replace the `PostUp` and
51`PostUp` and `PreDown` lines to enable LAN access. 50`PreDown` lines to enable LAN access.
52 51
53I recommend that you do this process as root, since you\'ll need to be 52I recommend that you do this process as root, since you'll need to be able to
54able to access files in `/etc/wireguard`, which are generally 53access files in `/etc/wireguard`, which are generally owned by root. You can
55owned by root. You can also try using `sudo` or 54also try using `sudo` or `doas`, but I didn't test that scenario so you may
56`doas`, but I didn\'t test that scenario so you may need to 55need to adjust, as necessary.
57adjust, as necessary.
58 56
59```sh 57```sh
60su 58su
61``` 59```
62 60
63Create the Python file that we\'ll be using to update the Wireguard 61Create the Python file that we'll be using to update the Wireguard
64configuration files. 62configuration files.
65 63
66```sh 64```sh
67nano replace.py 65nano replace.py
68``` 66```
69 67
70Within the Python file, copy and paste the logic below. This script will 68Within the Python file, copy and paste the logic below. This script will open a
71open a directory, loop through every configuration file within the 69directory, loop through every configuration file within the directory, and
72directory, and replace the `PostUp` and `PreDown` 70replace the `PostUp` and `PreDown` lines with the new LAN-enabled iptables
73lines with the new LAN-enabled iptables commands. 71commands.
74 72
75> Note: If your LAN is on a subnet other than 73> Note: If your LAN is on a subnet other than `192.168.1.0/24`, you'll need to
76> `192.168.1.0/24`, you\'ll need to update the Python script 74> update the Python script below appropriately.
77> below appropriately.
78 75
79``` python 76``` python
80import os 77import os
@@ -97,15 +94,15 @@ for file in os.listdir(dir):
97print("--- done ---") 94print("--- done ---")
98``` 95```
99 96
100Once you\'re done, save and close the file. You can now run the Python 97Once you're done, save and close the file. You can now run the Python script
101script and watch as each file is updated. 98and watch as each file is updated.
102 99
103```sh 100```sh
104python3 replace.py 101python3 replace.py
105``` 102```
106 103
107To confirm it worked, you can `cat` one of the configuration 104To confirm it worked, you can `cat` one of the configuration files to inspect
108files to inspect the new logic and connect to one to test it out. 105the new logic and connect to one to test it out.
109 106
110```sh 107```sh
111cat /etc/wireguard/us-chi-wg-001.conf 108cat /etc/wireguard/us-chi-wg-001.conf
@@ -128,16 +125,15 @@ AllowedIPs = <redacted>
128Endpoint = <redacted> 125Endpoint = <redacted>
129``` 126```
130 127
131If you connect to a Wireguard interface, such as 128If you connect to a Wireguard interface, such as `us-chi-wg-001`, you can test
132`us-chi-wg-001`, you can test your SSH functionality and see 129your SSH functionality and see that it works even while on the VPN.
133that it works even while on the VPN.
134 130
135```sh 131```sh
136wg-quick up us-chi-wg-001 132wg-quick up us-chi-wg-001
137ssh user@lan-host 133ssh user@lan-host
138``` 134```
139 135
140To confirm your VPN connection, you can curl Mullvad\'s connection API: 136To confirm your VPN connection, you can curl Mullvad's connection API:
141 137
142```sh 138```sh
143curl https://am.i.mullvad.net/connected 139curl https://am.i.mullvad.net/connected
content/blog/2023-07-19-plex-transcoder-errors.md +17 −21
@@ -7,9 +7,8 @@ draft = false
7 7
8# Plex Transcoder Error 8# Plex Transcoder Error
9 9
10Occasionally, you may see an error in your Plex client that references a 10Occasionally, you may see an error in your Plex client that references a failure
11failure with the transcoder conversion process. The specific error 11with the transcoder conversion process. The specific error wording is:
12wording is:
13 12
14``` txt 13``` txt
15Conversion failed. The transcoder failed to start up. 14Conversion failed. The transcoder failed to start up.
@@ -17,14 +16,13 @@ Conversion failed. The transcoder failed to start up.
17 16
18# Debugging the Cause 17# Debugging the Cause
19 18
20In order to get a better look at what is causing the error, I\'m going 19In order to get a better look at what is causing the error, I'm going to
21to observe the Plex console while the error occurs. To do this, open the 20observe the Plex console while the error occurs. To do this, open the Plex web
22Plex web client, go to `Settings` \> `Manage` \> 21client, go to `Settings` > `Manage` > `Console`. Now, try to play the title
23`Console`. Now, try to play the title again and watch to see 22again and watch to see which errors occur.
24which errors occur.
25 23
26In my case, you can see the errors below are related to a subtitle file 24In my case, you can see the errors below are related to a subtitle file (`.srt`)
27(`.srt`) causing the transcoder to crash. 25causing the transcoder to crash.
28 26
29``` txt 27``` txt
30Jul 19, 2023 16:49:34.945 [140184571120440] Error — Couldn't find the file to stream: /movies/Movie Title (2021)/Movie Title (2021).srt 28Jul 19, 2023 16:49:34.945 [140184571120440] Error — Couldn't find the file to stream: /movies/Movie Title (2021)/Movie Title (2021).srt
@@ -36,17 +34,17 @@ Jul 19, 2023 16:51:23.402 [140184510081848] Info — Library section 1 (Movies)
36 34
37# Solving the Error 35# Solving the Error
38 36
39In my case, I simply removed the subtitle file because it was not 37In my case, I simply removed the subtitle file because it was not critical to
40critical to keep. You may also avoid this by turning off subtitles if 38keep. You may also avoid this by turning off subtitles if you don't want to
41you don\'t want to delete the file. 39delete the file.
42 40
43```sh 41```sh
44rm -rf "/movies/Movie Title (2021)/Movie Title (2021).srt" 42rm -rf "/movies/Movie Title (2021)/Movie Title (2021).srt"
45``` 43```
46 44
47Once the subtitle is removed from the directory or subtitles are turned 45Once the subtitle is removed from the directory or subtitles are turned off, try
48off, try to play the title again. At this point, it should play without 46to play the title again. At this point, it should play without error. If not,
49error. If not, reopen or refresh your Plex client and the Plex server: 47reopen or refresh your Plex client and the Plex server:
50 48
51```sh 49```sh
52sudo systemctl restart plexmediaserver.service 50sudo systemctl restart plexmediaserver.service
@@ -56,10 +54,8 @@ sudo systemctl restart plexmediaserver.service
56 54
57Looking at [a related Plex forum 55Looking at [a related Plex forum
58post](https://forums.plex.tv/t/subtitles-crashing-plex-transcoder-samsung-q80-tv-with-or-without-hardware-transcode/741441/2), 56post](https://forums.plex.tv/t/subtitles-crashing-plex-transcoder-samsung-q80-tv-with-or-without-hardware-transcode/741441/2),
59it seems that `.srt` subtitles are the core issue here. 57it seems that `.srt` subtitles are the core issue here. However, Plex does not
60However, Plex does not seem to have a resolution that fixes these 58seem to have a resolution that fixes these errors.
61errors.
62 59
63Unfortunately, I would suggest converting subtitle formats, burning the 60Unfortunately, I would suggest converting subtitle formats, burning the
64subtitles into the title, or simply removing subtitles when they cause 61subtitles into the title, or simply removing subtitles when they cause crashes.
65crashes.
content/blog/2023-08-18-agile-auditing.md +101 −110
@@ -8,152 +8,143 @@ draft = false
8# What is Agile Auditing? 8# What is Agile Auditing?
9 9
10[Agile](https://en.wikipedia.org/wiki/Agile_software_development), the 10[Agile](https://en.wikipedia.org/wiki/Agile_software_development), the
11collaborative philosophy behind many software development methods, has 11collaborative philosophy behind many software development methods, has been
12been picking up steam as a beneficial tool to use in the external and 12picking up steam as a beneficial tool to use in the external and internal
13internal auditing world. 13auditing world.
14 14
15This blog post will walk through commonly used terms within Agile, 15This blog post will walk through commonly used terms within Agile, Scrum, and
16Scrum, and Kanban in order to translate these terms and roles into 16Kanban in order to translate these terms and roles into audit-specific terms.
17audit-specific terms.
18 17
19Whether your team is in charge of a financial statement audit, an 18Whether your team is in charge of a financial statement audit, an attestation
20attestation (SOC 1, SOC 2, etc.), or a unique internal audit, the terms 19(SOC 1, SOC 2, etc.), or a unique internal audit, the terms used throughout this
21used throughout this post should still apply. 20post should still apply.
22 21
23# Agile 22# Agile
24 23
25To start, I\'ll take a look at Agile. 24To start, I'll take a look at Agile.
26 25
27> The Agile methodology is a project management approach that involves 26> The Agile methodology is a project management approach that involves breaking
28> breaking the project into phases and emphasizes continuous 27> the project into phases and emphasizes continuous collaboration and
29> collaboration and improvement. Teams follow a cycle of planning, 28> improvement. Teams follow a cycle of planning, executing, and evaluating.
30> executing, and evaluating.
31 29
32While this approach may seem familiar to what audit teams have 30While this approach may seem familiar to what audit teams have historically
33historically done, an audit team must make distinct changes in their 31done, an audit team must make distinct changes in their mentality and how they
34mentality and how they approach and manage a project. 32approach and manage a project.
35 33
36## Agile Values 34## Agile Values
37 35
38The Agile Manifesto, written in 2001 at a summit in Utah, contain a set 36The Agile Manifesto, written in 2001 at a summit in Utah, contain a set of four
39of four main values that comprise the Agile approach: 37main values that comprise the Agile approach:
40 38
411. Individuals and interactions over processes and tools. 391. Individuals and interactions over processes and tools.
422. Working software over comprehensive documentation. 402. Working software over comprehensive documentation.
433. Customer collaboration over contract negotiation. 413. Customer collaboration over contract negotiation.
444. Responding to change over following a plan. 424. Responding to change over following a plan.
45 43
46Beyond the four values, [twelve 44Beyond the four values, [twelve
47principles](https://agilemanifesto.org/principles.html) were also 45principles](https://agilemanifesto.org/principles.html) were also written as
48written as part of the summit. 46part of the summit.
49 47
50In order to relate these values to an audit or attestation engagement, 48In order to relate these values to an audit or attestation engagement, we need
51we need to shift the focus from software development to the main goal of 49to shift the focus from software development to the main goal of an engagement:
52an engagement: completing sufficient audit testing to address to 50completing sufficient audit testing to address to relevant risks over the
53relevant risks over the processes and controls at hand. 51processes and controls at hand.
54 52
55Audit Examples: 53Audit Examples:
56 54
57- Engagement teams must value the team members, client contacts, and 55- Engagement teams must value the team members, client contacts, and their
58 their interactions over the historical processes and tools that have 56 interactions over the historical processes and tools that have been used.
59 been used. 57- Engagement teams must value a final report that contains sufficient audit
60- Engagement teams must value a final report that contains sufficient 58 documentation over excessive documentation or scope creep.
61 audit documentation over excessive documentation or scope creep. 59- Engagement teams must collaborate with the audit clients as much as feasible
62- Engagement teams must collaborate with the audit clients as much as 60 to ensure that both sides are constantly updated with current knowledge of the
63 feasible to ensure that both sides are constantly updated with 61 engagement's status and any potential findings, rather than waiting for
64 current knowledge of the engagement\'s status and any potential 62 pre-set meetings or the end of the engagement to communicate.
65 findings, rather than waiting for pre-set meetings or the end of the 63- Engagement teams must be able to respond to change in an engagement's
66 engagement to communicate. 64 schedule, scope, or environment to ensure that the project is completed in a
67- Engagement teams must be able to respond to change in an 65 timely manner and that all relevant areas are tested.
68 engagement\'s schedule, scope, or environment to ensure that the 66 - In terms of an audit department's portfolio, they must be able to respond
69 project is completed in a timely manner and that all relevant areas 67 to changes in their company's or client's environment and be able to
70 are tested. 68 dynamically change their audit plan accordingly.
71 - In terms of an audit department\'s portfolio, they must be able
72 to respond to changes in their company\'s or client\'s
73 environment and be able to dynamically change their audit plan
74 accordingly.
75 69
76# Scrum 70# Scrum
77 71
78The above section discusses the high-level details of the Agile 72The above section discusses the high-level details of the Agile philosophy and
79philosophy and how an audit team can potentially mold that mindset into 73how an audit team can potentially mold that mindset into the audit world, but
80the audit world, but how does a team implement these ideas? 74how does a team implement these ideas?
81 75
82There are many methods that use an Agile mindset, but I prefer 76There are many methods that use an Agile mindset, but I prefer
83[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)). 77[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)). Scrum is a
84Scrum is a framework based on Agile that enables a team to work through 78framework based on Agile that enables a team to work through a project through a
85a project through a series of roles, ceremonies, artifacts, and values. 79series of roles, ceremonies, artifacts, and values.
86 80
87Let\'s dive into each of these individually. 81Let's dive into each of these individually.
88 82
89## Scrum Team 83## Scrum Team
90 84
91A scrum project is only as good as the team running the project. 85A scrum project is only as good as the team running the project. Standard scrum
92Standard scrum teams are separated into three distinct areas: 86teams are separated into three distinct areas:
93 87
941. **Product Owner (Client Contact)**: The client contact is the audit 881. **Product Owner (Client Contact)**: The client contact is the audit
95 equivalent of the product owner in Scrum. They are responsible for 89 equivalent of the product owner in Scrum. They are responsible for partnering
96 partnering with the engagement or audit team to ensure progress is 90 with the engagement or audit team to ensure progress is being made,
97 being made, priorities are established, and clear guidance is given 91 priorities are established, and clear guidance is given when questions or
98 when questions or findings arise within each sprint. 92 findings arise within each sprint.
992. **Scrum Master (Engagement Lead)**: The engagement or audit team 932. **Scrum Master (Engagement Lead)**: The engagement or audit team lead is
100 lead is responsible for coaching the team and the client contact on 94 responsible for coaching the team and the client contact on the scrum
101 the scrum process, tracking team progress against plan, scheduling 95 process, tracking team progress against plan, scheduling necessary resources,
102 necessary resources, and helping remove obstacles. 96 and helping remove obstacles.
1033. **Scrum Developers (Engagement Members)**: The engagement or audit 973. **Scrum Developers (Engagement Members)**: The engagement or audit team is
104 team is the set of team members responsible for getting the work 98 the set of team members responsible for getting the work done. These team
105 done. These team members will work on each task, report progress, 99 members will work on each task, report progress, resolve obstacles, and
106 resolve obstacles, and collaborate with other team members and the 100 collaborate with other team members and the client contact to ensure goals
107 client contact to ensure goals are being met. 101 are being met.
108 102
109## Scrum Ceremonies 103## Scrum Ceremonies
110 104
111Scrum ceremonies are events that are performed on a regular basis. 105Scrum ceremonies are events that are performed on a regular basis.
112 106
1131. **Sprint Planning**: The team works together to plan the upcoming 1071. **Sprint Planning**: The team works together to plan the upcoming sprint goal
114 sprint goal and which user stories (tasks) will be added to the 108 and which user stories (tasks) will be added to the sprint to achieve that
115 sprint to achieve that goal. 109 goal.
1162. **Sprint**: The time period, typically at least one week and no more 1102. **Sprint**: The time period, typically at least one week and no more than one
117 than one month in length, where the team works on the stories and 111 month in length, where the team works on the stories and anything in the
118 anything in the backlog. 112 backlog.
1193. **Daily Scrum**: A very short meeting held each day, typically 15 1133. **Daily Scrum**: A very short meeting held each day, typically 15 minutes, to
120 minutes, to quickly emphasize alignment on the sprint goal and plan 114 quickly emphasize alignment on the sprint goal and plan the next 24 hours.
121 the next 24 hours. Each team member may share what they did the day 115 Each team member may share what they did the day before, what they'll do
122 before, what they\'ll do today, and any obstacles to their work. 116 today, and any obstacles to their work.
1234. **Sprint Review**: At the end of each sprint, the team will gather 1174. **Sprint Review**: At the end of each sprint, the team will gather and
124 and discuss the progress, obstacles, and backlog from the previous 118 discuss the progress, obstacles, and backlog from the previous sprint.
125 sprint. 1195. **Sprint Retrospective**: More specific than the sprint review, the
1265. **Sprint Retrospective**: More specific than the sprint review, the 120 retrospective is meant to discuss what worked and what did not work during
127 retrospective is meant to discuss what worked and what did not work 121 the sprint. This may be processes, tools, people, or even things related to
128 during the sprint. This may be processes, tools, people, or even 122 the Scrum ceremonies.
129 things related to the Scrum ceremonies. 123
130 124One additional ceremony that may be applicable is organizing the backlog. This
131One additional ceremony that may be applicable is organizing the 125is typically the responsibility of the engagement leader and is meant to
132backlog. This is typically the responsibility of the engagement leader 126prioritize and clarify what needs to be done to complete items in the backlog.
133and is meant to prioritize and clarify what needs to be done to complete
134items in the backlog.
135 127
136## Artifacts 128## Artifacts
137 129
138While artifacts are generally not customizable in the audit world (i.e., 130While artifacts are generally not customizable in the audit world (i.e., each
139each control test must include some kind of working paper with evidence 131control test must include some kind of working paper with evidence supporting
140supporting the test results), I wanted to include some quick notes on 132the test results), I wanted to include some quick notes on associating scrum
141associating scrum artifact terms with an audit. 133artifact terms with an audit.
142 134
1431. **Product Backlog**: This is the overall backlog of unfinished audit 1351. **Product Backlog**: This is the overall backlog of unfinished audit tasks
144 tasks from all prior sprints. 136 from all prior sprints.
1452. **Sprint Backlog**: This is the backlog of unfinished audit tasks 1372. **Sprint Backlog**: This is the backlog of unfinished audit tasks from one
146 from one individual sprint. 138 individual sprint.
1473. **Increment**: This is the output of each sprint - generally this is 1393. **Increment**: This is the output of each sprint - generally this is best
148 best thought of as any documentation prepared during the sprint, 140 thought of as any documentation prepared during the sprint, such as risk
149 such as risk assessments, control working papers, deficiency 141 assessments, control working papers, deficiency analysis, etc.
150 analysis, etc.
151 142
152# Kanban 143# Kanban
153 144
154Last but not least, Kanban is a methodology that relies on boards to 145Last but not least, Kanban is a methodology that relies on boards to categorize
155categorize work into distinct, descriptive categories that allow an 146work into distinct, descriptive categories that allow an agile or scrum team to
156agile or scrum team to effectively plan the work of a sprint or project. 147effectively plan the work of a sprint or project.
157 148
158See Atlassian\'s [Kanban](https://www.atlassian.com/agile/kanban) page 149See Atlassian's [Kanban](https://www.atlassian.com/agile/kanban) page for more
159for more information. 150information.
content/blog/2023-09-15-self-hosting-gitweb.md +11 −14
@@ -7,14 +7,12 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10[GitWeb](https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb) is a 10[GitWeb](https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb) is a simple
11simple web-based visualizer for git repositories. By default, GitWeb 11web-based visualizer for git repositories. By default, GitWeb will only run with
12will only run with the `lighttpd` or `webrick` web 12the `lighttpd` or `webrick` web servers.
13servers.
14 13
15However, this guide will show you how to keep GitWeb running in the 14However, this guide will show you how to keep GitWeb running in the background
16background and display information for all repositories in a chosen 15and display information for all repositories in a chosen directory.
17directory.
18 16
19See below for the final result: 17See below for the final result:
20 18
@@ -22,7 +20,7 @@ See below for the final result:
22 20
23# Install Dependencies 21# Install Dependencies
24 22
25To start, you\'ll need install the following packages: 23To start, you'll need install the following packages:
26 24
27```sh 25```sh
28sudo apt install git gitweb fcgiwrap nginx 26sudo apt install git gitweb fcgiwrap nginx
@@ -57,21 +55,20 @@ server {
57} 55}
58``` 56```
59 57
60To make the configuration active, you need to symlink it and then 58To make the configuration active, you need to symlink it and then restart Nginx.
61restart Nginx.
62 59
63```sh 60```sh
64sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/git.example.com 61sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/git.example.com
65sudo systemctl restart nginx.service 62sudo systemctl restart nginx.service
66``` 63```
67 64
68The GitWeb application should now be available via the URL you set in 65The GitWeb application should now be available via the URL you set in the Nginx
69the Nginx configuration above. 66configuration above.
70 67
71# Customize GitWeb 68# Customize GitWeb
72 69
73If you need to, you can customize many things about Gitweb by editing 70If you need to, you can customize many things about Gitweb by editing the
74the [gitweb.conf](https://git-scm.com/docs/gitweb.conf) file. 71[gitweb.conf](https://git-scm.com/docs/gitweb.conf) file.
75 72
76```sh 73```sh
77sudo nano /etc/gitweb.conf 74sudo nano /etc/gitweb.conf
content/blog/2023-09-19-audit-sql-scripts.md +33 −41
@@ -7,17 +7,16 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10When you have to scope a database into your engagement, you may be 10When you have to scope a database into your engagement, you may be curious how
11curious how to best extract the information from the database. While 11to best extract the information from the database. While there are numerous
12there are numerous different methods to extract this type of 12different methods to extract this type of information, I'm going to show an
13information, I\'m going to show an example of how to gather all users 13example of how to gather all users and privileges from three main database
14and privileges from three main database types: Oracle, Microsoft SQL, 14types: Oracle, Microsoft SQL, and MySQL.
15and MySQL.
16 15
17# Oracle 16# Oracle
18 17
19You can use the following SQL script to see all users and their 18You can use the following SQL script to see all users and their privileges in an
20privileges in an Oracle database: 19Oracle database:
21 20
22``` sql 21``` sql
23SELECT 22SELECT
@@ -37,23 +36,21 @@ WHERE
37 grantee IN (SELECT DISTINCT grantee FROM dba_tab_privs); 36 grantee IN (SELECT DISTINCT grantee FROM dba_tab_privs);
38``` 37```
39 38
40This script queries the `dba_sys_privs` and 39This script queries the `dba_sys_privs` and `dba_tab_privs` views to retrieve
41`dba_tab_privs` views to retrieve system and table-level 40system and table-level privileges respectively. It then combines the results
42privileges respectively. It then combines the results using 41using `UNION ALL` to show all users and their associated privileges. Please note
43`UNION ALL` to show all users and their associated 42that this method does not extract information from the `dba_role_privs` table -
44privileges. Please note that this method does not extract information 43use the method below for that data.
45from the `dba_role_privs` table - use the method below for
46that data.
47 44
48Please note that you might need appropriate privileges (e.g., DBA 45Please note that you might need appropriate privileges (e.g., DBA privileges) to
49privileges) to access these views, and you should exercise caution when 46access these views, and you should exercise caution when querying system tables
50querying system tables in a production Oracle database. 47in a production Oracle database.
51 48
52## Alternative Oracle Query 49## Alternative Oracle Query
53 50
54You can also extract each table\'s information separately and perform 51You can also extract each table's information separately and perform processing
55processing outside the database to explore and determine the information 52outside the database to explore and determine the information necessary for the
56necessary for the audit: 53audit:
57 54
58``` sql 55``` sql
59SELECT ** FROM sys.dba_role_privs; 56SELECT ** FROM sys.dba_role_privs;
@@ -64,9 +61,8 @@ SELECT ** FROM sys.dba_users;
64 61
65# Microsoft SQL 62# Microsoft SQL
66 63
67You can use the following SQL script to see all users and their 64You can use the following SQL script to see all users and their privileges in a
68privileges in a Microsoft SQL Server database 65Microsoft SQL Server database ([source](https://stackoverflow.com/a/30040784)):
69([source](https://stackoverflow.com/a/30040784)):
70 66
71``` sql 67``` sql
72/* 68/*
@@ -217,8 +213,8 @@ ORDER BY
217 213
218# MySQL 214# MySQL
219 215
220You can use the following SQL script to see all users and their 216You can use the following SQL script to see all users and their privileges in a
221privileges in a MySQL database: 217MySQL database:
222 218
223```sh 219```sh
224mysql -u root -p 220mysql -u root -p
@@ -230,26 +226,22 @@ Find all users and hosts with access to the database:
230SELECT ** FROM information_schema.user_privileges; 226SELECT ** FROM information_schema.user_privileges;
231``` 227```
232 228
233This script retrieves user information and their associated 229This script retrieves user information and their associated database-level
234database-level privileges from the 230privileges from the `information_schema.user_privileges` table in MySQL. It
235`information_schema.user_privileges` table in MySQL. It lists 231lists various privileges such as SELECT, INSERT, UPDATE, DELETE, CREATE, and
236various privileges such as SELECT, INSERT, UPDATE, DELETE, CREATE, and
237more for each user and database combination. 232more for each user and database combination.
238 233
239Please note that you may need appropriate privileges (e.g., 234Please note that you may need appropriate privileges (e.g., `SELECT` privileges
240`SELECT` privileges on 235on `information_schema.user_privileges`) to access this information in a MySQL
241`information_schema.user_privileges`) to access this 236database. Additionally, some privileges like GRANT OPTION, EXECUTE, EVENT, and
242information in a MySQL database. Additionally, some privileges like 237TRIGGER may not be relevant for all users and databases.
243GRANT OPTION, EXECUTE, EVENT, and TRIGGER may not be relevant for all
244users and databases.
245 238
246## Alternative MySQL Query 239## Alternative MySQL Query
247 240
248You can also grab individual sets of data from MySQL if you prefer to 241You can also grab individual sets of data from MySQL if you prefer to join them
249join them after extraction. I have marked the queries below with 242after extraction. I have marked the queries below with `SELECT ...` and excluded
250`SELECT ...` and excluded most `WHERE` clauses for 243most `WHERE` clauses for brevity. You should determine the relevant privileges
251brevity. You should determine the relevant privileges in-scope and query 244in-scope and query for those privileges to reduce the length of time to query.
252for those privileges to reduce the length of time to query.
253 245
254``` sql 246``` sql
255-- Global Permissions 247-- Global Permissions
content/blog/2023-10-04-digital-minimalism.md +65 −73
@@ -5,103 +5,95 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8I\'ve written [a note about minimalism](file:///wiki/#digital-garden) 8I've written [a note about minimalism](file:///wiki/#digital-garden) before,
9before, but I wanted to dedicate some time to reflect on digital 9but I wanted to dedicate some time to reflect on digital minimalism and how
10minimalism and how I\'ve been able to minimize the impact of digital 10I've been able to minimize the impact of digital devices in my life.
11devices in my life. 11
12 12> These changes crept up on us and happened fast, before we had a chance to step
13> These changes crept up on us and happened fast, before we had a chance 13> back and ask what we really wanted out of the rapid advances of the past
14> to step back and ask what we really wanted out of the rapid advances 14> decade. We added new technologies to the periphery of our experience for minor
15> of the past decade. We added new technologies to the periphery of our 15> reasons, then woke one morning to discover that they had colonized the core of
16> experience for minor reasons, then woke one morning to discover that 16> our daily life. We didn't, in other words, sign up for the digital world in
17> they had colonized the core of our daily life. We didn\'t, in other 17> which we're currently entrenched; we seem to have stumbled backward into it.
18> words, sign up for the digital world in which we\'re currently
19> entrenched; we seem to have stumbled backward into it.
20> 18>
21> *(Digital Minimalism, 2019)* 19> *(Digital Minimalism, 2019)*
22 20
23# The Principles of Digital Minimalism 21# The Principles of Digital Minimalism
24 22
25As noted in Cal Newport\'s book, *Digital Minimalism*, there are three 23As noted in Cal Newport's book, *Digital Minimalism*, there are three main
26main principles to digital minimalism that I tend to agree with: 24principles to digital minimalism that I tend to agree with:
27 25
281. Clutter is costly. 261. Clutter is costly.
29 - Digital minimalists recognize that cluttering their time and 27 - Digital minimalists recognize that cluttering their time and attention
30 attention with too many devices, apps, and services creates an 28 with too many devices, apps, and services creates an overall negative cost
31 overall negative cost that can swamp the small benefits that 29 that can swamp the small benefits that each individual item provides in
32 each individual item provides in isolation. 30 isolation.
332. Optimization is important. 312. Optimization is important.
34 - Digital minimalists believe that deciding a particular 32 - Digital minimalists believe that deciding a particular technology supports
35 technology supports something they value is only the first step. 33 something they value is only the first step. To truly extract its full
36 To truly extract its full potential benefit, it\'s necessary to 34 potential benefit, it's necessary to think carefully about how they'll
37 think carefully about how they\'ll use the technology. 35 use the technology.
383. Intentionality is satisfying. 363. Intentionality is satisfying.
39 - Digital minimalists derive significant satisfaction from their 37 - Digital minimalists derive significant satisfaction from their general
40 general commitment to being more intentional about how they 38 commitment to being more intentional about how they engage with new
41 engage with new technologies. This source of satisfaction is 39 technologies. This source of satisfaction is independent of the specific
42 independent of the specific decisions they make and is one of 40 decisions they make and is one of the biggest reasons that minimalism
43 the biggest reasons that minimalism tends to be immensely 41 tends to be immensely meaningful to its practitioners.
44 meaningful to its practitioners.
45 42
46# Taking Action 43# Taking Action
47 44
48In order to put the logic into practice, I\'ve created a few new habits 45In order to put the logic into practice, I've created a few new habits and
49and continued performing old habits that are working well: 46continued performing old habits that are working well:
50 47
51## Using Devices With Intention 48## Using Devices With Intention
52 49
53- I already rarely use \"social media\", mostly limited to forums such 50- I already rarely use "social media", mostly limited to forums such as Hacker
54 as Hacker News and Tildes, so I\'ve just tweaked my behavior to stop 51 News and Tildes, so I've just tweaked my behavior to stop looking for content
55 looking for content in those places when I\'m bored. 52 in those places when I'm bored.
56- Use devices with intention. Each time I pick up a digital device, 53- Use devices with intention. Each time I pick up a digital device, there should
57 there should be an intention to use the device to improve my current 54 be an intention to use the device to improve my current situation. No more
58 situation. No more endless scrolling or searching for something to 55 endless scrolling or searching for something to interest me.
59 interest me.
60 56
61## Prevent Distractions 57## Prevent Distractions
62 58
63- Disable (most) notifications on all devices. I spent 15-30 minutes 59- Disable (most) notifications on all devices. I spent 15-30 minutes going
64 going through the notifications on my phone, watch, and computer to 60 through the notifications on my phone, watch, and computer to ensure that only
65 ensure that only a select few apps have the ability to interrupt me: 61 a select few apps have the ability to interrupt me: Calendar, Messages, Phone,
66 Calendar, Messages, Phone, Reminders, & Signal. 62 Reminders, & Signal.
67- Disable badges for any apps except the ones mentioned in the bullet 63- Disable badges for any apps except the ones mentioned in the bullet above.
68 above. 64- Set-up focus profiles across devices so that I can enable different modes,
69- Set-up focus profiles across devices so that I can enable different 65 such as Personal when I only want to see notifications from people I care
70 modes, such as Personal when I only want to see notifications from 66 about or Do Not Disturb, where absolutely nothing can interrupt me.
71 people I care about or Do Not Disturb, where absolutely nothing can 67- Clean up my home screens. This one was quite easy as I already maintain a
72 interrupt me. 68 minimalist set-up, but I went extreme by limiting my phone to just eight apps
73- Clean up my home screens. This one was quite easy as I already 69 on the home screen and four in the dock. If I need another app, I'll have to
74 maintain a minimalist set-up, but I went extreme by limiting my 70 search or use the app library.
75 phone to just eight apps on the home screen and four in the dock. If 71- Remove the work profile from my phone. This was a tough decision as having my
76 I need another app, I\'ll have to search or use the app library. 72 work profile on my device definitely makes my life easier at times, but it
77- Remove the work profile from my phone. This was a tough decision as 73 also has quite a negative effect when I'm "always online" and can see the
78 having my work profile on my device definitely makes my life easier 74 notifications and team activity 24/7. I believe creating a distinct barrier
79 at times, but it also has quite a negative effect when I\'m \"always 75 between my work and personal devices will be beneficial in the end.
80 online\" and can see the notifications and team activity 24/7. I
81 believe creating a distinct barrier between my work and personal
82 devices will be beneficial in the end.
83 76
84## Creating Alternative Activities 77## Creating Alternative Activities
85 78
86This is the most difficult piece, as most of my hobbies and interests 79This is the most difficult piece, as most of my hobbies and interests lie in the
87lie in the digital world. However, I\'m making a concerted effort to put 80digital world. However, I'm making a concerted effort to put devices down
88devices down unless necessary and force myself to perform other 81unless necessary and force myself to perform other activities in the physical
89activities in the physical world instead. 82world instead.
90 83
91I\'ve started with a few basics that are always readily available to me: 84I've started with a few basics that are always readily available to me:
92 85
93- Do a chore, such as organizing or cleaning. 86- Do a chore, such as organizing or cleaning.
94- Read a book, study a piece of art, etc. 87- Read a book, study a piece of art, etc.
95- Exercise or get outdoors. 88- Exercise or get outdoors.
96- Participate in a hobby, such as photography, birding, disc golf, 89- Participate in a hobby, such as photography, birding, disc golf, etc.
97 etc. 90- Let yourself be bored and wander into creativity.
98- Let yourself be bored and wander into creativity.
99 91
100# Making Progress 92# Making Progress
101 93
102I\'ll be taking notes as I continue down this journey and hope to see 94I'll be taking notes as I continue down this journey and hope to see positive
103positive trends. I\'ve always been a minimalist in the physical world 95trends. I've always been a minimalist in the physical world and it feels
104and it feels refreshing to filter out the clutter that has come to 96refreshing to filter out the clutter that has come to dominate my digital life
105dominate my digital life over the years. 97over the years.
106 98
107I\'m excited to see where this journey leads. 99I'm excited to see where this journey leads.
content/blog/2023-10-11-self-hosting-authelia.md +60 −69
@@ -7,49 +7,47 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10[Authelia](https://www.authelia.com/) is an open-source authentication 10[Authelia](https://www.authelia.com/) is an open-source authentication service
11service that allows you to place a portal between end users on the 11that allows you to place a portal between end users on the internet and
12internet and self-hosted services on your server. 12self-hosted services on your server.
13 13
14You can require one factor (username+password) or two factor 14You can require one factor (username+password) or two factor authentication for
15authentication for any such user before allowing them to access a 15any such user before allowing them to access a specific service on your domain.
16specific service on your domain.
17 16
18This guide will walk through a standard installation of Authelia for 17This guide will walk through a standard installation of Authelia for
19`example.com`, using `auth.example.com` as 18`example.com`, using `auth.example.com` as Authelia's authentication domain and
20Authelia\'s authentication domain and `teddit.example.com` as 19`teddit.example.com` as the website we want to protect behind the authentication
21the website we want to protect behind the authentication portal. 20portal.
22 21
23# Prerequisites 22# Prerequisites
24 23
25This guide assumes you have the following already set-up: 24This guide assumes you have the following already set-up:
26 25
27- A registered domain with DNS pointing to your server. 26- A registered domain with DNS pointing to your server.
28- A subdomain for Authelia (`auth.example.com`) and a 27- A subdomain for Authelia (`auth.example.com`) and a subdomain to protect via
29 subdomain to protect via Authelia (`app.example.com`). 28 Authelia (`app.example.com`).
30- A working Nginx web server. 29- A working Nginx web server.
31- Docker and docker-compose installed. 30- Docker and docker-compose installed.
32 31
33# Installation 32# Installation
34 33
35This guide will walk through each installation step one-by-one, starting 34This guide will walk through each installation step one-by-one, starting with
36with the container and finishing by cleaning up external access via an 35the container and finishing by cleaning up external access via an Nginx reverse
37Nginx reverse proxy. 36proxy.
38 37
39## Docker-Compose 38## Docker-Compose
40 39
41To start, create a directory for Authelia and create a 40To start, create a directory for Authelia and create a `docker-compose.yml`
42`docker-compose.yml` file. 41file.
43 42
44```sh 43```sh
45mkdir ~/authelia 44mkdir ~/authelia
46nano ~/authelia/docker-compose.yml 45nano ~/authelia/docker-compose.yml
47``` 46```
48 47
49Within this file, paste the following content. If you prefer a different 48Within this file, paste the following content. If you prefer a different local
50local port, modify the port on the left side of the colon on the 49port, modify the port on the left side of the colon on the `9091:9091` line. Be
51`9091:9091` line. Be sure to modify the `TZ` 50sure to modify the `TZ` variable to your timezone.
52variable to your timezone.
53 51
54``` yml 52``` yml
55version: '3.3' 53version: '3.3'
@@ -72,45 +70,40 @@ Start the container with docker-compose:
72sudo docker-compose up -d 70sudo docker-compose up -d
73``` 71```
74 72
75After the first start, the container will automatically exit and require 73After the first start, the container will automatically exit and require you to
76you to modify the app\'s configuration files before continuing. Read on 74modify the app's configuration files before continuing. Read on to learn more.
77to learn more.
78 75
79## Authelia Configuration 76## Authelia Configuration
80 77
81To configure Authelia before we restart the container, we need to open 78To configure Authelia before we restart the container, we need to open the
82the `config` directory and modify the files. Start by editing 79`config` directory and modify the files. Start by editing the
83the `configuration.yml` file, where all of Authelia\'s 80`configuration.yml` file, where all of Authelia's settings are stored.
84settings are stored.
85 81
86My personal preference is to copy the original configuration file to a 82My personal preference is to copy the original configuration file to a backup
87backup file and edit a fresh copy. 83file and edit a fresh copy.
88 84
89```sh 85```sh
90sudo cp ~/authelia/config/configuration.yml ~/authelia/config/configuration.yml.bk 86sudo cp ~/authelia/config/configuration.yml ~/authelia/config/configuration.yml.bk
91sudo nano ~/authelia/config/configuration.yml 87sudo nano ~/authelia/config/configuration.yml
92``` 88```
93 89
94Within the blank `configuration.yml` file, paste the 90Within the blank `configuration.yml` file, paste the following information. You
95following information. You will need to make quite a few updates, so be 91will need to make quite a few updates, so be sure to read each line carefully
96sure to read each line carefully and modify as necessary. 92and modify as necessary.
97 93
98The major required changes are: 94The major required changes are:
99 95
100- Any instances of `example.com` should be replaced by your 96- Any instances of `example.com` should be replaced by your domain.
101 domain. 97- `jwt_secret` - Use the `pwgen 40 1` command to generate a secret for yourself.
102- `jwt_secret` - Use the `pwgen 40 1` command to 98- `access_control` - Set the Authelia domain to bypass here, as well as any
103 generate a secret for yourself. 99 subdomains you want to protect.
104- `access_control` - Set the Authelia domain to bypass 100- `session` > `secret` - Use the `pwgen 40 1` command to generate a secret for
105 here, as well as any subdomains you want to protect. 101 yourself.
106- `session` \> `secret` - Use the 102- `regulation` - Set the variables here to restrict login attempts and bans.
107 `pwgen 40 1` command to generate a secret for yourself. 103- `storage` > `encryption_key` - Use the `pwgen 40 1` command to generate a
108- `regulation` - Set the variables here to restrict login 104 secret for yourself.
109 attempts and bans. 105- `smtp` - If you have access to an SMTP service, set up the information here to
110- `storage` \> `encryption_key` - Use the 106 active outgoing emails.
111 `pwgen 40 1` command to generate a secret for yourself.
112- `smtp` - If you have access to an SMTP service, set up
113 the information here to active outgoing emails.
114 107
115``` yml 108``` yml
116# yamllint disable rule:comments-indentation 109# yamllint disable rule:comments-indentation
@@ -211,14 +204,13 @@ Next, create the users file for authentication.
211sudo nano ~/authelia/config/users_database.yml 204sudo nano ~/authelia/config/users_database.yml
212``` 205```
213 206
214Within the file, you will need to create an entry for each user that 207Within the file, you will need to create an entry for each user that needs
215needs access to Authelia. The `my_username` entry will be the 208access to Authelia. The `my_username` entry will be the username used on the
216username used on the login page. 209login page.
217 210
218To generate the password, go to [Argon2 Hash 211To generate the password, go to [Argon2 Hash Generator](https://argon2.online),
219Generator](https://argon2.online), generate a random salt, and make sure 212generate a random salt, and make sure the rest of the settings match the
220the rest of the settings match the `authentication_backend` 213`authentication_backend` section of `configuration.yml` file.
221section of `configuration.yml` file.
222 214
223``` yaml 215``` yaml
224users: 216users:
@@ -242,8 +234,8 @@ sudo docker-compose down && sudo docker-compose up -d
242 234
243## Nginx: Authelia Domain 235## Nginx: Authelia Domain
244 236
245Once the container is running and configured, the final step is to 237Once the container is running and configured, the final step is to configure
246configure external access to the server via Nginx reverse proxy. 238external access to the server via Nginx reverse proxy.
247 239
248Start by creating the Authelia domain. 240Start by creating the Authelia domain.
249 241
@@ -252,9 +244,8 @@ sudo nano /etc/nginx/sites-available/auth
252``` 244```
253 245
254Within this file, paste the following information and be sure to update 246Within this file, paste the following information and be sure to update
255`example.com` to your domain. Make sure the 247`example.com` to your domain. Make sure the `$upstream_authelia` variable
256`$upstream_authelia` variable matches the location of your 248matches the location of your Authelia container.
257Authelia container.
258 249
259``` conf 250``` conf
260server { 251server {
@@ -310,8 +301,8 @@ server {
310} 301}
311``` 302```
312 303
313Next, symlink the file and restart Nginx. If there are errors, be sure 304Next, symlink the file and restart Nginx. If there are errors, be sure to
314to resolve those before moving on. 305resolve those before moving on.
315 306
316```sh 307```sh
317sudo ln -s /etc/nginx/sites-available/auth /etc/nginx/sites-enabled/auth 308sudo ln -s /etc/nginx/sites-available/auth /etc/nginx/sites-enabled/auth
@@ -320,9 +311,9 @@ sudo systemctl restart nginx.service
320 311
321## Nginx: Protected Domain(s) 312## Nginx: Protected Domain(s)
322 313
323Now that Authelia is accessible externally, you need to configure the 314Now that Authelia is accessible externally, you need to configure the domain you
324domain you intend to protect with Authelia. In this example, I\'m 315intend to protect with Authelia. In this example, I'm protecting
325protecting `teddit.example.com`. 316`teddit.example.com`.
326 317
327Similar to the process above, paste the content and update the relevant 318Similar to the process above, paste the content and update the relevant
328variables. 319variables.
@@ -450,9 +441,9 @@ authentication domain and presented with the Authelia login portal.
450![Authelia 441![Authelia
451Portal](https://img.cleberg.net/blog/20231010-authelia/authelia_portal.png) 442Portal](https://img.cleberg.net/blog/20231010-authelia/authelia_portal.png)
452 443
453Once you\'ve successfully authenticated, you can visit your 444Once you've successfully authenticated, you can visit your authentication
454authentication domain directly and see that you\'re currently 445domain directly and see that you're currently authenticated to any domain
455authenticated to any domain protected by Authelia. 446protected by Authelia.
456 447
457![Authelia 448![Authelia
458Success](https://img.cleberg.net/blog/20231010-authelia/authelia_success.png) 449Success](https://img.cleberg.net/blog/20231010-authelia/authelia_success.png)
content/blog/2023-10-15-alpine-ssh-hardening.md +8 −8
@@ -8,13 +8,13 @@ draft = false
8# Overview 8# Overview
9 9
10This guide follows the standard 10This guide follows the standard
11[ssh-audit](https://www.ssh-audit.com/hardening_guides.html) hardening 11[ssh-audit](https://www.ssh-audit.com/hardening_guides.html) hardening guide,
12guide, tweaked for Alpine Linux. 12tweaked for Alpine Linux.
13 13
14# Hardening Guide 14# Hardening Guide
15 15
16These steps must be performed as root. You can try to use 16These steps must be performed as root. You can try to use `doas` or `sudo`, but
17`doas` or `sudo`, but there may be issues. 17there may be issues.
18 18
191. Re-generate the RSA and ED25519 keys 191. Re-generate the RSA and ED25519 keys
20 20
@@ -31,8 +31,8 @@ awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe
31mv /etc/ssh/moduli.safe /etc/ssh/moduli 31mv /etc/ssh/moduli.safe /etc/ssh/moduli
32``` 32```
33 33
343. Enable the RSA and ED25519 HostKey directives in the 343. Enable the RSA and ED25519 HostKey directives in the /etc/ssh/sshd~config~
35 /etc/ssh/sshd~config~ file 35 file
36 36
37```sh 37```sh
38sed -i 's/^\#HostKey \/etc\/ssh\/ssh_host_\(rsa\|ed25519\)_key$/HostKey \/etc\/ssh\/ssh_host_\1_key/g' /etc/ssh/sshd_config 38sed -i 's/^\#HostKey \/etc\/ssh\/ssh_host_\(rsa\|ed25519\)_key$/HostKey \/etc\/ssh\/ssh_host_\1_key/g' /etc/ssh/sshd_config
@@ -65,8 +65,8 @@ pip3 install ssh-audit
65ssh-audit localhost 65ssh-audit localhost
66``` 66```
67 67
68If everything succeeded, the results will show as all green. If anything 68If everything succeeded, the results will show as all green. If anything is
69is yellow, orange, or red, you may need to tweak additional settings. 69yellow, orange, or red, you may need to tweak additional settings.
70 70
71``` txt 71``` txt
72#+caption: ssh audit 72#+caption: ssh audit
content/blog/2023-10-17-self-hosting-anonymousoverflow.md +17 −20
@@ -8,18 +8,17 @@ draft = false
8# Overview 8# Overview
9 9
10I recently launched an instance of AnonymousOverflow at 10I recently launched an instance of AnonymousOverflow at
11[ao.cleberg.net](https://ao.cleberg.net) and wanted to write a brief 11[ao.cleberg.net](https://ao.cleberg.net) and wanted to write a brief post on how
12post on how easy it is to install with Docker Compose and Nginx. 12easy it is to install with Docker Compose and Nginx.
13 13
14This guide uses Ubuntu server, Docker Compose, and Nginx as a reverse 14This guide uses Ubuntu server, Docker Compose, and Nginx as a reverse proxy.
15proxy.
16 15
17# Installation 16# Installation
18 17
19## Docker Compose 18## Docker Compose
20 19
21To install AnonymousOverflow, start by creating a directory for the 20To install AnonymousOverflow, start by creating a directory for the application
22application and create its `docker-compose.yml` file. 21and create its `docker-compose.yml` file.
23 22
24```sh 23```sh
25mkdir ~/anonymousoverflow && cd ~/anonymousoverflow 24mkdir ~/anonymousoverflow && cd ~/anonymousoverflow
@@ -27,8 +26,7 @@ nano docker-compose.yml
27``` 26```
28 27
29Within this file, paste the following information. Be sure to change the 28Within this file, paste the following information. Be sure to change the
30`APP_URL`, `JWT_SIGNING_SECRET`, and 29`APP_URL`, `JWT_SIGNING_SECRET`, and `ports` to match your needs.
31`ports` to match your needs.
32 30
33``` yaml 31``` yaml
34version: '3' 32version: '3'
@@ -45,8 +43,8 @@ services:
45 restart: 'always' 43 restart: 'always'
46``` 44```
47 45
48Save and exit the file when complete. You can now launch the container 46Save and exit the file when complete. You can now launch the container and
49and access it via your local network. 47access it via your local network.
50 48
51```sh 49```sh
52sudo docker-compose up -d 50sudo docker-compose up -d
@@ -54,19 +52,18 @@ sudo docker-compose up -d
54 52
55## Nginx Reverse Proxy 53## Nginx Reverse Proxy
56 54
57If you want to access this service outside the local network, I 55If you want to access this service outside the local network, I recommend using
58recommend using Nginx as a reverse proxy. 56Nginx as a reverse proxy.
59 57
60Let\'s start by creating a configuration file. 58Let's start by creating a configuration file.
61 59
62```sh 60```sh
63sudo nano /etc/nginx/sites-available/ao 61sudo nano /etc/nginx/sites-available/ao
64``` 62```
65 63
66Within this file, paste the following content and repace 64Within this file, paste the following content and repace `ao.example.com` with
67`ao.example.com` with your URL. You may need to update the 65your URL. You may need to update the SSL certificate statements if your
68SSL certificate statements if your certificates are in a different 66certificates are in a different location.
69location.
70 67
71``` conf 68``` conf
72server { 69server {
@@ -122,9 +119,9 @@ server {
122} 119}
123``` 120```
124 121
125Save and exit the file when complete. On Ubuntu, you will need to 122Save and exit the file when complete. On Ubuntu, you will need to symlink the
126symlink the configuration file before it will be recognized by Nginx. 123configuration file before it will be recognized by Nginx. Once complete, simply
127Once complete, simply restart the web server. 124restart the web server.
128 125
129```sh 126```sh
130sudo ln -s /etc/nginx/sites-available/ao /etc/nginx/sites-enabled/ao 127sudo ln -s /etc/nginx/sites-available/ao /etc/nginx/sites-enabled/ao
content/blog/2023-11-08-scli.md +54 −65
@@ -5,49 +5,42 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8[scli](https://github.com/isamert/scli) is a command-line tool that 8[scli](https://github.com/isamert/scli) is a command-line tool that allows you
9allows you to connect to your Signal messenger account. This program 9to connect to your Signal messenger account. This program utilizes a two-pane
10utilizes a two-pane display that shows you chats on the left and the 10display that shows you chats on the left and the focused conversation on the
11focused conversation on the right. 11right.
12 12
13This guide will show you how to install `scli` and its 13This guide will show you how to install `scli` and its dependencies on Alpine
14dependencies on Alpine Linux, which requires some extra work due to 14Linux, which requires some extra work due to musl.
15musl.
16 15
17If you\'re using a non-musl system, you can likely following the 16If you're using a non-musl system, you can likely following the `scli` README
18`scli` README and download the packaged binaries for an 17and download the packaged binaries for an easier installation process.
19easier installation process.
20 18
21# Dependencies 19# Dependencies
22 20
23In order to use `scli`, you need a few dependencies: 21In order to use `scli`, you need a few dependencies:
24 22
25- `openjdk17-jre` - Used as a dependency for the 23- `openjdk17-jre` - Used as a dependency for the `signal-cli` tool. Version may
26 `signal-cli` tool. Version may vary. 24 vary.
27- `signal-cli` - Used as the backbone of the 25- `signal-cli` - Used as the backbone of the `scli` tool.
28 `scli` tool. 26- `findutils` - Replaces the standard Busybox version of `xargs`.
29- `findutils` - Replaces the standard Busybox version of 27- `urwid` - A console user interface library for Python.
30 `xargs`. 28- `urwid-readline` - For GNU emacs-like keybinds on the input line.
31- `urwid` - A console user interface library for Python. 29- `qrencode` - Displays a QR code in the terminal to link the device using your
32- `urwid-readline` - For GNU emacs-like keybinds on the 30 phone. Not necessary if you're only linking on desktop and can copy/paste the
33 input line. 31 connection URL.
34- `qrencode` - Displays a QR code in the terminal to link 32
35 the device using your phone. Not necessary if you\'re only linking 33Let's start by installing the packages available via Alpine's repositories. Be
36 on desktop and can copy/paste the connection URL. 34sure to install the latest version of `openjdk`. If you run into Java-related
37 35issues, uninstall `openjdk` and install an older version.
38Let\'s start by installing the packages available via Alpine\'s
39repositories. Be sure to install the latest version of
40`openjdk`. If you run into Java-related issues, uninstall
41`openjdk` and install an older version.
42 36
43```sh 37```sh
44doas apk add openjdk17-jre findutils qrencode 38doas apk add openjdk17-jre findutils qrencode
45``` 39```
46 40
47Next, let\'s install `signal-cli`. Be sure to export the 41Next, let's install `signal-cli`. Be sure to export the version of `signal-cli`
48version of `signal-cli` that you want. I use version 42that you want. I use version `0.12.4` below, but that may be outdated by the
49`0.12.4` below, but that may be outdated by the time you\'re 43time you're reading this.
50reading this.
51 44
52```sh 45```sh
53export VERSION="0.12.4" 46export VERSION="0.12.4"
@@ -56,8 +49,7 @@ doas tar xf signal-cli-"${VERSION}".tar.gz -C /opt
56doas ln -sf /opt/signal-cli-${VERSION}"/bin/signal/cli /usr/local/bin 49doas ln -sf /opt/signal-cli-${VERSION}"/bin/signal/cli /usr/local/bin
57``` 50```
58 51
59Finally, install the `urwid` packages using the Python 52Finally, install the `urwid` packages using the Python packaging utility.
60packaging utility.
61 53
62```sh 54```sh
63pip3 install urwid urwid-readline 55pip3 install urwid urwid-readline
@@ -65,25 +57,24 @@ pip3 install urwid urwid-readline
65 57
66# Installation 58# Installation
67 59
68Now that we have all of the dependencies we need, we can install 60Now that we have all of the dependencies we need, we can install `scli`. Start
69`scli`. Start by simply cloning the repository. 61by simply cloning the repository.
70 62
71```sh 63```sh
72git clone https://github.com/isamert/scli 64git clone https://github.com/isamert/scli
73``` 65```
74 66
75When I cloned this repository on 2023-11-08, I found a bug in the logic 67When I cloned this repository on 2023-11-08, I found a bug in the logic that
76that required a fix. You must edit the `scli` file and 68required a fix. You must edit the `scli` file and replace the one instance of
77replace the one instance of `RLIMIT_OFILE` with 69`RLIMIT_OFILE` with `RLIMIT_NOFILE`.
78`RLIMIT_NOFILE`.
79 70
80```sh 71```sh
81cd scli 72cd scli
82nano scli 73nano scli
83``` 74```
84 75
85Once complete, you can move this program to anywhere on your 76Once complete, you can move this program to anywhere on your `$PATH`. I chose
86`$PATH`. I chose the following directory. 77the following directory.
87 78
88```sh 79```sh
89doas mv scli /usr/local/bin/scli 80doas mv scli /usr/local/bin/scli
@@ -91,43 +82,41 @@ doas mv scli /usr/local/bin/scli
91 82
92# Initial Setup 83# Initial Setup
93 84
94Now that everything is installed, we can login and configure the client. 85Now that everything is installed, we can login and configure the client. Start
95Start by generating a connection link. 86by generating a connection link.
96 87
97```sh 88```sh
98signal-cli link -n "YOUR-DEVICE-NICKNAME" | tee >(xargs -L 1 qrencode -t utf8) 89signal-cli link -n "YOUR-DEVICE-NICKNAME" | tee >(xargs -L 1 qrencode -t utf8)
99``` 90```
100 91
101This will generate a connection link and related QR code for you to use 92This will generate a connection link and related QR code for you to use to link
102to link the devices together. Once complete, **wait patiently\*** for 93the devices together. Once complete, **wait patiently** for the connection
103the connection process to finish. 94process to finish.
104 95
105Once it completes, it will exit and return you to the prompt. From here, 96Once it completes, it will exit and return you to the prompt. From here, you
106you need to perform an initial `receive` command to start 97need to perform an initial `receive` command to start things off. The `USERNAME`
107things off. The `USERNAME` variable should be your phone 98variable should be your phone number, such as `+15551237890`.
108number, such as `+15551237890`.
109 99
110```sh 100```sh
111signal-cli -u USERNAME receive 101signal-cli -u USERNAME receive
112``` 102```
113 103
114Also be sure to test the daemon to ensure it works properly. If no 104Also be sure to test the daemon to ensure it works properly. If no errors occur,
115errors occur, it\'s working. If you run into errors because you\'re not 105it's working. If you run into errors because you're not running a DBUS
116running a DBUS session, see my notes below. 106session, see my notes below.
117 107
118```sh 108```sh
119signal-cli -u USERNAME daemon 109signal-cli -u USERNAME daemon
120``` 110```
121 111
122Once the initial reception is complete, you are ready to use 112Once the initial reception is complete, you are ready to use `scli`.
123`scli`.
124 113
125This process will differ depending on your desktop environment (DE). If 114This process will differ depending on your desktop environment (DE). If you are
126you are running a DE, you likely have a DBUS session running already and 115running a DE, you likely have a DBUS session running already and can simply
127can simply launch the program. 116launch the program.
128 117
129However, if you\'re like me and running your computer straight on the 118However, if you're like me and running your computer straight on the TTY
130TTY without a DE, you\'ll need to start a DBUS session for this program. 119without a DE, you'll need to start a DBUS session for this program.
131 120
132```sh 121```sh
133# If you're not running a DBUS session yet, you need to start one for scli 122# If you're not running a DBUS session yet, you need to start one for scli
@@ -139,9 +128,9 @@ scli
139 128
140# Configuration 129# Configuration
141 130
142Lastly, there are a number of configuration options that you can pass 131Lastly, there are a number of configuration options that you can pass via the
143via the command or in the `~/.config/sclirc` file. See the 132command or in the `~/.config/sclirc` file. See the Github README for more
144Github README for more information on configuration options. 133information on configuration options.
145 134
146```sh 135```sh
147nano ~/.config/sclirc 136nano ~/.config/sclirc
@@ -154,5 +143,5 @@ wrap-at = 80
154enable-notifications = true 143enable-notifications = true
155``` 144```
156 145
157That\'s it! Following this guide, I have a functional `scli` 146That's it! Following this guide, I have a functional `scli` program that
158program that successfully sends messages to my contacts and myself! 147successfully sends messages to my contacts and myself!
content/blog/2023-12-03-unifi-nextdns.md +31 −34
@@ -9,32 +9,31 @@ draft = false
9 9
10I recently installed NextDNS on my Unifi Dream Machine router using the 10I recently installed NextDNS on my Unifi Dream Machine router using the
11[UnifiOS](https://github.com/nextdns/nextdns/wiki/UnifiOS) wiki page on 11[UnifiOS](https://github.com/nextdns/nextdns/wiki/UnifiOS) wiki page on
12NextDNS\'s GitHub repository. 12NextDNS's GitHub repository.
13 13
14As a result of this, I wanted to write down the process in case the wiki 14As a result of this, I wanted to write down the process in case the wiki or
15or installer ever gets lost. 15installer ever gets lost.
16 16
17# Wiki 17# Wiki
18 18
19The following is copied from the wiki page linked above, with one 19The following is copied from the wiki page linked above, with one difference in
20difference in the `ssh` command. 20the `ssh` command.
21 21
22Install instructions for Unifi Dream Machine (UDM) standard and pro 22Install instructions for Unifi Dream Machine (UDM) standard and pro routers.
23routers.
24 23
25## Install 24## Install
26 25
27Enable SSH: 26Enable SSH:
28 27
29- Go to your unifi admin interface and select your device (not the 28- Go to your unifi admin interface and select your device (not the controller
30 controller settings, but the Dream Machine settings) 29 settings, but the Dream Machine settings)
31- Click on \"Settings\" at the bottom of the page 30- Click on "Settings" at the bottom of the page
32- Go to the \"Advanced\" section on the left pan 31- Go to the "Advanced" section on the left pan
33- Enable SSH 32- Enable SSH
34- Set a SSH password 33- Set a SSH password
35 34
36Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with 35Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with the password you
37the password you configured. 36configured.
38 37
39Run the following command and follow the instructions: 38Run the following command and follow the instructions:
40 39
@@ -42,25 +41,24 @@ Run the following command and follow the instructions:
42sh -c 'sh -c "$(curl -sL https://nextdns.io/install)"' 41sh -c 'sh -c "$(curl -sL https://nextdns.io/install)"'
43``` 42```
44 43
45Note: Queries from the UDM itself won\'t be routed to NextDNS nor 44Note: Queries from the UDM itself won't be routed to NextDNS nor encrypted due
46encrypted due to current system limitation. All traffic from other 45to current system limitation. All traffic from other devices on then network
47devices on then network will. 46will.
48 47
49## Upgrade 48## Upgrade
50 49
51To upgrade to the last version, simply re-run the installer above. If a 50To upgrade to the last version, simply re-run the installer above. If a new
52new version is available, the upgrade action will added to the list of 51version is available, the upgrade action will added to the list of possible
53possible actions. 52actions.
54 53
55## Uninstall 54## Uninstall
56 55
57To uninstall, re-run the installer above and select \"Remove\" in the 56To uninstall, re-run the installer above and select "Remove" in the menu.
58menu.
59 57
60## Troubleshooting 58## Troubleshooting
61 59
62If the installation fail, please the installer in debug mode and contact 60If the installation fail, please the installer in debug mode and contact us at
63us at team@nextdns.io with the transcript of the installation: 61team@nextdns.io with the transcript of the installation:
64 62
65```sh 63```sh
66sh -c 'DEBUG=1 sh -c "$(curl -sL https://nextdns.io/install)"' 64sh -c 'DEBUG=1 sh -c "$(curl -sL https://nextdns.io/install)"'
@@ -68,15 +66,15 @@ sh -c 'DEBUG=1 sh -c "$(curl -sL https://nextdns.io/install)"'
68 66
69### Content Filtering Conflict 67### Content Filtering Conflict
70 68
71NextDNS CLI and the UDM Content Filtering or the Ad Blocking features 69NextDNS CLI and the UDM Content Filtering or the Ad Blocking features are
72are incompatible. If you want to use NextDNS CLI, please make sure they 70incompatible. If you want to use NextDNS CLI, please make sure they are
73are disabled. 71disabled.
74 72
75To disable Content Filtering, go to Settings \> Network, then for each 73To disable Content Filtering, go to Settings > Network, then for each network,
76network, set the Content Filtering feature to None 74set the Content Filtering feature to None
77 75
78To disable Ad Blocking, go to Settings \> Application Firewall. In the 76To disable Ad Blocking, go to Settings > Application Firewall. In the General
79General tab, uncheck the Ad Blocking checkbox. 77tab, uncheck the Ad Blocking checkbox.
80 78
81### APT Error 79### APT Error
82 80
@@ -96,8 +94,7 @@ sed -i -e 's/deb.debian.org/archive.debian.org/g' \
96 94
97## install.sh 95## install.sh
98 96
99Here are the contents of the `install.sh` file used above, as 97Here are the contents of the `install.sh` file used above, as of 2023-12-03:
100of 2023-12-03:
101 98
102```sh 99```sh
103#!/bin/sh 100#!/bin/sh
content/blog/2024-01-08-dont-say-hello.md +16 −16
@@ -5,25 +5,25 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8I recently came back from a winter break and have started working 8I recently came back from a winter break and have started working again... only
9again... only to immediately run into the dilemma of people sending me 9to immediately run into the dilemma of people sending me cliffhanger messages
10cliffhanger messages again. 10again.
11 11
12# No Hello 12# No Hello
13 13
14A year or two ago, I discovered [no hello](https://nohello.net/en/) and 14A year or two ago, I discovered [no hello](https://nohello.net/en/) and have
15have thought about it often since then. I\'ve even sent it to a few 15thought about it often since then. I've even sent it to a few people since then
16people since then (who wouldn\'t take offense to it). 16(who wouldn't take offense to it).
17 17
18I work in a fast-paced environment where efficiency is extremely 18I work in a fast-paced environment where efficiency is extremely valuable.
19valuable. Therefore, I have always held a deep displeasure for 19Therefore, I have always held a deep displeasure for conversations where people
20conversations where people start with \"Hello\" and then. 20start with "Hello" and then.
21 21
22I searched back through my work messages and found that I received \~50 22I searched back through my work messages and found that I received ~50 messages
23messages from \~10 people last year from people that contained \"hi\", 23from ~10 people last year from people that contained "hi", "hey", or
24\"hey\", or \"hello\" and did not contain any indication of the purpose 24"hello" and did not contain any indication of the purpose of the conversation.
25of the conversation. I also noticed that a few of the users were 25I also noticed that a few of the users were responsible for the large majority
26responsible for the large majority of the cliffhangers. 26of the cliffhangers.
27 27
28There\'s no real point to this post, just a desparate request for people 28There's no real point to this post, just a desparate request for people to
29to please stop doing this. 29please stop doing this.
content/blog/2024-01-09-macos-customization.md +60 −71
@@ -5,42 +5,38 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8I have been using macOS more than Linux lately, so I wrote this post to 8I have been using macOS more than Linux lately, so I wrote this post to describe
9describe some simple options to customize macOS beyond the normal 9some simple options to customize macOS beyond the normal built-in settings menu.
10built-in settings menu.
11 10
12While not all-encompassing, the options below should be a good start for 11While not all-encompassing, the options below should be a good start for anyone
13anyone looking to dive down the rabbit hole. 12looking to dive down the rabbit hole.
14 13
15# Basics 14# Basics
16 15
17## Package Management 16## Package Management
18 17
19To install a lot of software on macOS, you will need 18To install a lot of software on macOS, you will need
20[Homebrew](https://brew.sh/). You can use their installation script to 19[Homebrew](https://brew.sh/). You can use their installation script to get
21get started. Simply open the `Terminal` application and paste 20started. Simply open the `Terminal` application and paste the following snippet:
22the following snippet:
23 21
24```sh 22```sh
25/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 23/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
26``` 24```
27 25
28This will allow you to easily install and manage applications and other 26This will allow you to easily install and manage applications and other software
29software easily through the `brew` command. 27easily through the `brew` command.
30 28
31## Terminal 29## Terminal
32 30
33If you\'re serious about customizing your macOS system, I highly 31If you're serious about customizing your macOS system, I highly recommend
34recommend installing a terminal emulator that you like and if you\'re 32installing a terminal emulator that you like and if you're not comfortable on
35not comfortable on the command line yet, start learning. A lot of 33the command line yet, start learning. A lot of customization options require you
36customization options require you to edit hidden files, which is easiest 34to edit hidden files, which is easiest in a terminal.
37in a terminal.
38 35
39There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the 36There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the built-in
40built-in Terminal app. 37Terminal app.
41 38
42I use [iTerm2](https://iterm2.com/), which can be installed with 39I use [iTerm2](https://iterm2.com/), which can be installed with Homebrew:
43Homebrew:
44 40
45```sh 41```sh
46brew install iterm2 42brew install iterm2
@@ -48,39 +44,37 @@ brew install iterm2
48 44
49![iTerm2](https://img.cleberg.net/blog/20240109-macos-customization/iterm2.png) 45![iTerm2](https://img.cleberg.net/blog/20240109-macos-customization/iterm2.png)
50 46
51To install color schemes, such as the Dracula scheme shown in the 47To install color schemes, such as the Dracula scheme shown in the screenshot
52screenshot above, you visit [iTerm 48above, you visit [iTerm Themes](https://iterm2colorschemes.com/) and follow
53Themes](https://iterm2colorschemes.com/) and follow their installation 49their installation instructions to install any of the themes.
54instructions to install any of the themes.
55 50
56# Desktop 51# Desktop
57 52
58## Window Management 53## Window Management
59 54
60[yabai](https://github.com/koekeishiya/yabai) is a tiling window manager 55[yabai](https://github.com/koekeishiya/yabai) is a tiling window manager for
61for macOS. While other window managers exist, I found that most of them 56macOS. While other window managers exist, I found that most of them struggled to
62struggled to create logical layouts and to allow me to easily move 57create logical layouts and to allow me to easily move windows around the screen.
63windows around the screen.
64 58
65Some advanced settings for yabai are only available if partially disable 59Some advanced settings for yabai are only available if partially disable System
66System Integrity Protection (SIP). However, I chose not to do this and 60Integrity Protection (SIP). However, I chose not to do this and it hasn't
67it hasn\'t affected my basic usage of yabai at all. 61affected my basic usage of yabai at all.
68 62
69Refer to the [yabai 63Refer to the [yabai
70wiki](https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)) 64wiki](https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release))
71for installation instructions. You will need to ensure that yabai is 65for installation instructions. You will need to ensure that yabai is allowed to
72allowed to access the accessibility and screen recording APIs. 66access the accessibility and screen recording APIs.
73 67
74You can see a basic three-pane layout atuomatically configured by yabai 68You can see a basic three-pane layout atuomatically configured by yabai for me
75for me as I opened the windows below. 69as I opened the windows below.
76 70
77![yabai window 71![yabai window
78manager](https://img.cleberg.net/blog/20240109-macos-customization/yabai.png) 72manager](https://img.cleberg.net/blog/20240109-macos-customization/yabai.png)
79 73
80## Keyboard Shortcuts 74## Keyboard Shortcuts
81 75
82[skhd](https://github.com/koekeishiya/skhd) is a simple hotkey daemon 76[skhd](https://github.com/koekeishiya/skhd) is a simple hotkey daemon that
83that allows you to define hotkeys in a file for usage on your system. 77allows you to define hotkeys in a file for usage on your system.
84 78
85Installation is simple: 79Installation is simple:
86 80
@@ -89,11 +83,10 @@ brew install koekeishiya/formulae/skhd
89skhd --start-service 83skhd --start-service
90``` 84```
91 85
92After installation, be sure to allow `skhd` access to the 86After installation, be sure to allow `skhd` access to the accessibility API in
93accessibility API in the macOS privacy settings. 87the macOS privacy settings.
94 88
95You can configure your hotkeys in the `~/.config/skhd/skhdrc` 89You can configure your hotkeys in the `~/.config/skhd/skhdrc` file:
96file:
97 90
98```sh 91```sh
99nano ~/.config/skhd/skhdrc 92nano ~/.config/skhd/skhdrc
@@ -112,14 +105,13 @@ cmd + shift - return : /Applications/LibreWolf.app/Contents/MacOS/librewolf
112## Widgets 105## Widgets
113 106
114[uebersicht](https://github.com/felixhageloh/uebersicht/) is a handy 107[uebersicht](https://github.com/felixhageloh/uebersicht/) is a handy
115desktop-based widget tool with a plethora of community-made widgets 108desktop-based widget tool with a plethora of community-made widgets available in
116available in the [widgets 109the [widgets gallery](https://tracesof.net/uebersicht-widgets/). You can also
117gallery](https://tracesof.net/uebersicht-widgets/). You can also write 110write your own widgets with this tool.
118your own widgets with this tool.
119 111
120To install, simply download the latest release from the [uebersicht 112To install, simply download the latest release from the [uebersicht
121website](https://tracesof.net/uebersicht/) and copy it to the 113website](https://tracesof.net/uebersicht/) and copy it to the Applications
122Applications folder. 114folder.
123 115
124See below for an example of the 116See below for an example of the
125[Mond](https://tracesof.net/uebersicht-widgets/#Mond) widget in action. 117[Mond](https://tracesof.net/uebersicht-widgets/#Mond) widget in action.
@@ -137,22 +129,20 @@ You can browse a discussion where various users shared their
137for inspiration or to copy their dotfiles. 129for inspiration or to copy their dotfiles.
138 130
139See below for a quick (& slightly broken) copy of 131See below for a quick (& slightly broken) copy of
140[zer0yu\'s](https://github.com/zer0yu/dotfiles) SketchyBar 132[zer0yu's](https://github.com/zer0yu/dotfiles) SketchyBar configuration.
141configuration.
142 133
143![SketchyBar](https://img.cleberg.net/blog/20240109-macos-customization/sketchybar.png) 134![SketchyBar](https://img.cleberg.net/blog/20240109-macos-customization/sketchybar.png)
144 135
145## Dock 136## Dock
146 137
147The easiest way to customize the dock is to install 138The easiest way to customize the dock is to install
148[uBar](https://ubarapp.com/), which uses a Windows-like menu bar as the 139[uBar](https://ubarapp.com/), which uses a Windows-like menu bar as the default
149default style. 140style.
150 141
151However, the built-in macOS dock cannot be disabled and can only be set 142However, the built-in macOS dock cannot be disabled and can only be set to
152to \"always hidden\". This can be annoying as it will pop out any time 143"always hidden". This can be annoying as it will pop out any time your mouse
153your mouse cursor passes closely to the dock edge of the screen. Because 144cursor passes closely to the dock edge of the screen. Because of this, I simply
154of this, I simply use the built-in dock instead of customizing it with 145use the built-in dock instead of customizing it with third-party software.
155third-party software.
156 146
157Regardless, see below for the default installation style of uBar. 147Regardless, see below for the default installation style of uBar.
158 148
@@ -160,22 +150,21 @@ Regardless, see below for the default installation style of uBar.
160 150
161## Application Icons 151## Application Icons
162 152
163You can also customize the icon of any application in macOS, which will 153You can also customize the icon of any application in macOS, which will show up
164show up in Finder, the Dock, Launchpad, search results, etc. I recommend 154in Finder, the Dock, Launchpad, search results, etc. I recommend using
165using [macOSicons](https://macosicons.com/) to download icons you want, 155[macOSicons](https://macosicons.com/) to download icons you want, and then apply
166and then apply them by following this process. 156them by following this process.
167 157
1681. Open the Finder application. 1581. Open the Finder application.
1692. Navigate to the `Applications` folder. 1592. Navigate to the `Applications` folder.
1703. Right-click an application of your choice, and select 1603. Right-click an application of your choice, and select `Get Info`.
171 `Get Info`. 1614. Drag the image you downloaded on top of the application's icon at the top of
1724. Drag the image you downloaded on top of the application\'s icon at 162 information window (you will see a green "plus" symbol when you're
173 the top of information window (you will see a green \"plus\" symbol 163 hovering over it).
174 when you\'re hovering over it). 1645. Release the new icon on top of the old icon and it will update!
1755. Release the new icon on top of the old icon and it will update! 165
176 166You can see an example of me dragging a new `signal.icns` file onto my
177You can see an example of me dragging a new `signal.icns` 167Signal.app information window to update it below:
178file onto my Signal.app information window to update it below:
179 168
180![replace macOS 169![replace macOS
181icons](https://img.cleberg.net/blog/20240109-macos-customization/replace_icon.png) 170icons](https://img.cleberg.net/blog/20240109-macos-customization/replace_icon.png)
content/blog/2024-01-13-local-llm.md +53 −59
@@ -7,40 +7,38 @@ draft = false
7 7
8# Requirements 8# Requirements
9 9
10I\'ve recently started playing with large language models (LLMs), mostly 10I've recently started playing with large language models (LLMs), mostly in the
11in the popular chatbot form, as part of my job and have decided to see 11popular chatbot form, as part of my job and have decided to see if there's a
12if there\'s a consistent and reliable way to interact with these models 12consistent and reliable way to interact with these models on Apple devices
13on Apple devices without sacrificing privacy or requiring in-depth 13without sacrificing privacy or requiring in-depth technical setup.
14technical setup.
15 14
16My requirements for this test: 15My requirements for this test:
17 16
18- Open source platform 17- Open source platform
19- On-device model files 18- On-device model files
20- Minimal required configuration 19- Minimal required configuration
21- Preferably pre-built, but a simple build process is acceptable 20- Preferably pre-built, but a simple build process is acceptable
22 21
23I tested a handful of apps and have summarized my favorite (so far) for 22I tested a handful of apps and have summarized my favorite (so far) for macOS
24macOS and iOS below. 23and iOS below.
25 24
26> TL;DR - Here are the two that met my requirements and I have found the 25> TL;DR - Here are the two that met my requirements and I have found the easiest
27> easiest to install and use so far: 26> to install and use so far:
28 27
29- macOS: [Ollama](https://ollama.ai/) 28- macOS: [Ollama](https://ollama.ai/)
30- iOS : [LLM Farm](https://llmfarm.site/) 29- iOS : [LLM Farm](https://llmfarm.site/)
31 30
32# macOS 31# macOS
33 32
34[Ollama](https://ollama.ai/) is a simple Go application for macOS and 33[Ollama](https://ollama.ai/) is a simple Go application for macOS and Linux that
35Linux that can run various LLMs locally. 34can run various LLMs locally.
36 35
37For macOS, you can download the pplication on the [Ollama download 36For macOS, you can download the pplication on the [Ollama download
38page](https://ollama.ai/download/mac) and install it by unzipping the 37page](https://ollama.ai/download/mac) and install it by unzipping the
39`Ollama.app` file and moving it to the 38`Ollama.app` file and moving it to the `Applications` folder.
40`Applications` folder.
41 39
42If you prefer the command line, you can run these commands after the 40If you prefer the command line, you can run these commands after the download
43download finished: 41finished:
44 42
45```sh 43```sh
46cd ~/Downloads && \ 44cd ~/Downloads && \
@@ -48,64 +46,60 @@ unzip Ollama-darwin.zip && \
48mv ~/Downloads/Ollama.app /Applications/ 46mv ~/Downloads/Ollama.app /Applications/
49``` 47```
50 48
51After running the app, the app will ask you to open a terminal and run 49After running the app, the app will ask you to open a terminal and run the
52the default `llama2` model, which will open an interactive 50default `llama2` model, which will open an interactive chat session in the
53chat session in the terminal. You can startfully using the application 51terminal. You can startfully using the application at this point.
54at this point.
55 52
56![Ollama](https://img.cleberg.net/blog/20240113-local-llm/ollama.png) 53![Ollama](https://img.cleberg.net/blog/20240113-local-llm/ollama.png)
57 54
58If you don\'t want to use the default `llama2` model, you can 55If you don't want to use the default `llama2` model, you can download and run
59download and run additional models found on the 56additional models found on the [Models](https://ollama.ai/library) page.
60[Models](https://ollama.ai/library) page.
61 57
62To see the information for the currently-used model, you can run the 58To see the information for the currently-used model, you can run the `/show
63`/show info` command in the chat. 59info` command in the chat.
64 60
65![Model 61![Model Info](https://img.cleberg.net/blog/20240113-local-llm/ollama_info.png)
66Info](https://img.cleberg.net/blog/20240113-local-llm/ollama_info.png)
67 62
68## Community Integrations 63## Community Integrations
69 64
70I highly recommend browsing the [Community 65I highly recommend browsing the [Community
71Integrations](https://github.com/jmorganca/ollama#community-integrations) 66Integrations](https://github.com/jmorganca/ollama#community-integrations)
72section of the project to see how you would prefer to extend Ollama 67section of the project to see how you would prefer to extend Ollama beyond a
73beyond a simple command-line interface. There are options for APIs, 68simple command-line interface. There are options for APIs, browser UIs, advanced
74browser UIs, advanced terminal configurations, and more. 69terminal configurations, and more.
75 70
76![Ollama 71![Ollama
77SwiftUI](https://img.cleberg.net/blog/20240113-local-llm/ollama-swiftui.png) 72SwiftUI](https://img.cleberg.net/blog/20240113-local-llm/ollama-swiftui.png)
78 73
79# iOS 74# iOS
80 75
81While there are a handful of decent macOS options, it was quite 76While there are a handful of decent macOS options, it was quite difficult to
82difficult to find an iOS app that offered an open source platform 77find an iOS app that offered an open source platform without an extensive
83without an extensive configuration and building process. I found LLM 78configuration and building process. I found LLM Farm to be decent enough in
84Farm to be decent enough in quality to sit at the top of my list - 79quality to sit at the top of my list - however, it's definitely not user
85however, it\'s definitely not user friendly enough for me to consider 80friendly enough for me to consider using it on a daily basis.
86using it on a daily basis.
87 81
88[LLM Farm](https://llmfarm.site/) is available on TestFlight, so 82[LLM Farm](https://llmfarm.site/) is available on TestFlight, so there's no
89there\'s no manual build process required. However, you can view the 83manual build process required. However, you can view the [LLMFarm
90[LLMFarm repository](https://github.com/guinmoon/LLMFarm) if you wish. 84repository](https://github.com/guinmoon/LLMFarm) if you wish.
91 85
92The caveat is that you will have to manually download the model files 86The caveat is that you will have to manually download the model files from the
93from the links in the 87links in the
94[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md) 88[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md) file to
95file to your iPhone to use the app - there\'s currently no option in the 89your iPhone to use the app - there's currently no option in the app to reach
96app to reach out and grab the latest version of any supported model. 90out and grab the latest version of any supported model.
97 91
98Once you have a file downloaded, you simply create a new chat and select 92Once you have a file downloaded, you simply create a new chat and select the
99the downloaded model file and ensure the inference matches the 93downloaded model file and ensure the inference matches the requirement in the
100requirement in the `models.md` file. 94`models.md` file.
101 95
102See below for a test of the ORCA Mini v3 model: 96See below for a test of the ORCA Mini v3 model:
103 97
104 Chat List Chat 98| Chat List | Chat |
105 ------------------------------------------------------------------------- ------------------------------------------------------------------- 99|-------------------------------------------------------------------------|-------------------------------------------------------------------|
106 ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png) 100| ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) | ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png) |
107 101
108[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for 102[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for private
109private AI models, but it requires a public-facing Ollama API, which did 103AI models, but it requires a public-facing Ollama API, which did not meet my
110not meet my \"on device requirement.\" Nonetheless, it\'s an interesting 104"on device requirement." Nonetheless, it's an interesting looking app and I
111looking app and I will likely set it up to test soon. 105will likely set it up to test soon.
content/blog/2024-01-26-audit-dashboard.md +96 −107
@@ -5,9 +5,9 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8Alteryx and Power BI are powerful tools that can help turn your 8Alteryx and Power BI are powerful tools that can help turn your old-school audit
9old-school audit trackers into interactive tools that provide useful 9trackers into interactive tools that provide useful insights and potential
10insights and potential action plans. 10action plans.
11 11
12With these tools, we are going to build the following dashboard: 12With these tools, we are going to build the following dashboard:
13 13
@@ -18,59 +18,57 @@ With these tools, we are going to build the following dashboard:
18 18
19This project assumes the following: 19This project assumes the following:
20 20
21- You have access to Alteryx Designer and Power BI Desktop. 21- You have access to Alteryx Designer and Power BI Desktop.
22 - If you only have Power BI Desktop, you may need to perform some 22 - If you only have Power BI Desktop, you may need to perform some analysis
23 analysis in Power BI instead of Alteryx. 23 in Power BI instead of Alteryx.
24- Your data is in a format that can be imported into Alteryx and/or 24- Your data is in a format that can be imported into Alteryx and/or Power BI.
25 Power BI. 25- You have a basic understanding of data types and visualization.
26- You have a basic understanding of data types and visualization.
27 26
28# Alteryx: Data Preparation & Analysis 27# Alteryx: Data Preparation & Analysis
29 28
30## Import Data 29## Import Data
31 30
32With Alteryx, importing data is easy with the use of the 31With Alteryx, importing data is easy with the use of the `Input Data` tool.
33`Input Data` tool. Simply drag this tool onto the canvas from 32Simply drag this tool onto the canvas from the `In/Out` tab in the Ribbon to
34the `In/Out` tab in the Ribbon to create it as a node. 33create it as a node.
35 34
36You can choose the File Format manually or simply connect to your 35You can choose the File Format manually or simply connect to your file/database
37file/database and let Alteryx determine the format for you. For this 36and let Alteryx determine the format for you. For this example, we will be
38example, we will be importing an Excel file and changing the 37importing an Excel file and changing the `Start Data Import on Line` variable to
39`Start Data Import on Line` variable to `2`. 38`2`.
40 39
41![Alteryx Excel 40![Alteryx Excel
42Import](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_import.png) 41Import](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_import.png)
43 42
44## Transform Data 43## Transform Data
45 44
46Next, let\'s replace null data and remove whitespace to clean up our 45Next, let's replace null data and remove whitespace to clean up our data. We
47data. We can do this with the `Data Cleansing` tool in the 46can do this with the `Data Cleansing` tool in the `Preparation` tab in the
48`Preparation` tab in the Ribbon. 47Ribbon.
49 48
50Ensure that the following options are enabled: 49Ensure that the following options are enabled:
51 50
52- Replace Nulls 51- Replace Nulls
53 - Replace with Blanks (String Fields) 52 - Replace with Blanks (String Fields)
54 - Replace with 0 (Numeric Fields) 53 - Replace with 0 (Numeric Fields)
55- Remove Unwanted Characters 54- Remove Unwanted Characters
56 - Leading and Trailing Whitespace 55 - Leading and Trailing Whitespace
57 56
58![Data 57![Data
59Cleansing](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_cleansing.png) 58Cleansing](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_cleansing.png)
60 59
61For our next step, we will transform the date fields from strings to 60For our next step, we will transform the date fields from strings to datetime
62datetime format. Add a `Datetime` tool for each field you 61format. Add a `Datetime` tool for each field you want to transform - in the
63want to transform - in the example below, I am using the tool twice for 62example below, I am using the tool twice for the "Started On" and "Submitted
64the \"Started On\" and \"Submitted On\" fields. 63On" fields.
65 64
66![Data 65![Data
67Transformation](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_transformation.png) 66Transformation](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_transformation.png)
68 67
69Now that the dates are in the correct format, let\'s perform a 68Now that the dates are in the correct format, let's perform a calculation based
70calculation based on those fields. Start by adding a `Filter` 69on those fields. Start by adding a `Filter` tool, naming a new Output Column,
71tool, naming a new Output Column, and pasting the formula below into it 70and pasting the formula below into it (the two fields used in this formula must
72(the two fields used in this formula must match the output of the 71match the output of the `Datetime` tools above):
73`Datetime` tools above):
74 72
75``` txt 73``` txt
76DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days") 74DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days")
@@ -81,8 +79,8 @@ Analysis](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_analysis
81 79
82## Export Data 80## Export Data
83 81
84Finalize the process by exporting the transformed data set to a new 82Finalize the process by exporting the transformed data set to a new file, for
85file, for use in the following visualization step. 83use in the following visualization step.
86 84
87![Data 85![Data
88Export](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_export.png) 86Export](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_export.png)
@@ -91,17 +89,15 @@ Export](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_export.png
91 89
92## Import Data 90## Import Data
93 91
94To start, open the Power BI Desktop application. Upon first use, Power 92To start, open the Power BI Desktop application. Upon first use, Power BI will
95BI will ask if you want to open an existing dashboard or import new 93ask if you want to open an existing dashboard or import new data.
96data.
97 94
98As we are creating our first dashboard, let\'s import our data. In my 95As we are creating our first dashboard, let's import our data. In my example
99example below, I\'m importing data from the \"Tracker\" sheet of the 96below, I'm importing data from the "Tracker" sheet of the Excel file I'm
100Excel file I\'m using for this project. 97using for this project.
101 98
102During this process, I also imported the export from the Alteryx 99During this process, I also imported the export from the Alteryx workflow above.
103workflow above. Therefore, we have two different files available for use 100Therefore, we have two different files available for use in our dashboard.
104in our dashboard.
105 101
106![Excel 102![Excel
107Tracker](https://img.cleberg.net/blog/20240126-audit-dashboard/excel_tracker.png) 103Tracker](https://img.cleberg.net/blog/20240126-audit-dashboard/excel_tracker.png)
@@ -111,78 +107,71 @@ Import](https://img.cleberg.net/blog/20240126-audit-dashboard/powerbi_import.png
111 107
112## Add Visuals 108## Add Visuals
113 109
114To create the dashboard below, you will need to follow the list 110To create the dashboard below, you will need to follow the list instructions
115instructions below and format as needed: 111below and format as needed:
116 112
117![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_01.png) 113![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_01.png)
118![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_02.png) 114![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_02.png)
119 115
120Instructions to create the visuals above: 116Instructions to create the visuals above:
121 117
122- `Text Box`: Explain the name and purpose of the 118- `Text Box`: Explain the name and purpose of the dashboard. You can also add
123 dashboard. You can also add images and logos at the top of the 119 images and logos at the top of the dashboard.
124 dashboard. 120- `Donut Chart`: Overall status of the project.
125- `Donut Chart`: Overall status of the project. 121 - `Legend`: Status
126 - `Legend`: Status 122 - `Values`: Count of Status
127 - `Values`: Count of Status 123- `Stacked Column Chart`: Task count by assignee.
128- `Stacked Column Chart`: Task count by assignee. 124 - `X-axis`: Preparer
129 - `X-axis`: Preparer 125 - `Y-axis`: Count of Control ID
130 - `Y-axis`: Count of Control ID 126 - `Legend`: Status
131 - `Legend`: Status 127- `Treemap`: Top N client submitters by average days to submit.
132- `Treemap`: Top N client submitters by average days to 128 - `Details`: Preparer
133 submit. 129 - `Values`: Sum of Avg~DaysToSubmit~
134 - `Details`: Preparer 130- `Line Chart`: Projected vs. actual hours over time.
135 - `Values`: Sum of Avg~DaysToSubmit~ 131- `Clustered Bar Chart`: Projected vs. actual hours per person.
136- `Line Chart`: Projected vs. actual hours over time. 132- `Slicer & Table` - Upcoming due dates.
137- `Clustered Bar Chart`: Projected vs. actual hours per 133 - `Slicer`:
138 person. 134 - `Values`: Date Due
139- `Slicer & Table` - Upcoming due dates. 135 - `Table`:
140 - `Slicer`: 136 - `Columns`: Count of Control ID, Date Due, Preparer, Status
141 - `Values`: Date Due
142 - `Table`:
143 - `Columns`: Count of Control ID, Date Due,
144 Preparer, Status
145 137
146## Format the Dashboard 138## Format the Dashboard
147 139
148You can choose a theme in the View tab of the Ribbon. You can even 140You can choose a theme in the View tab of the Ribbon. You can even browse for
149browse for custom JSON files that define themes, such as ones found 141custom JSON files that define themes, such as ones found online or custom ones
150online or custom ones created by your organization. 142created by your organization.
151 143
152For each visual, you can click the `Format` button in the 144For each visual, you can click the `Format` button in the `Visualizations` side
153`Visualizations` side pane and explore the options. You can 145pane and explore the options. You can custom options such as:
154custom options such as: 146
155 147- Visual
156- Visual 148 - Legend
157 - Legend 149 - Colors
158 - Colors 150 - Data labels
159 - Data labels 151 - Category labels
160 - Category labels 152- General
161- General 153 - Properties
162 - Properties 154 - Title
163 - Title 155 - Effects
164 - Effects 156 - Header icons
165 - Header icons 157 - Tooltips
166 - Tooltips 158 - Alt text
167 - Alt text 159
168 160You can always look online for inspiration when trying to decide how best to
169You can always look online for inspiration when trying to decide how 161organize and style your dashboard.
170best to organize and style your dashboard.
171 162
172# Sharing the Results 163# Sharing the Results
173 164
174Generally, you have a few different options for sharing your dashboards 165Generally, you have a few different options for sharing your dashboards with
175with others: 166others:
176 167
1771. Export the dashboard as a PDF in the file menu of Power BI. This 1681. Export the dashboard as a PDF in the file menu of Power BI. This will export
178 will export all tabs and visuals as they are set when the export 169 all tabs and visuals as they are set when the export button is pressed. You
179 button is pressed. You will lose all interactivity with this option. 170 will lose all interactivity with this option.
1802. Send the full Power BI file to those you wish to share the 1712. Send the full Power BI file to those you wish to share the dashboard. This
181 dashboard. This will retain all settings and interactivity. However, 172 will retain all settings and interactivity. However, you will also need to
182 you will also need to send the source files if they need to refresh 173 send the source files if they need to refresh the dashboard and you will need
183 the dashboard and you will need to re-send the files if you make 174 to re-send the files if you make updates.
184 updates. 1753. Store the dashboard in a synced location, such as a shared drive or Microsoft
1853. Store the dashboard in a synced location, such as a shared drive or 176 Teams. Depending on how a user configures their local Windows paths, the data
186 Microsoft Teams. Depending on how a user configures their local 177 source paths may not be compatible for all users with such a setup.
187 Windows paths, the data source paths may not be compatible for all
188 users with such a setup.
content/blog/2024-01-27-tableau-dashboard.md +48 −51
@@ -5,12 +5,12 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8In this project, I am going to show you how to use Tableau Public for 8In this project, I am going to show you how to use Tableau Public for free to
9free to create simple dashboards. 9create simple dashboards.
10 10
11I will be creating simple visuals from an Omaha crime data set and 11I will be creating simple visuals from an Omaha crime data set and combining
12combining them to create the dashboard below. You can view this 12them to create the dashboard below. You can view this dashboard interactively
13dashboard interactively online here: [Omaha Crime Data (2015 - 13online here: [Omaha Crime Data (2015 -
142023)](https://public.tableau.com/app/profile/c.c7042/viz/OmahaCrimeData2015-2023/OmahaCrimeData2015-2023#1). 142023)](https://public.tableau.com/app/profile/c.c7042/viz/OmahaCrimeData2015-2023/OmahaCrimeData2015-2023#1).
15 15
16![Tableau 16![Tableau
@@ -27,10 +27,10 @@ Each file will be downloaded as a CSV file, approximately 3 MB - 8 MB.
27 27
28# Clean and Transform the Data 28# Clean and Transform the Data
29 29
30I have used Python to combine the files into a single CSV file, as well 30I have used Python to combine the files into a single CSV file, as well as
31as adding a custom `datetime` column. You could do this step 31adding a custom `datetime` column. You could do this step in any software you
32in any software you prefer, but I prefer Python as its free, easy to 32prefer, but I prefer Python as its free, easy to use, and has a plethora of
33use, and has a plethora of support resources online. 33support resources online.
34 34
35Start by opening a terminal, navigating to your Downloads directory, and 35Start by opening a terminal, navigating to your Downloads directory, and
36creating a python script. 36creating a python script.
@@ -77,90 +77,87 @@ Once pasted, save and close the file. You can execute the file like so:
77python3 data_processing.py 77python3 data_processing.py
78``` 78```
79 79
80After this, you should have a combined data file that contains all 80After this, you should have a combined data file that contains all incidents
81incidents between 2015 and 2023. Mine was approximately 55 MB. 81between 2015 and 2023. Mine was approximately 55 MB.
82 82
83# Tableau Public 83# Tableau Public
84 84
85[Tableau Public](https://public.tableau.com/) is a free-to-use web 85[Tableau Public](https://public.tableau.com/) is a free-to-use web application
86application that allows you to create visualizations by uploading data 86that allows you to create visualizations by uploading data sources. Note that
87sources. Note that there\'s no way to keep the data and visualizations 87there's no way to keep the data and visualizations private, so don't upload
88private, so don\'t upload anything private. 88anything private.
89 89
90After creating an account, you can click the `Create` \> 90After creating an account, you can click the `Create` > `Web Authoring` link to
91`Web Authoring` link to create your first visualization. 91create your first visualization.
92 92
93![Create 93![Create
94Button](https://img.cleberg.net/blog/20240127-tableau-dashboard/create_button.png) 94Button](https://img.cleberg.net/blog/20240127-tableau-dashboard/create_button.png)
95 95
96## Upload the Data 96## Upload the Data
97 97
98Once you\'ve opened your first project, Tableau will ask you to connect 98Once you've opened your first project, Tableau will ask you to connect to your
99to your data. For this project, click the 99data. For this project, click the `Upload from computer` button and select the
100`Upload from computer` button and select the CSV file 100CSV file previously combined in the step above.
101previously combined in the step above.
102 101
103![Connect 102![Connect
104Data](https://img.cleberg.net/blog/20240127-tableau-dashboard/connect_data.png) 103Data](https://img.cleberg.net/blog/20240127-tableau-dashboard/connect_data.png)
105 104
106Once connected, you can refresh the preview of the data with the 105Once connected, you can refresh the preview of the data with the `Refresh Data
107`Refresh Data Source` button in the toolbar. 106Source` button in the toolbar.
108 107
109![Data 108![Data
110Preview](https://img.cleberg.net/blog/20240127-tableau-dashboard/data_preview.png) 109Preview](https://img.cleberg.net/blog/20240127-tableau-dashboard/data_preview.png)
111 110
112If you need to edit any of the data types, column names, etc., you can 111If you need to edit any of the data types, column names, etc., you can do so
113do so now. Once complete, generate an extract so that you can start 112now. Once complete, generate an extract so that you can start creating
114creating visualizations. 113visualizations.
115 114
116## Create Visualizations 115## Create Visualizations
117 116
118To start, create a worksheet in the toolbar at the bottom of the screen. 117To start, create a worksheet in the toolbar at the bottom of the screen.
119 118
120Within this screen, select a column from the `Data` side bar 119Within this screen, select a column from the `Data` side bar on the left and
121on the left and drag it into the `Columns` or 120drag it into the `Columns` or `Rows` area of the canvas.
122`Rows` area of the canvas.
123 121
124See below for the map visualization. You can recreate this by adding the 122See below for the map visualization. You can recreate this by adding the
125following fields: 123following fields:
126 124
127- `Columns`: Lon 125- `Columns`: Lon
128- `Rows`: Lat 126- `Rows`: Lat
129- `Marks`: 127- `Marks`:
130 - Description 128 - Description
131 - Datetime 129 - Datetime
132- `Filters`: Datetime 130- `Filters`: Datetime
133 131
134![Worksheet 132![Worksheet
135Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/worksheet_edit.png) 133Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/worksheet_edit.png)
136 134
137You can repeat this process for each visualization you want to create. 135You can repeat this process for each visualization you want to create. Explore
138Explore your options by dragging data fields to different areas and by 136your options by dragging data fields to different areas and by opening the field
139opening the field options to explore what operations can be performed on 137options to explore what operations can be performed on different data types
140different data types (e.g., average, count, etc.). 138(e.g., average, count, etc.).
141 139
142## Create Dashboard 140## Create Dashboard
143 141
144To create a dashboard, click the button on the toolbar at the bottom of 142To create a dashboard, click the button on the toolbar at the bottom of the
145the screen. Within the dashboard, drag each sheet from the left side bar 143screen. Within the dashboard, drag each sheet from the left side bar onto the
146onto the dashboard canvas. 144dashboard canvas.
147 145
148![Dashboard 146![Dashboard
149Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard_edit.png) 147Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard_edit.png)
150 148
151## Formatting 149## Formatting
152 150
153You can explore a ton of different formatting options throughout the 151You can explore a ton of different formatting options throughout the worksheets
154worksheets and dashboard. Specifically for maps, you can alter the map 152and dashboard. Specifically for maps, you can alter the map layers, background,
155layers, background, and visible features through the `Map` 153and visible features through the `Map` menu in the top file menu of the editing
156menu in the top file menu of the editing screen. 154screen.
157 155
158In the finished dashboard below, I opted for a dark mode with a map that 156In the finished dashboard below, I opted for a dark mode with a map that showed
159showed county lines and city names. 157county lines and city names.
160 158
161There\'s a ton of other options available to be used in a dashboard like 159There's a ton of other options available to be used in a dashboard like this,
162this, but this project shows a quick preview of what you can do in 160but this project shows a quick preview of what you can do in Tableau Public.
163Tableau Public.
164 161
165![Tableau 162![Tableau
166Dashboard](https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png) 163Dashboard](https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png)
content/blog/2024-02-06-zfs.md +69 −83
@@ -8,14 +8,12 @@ draft = false
8This post details the process I used to create ZFS pools, datasets, and 8This post details the process I used to create ZFS pools, datasets, and
9snapshots on Ubuntu Server. 9snapshots on Ubuntu Server.
10 10
11I found the following pages very helpful while going through this 11I found the following pages very helpful while going through this process:
12process:
13 12
14- [Setup a ZFS storage 13- [Setup a ZFS storage
15 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool) 14 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool)
16- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS) 15- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS)
17- [ZFS for 16- [ZFS for Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/)
18 Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/)
19 17
20# Installation 18# Installation
21 19
@@ -25,8 +23,7 @@ To start, I installed the ZFS package with the following command:
25sudo apt install zfsutils-linux 23sudo apt install zfsutils-linux
26``` 24```
27 25
28Once installed, you can check the version to see if it installed 26Once installed, you can check the version to see if it installed correctly.
29correctly.
30 27
31```sh 28```sh
32> zsf --version 29> zsf --version
@@ -39,32 +36,32 @@ zfs-kmod-2.1.5-1ubuntu6~22.04.1
39 36
40Now that ZFS is installed, we can create and configure the pool. 37Now that ZFS is installed, we can create and configure the pool.
41 38
42You have various options for configuring ZFS pools that all come 39You have various options for configuring ZFS pools that all come different pros
43different pros and cons. I suggest visiting the links at the top of this 40and cons. I suggest visiting the links at the top of this post or searching
44post or searching online for the best configuration for your use-case. 41online for the best configuration for your use-case.
45 42
46- Striped VDEVs (Raid0) 43- Striped VDEVs (Raid0)
47- Mirrored VDEVs (Raid1) 44- Mirrored VDEVs (Raid1)
48- Striped Mirrored VDEVs (Raid10) 45- Striped Mirrored VDEVs (Raid10)
49- RAIDz (Raid5) 46- RAIDz (Raid5)
50- RAIDz2 (Raidd6) 47- RAIDz2 (Raidd6)
51- RAIDz3 48- RAIDz3
52- Nested RAIDz (Raid50, Raid60) 49- Nested RAIDz (Raid50, Raid60)
53 50
54I will be using Raid10 in this guide. However, the majority of the steps 51I will be using Raid10 in this guide. However, the majority of the steps are the
55are the same regardless of your chosen pool configuration. 52same regardless of your chosen pool configuration.
56 53
57## Creating the Pool 54## Creating the Pool
58 55
59To start, let\'s list the disks available to use. You can use 56To start, let's list the disks available to use. You can use `fdisk` command to
60`fdisk` command to see all available disks. 57see all available disks.
61 58
62```sh 59```sh
63sudo fdisk -l 60sudo fdisk -l
64``` 61```
65 62
66Or, if you currently have them mounted, you can use the `df` 63Or, if you currently have them mounted, you can use the `df` command to view
67command to view your disks. 64your disks.
68 65
69```sh 66```sh
70> sudo df -h 67> sudo df -h
@@ -79,24 +76,23 @@ Filesystem Size Used Avail Use% Mounted on
79/dev/sdf1 7.3T 28K 6.9T 1% /mnt/red-04 76/dev/sdf1 7.3T 28K 6.9T 1% /mnt/red-04
80``` 77```
81 78
82If you\'re going to use mounted disks, make sure to umount them before 79If you're going to use mounted disks, make sure to umount them before creating
83creating the pool. 80the pool.
84 81
85```sh 82```sh
86sudo umount /dev/sda1 83sudo umount /dev/sda1
87sudo umount /dev/sdb1 84sudo umount /dev/sdb1
88``` 85```
89 86
90Now that I\'ve identified the disks I want to use and have them 87Now that I've identified the disks I want to use and have them unmounted,
91unmounted, let\'s create the pool. For this example, I will call it 88let's create the pool. For this example, I will call it `tank`.
92`tank`.
93 89
94```sh 90```sh
95sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb 91sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb
96``` 92```
97 93
98See below for the results of the new ZFS pool named `tank`, 94See below for the results of the new ZFS pool named `tank`, with a vdev
99with a vdev automatically named `mirror-0`. 95automatically named `mirror-0`.
100 96
101```sh 97```sh
102> zfs list 98> zfs list
@@ -121,8 +117,8 @@ config:
121errors: No known data errors 117errors: No known data errors
122``` 118```
123 119
124We can also look at the mounted filesystem to see where the pool is 120We can also look at the mounted filesystem to see where the pool is mounted and
125mounted and some quick stats. 121some quick stats.
126 122
127```sh 123```sh
128> df -h 124> df -h
@@ -134,28 +130,25 @@ tank 7.2T 128K 7.2T 1% /tank
134 130
135## Expanding the Pool 131## Expanding the Pool
136 132
137If you want to expand this pool, you will need to add a new VDEV to the 133If you want to expand this pool, you will need to add a new VDEV to the pool.
138pool. Since I am using 2 disks per VDEV, I will need to add a new 2-disk 134Since I am using 2 disks per VDEV, I will need to add a new 2-disk VDEV to the
139VDEV to the existing `tank` pool. 135existing `tank` pool.
140 136
141```sh 137```sh
142sudo zpool add tank mirror /dev/sdX /dev/sdY 138sudo zpool add tank mirror /dev/sdX /dev/sdY
143``` 139```
144 140
145If you\'re adding disks of different sizes, you\'ll need to use the 141If you're adding disks of different sizes, you'll need to use the `-f` flag.
146`-f` flag. Keep in mind that the max size will be limited to 142Keep in mind that the max size will be limited to the smallest disk added.
147the smallest disk added.
148 143
149```sh 144```sh
150sudo zpool add -f tank mirror /dev/sdX /dev/sdY 145sudo zpool add -f tank mirror /dev/sdX /dev/sdY
151``` 146```
152 147
153I added two 8TB hard drives and this process took around 10 seconds to 148I added two 8TB hard drives and this process took around 10 seconds to complete.
154complete.
155 149
156When viewing the pool again, you can see that the pool has now doubled 150When viewing the pool again, you can see that the pool has now doubled in size.
157in size. We have 14.3 TB useable space and the same space used for 151We have 14.3 TB useable space and the same space used for mirroring.
158mirroring.
159 152
160```sh 153```sh
161> zfs list 154> zfs list
@@ -168,8 +161,8 @@ tank/media 96K 14.3T 96K /tank/media
168 161
169### Converting Disks 162### Converting Disks
170 163
171Some disks, such as NTFS-formatted drives, will need to be partitioned 164Some disks, such as NTFS-formatted drives, will need to be partitioned and
172and formatted prior to being added to the pool. 165formatted prior to being added to the pool.
173 166
174Start by identifying the disks you want to format and add to the pool. 167Start by identifying the disks you want to format and add to the pool.
175 168
@@ -177,18 +170,16 @@ Start by identifying the disks you want to format and add to the pool.
177sudo fdisk -l | grep /dev 170sudo fdisk -l | grep /dev
178``` 171```
179 172
180I am going to format my `/dev/sdc` and `/dev/sdd` 173I am going to format my `/dev/sdc` and `/dev/sdd` disks with the `fdisk`
181disks with the `fdisk` command. 174command.
182 175
183See below for instructions on how to use `fdisk`. Here\'s 176See below for instructions on how to use `fdisk`. Here's what I did to create
184what I did to create basic Linux formatted disks: 177basic Linux formatted disks:
185 178
186- `g` : Create GPT partition table 179- `g` : Create GPT partition table
187- `n` : Create a new partition, hit Enter for all default 180- `n` : Create a new partition, hit Enter for all default options
188 options 181- `t` : Change partition type to `20` for `Linux filesystem`
189- `t` : Change partition type to `20` for 182- `w` : Write the changes to disk and exit
190 `Linux filesystem`
191- `w` : Write the changes to disk and exit
192 183
193I repeated this process for both disks. 184I repeated this process for both disks.
194 185
@@ -247,9 +238,9 @@ sudo zpool add tank mirror /dev/sdc /dev/sdd
247``` 238```
248 239
249When we list the pool again, we can see that our size is now updated to 240When we list the pool again, we can see that our size is now updated to
250approximately 22TB. This represents my hard drives totalling 45.6TB when 241approximately 22TB. This represents my hard drives totalling 45.6TB when shown
251shown with `fdisk -l`, with a Raid10 configuration using 22TB 242with `fdisk -l`, with a Raid10 configuration using 22TB for mirroring and 22TB
252for mirroring and 22TB of useable space. 243of useable space.
253 244
254```sh 245```sh
255> zfs list 246> zfs list
@@ -263,24 +254,22 @@ tank/media 145GT 21.7T 96K /tank/media
263## Creating Datasets 254## Creating Datasets
264 255
265According to [ZFS 256According to [ZFS
266Terminology](https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html), 257Terminology](https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html), a
267a `dataset` can refer to "clones, file systems, snapshots, 258`dataset` can refer to "clones, file systems, snapshots, and volumes.
268and volumes.
269 259
270For this guide, I will use the `dataset` term to refer to 260For this guide, I will use the `dataset` term to refer to file systems created
271file systems created under a pool. 261under a pool.
272 262
273Within my `tank` pool, I am going to create some datasets to 263Within my `tank` pool, I am going to create some datasets to help organize my
274help organize my files. This will give me location to store data rather 264files. This will give me location to store data rather than simply dumping
275than simply dumping everything at the `/tank/` location. 265everything at the `/tank/` location.
276 266
277```sh 267```sh
278sudo zfs create tank/cloud 268sudo zfs create tank/cloud
279sudo zfs create tank/media 269sudo zfs create tank/media
280``` 270```
281 271
282Once created, you can see these datasets in the output of your pool 272Once created, you can see these datasets in the output of your pool list:
283list:
284 273
285```sh 274```sh
286> zfs list 275> zfs list
@@ -292,9 +281,9 @@ tank/media 96K 7.14T 96K /tank/media
292 281
293## Creating Snapshots 282## Creating Snapshots
294 283
295Next, let\'s create our first snapshot. We can do this by calling the 284Next, let's create our first snapshot. We can do this by calling the `snapshot`
296`snapshot` command and give it an output name. I will be 285command and give it an output name. I will be throwing the current date and time
297throwing the current date and time into my example. 286into my example.
298 287
299```sh 288```sh
300sudo zfs snapshot tank@$(date '+%Y-%m-%d_%H-%M') 289sudo zfs snapshot tank@$(date '+%Y-%m-%d_%H-%M')
@@ -325,13 +314,10 @@ no datasets available
325 314
326# My Thoughts on ZFS So Far 315# My Thoughts on ZFS So Far
327 316
328- I sacrificed 25TB to be able to mirror my data, but I feel more 317- I sacrificed 25TB to be able to mirror my data, but I feel more comfortable
329 comfortable with the potential to save my data by quickly replacing 318 with the potential to save my data by quickly replacing a disk if I need to.
330 a disk if I need to. 319- The set-up was surprisingly easy and fast.
331- The set-up was surprisingly easy and fast. 320- Disk I/O is fast as well. I was worried that the data transfer speeds would be
332- Disk I/O is fast as well. I was worried that the data transfer 321 slower due to the RAID configuration.
333 speeds would be slower due to the RAID configuration. 322- Media streaming and transcoding has seen no noticeable drop in performance.
334- Media streaming and transcoding has seen no noticeable drop in 323- My only limitation really is the number of HDD bays in my server HDD cage.
335 performance.
336- My only limitation really is the number of HDD bays in my server HDD
337 cage.
content/blog/2024-02-13-ubuntu-emergency-mode.md +23 −26
@@ -7,12 +7,12 @@ draft = false
7 7
8# The Problem 8# The Problem
9 9
10I recently [migrated my hard drives to a ZFS pool](../zfs/) and found 10I recently [migrated my hard drives to a ZFS pool](../zfs/) and found myself
11myself stuck in Ubuntu\'s emergency mode after the first reboot I 11stuck in Ubuntu's emergency mode after the first reboot I performed after
12performed after creating the ZFS pool. 12creating the ZFS pool.
13 13
14My server was stuck in the boot process and showed the following error 14My server was stuck in the boot process and showed the following error on the
15on the screen: 15screen:
16 16
17``` txt 17``` txt
18You are in emergency mode. 18You are in emergency mode.
@@ -21,34 +21,33 @@ After logging in, type "journalctl -xb" to view system logs,
21or ^D to try again to boot into default mode". 21or ^D to try again to boot into default mode".
22``` 22```
23 23
24After rebooting the server and watching the logs scroll on a monitor, I 24After rebooting the server and watching the logs scroll on a monitor, I noticed
25noticed the root cause was related to a very long search for certain 25the root cause was related to a very long search for certain drives. I kept
26drives. I kept seeing errors like this: 26seeing errors like this:
27 27
28``` txt 28``` txt
29[ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid] 29[ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid]
30``` 30```
31 31
32I realized that I had not removed the `/etc/fstab` references 32I realized that I had not removed the `/etc/fstab` references that asked Ubuntu
33that asked Ubuntu to mount two disks on boot, but I had recently changed 33to mount two disks on boot, but I had recently changed those disks to be part of
34those disks to be part of my ZFS pool instead. Therefore, Ubuntu was 34my ZFS pool instead. Therefore, Ubuntu was trying to identify and mount a disk
35trying to identify and mount a disk that was not available. 35that was not available.
36 36
37Now that we have an idea of the issue, let\'s move to solution. 37Now that we have an idea of the issue, let's move to solution.
38 38
39# The Solution 39# The Solution
40 40
41In order to fix the issue, I waited until I was allowed to type the root 41In order to fix the issue, I waited until I was allowed to type the root user's
42user\'s password, and then I executed the following command: 42password, and then I executed the following command:
43 43
44```sh 44```sh
45nano /etc/fstab 45nano /etc/fstab
46``` 46```
47 47
48Within the `fstab` file, I needed to comment/remove the 48Within the `fstab` file, I needed to comment/remove the following lines at the
49following lines at the bottom of the file. You can comment-out a line by 49bottom of the file. You can comment-out a line by prepending a `#` symbol at the
50prepending a `#` symbol at the beginning of the line. You can 50beginning of the line. You can also delete the line entirely.
51also delete the line entirely.
52 51
53``` conf 52``` conf
54# What it looked like when running into the issue: 53# What it looked like when running into the issue:
@@ -60,16 +59,14 @@ UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0
60# UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0 59# UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0
61``` 60```
62 61
63Once removing the lines above from the `/etc/fstab` file, 62Once removing the lines above from the `/etc/fstab` file, save and exit the file
64save and exit the file by hitting the `Ctrl` + `x` 63by hitting the `Ctrl` + `x` key combo.
65key combo.
66 64
67You can now hit `Ctrl` + `D` to continue, or 65You can now hit `Ctrl` + `D` to continue, or reboot:
68reboot:
69 66
70```sh 67```sh
71systemctl reboot 68systemctl reboot
72``` 69```
73 70
74Once rebooted, I was able to watch the machine boot properly and launch 71Once rebooted, I was able to watch the machine boot properly and launch to the
75to the TTY login screen without errors! 72TTY login screen without errors!
content/blog/2024-02-21-self-hosting-otter-wiki.md +27 −31
@@ -7,33 +7,32 @@ draft = false
7 7
8# An Otter Wiki 8# An Otter Wiki
9 9
10[An Otter Wiki](https://otterwiki.com/) is an easy to use wiki software 10[An Otter Wiki](https://otterwiki.com/) is an easy to use wiki software that
11that takes almost no effort to set up and maintain. 11takes almost no effort to set up and maintain.
12 12
13# Installation 13# Installation
14 14
15To install An Otter Wiki, I\'m going to use Docker Compose to create the 15To install An Otter Wiki, I'm going to use Docker Compose to create the
16container and then use Nginx as a reverse proxy to allow external access 16container and then use Nginx as a reverse proxy to allow external access via a
17via a subdomain I own. 17subdomain I own.
18 18
19## Docker Compose 19## Docker Compose
20 20
21Start by creating a directory for the container\'s files. 21Start by creating a directory for the container's files.
22 22
23```sh 23```sh
24mkdir ~/otterwiki 24mkdir ~/otterwiki
25``` 25```
26 26
27Next, create the `docker-compose.yml` file to define the 27Next, create the `docker-compose.yml` file to define the container's
28container\'s parameters. 28parameters.
29 29
30```sh 30```sh
31nano ~/otterwiki/docker-compose.yml 31nano ~/otterwiki/docker-compose.yml
32``` 32```
33 33
34Within the file, paste the following content. You can read the 34Within the file, paste the following content. You can read the project's
35project\'s documentation if you want to further override or customize 35documentation if you want to further override or customize the container.
36the container.
37 36
38``` conf 37``` conf
39version: '3' 38version: '3'
@@ -56,23 +55,22 @@ cd ~/otterwiki
56sudo docker-compose up -d 55sudo docker-compose up -d
57``` 56```
58 57
59The container is now available at `localhost:8337`. Next, we 58The container is now available at `localhost:8337`. Next, we will use Nginx to
60will use Nginx to serve this app externally. 59serve this app externally.
61 60
62## Nginx 61## Nginx
63 62
64To access the app externally, let\'s set up a reverse proxy. I\'ll start 63To access the app externally, let's set up a reverse proxy. I'll start by
65by creating the Nginx configuration file for my wiki. 64creating the Nginx configuration file for my wiki.
66 65
67```sh 66```sh
68sudo nano /etc/nginx/sites-available/wiki 67sudo nano /etc/nginx/sites-available/wiki
69``` 68```
70 69
71Within the file, I have saved the following content. This assumes you 70Within the file, I have saved the following content. This assumes you already
72already have a TLS/SSL cert to use with this subdomain. If not, simply 71have a TLS/SSL cert to use with this subdomain. If not, simply remove the
73remove the `ssl_*` variables, remove the `80` 72`ssl_*` variables, remove the `80` server block, and change the `443` server
74server block, and change the `443` server block to 73block to `80` to serve the app without SSL.
75`80` to serve the app without SSL.
76 74
77``` conf 75``` conf
78server { 76server {
@@ -110,15 +108,14 @@ server {
110} 108}
111``` 109```
112 110
113Save and close the configuration file. On Nginx, we need to symlink the 111Save and close the configuration file. On Nginx, we need to symlink the file to
114file to enable it. 112enable it.
115 113
116```sh 114```sh
117sudo ln -s /etc/nginx/sites-available/wiki /etc/nginx/sites-enabled/wiki 115sudo ln -s /etc/nginx/sites-available/wiki /etc/nginx/sites-enabled/wiki
118``` 116```
119 117
120Once enabled, restart the Nginx server to start serving the app 118Once enabled, restart the Nginx server to start serving the app externally.
121externally.
122 119
123```sh 120```sh
124sudo systemctl restart nginx.service 121sudo systemctl restart nginx.service
@@ -126,18 +123,17 @@ sudo systemctl restart nginx.service
126 123
127# Screenshots 124# Screenshots
128 125
129In the screenshot below, you can see the initial launch screen for An 126In the screenshot below, you can see the initial launch screen for An Otter
130Otter Wiki. Start by creating your admin account and configure the app 127Wiki. Start by creating your admin account and configure the app as necessary.
131as necessary.
132 128
133![An Otter Wiki - Initial 129![An Otter Wiki - Initial
134Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki.png) 130Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki.png)
135 131
136You can also see the default editing screen for creating and editing 132You can also see the default editing screen for creating and editing pages.
137pages. It\'s as easy as typing Markdown and hitting the save button. 133It's as easy as typing Markdown and hitting the save button.
138 134
139![An Otter Wiki - Editing 135![An Otter Wiki - Editing
140Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki-edit.png) 136Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki-edit.png)
141 137
142Overall, I like An Otter Wiki and will be looking forward to seeing how 138Overall, I like An Otter Wiki and will be looking forward to seeing how much use
143much use I get out of it going forward. 139I get out of it going forward.
content/blog/2024-03-13-doom-emacs.md +134 −153
@@ -7,12 +7,11 @@ draft = false
7 7
8## Screenshots 8## Screenshots
9 9
10These screenshots are showing a project opened with projectile, a 10These screenshots are showing a project opened with projectile, a treemacs side
11treemacs side pane open with the project contents, multiple buffers 11pane open with the project contents, multiple buffers tiled next to each other,
12tiled next to each other, and the help pane open at the bottomm. 12and the help pane open at the bottomm.
13 13
14The themes are `doom-homage-white` and 14The themes are `doom-homage-white` and `doom-homage-black`.
15`doom-homage-black`.
16 15
17![Doom Emacs Light 16![Doom Emacs Light
18Mode](https://img.cleberg.net/blog/20240314-doom-emacs/light.png) 17Mode](https://img.cleberg.net/blog/20240314-doom-emacs/light.png)
@@ -24,42 +23,38 @@ Mode](https://img.cleberg.net/blog/20240314-doom-emacs/dark.png)
24 23
25I have been switching back and forth between 24I have been switching back and forth between
26[markdown](https://en.wikipedia.org/wiki/Markdown) and 25[markdown](https://en.wikipedia.org/wiki/Markdown) and
27[org-mode](https://en.wikipedia.org/wiki/Org-mode) recently for my 26[org-mode](https://en.wikipedia.org/wiki/Org-mode) recently for my personal note
28personal note taking, wiki, and even this blog. As a result, I have been 27taking, wiki, and even this blog. As a result, I have been stumbling further
29stumbling further into the world of Emacs and found myself at a point 28into the world of Emacs and found myself at a point where I now prefer to do
30where I now prefer to do most of my basic editing within Emacs. 29most of my basic editing within Emacs.
31 30
32I\'ll leave the markdown vs. org-mode debate for another post, but I 31I'll leave the markdown vs. org-mode debate for another post, but I love
33love org-mode\'s extensibility and interactive nature within Emacs, but 32org-mode's extensibility and interactive nature within Emacs, but it becomes
34it becomes very unwieldy in any other client implementation of 33very unwieldy in any other client implementation of org-mode - especially on
35org-mode - especially on iOS. On the flip side, markdown is limited in 34iOS. On the flip side, markdown is limited in functionality and fractured into
36functionality and fractured into different standards, but it\'s simple 35different standards, but it's simple and popular enough that there are a
37and popular enough that there are a plethora of great clients to choose 36plethora of great clients to choose from that will get the job done.
38from that will get the job done. 37
39 38For now, I want to focus on how I have been using Emacs and some of the things
40For now, I want to focus on how I have been using Emacs and some of the 39that would have helped me learn it faster had I known where to start.
41things that would have helped me learn it faster had I known where to
42start.
43 40
44### Installation 41### Installation
45 42
46This post focuses on [Doom 43This post focuses on [Doom Emacs](https://github.com/doomemacs/doomemacs), which
47Emacs](https://github.com/doomemacs/doomemacs), which is an Emacs 44is an Emacs framework that provides an alternative experience to the vanilla
48framework that provides an alternative experience to the vanilla [GNU 45[GNU Emacs](https://www.gnu.org/software/emacs/).
49Emacs](https://www.gnu.org/software/emacs/).
50 46
51The [Getting Start 47The [Getting Start
52Guide](https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org) 48Guide](https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org)
53has an extremely detailed walkthrough of installation for all systems, 49has an extremely detailed walkthrough of installation for all systems, so please
54so please refer to that guide for up-to-date instructions. 50refer to that guide for up-to-date instructions.
55 51
56I chose to install on macOS, using the Homebrew option with the 52I chose to install on macOS, using the Homebrew option with the
57`railwaycat/emacsmacport` version of Emacs. 53`railwaycat/emacsmacport` version of Emacs.
58 54
59Once the program is installed, you can run the program by typing 55Once the program is installed, you can run the program by typing `emacs` in a
60`emacs` in a terminal. If you installed a version of Emacs 56terminal. If you installed a version of Emacs that supports both a GUI and TUI,
61that supports both a GUI and TUI, you will have to run 57you will have to run `emacs -nw` to get the TUI instead of the default GUI.
62`emacs -nw` to get the TUI instead of the default GUI.
63 58
64### Configuration 59### Configuration
65 60
@@ -68,13 +63,13 @@ Once installed, you can configure Doom by editing the files within the
68 63
691. `config.el` - Personal configuration file 641. `config.el` - Personal configuration file
702. `custom.el` - Custom set variables 652. `custom.el` - Custom set variables
713. `init.el` - Doom modules and load order, must run 663. `init.el` - Doom modules and load order, must run `doom sync` after
72 `doom sync` after modifying 67 modifying
734. `packages.el` - Declare packages to install in this file, 684. `packages.el` - Declare packages to install in this file, then run `doom
74 then run `doom sync` to install 69 sync` to install
75 70
76I only needed a few customizations for my configuration, so I\'ll list 71I only needed a few customizations for my configuration, so I'll list them
77them below. 72below.
78 73
79```lisp 74```lisp
80;; ~/.doom.d/config.el 75;; ~/.doom.d/config.el
@@ -148,140 +143,127 @@ them below.
148 (default +bindings +smartparens)) 143 (default +bindings +smartparens))
149``` 144```
150 145
151If you\'re editing these files within Doom directly, remember to run 146If you're editing these files within Doom directly, remember to run `SPC h r r`
152`SPC h r r` to reload the configuration. Also remember to run 147to reload the configuration. Also remember to run `doom sync` for any changes to
153`doom sync` for any changes to the `init.el` or 148the `init.el` or `packages.el` files.
154`packages.el` files.
155 149
156## Basic Functionality 150## Basic Functionality
157 151
158I kept a cheat sheet note open at first with all of the basic functions 152I kept a cheat sheet note open at first with all of the basic functions typed
159typed out, copied as I went through the tutorial. After a little while, 153out, copied as I went through the tutorial. After a little while, I no longer
160I no longer needed it. I highly recommend writing down the most 154needed it. I highly recommend writing down the most applicable shortcuts for
161applicable shortcuts for your preferred functionality and refer back to 155your preferred functionality and refer back to it until you've memorized it.
162it until you\'ve memorized it. 156
163 157Memorizing the shortcuts will differ based on the type of Emacs framework being
164Memorizing the shortcuts will differ based on the type of Emacs 158used. Personally, migrating from vanilla Emacs to Doom Emacs simplified
165framework being used. Personally, migrating from vanilla Emacs to Doom 159everything by a large factor and instantly enabled me to start working on my
166Emacs simplified everything by a large factor and instantly enabled me 160projects, eliminating most of the hurdles I was running into. The vanilla emacs
167to start working on my projects, eliminating most of the hurdles I was 161hotkeys became obnoxious and I actually stopped using Emacs entirely for about a
168running into. The vanilla emacs hotkeys became obnoxious and I actually 162month before trying Doom.
169stopped using Emacs entirely for about a month before trying Doom. 163
170 164For me, the first logical step is to interact with the local filesystem. To do
171For me, the first logical step is to interact with the local filesystem. 165this, I needed to know how to open directories, open files, save files, discard
172To do this, I needed to know how to open directories, open files, save 166changes, close files, and switch between open files. Here are some example
173files, discard changes, close files, and switch between open files. Here 167shortcuts I've written down in order to accomplish file-based actions.
174are some example shortcuts I\'ve written down in order to accomplish 168
175file-based actions. 169| Doom Hotkey | Emacs Hotkey | Description |
176 170|-----------------|--------------|----------------------------------------|
177 Doom Hotkey Emacs Hotkey Description 171| `SPC :` | `C-x` | Run functions |
178 ---------------------------- --------------------------- ---------------------------------------- 172| `SPC f f` | `C-x f` | Open file in buffer |
179 `SPC :` `C-x` Run functions 173| `SPC f d` | `C-x d` | Open directory with `dired` |
180 `SPC f f` `C-x f` Open file in buffer 174| `i` | `C-x C-q` | Edit current buffer (insert mode) |
181 `SPC f d` `C-x d` Open directory with `dired` 175| `q` | `C-x C-q` | Quit out of insert mode |
182 `i` `C-x C-q` Edit current buffer (insert mode) 176| `SPC f s` | `C-x s` | Save current buffer |
183 `q` `C-x C-q` Quit out of insert mode 177| `SPC b k` | `C-x k` | Kill current buffer |
184 `SPC f s` `C-x s` Save current buffer 178| `SPC w h/j/k/l` | `C-x o`[^1] | Move left/down/up/right to next buffer |
185 `SPC b k` `C-x k` Kill current buffer 179
186 `SPC w h/j/k/l` `C-x o`\[^1^\] Move left/down/up/right to next buffer 180[^1]: Doom's evil-window functionality is a bit different from GNU Emacs, but
187 181you can always switch to the "other" buffer with `C-x o` or `C-x b` to get a
188\[^1^\] Doom\'s evil-window functionality is a bit different from GNU 182list of buffers to select.
189Emacs, but you can always switch to the \"other\" buffer with 183
190`C-x o` or `C-x b` to get a list of buffers to 184In general, when in Doom, you can press `SPC` and wait a second for the help
191select. 185pane to appear with all available hotkey options. For example, you can press
192 186`SPC`, wait for the help pane, and then select a key such as `g` to enter the
193In general, when in Doom, you can press `SPC` and wait a 187git help pane and explore further command options.
194second for the help pane to appear with all available hotkey options.
195For example, you can press `SPC`, wait for the help pane, and
196then select a key such as `g` to enter the git help pane and
197explore further command options.
198 188
199## Editing 189## Editing
200 190
201Next in my process is to dive into editing for any languages I\'m 191Next in my process is to dive into editing for any languages I'm currently
202currently using. In this post, I will just cover Markdown and Org-Mode 192using. In this post, I will just cover Markdown and Org-Mode but I have also
203but I have also been slowly adoping some Python and general web dev 193been slowly adoping some Python and general web dev tools as well.
204tools as well.
205 194
206### Markdown 195### Markdown
207 196
208![Markdown 197![Markdown
209Preview](https://img.cleberg.net/blog/20240314-doom-emacs/markdown.png) 198Preview](https://img.cleberg.net/blog/20240314-doom-emacs/markdown.png)
210 199
211Markdown is fairly simple as the syntax is limited, so just make sure 200Markdown is fairly simple as the syntax is limited, so just make sure the
212the `~/.doom.d/init.el` includes the `markdown` 201`~/.doom.d/init.el` includes the `markdown` declaration in the `:lang` section.
213declaration in the `:lang` section.
214 202
215This package includes the following hotkey menus. The insert and toggle 203This package includes the following hotkey menus. The insert and toggle menu
216menu expands further, allowing you to insert various markdown elements 204expands further, allowing you to insert various markdown elements and toggle
217and toggle things like link hiding. 205things like link hiding.
218 206
219 Doom Hotkey Function 207| Doom Hotkey | Function |
220 ----------------------------------------- -------------------------- 208|------------------------------|--------------------------|
221 `SPC m '` markdown-edit-code-block 209| `SPC m '` | markdown-edit-code-block |
222 `SPC m e` markdown-export 210| `SPC m e` | markdown-export |
223 `SPC m i` +insert 211| `SPC m i` | +insert |
224 `SPC m o` markdown-open 212| `SPC m o` | markdown-open |
225 `SPC m p` markdown-preview 213| `SPC m p` | markdown-preview |
226 `SPC m t` +toggle 214| `SPC m t` | +toggle |
227 `SPC : markdown-table-align` markdown-table-align 215| `SPC : markdown-table-align` | markdown-table-align |
228 216
229### Org-Mode 217### Org-Mode
230 218
231![Org-Mode 219![Org-Mode Preview](https://img.cleberg.net/blog/20240314-doom-emacs/org.png)
232Preview](https://img.cleberg.net/blog/20240314-doom-emacs/org.png) 220
233 221Similar to the markdown section above, ensure that the `~/.doom.d/init.el`
234Similar to the markdown section above, ensure that the 222includes the `org` declaration in the `:lang` section.
235`~/.doom.d/init.el` includes the `org` declaration 223
236in the `:lang` section. 224There are a few hot keys, but a quick search with `SPC : org` shows that there
237 225are 865 possible org-related functions you can run. I won't possibly be able to
238There are a few hot keys, but a quick search with `SPC : org` 226list them all, so I will simply cover a few of the basic commands I use myself.
239shows that there are 865 possible org-related functions you can run. I 227
240won\'t possibly be able to list them all, so I will simply cover a few 228| Doom Hotkey | Function |
241of the basic commands I use myself. 229|----------------|---------------------------------------|
242 230| `SPC m t` | org-todo |
243 Doom Hotkey Function 231| `SPC n t` | org-todo-list |
244 --------------------------- --------------------------------------- 232| `SPC o A` | org-agenda |
245 `SPC m t` org-todo 233| `SPC X` | org-capture |
246 `SPC n t` org-todo-list 234| `SPC m p p` | org-priority |
247 `SPC o A` org-agenda 235| `SPC m d s` | org-schedule |
248 `SPC X` org-capture 236| `TAB` | org-cycle |
249 `SPC m p p` org-priority 237| `SHIFT TAB` | Collapse/open all headings in buffer |
250 `SPC m d s` org-schedule 238| `M-q` | Format/wrap current section |
251 `TAB` org-cycle 239| `M-Left/Right` | Demote/promote current heading |
252 `SHIFT TAB` Collapse/open all headings in buffer 240| `M-Down/Up` | Shift current heading section down/up |
253 `M-q` Format/wrap current section
254 `M-Left/Right` Demote/promote current heading
255 `M-Down/Up` Shift current heading section down/up
256 241
2571. Org-Publish 2421. Org-Publish
258 243
259 Org includes a [publishing management 244 Org includes a [publishing management
260 system](https://orgmode.org/manual/Publishing.html) by default that 245 system](https://orgmode.org/manual/Publishing.html) by default that allows
261 allows you to export org files to Org, iCalendar, HTML, LaTex, 246 you to export org files to Org, iCalendar, HTML, LaTex, Markdown, ODT, and
262 Markdown, ODT, and Plain Text. Most of these can be exported into 247 Plain Text. Most of these can be exported into another buffer and opened, or
263 another buffer and opened, or simply to an external file. 248 simply to an external file.
264 249
265 While inside an org file, simply run `SPC m e` or 250 While inside an org file, simply run `SPC m e` or `M-x org-export-dispatch`
266 `M-x org-export-dispatch` to open the export menu. This 251 to open the export menu. This menu will show all options and ask you to
267 menu will show all options and ask you to select an option. If you 252 select an option. If you want to export to HTML, simply press `h` and then
268 want to export to HTML, simply press `h` and then 253 `H` (As HTML buffer), `h` (As HTML file), or `o` (As HTML file and open).
269 `H` (As HTML buffer), `h` (As HTML file), or
270 `o` (As HTML file and open).
271 254
2722. Projects 2552. Projects
273 256
274 Some publishing options are easier with a defined project in Emacs. 257 Some publishing options are easier with a defined project in Emacs. To
275 To create a project within Emacs, I use two methods: 258 create a project within Emacs, I use two methods:
276 259
277 1. Add the project via the projectile command `SPC p a`. 260 1. Add the project via the projectile command `SPC p a`. Does not always
278 Does not always work for me. 261 work for me.
279 2. Add an empty `.projectile` file in the project root. 262 2. Add an empty `.projectile` file in the project root.
280 263
281 Once a project has been created, you can create custom publishing 264 Once a project has been created, you can create custom publishing actions
282 actions within your `~/.doom.d/config.el` file. For 265 within your `~/.doom.d/config.el` file. For example, here's a test project
283 example, here\'s a test project I created to try and convert this 266 I created to try and convert this blog to org-mode recently.
284 blog to org-mode recently.
285 267
286 ```lisp 268 ```lisp
287 ;; org-publish 269 ;; org-publish
@@ -352,11 +334,10 @@ of the basic commands I use myself.
352 334
353## General Thoughts 335## General Thoughts
354 336
355I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely 337I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely continue to
356continue to use it as my main editor for the time being. Org-Mode is 338use it as my main editor for the time being. Org-Mode is certainly the largest
357certainly the largest factor here, as I far prefer it over Markdown due 339factor here, as I far prefer it over Markdown due to its inherent features and
358to its inherent features and detailed markup options. However, working 340detailed markup options. However, working with org-mode on iOS has been a pain
359with org-mode on iOS has been a pain and I will have to see if there\'s 341and I will have to see if there's an easier way to resolve those issues or if
360an easier way to resolve those issues or if going back to separate 342going back to separate Markdown, Reminders, and Calendar apps is easier to work
361Markdown, Reminders, and Calendar apps is easier to work with than an 343with than an all-in-one org solution.
362all-in-one org solution.
content/blog/2024-03-15-self-hosting-ddns-updater.md +51 −63
@@ -8,25 +8,22 @@ draft = false
8![DDNS Updater Web 8![DDNS Updater Web
9View](https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png) 9View](https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png)
10 10
11[DDNS Updater](https://github.com/qdm12/ddns-updater) is a program to 11[DDNS Updater](https://github.com/qdm12/ddns-updater) is a program to keep DNS A
12keep DNS A and/or AAAA records updated for multiple DNS providers. 12and/or AAAA records updated for multiple DNS providers.
13 13
14If you\'ve read any of my other posts, you\'ll notice that I have been 14If you've read any of my other posts, you'll notice that I have been searching
15searching for and using a few different DDNS updating solutions for 15for and using a few different DDNS updating solutions for years. You'll also
16years. You\'ll also notice that I love any projects that offer a Docker 16notice that I love any projects that offer a Docker Compose solution.
17Compose solution.
18 17
19Luckily, DDNS Upater fits both of these preferences. 18Luckily, DDNS Upater fits both of these preferences.
20 19
21## Installation 20## Installation
22 21
23To get started, always make sure to review the project\'s 22To get started, always make sure to review the project's
24[README](https://github.com/qdm12/ddns-updater/blob/master/README.md). 23[README](https://github.com/qdm12/ddns-updater/blob/master/README.md). I'll be
25I\'ll be documenting my steps below, but they may have changed by the 24documenting my steps below, but they may have changed by the time you read this.
26time you read this.
27 25
28The first step is to set up the directories and files required for the 26The first step is to set up the directories and files required for the project.
29project.
30 27
31```sh 28```sh
32mkdir ~/ddns-updater 29mkdir ~/ddns-updater
@@ -36,46 +33,38 @@ touch ~/ddns-updater/data/config.json
36 33
37### Configuration 34### Configuration
38 35
39The main configuration you need to update is the 36The main configuration you need to update is the `data/config.json` file. There
40`data/config.json` file. There is a large list of supported 37is a large list of supported providers in the README, but I'm going to use
41providers in the README, but I\'m going to use Cloudflare in this 38Cloudflare in this example.
42example.
43 39
44```sh 40```sh
45nano ~/ddns-updater/data/config.json 41nano ~/ddns-updater/data/config.json
46``` 42```
47 43
48When setting up the configuration for Cloudflare, you\'ll need the 44When setting up the configuration for Cloudflare, you'll need the following:
49following: 45
50 46- Required Parameters
51- Required Parameters 47 - `"zone_identifier"` is the Zone ID of your site from the domain overview
52 - `"zone_identifier"` is the Zone ID of your site from 48 page
53 the domain overview page 49 - `"host"` is your host and can be `"@"`, a subdomain or the wildcard `"*"`.
54 - `"host"` is your host and can be `"@"`, a 50 See [this issue comment for
55 subdomain or the wildcard `"*"`. See [this issue 51 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949).
56 comment for 52 - `"ttl"` integer value for record TTL in seconds (specify 1 for automatic)
57 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949). 53 - One of the following ([how to find API
58 - `"ttl"` integer value for record TTL in seconds 54 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)):
59 (specify 1 for automatic) 55 - Email `"email"` and Global API Key `"key"`
60 - One of the following ([how to find API 56 - User service key `"user_service_key"`
61 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)): 57 - API Token `"token"`, configured with DNS edit permissions for your DNS
62 - Email `"email"` and Global API Key 58 name's zone
63 `"key"` 59- Optional Parameters
64 - User service key `"user_service_key"` 60 - `"proxied"` can be set to `true` to use the proxy services of Cloudflare
65 - API Token `"token"`, configured with DNS edit 61 - `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or
66 permissions for your DNS name\'s zone 62 `ipv4 or ipv6` (update one of the two, depending on the public ip
67- Optional Parameters 63 found). It defaults to `ipv4 or ipv6`.
68 - `"proxied"` can be set to `true` to use 64 - `"ipv6_suffix"` is the IPv6 interface identifier suffix to use. It can be
69 the proxy services of Cloudflare 65 for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults
70 - `"ip_version"` can be `ipv4` (A records), 66 to no suffix and the raw public IPv6 address obtained is used in the
71 or `ipv6` (AAAA records) or 67 record updating.
72 `ipv4 or ipv6` (update one of the two, depending on
73 the public ip found). It defaults to `ipv4 or ipv6`.
74 - `"ipv6_suffix"` is the IPv6 interface identifier
75 suffix to use. It can be for example
76 `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it
77 defaults to no suffix and the raw public IPv6 address obtained
78 is used in the record updating.
79 68
80``` conf 69``` conf
81{ 70{
@@ -95,8 +84,8 @@ following:
95} 84}
96``` 85```
97 86
98Once you have configured the provider of your choice, correct the file 87Once you have configured the provider of your choice, correct the file and
99and directory permissions and ownership. 88directory permissions and ownership.
100 89
101```sh 90```sh
102cd ~/ddns_updater 91cd ~/ddns_updater
@@ -110,8 +99,8 @@ chmod 400 data/config.json
110 99
111### Docker Compose 100### Docker Compose
112 101
113After creating the project structure, let\'s create the 102After creating the project structure, let's create the `docker-compose.yml`
114`docker-compose.yml` file. 103file.
115 104
116```sh 105```sh
117nano ~/ddns_-pdater/docker-compose.yml 106nano ~/ddns_-pdater/docker-compose.yml
@@ -155,22 +144,22 @@ services:
155 restart: always 144 restart: always
156``` 145```
157 146
158After configuring your preferences in the 147After configuring your preferences in the `docker-compose.yml`, launch the
159`docker-compose.yml`, launch the container. 148container.
160 149
161```sh 150```sh
162cd ~/ddns-updater 151cd ~/ddns-updater
163sudo docker-compose up -d 152sudo docker-compose up -d
164``` 153```
165 154
166If you\'ve launched this on your local machine, you can launch 155If you've launched this on your local machine, you can launch `localhost:8097`
167`localhost:8097` in your browser to see the results. 156in your browser to see the results.
168 157
169### Nginx Reverse Proxy 158### Nginx Reverse Proxy
170 159
171If you launched this service on a server, other machine, or just want to 160If you launched this service on a server, other machine, or just want to access
172access it remotely via a domain name, you can use Nginx as a reverse 161it remotely via a domain name, you can use Nginx as a reverse proxy to expose
173proxy to expose the service publicly. 162the service publicly.
174 163
175Start by creating the Nginx configuration file. 164Start by creating the Nginx configuration file.
176 165
@@ -178,7 +167,7 @@ Start by creating the Nginx configuration file.
178sudo nano /etc/nginx/sites-available/ddns 167sudo nano /etc/nginx/sites-available/ddns
179``` 168```
180 169
181Here\'s a basic example that should work properly. 170Here's a basic example that should work properly.
182 171
183``` conf 172``` conf
184server { 173server {
@@ -198,8 +187,8 @@ server {
198} 187}
199``` 188```
200 189
201Here\'s a full example that uses my Authelia authentication service to 190Here's a full example that uses my Authelia authentication service to require
202require authentication before someone can access the web page. 191authentication before someone can access the web page.
203 192
204``` conf 193``` conf
205server { 194server {
@@ -317,5 +306,4 @@ sudo ln -s /etc/nginx/sites-available/ddns /etc/nginx/sites-enabled/ddns
317sudo systemctl restart nginx.service 306sudo systemctl restart nginx.service
318``` 307```
319 308
320Your ddns-updater service will now be available via 309Your ddns-updater service will now be available via `ddns.example.com`!
321`ddns.example.com`!
content/blog/2024-03-29-org-blog.md +60 −72
@@ -5,49 +5,45 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8First and foremost, apologies to those who subscribe via RSS as I know 8First and foremost, apologies to those who subscribe via RSS as I know that my
9that my feed duplicated itself when I moved this blog over to org-mode 9feed duplicated itself when I moved this blog over to org-mode last night.
10last night.
11 10
12This post focuses specifically on the configuration and tools I use to 11This post focuses specifically on the configuration and tools I use to blog from
13blog from Emacs with Org-Mode and does not focus on Emacs or Org-Mode 12Emacs with Org-Mode and does not focus on Emacs or Org-Mode themselves. Refer to
14themselves. Refer to the post I wrote about [Doom Emacs & 13the post I wrote about [Doom Emacs &
15Org-Mode](file:///blog/doom-emacs-org-mode.html) for more information 14Org-Mode](file:///blog/doom-emacs-org-mode.html) for more information about my
16about my base Emacs configuration. 15base Emacs configuration.
17 16
18# Weblorg 17# Weblorg
19 18
20The first step in blogging with Org-Mode is to choose a method to 19The first step in blogging with Org-Mode is to choose a method to convert the
21convert the source files to HTML and publish them. The Worg site 20source files to HTML and publish them. The Worg site maintains a nice list of
22maintains a nice list of [Blogs and Wikis with 21[Blogs and Wikis with Org](https://orgmode.org/worg/org-blog-wiki.html), but the
23Org](https://orgmode.org/worg/org-blog-wiki.html), but the tools are 22tools are inevitably different and opinionated, so you'll need to find what
24inevitably different and opinionated, so you\'ll need to find what works 23works for you.
25for you. 24
26 25I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and the
27I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and 26native org-publish functions before finally settling on Weblorg. For one reason
28the native org-publish functions before finally settling on Weblorg. For 27or another, the other solutions were a drastic step down from my previous
29one reason or another, the other solutions were a drastic step down from 28workflow that used [Zola](https://www.getzola.org/) with Markdown content.
30my previous workflow that used [Zola](https://www.getzola.org/) with 29
31Markdown content. 30[Weblorg](https://github.com/emacs-love/weblorg) is a static site generator for
32 31[org-mode](https://orgmode.org/), built for use within
33[Weblorg](https://github.com/emacs-love/weblorg) is a static site 32[Emacs](https://www.gnu.org/software/emacs/). Since it's written in Emacs Lisp,
34generator for [org-mode](https://orgmode.org/), built for use within 33there's no need to install other languages or frameworks to get started. More
35[Emacs](https://www.gnu.org/software/emacs/). Since it\'s written in 34than that, you can write in any editor you please and simply invoke the Emacs
36Emacs Lisp, there\'s no need to install other languages or frameworks to 35build process with the `--script` parameter instead of requiring you to blog
37get started. More than that, you can write in any editor you please and 36inside Emacs.
38simply invoke the Emacs build process with the `--script`
39parameter instead of requiring you to blog inside Emacs.
40 37
41## Installation 38## Installation
42 39
43The [Getting Started](https://emacs.love/weblorg/doc/index.html) page 40The [Getting Started](https://emacs.love/weblorg/doc/index.html) page details
44details broad installation requirements. I am using Doom Emacs on macOS, 41broad installation requirements. I am using Doom Emacs on macOS, which requires
45which requires you to add the package to the 42you to add the package to the `~/.doom.d/packages.el` file and configure the
46`~/.doom.d/packages.el` file and configure the
47`publish.el` file slightly differently. 43`publish.el` file slightly differently.
48 44
49To start, add the `htmlize` and `weblorg` packages 45To start, add the `htmlize` and `weblorg` packages to Doom, sync the changes,
50to Doom, sync the changes, and reload. 46and reload.
51 47
52```sh 48```sh
53nano ~/.doom.d/packages.el 49nano ~/.doom.d/packages.el
@@ -62,23 +58,20 @@ nano ~/.doom.d/packages.el
62doom sync 58doom sync
63``` 59```
64 60
65Either re-open Emacs or hit `SPC h r r` to reload the 61Either re-open Emacs or hit `SPC h r r` to reload the changes.
66changes.
67 62
68## Configuration 63## Configuration
69 64
70Now that I\'ve installed weblorg, I need to configure the project. I\'ll 65Now that I've installed weblorg, I need to configure the project. I'll start
71start by navigating to my site\'s source code and creating a 66by navigating to my site's source code and creating a `publish.el` file.
72`publish.el` file.
73 67
74```sh 68```sh
75cd ~/Source/cleberg.net && nano publish.el 69cd ~/Source/cleberg.net && nano publish.el
76``` 70```
77 71
78Since I\'m using Doom, Emacs will not automatically load the packages I 72Since I'm using Doom, Emacs will not automatically load the packages I need
79need later in the build process. To compensate, my 73later in the build process. To compensate, my `publish.el` file needs to
80`publish.el` file needs to explicitly tell Emacs where Doom 74explicitly tell Emacs where Doom stores the `htmlize`, `weblorg`, and
81stores the `htmlize`, `weblorg`, and
82`templatel` packages. 75`templatel` packages.
83 76
84```lisp 77```lisp
@@ -189,12 +182,10 @@ stores the `htmlize`, `weblorg`, and
189## Structure 182## Structure
190 183
191The project structure for weblorg is highly customizable and the main 184The project structure for weblorg is highly customizable and the main
192restriction is that the `publish.el` file must point to the 185restriction is that the `publish.el` file must point to the correct paths.
193correct paths.
194 186
195For my blog, I prefer to keep the blog content out of the top-level 187For my blog, I prefer to keep the blog content out of the top-level directory.
196directory. This results in the following structure (shortened for 188This results in the following structure (shortened for brevity):
197brevity):
198 189
199``` txt 190``` txt
200.build/ 191.build/
@@ -222,17 +213,17 @@ build.sh
222publish.el 213publish.el
223``` 214```
224 215
225This is simply my preferred structure and you can alter it to fit your 216This is simply my preferred structure and you can alter it to fit your needs.
226needs. The key here really is that you can customize at will, as long as 217The key here really is that you can customize at will, as long as the
227the `publish.el` file matches. 218`publish.el` file matches.
228 219
229## Build & Deploy 220## Build & Deploy
230 221
231Once you\'re content with the status of the project, you\'re ready to 222Once you're content with the status of the project, you're ready to build and
232build and deploy the blog. 223deploy the blog.
233 224
234My process utilizes a `build.sh` script that combines the 225My process utilizes a `build.sh` script that combines the steps I take every
235steps I take every time. 226time.
236 227
237```sh 228```sh
238touch build.sh && chmod +x build.sh && nano build.sh 229touch build.sh && chmod +x build.sh && nano build.sh
@@ -240,14 +231,12 @@ touch build.sh && chmod +x build.sh && nano build.sh
240 231
241Within this script, I do the following: 232Within this script, I do the following:
242 233
2431. Remove any files within the `.build` directory that I use 2341. Remove any files within the `.build` directory that I use to store published
244 to store published files. 235 files.
2452. Set the environment variable to `prod` to ensure the 2362. Set the environment variable to `prod` to ensure the `base_url` matches my
246 `base_url` matches my configuration in 237 configuration in `publish.el`.
247 `publish.el`. 2383. Build the site with Emacs & `publish.el`.
2483. Build the site with Emacs & `publish.el`. 2394. Use `scp` to copy files to my site's public directory on my server.
2494. Use `scp` to copy files to my site\'s public directory on
250 my server.
251 240
252```sh 241```sh
253rm -rf .build/* && \ 242rm -rf .build/* && \
@@ -259,13 +248,12 @@ scp -r .build/* ubuntu:/var/www/cleberg.net/
259 248
260My only current complaints are: 249My only current complaints are:
261 250
2621. Errors messages are not helpful. It takes work to determine what the 2511. Errors messages are not helpful. It takes work to determine what the error is
263 error is and where it\'s coming from. I generally have to sit and 252 and where it's coming from. I generally have to sit and watch the build
264 watch the build process to see the file that weblorg pubslishes 253 process to see the file that weblorg pubslishes right before the error
265 right before the error occurred. 254 occurred.
2662. The build process re-builds every single file on each run, which 2552. The build process re-builds every single file on each run, which takes a long
267 takes a long time for a blog of my size. See below for the last time 256 time for a blog of my size. See below for the last time I measured.
268 I measured.
269 257
270```sh 258```sh
271> time ./build.sh 259> time ./build.sh
@@ -273,5 +261,5 @@ My only current complaints are:
273./build.sh 35.46s user 0.59s system 85% cpu 41.965 total 261./build.sh 35.46s user 0.59s system 85% cpu 41.965 total
274``` 262```
275 263
276Overall, I have thoroughly enjoyed using weblog and will continue to use 264Overall, I have thoroughly enjoyed using weblog and will continue to use it
277it going forward until I find something better. 265going forward until I find something better.
content/blog/2024-04-06-convert-onenote-to-markdown.md +46 −54
@@ -5,25 +5,23 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8If you\'re looking to convert your OneNote content to another format, 8If you're looking to convert your OneNote content to another format, such as
9such as Markdown or Org-Mode, you\'re in luck. I use a solution that 9Markdown or Org-Mode, you're in luck. I use a solution that doesn't require
10doesn\'t require other programs, such as Evernote or Notion. Personally, 10other programs, such as Evernote or Notion. Personally, I used this solution on
11I used this solution on a managed corporate laptop that doesn\'t allow 11a managed corporate laptop that doesn't allow installation of other programs
12installation of other programs like these. 12like these.
13 13
14This solution uses OneNote and Pandoc on Windows 10. 14This solution uses OneNote and Pandoc on Windows 10.
15 15
16# Export OneNote Content to Word 16# Export OneNote Content to Word
17 17
18To start, export any pages or tabs from OneNote to the Word format 18To start, export any pages or tabs from OneNote to the Word format (`.docx`):
19(`.docx`):
20 19
211. Open OneNote desktop. 201. Open OneNote desktop.
222. Select `File` and then `Export`. 212. Select `File` and then `Export`.
233. Select the scope of content to export, such as `Tab` or 223. Select the scope of content to export, such as `Tab` or `Page`.
24 `Page`. 234. Name and save the file in an easy to remember location. I recommend your
254. Name and save the file in an easy to remember location. I recommend 24 Downloads or Desktop folder.
26 your Downloads or Desktop folder.
27 25
28See below for a visual walkthrough of the export process. 26See below for a visual walkthrough of the export process.
29 27
@@ -39,46 +37,42 @@ Document](https://img.cleberg.net/blog/20240406-convert-onenote-to-markdown/word
39# Download Pandoc 37# Download Pandoc
40 38
41Start by downloading Pandoc from their [GitHub 39Start by downloading Pandoc from their [GitHub
42releases](https://github.com/jgm/pandoc/releases) page. I cannot install 40releases](https://github.com/jgm/pandoc/releases) page. I cannot install `.msi`
43`.msi` files on my corporate laptop, so I downloaded the 41files on my corporate laptop, so I downloaded the
44`pandoc-3.1.12.3-windows-x86_64.zip` file, which contains a 42`pandoc-3.1.12.3-windows-x86_64.zip` file, which contains a simple `.exe` file
45simple `.exe` file that you do not need to install - you will 43that you do not need to install - you will simply run it from the command line
46simply run it from the command line below. 44below.
47 45
48Once downloaded, unzip the archive and move the `pandoc.exe` 46Once downloaded, unzip the archive and move the `pandoc.exe` file to the same
49file to the same folder where your Word documents were saved above. If 47folder where your Word documents were saved above. If you prefer, you can move
50you prefer, you can move this file to an easier location, such as 48this file to an easier location, such as `C:\Users\youruser\Downloads`.
51`C:\Users\youruser\Downloads`.
52 49
53# Convert Word to Markdown 50# Convert Word to Markdown
54 51
55In this example, I will be converting the Word documents to Markdown, 52In this example, I will be converting the Word documents to Markdown, but Pandoc
56but Pandoc supports [a ton of different formats for 53supports [a ton of different formats for
57conversion](https://github.com/jgm/pandoc?tab=readme-ov-file#the-universal-markup-converter). 54conversion](https://github.com/jgm/pandoc?tab=readme-ov-file#the-universal-markup-converter).
58Choose the format you prefer and then modify the following commands as 55Choose the format you prefer and then modify the following commands as needed.
59needed.
60 56
61To perform the conversion, open the Command Prompt. If you can\'t find 57To perform the conversion, open the Command Prompt. If you can't find it, open
62it, open the start menu and search for it. 58the start menu and search for it.
63 59
64Within the command prompt, navigate to the directory where you stored 60Within the command prompt, navigate to the directory where you stored the
65the `pandoc.exe` file and the Word documents. 61`pandoc.exe` file and the Word documents.
66 62
67```ps1 63```ps1
68cd "C:\Users\yourusername\Downloads" 64cd "C:\Users\yourusername\Downloads"
69``` 65```
70 66
71You can verify that you\'re in the correct directory with the 67You can verify that you're in the correct directory with the `dir` command.
72`dir` command.
73 68
74```ps1 69```ps1
75dir 70dir
76``` 71```
77 72
78Once you have verified that you have the command prompt open in the 73Once you have verified that you have the command prompt open in the correct
79correct directory with the `pandoc.exe` and the Word 74directory with the `pandoc.exe` and the Word documents, you can run the
80documents, you can run the following loop to convert all Word documents 75following loop to convert all Word documents to Markdown.
81to Markdown.
82 76
83```ps1 77```ps1
84for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f.md") 78for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f.md")
@@ -86,29 +80,27 @@ for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f.
86 80
87This loop will perform the following actions: 81This loop will perform the following actions:
88 82
891. Find all documents matching the pattern `*.docx`, which 831. Find all documents matching the pattern `*.docx`, which means all Word
90 means all Word documents ending with that file extension. 84 documents ending with that file extension.
912. Iterate through all files found in step 1. 852. Iterate through all files found in step 1.
923. For each file, perform the pandoc command. 863. For each file, perform the pandoc command.
934. Within the pandoc command, `--extract-media` saves all 874. Within the pandoc command, `--extract-media` saves all media found in the
94 media found in the files to the current folder, with pandoc 88 files to the current folder, with pandoc automatically creating a `media`
95 automatically creating a `media` subfolder to hold all 89 subfolder to hold all images.
96 images. 905. Within the pandoc command, `--wrap=preserve` will attempt to prseerve the
975. Within the pandoc command, `--wrap=preserve` will attempt 91 wrapping from the source document.
98 to prseerve the wrapping from the source document. 926. Within the pandoc command, the final step is to specify the output path with
996. Within the pandoc command, the final step is to specify the output 93 `-o`. This option adds the `.md` file extension to recognize the output files
100 path with `-o`. This option adds the `.md` 94 as Markdown files.
101 file extension to recognize the output files as Markdown files.
102 95
103![Pandoc 96![Pandoc
104Conversion](https://img.cleberg.net/blog/20240406-convert-onenote-to-markdown/command.png) 97Conversion](https://img.cleberg.net/blog/20240406-convert-onenote-to-markdown/command.png)
105 98
106If you want to export to another format, simply specify the 99If you want to export to another format, simply specify the `-f=`/`--from=` and
107`-f=`/`--from=` and `-t=`/`--to=` options. 100`-t=`/`--to=` options.
108 101
109For example, you can convert the Word document to org-mode. You can also 102For example, you can convert the Word document to org-mode. You can also convert
110convert to one format and subsequently convert to other formats as 103to one format and subsequently convert to other formats as needed.
111needed.
112 104
113```ps1 105```ps1
114pandoc.exe -f docx -t org file.docx 106pandoc.exe -f docx -t org file.docx
content/blog/2024-04-08-docker-local-web-server.md +49 −58
@@ -5,56 +5,52 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8When developing websites locally, I often use a simple Python web server 8When developing websites locally, I often use a simple Python web server to
9to observe the changes. 9observe the changes.
10 10
11```sh 11```sh
12python3 -m http.server 12python3 -m http.server
13``` 13```
14 14
15However, this approach has its limitations. For example, this approach 15However, this approach has its limitations. For example, this approach does not
16does not enable logging or access controls. You also need to customize 16enable logging or access controls. You also need to customize `SimpleHTTPServer`
17`SimpleHTTPServer` if you have advanced needs from your web 17if you have advanced needs from your web server.
18server.
19 18
20So, I went to find an alternative that is almost as easy and far more 19So, I went to find an alternative that is almost as easy and far more extensible
21extensible and found Docker Desktop to be a suitable replacement. 20and found Docker Desktop to be a suitable replacement.
22 21
23# Docker Desktop 22# Docker Desktop
24 23
25## Installation 24## Installation
26 25
27[Docker Desktop](https://www.docker.com/products/docker-desktop/) is a 26[Docker Desktop](https://www.docker.com/products/docker-desktop/) is a desktop
28desktop GUI for the phenomenal Docker container software. This allows 27GUI for the phenomenal Docker container software. This allows you to manage
29you to manage containers, images, volumes, environments, and extensions 28containers, images, volumes, environments, and extensions via an easy-to-use
30via an easy-to-use GUI. 29GUI.
31 30
32To install, open the link above and click the `Download` 31To install, open the link above and click the `Download` button for your
33button for your platform. I\'m going through this process on an M2 32platform. I'm going through this process on an M2 Macbook, so I downloaded the
34Macbook, so I downloaded the Mac - Apple Chip version. 33Mac - Apple Chip version.
35 34
36Open the installer and follow the installation process until the 35Open the installer and follow the installation process until the application
37application finishes the installation process. 36finishes the installation process.
38 37
39![Docker Desktop on 38![Docker Desktop on
40macOS](https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png) 39macOS](https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png)
41 40
42## Creating an Nginx Container 41## Creating an Nginx Container
43 42
44I prefer to use the command line to create containers, so the following 43I prefer to use the command line to create containers, so the following commands
45commands will be input via the terminal. 44will be input via the terminal.
46 45
47The following command will create a container, using the 46The following command will create a container, using the `nginx` image:
48`nginx` image:
49 47
501. `-d`: Run this container as a daemon (detach) 481. `-d`: Run this container as a daemon (detach)
512. `-p`: Allocate a port in the format 492. `-p`: Allocate a port in the format `<external>:<internal>`
52 `<external>:<internal>` 503. `-i`: Keep STDIN open even if not attached
533. `-i`: Keep STDIN open even if not attached 514. `-t`: Allocate a pseudo-TTY
544. `-t`: Allocate a pseudo-TTY 525. `-p`: Allocate a port in the format `<external>:<internal>`
555. `-p`: Allocate a port in the format 536. `--rm`: Remove the container once it's done running
56 `<external>:<internal>`
576. `--rm`: Remove the container once it\'s done running
58 54
59```sh 55```sh
60docker run -it --rm -d -p 8000:80 --name web nginx 56docker run -it --rm -d -p 8000:80 --name web nginx
@@ -67,27 +63,26 @@ Container](https://img.cleberg.net/blog/20240408-docker-local-web-server/default
67 63
68## Customizing the Nginx Container 64## Customizing the Nginx Container
69 65
70Now that I have a container running the Nginx web server, I need to link 66Now that I have a container running the Nginx web server, I need to link some
71some volumes so that I can modify the site configuration and provide the 67volumes so that I can modify the site configuration and provide the web files to
72web files to serve. 68serve.
73 69
74Let\'s start with the new command, which adds two volumes: 70Let's start with the new command, which adds two volumes:
75 71
761. `<your_content>:/usr/share/nginx/html`: This is the 721. `<your_content>:/usr/share/nginx/html`: This is the directory where you will
77 directory where you will provide the web pages for the server to 73 provide the web pages for the server to serve.
78 serve. 742. `<your_config>:/etc/nginx/conf.d/default.conf`: This is the Nginx
792. `<your_config>:/etc/nginx/conf.d/default.conf`: This is 75 configuration file for your site.
80 the Nginx configuration file for your site.
81 76
82To see the updates, you can delete the previous container in the GUI or 77To see the updates, you can delete the previous container in the GUI or run
83run `docker stop web` to stop the container. Once stopped, 78`docker stop web` to stop the container. Once stopped, you can run the new
84you can run the new `docker run` command below. 79`docker run` command below.
85 80
86```sh 81```sh
87docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/share/nginx/html -v ~/Source/cleberg.net/nginx-config.conf:/etc/nginx/conf.d/default.conf nginx 82docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/share/nginx/html -v ~/Source/cleberg.net/nginx-config.conf:/etc/nginx/conf.d/default.conf nginx
88``` 83```
89 84
90Here\'s an example of my development configuration file. 85Here's an example of my development configuration file.
91 86
92``` conf 87``` conf
93# nginx-config.conf 88# nginx-config.conf
@@ -114,19 +109,16 @@ server {
114 109
115# Customizing Deployment Actions 110# Customizing Deployment Actions
116 111
117I am currently blogging with [weblorg](https://emacs.love/weblorg/), 112I am currently blogging with [weblorg](https://emacs.love/weblorg/), which uses
118which uses a custom `publish.el` file to build the static 113a custom `publish.el` file to build the static site. Within this file, I have
119site. Within this file, I have configured my deployment process to check 114configured my deployment process to check for the `ENV` variable in thesh and if
120for the `ENV` variable in thesh and if it\'s set to 115it's set to `prod`, the script will set the base URLs to `https://cleberg.net`.
121`prod`, the script will set the base URLs to 116If not, it sets the base URLs to `localhost:8000` (which matches the port used
122`https://cleberg.net`. If not, it sets the base URLs to 117in the container above).
123`localhost:8000` (which matches the port used in the
124container above).
125 118
126Therefore, I have modified my `build.sh` script to build with 119Therefore, I have modified my `build.sh` script to build with `localhost` URLs
127`localhost` URLs if `ENV` is not set to 120if `ENV` is not set to `prod`. It also prevents the build process from sending
128`prod`. It also prevents the build process from sending the 121the built files to the production web server.
129built files to the production web server.
130 122
131```sh 123```sh
132#!/bin/bash 124#!/bin/bash
@@ -143,7 +135,6 @@ else
143fi 135fi
144``` 136```
145 137
146You can modify the container in numerous ways and this approach allows 138You can modify the container in numerous ways and this approach allows you to
147you to create complex scenarios for your web development purposes. I 139create complex scenarios for your web development purposes. I highly recommend
148highly recommend switching over to a container-based approach for 140switching over to a container-based approach for simple, local web development.
149simple, local web development.
content/blog/2024-04-18-mu4e.md +45 −54
@@ -6,19 +6,18 @@ draft = false
6+++ 6+++
7 7
8This post was heavily inspired by [Email setup in Emacs with Mu4e on 8This post was heavily inspired by [Email setup in Emacs with Mu4e on
9macOS](https://macowners.club/posts/email-emacs-mu4e-macos/), but with 9macOS](https://macowners.club/posts/email-emacs-mu4e-macos/), but with my own
10my own tweaks for a single-account configuration and some Doom-specific 10tweaks for a single-account configuration and some Doom-specific configurations.
11configurations.
12 11
13# Overview 12# Overview
14 13
15[Mu4e](https://github.com/emacsmirror/mu4e) is an Emacs-based email 14[Mu4e](https://github.com/emacsmirror/mu4e) is an Emacs-based email client based
16client based on [mu](https://www.djcbsoftware.nl/code/mu/), an indexer 15on [mu](https://www.djcbsoftware.nl/code/mu/), an indexer that stores email in
17that stores email in the Maildir format. 16the Maildir format.
18 17
19This blog post covers the installation of Mu4e in Doom Emacs on macOS. 18This blog post covers the installation of Mu4e in Doom Emacs on macOS. This
20This guide should be very similar to GNU Emacs and Linux-based systems, 19guide should be very similar to GNU Emacs and Linux-based systems, with a few
21with a few tweaks required in the various configuration files. 20tweaks required in the various configuration files.
22 21
23# Installation 22# Installation
24 23
@@ -36,33 +35,32 @@ mkdir ~/.maildir/certificates # used to store system root certificates
36 35
37### Store Email Account Passwords in macOS Keychain 36### Store Email Account Passwords in macOS Keychain
38 37
39Next, I will be using the macOS Keychain to store my email account 38Next, I will be using the macOS Keychain to store my email account passwords
40passwords using the command below. 39using the command below.
41 40
42```sh 41```sh
43security add-generic-password -s mu4e-example -a you@example.com -w 42security add-generic-password -s mu4e-example -a you@example.com -w
44``` 43```
45 44
46This will prompt you to input your password twice to confirm. Keep the 45This will prompt you to input your password twice to confirm. Keep the
47`mu4e-example` name in mind, as you will need to reference it 46`mu4e-example` name in mind, as you will need to reference it later in the IMAP
48later in the IMAP and SMTP configuration files. 47and SMTP configuration files.
49 48
50### Store Root Certificates 49### Store Root Certificates
51 50
52In order to use IMAP and SMTP, we need to provide certificates to the 51In order to use IMAP and SMTP, we need to provide certificates to the local
53local services. We will use the macOS defaults for this. 52services. We will use the macOS defaults for this.
54 53
551. Open `Keychain Access.app`. 541. Open `Keychain Access.app`.
562. Select `System Roots` in the sidebar. 552. Select `System Roots` in the sidebar.
573. Select all items with `CMD + a`. 563. Select all items with `CMD + a`.
584. Export selected items with `SHIFT + CMD + a` to the file 574. Export selected items with `SHIFT + CMD + a` to the file
59 `~/.maildir/certificates/root-certificates.pem`. 58 `~/.maildir/certificates/root-certificates.pem`.
60 59
61### Install Dependencies 60### Install Dependencies
62 61
63Install `mbsync` (via `isync`) to fetch emails via 62Install `mbsync` (via `isync`) to fetch emails via IMAP, `mu` to index emails,
64IMAP, `mu` to index emails, and `msmtp` to send 63and `msmtp` to send emails via SMTP.
65emails via SMTP.
66 64
67```sh 65```sh
68brew install mu isync msmtp 66brew install mu isync msmtp
@@ -76,9 +74,8 @@ Within Doom Emacs, we can install Mu4e by enabling the package.
76nano ~/.doom.d/init.el 74nano ~/.doom.d/init.el
77``` 75```
78 76
79In this file, uncomment the `mu4e` line within the 77In this file, uncomment the `mu4e` line within the `:email` section. You can
80`:email` section. You can also enable the `+org` 78also enable the `+org` and `+gmail` options if you prefer.
81and `+gmail` options if you prefer.
82 79
83```lisp 80```lisp
84(doom! :input 81(doom! :input
@@ -92,9 +89,9 @@ and `+gmail` options if you prefer.
92 89
93# Configuration 90# Configuration
94 91
95As an overall suggestion, I create the following configuration files in 92As an overall suggestion, I create the following configuration files in the
96the `~/.maildir` directory and using symlinks to their proper 93`~/.maildir` directory and using symlinks to their proper locations so that I
97locations so that I can backup and restore these files easily. 94can backup and restore these files easily.
98 95
99```sh 96```sh
100touch ~/.maildir/.mbsyncrc && \ 97touch ~/.maildir/.mbsyncrc && \
@@ -103,14 +100,13 @@ ln -s /Users/username/.maildir/.mbsyncrc /Users/username/.mbsyncrc && \
103ln -s /Users/username/.maildir/.msmtprc /Users/username/.msmtprc 100ln -s /Users/username/.maildir/.msmtprc /Users/username/.msmtprc
104``` 101```
105 102
106You can also create these files in your home directory and skip the 103You can also create these files in your home directory and skip the symlinking
107symlinking process above. 104process above.
108 105
109## IMAP 106## IMAP
110 107
111Next, let\'s configure `mbsync` in the file created above. 108Next, let's configure `mbsync` in the file created above. Paste the following
112Paste the following information and customize it to match your mail 109information and customize it to match your mail provider's information.
113provider\'s information.
114 110
115```sh 111```sh
116nano ~/.maildir/.mbsyncrc 112nano ~/.maildir/.mbsyncrc
@@ -146,9 +142,8 @@ SyncState *
146 142
147## SMTP 143## SMTP
148 144
149Next, let\'s configured `msmtprc` in the file created above. 145Next, let's configured `msmtprc` in the file created above. Paste the following
150Paste the following information and customize it to match your mail 146information and customize it to match your mail provider's information.
151provider\'s information.
152 147
153```sh 148```sh
154nano ~/.maildir/.msmtprc 149nano ~/.maildir/.msmtprc
@@ -180,8 +175,8 @@ account default : startmail
180 175
181## Doom Emacs 176## Doom Emacs
182 177
183Finally, we need to configure Doom Emacs to use the proper packages and 178Finally, we need to configure Doom Emacs to use the proper packages and set some
184set some variables and functions. 179variables and functions.
185 180
186```sh 181```sh
187nano ~/.doom.d/config.el 182nano ~/.doom.d/config.el
@@ -279,14 +274,12 @@ Be sure to sync Doom to update the current configurations.
279doom sync 274doom sync
280``` 275```
281 276
282If you have Doom open, execute `SPC h r r` to reload the new 277If you have Doom open, execute `SPC h r r` to reload the new configurations.
283configurations.
284 278
285# Initial Sync 279# Initial Sync
286 280
287Once you have configured all of the relevant files, you can perform an 281Once you have configured all of the relevant files, you can perform an initial
288initial sync. Note that you can perform syncing within Mu4e itself afer 282sync. Note that you can perform syncing within Mu4e itself afer this.
289this.
290 283
291```sh 284```sh
292mbsync -aV 285mbsync -aV
@@ -303,21 +296,19 @@ The emails will now to be ready to use!
303 296
304# Screenshots 297# Screenshots
305 298
306You can now launch Doom and open Mu4e with `SPC o m`. You can 299You can now launch Doom and open Mu4e with `SPC o m`. You can also explore the
307also explore the Mu4e options with `SPC : mu4e`. 300Mu4e options with `SPC : mu4e`.
308 301
309The home page shows various options and metdata about the account 302The home page shows various options and metdata about the account you've
310you\'ve opened. 303opened.
311 304
312![Mu4e Home Page](https://img.cleberg.net/blog/20240418-mu4e/mu4e.png) 305![Mu4e Home Page](https://img.cleberg.net/blog/20240418-mu4e/mu4e.png)
313 306
314When composing an email, you can see the metadata fields at the top and 307When composing an email, you can see the metadata fields at the top and compose
315compose the message below the indicator line. 308the message below the indicator line.
316 309
317![Composition 310![Composition Screen](https://img.cleberg.net/blog/20240418-mu4e/draft.png)
318Screen](https://img.cleberg.net/blog/20240418-mu4e/draft.png)
319 311
320When in a folder, you can view emails in a pane and perform actions as 312When in a folder, you can view emails in a pane and perform actions as needed.
321needed.
322 313
323![Inbox](https://img.cleberg.net/blog/20240418-mu4e/inbox.png) 314![Inbox](https://img.cleberg.net/blog/20240418-mu4e/inbox.png)
content/services.md +2 −2
@@ -8,9 +8,9 @@ draft = false
8- [FileArchive](https://files.cleberg.net/) - An interesting file archive 8- [FileArchive](https://files.cleberg.net/) - An interesting file archive
9- [FlashPaper](https://paste.cleberg.net/) - One-time encrypted password/secret sharing 9- [FlashPaper](https://paste.cleberg.net/) - One-time encrypted password/secret sharing
10- [GotHub](https://gh.cleberg.net/) - An alternative front-end for GitHub 10- [GotHub](https://gh.cleberg.net/) - An alternative front-end for GitHub
11- [ifconfig.php](https://ip.cleberg.net/) - A \"whatsmyip\" tool 11- [ifconfig.php](https://ip.cleberg.net/) - A "whatsmyip" tool
12- [Invidious](https://invidious.cleberg.net/) - A YouTube proxy 12- [Invidious](https://invidious.cleberg.net/) - A YouTube proxy
13- [Office](https://office.cleberg.net/) - The world\'s smallest office suite 13- [Office](https://office.cleberg.net/) - The world's smallest office suite
14- [Org-Live](https://org.cleberg.net/) - A basic org-mode editor for the web I built 14- [Org-Live](https://org.cleberg.net/) - A basic org-mode editor for the web I built
15- [SearXNG](https://search.cleberg.net/) - A privacy-respecting, open metasearch engine 15- [SearXNG](https://search.cleberg.net/) - A privacy-respecting, open metasearch engine
16 16
content/wiki/blogroll.md +1 −1
@@ -27,7 +27,7 @@ A list of various plaintext websites and lists.
27 27
28## Webrings 28## Webrings
29 29
30Instead of listing my personal favorites, I\'m just going to drop a link to [brisay's webring list](https://brisray.com/web/webring-list.htm), which contains 237 webrings for a total of 7078 websites, as of 2024-03-15. 30Instead of listing my personal favorites, I'm just going to drop a link to [brisay's webring list](https://brisray.com/web/webring-list.htm), which contains 237 webrings for a total of 7078 websites, as of 2024-03-15.
31 31
32## Everything Else 32## Everything Else
33 33
content/wiki/hardware.md +1 −1
@@ -47,7 +47,7 @@ and quiet as my top priorities.
47 47
48### IoT 48### IoT
49 49
50A collection of mainly smart lights, sensors, and smart appliances. My first preference is to disable all networking for new smart devices or simply not connect internet in the first place (e.g. I never enable internet on my smart TVs). If the smart device requires LAN access, I will connect the device to my guest-restricted IoT network. As a last resort, I will set-up the internet but monitor the DNS lookups via NextDNS and forcibly block any domains I do not want the device to be using. If the device is egregious or shady, I\'ll just sell it and either replace it or live without it. 50A collection of mainly smart lights, sensors, and smart appliances. My first preference is to disable all networking for new smart devices or simply not connect internet in the first place (e.g. I never enable internet on my smart TVs). If the smart device requires LAN access, I will connect the device to my guest-restricted IoT network. As a last resort, I will set-up the internet but monitor the DNS lookups via NextDNS and forcibly block any domains I do not want the device to be using. If the device is egregious or shady, I'll just sell it and either replace it or live without it.
51 51
52- Other Appliances (washer, dryer, humidifier, fans, etc.) 52- Other Appliances (washer, dryer, humidifier, fans, etc.)
53 - [Roomba i7+](https://about.irobot.com/sitecore/content/north-america/irobot-us/home/roomba/i7-series) 53 - [Roomba i7+](https://about.irobot.com/sitecore/content/north-america/irobot-us/home/roomba/i7-series)
content/wiki/ios.md +12 −12
@@ -51,19 +51,19 @@ Here's the baseline I start with:
51- Disable: 51- Disable:
52 - Analytics & Improvements 52 - Analytics & Improvements
53 - Apple Advertising 53 - Apple Advertising
54 - Apple ID \> Sign-In & Security \> Two-Factor Authentication 54 - Apple ID > Sign-In & Security > Two-Factor Authentication
55 - Location Services \> System Services \> Product Improvement 55 - Location Services > System Services > Product Improvement
56 - Tracking \> Allow Apps to Request to Track 56 - Tracking > Allow Apps to Request to Track
57 - Safari \> Advanced \> Privacy Preserving Ad Measurement 57 - Safari > Advanced > Privacy Preserving Ad Measurement
58- Enable: 58- Enable:
59 - Apple ID \> iCloud \> Advanced Data Protection 59 - Apple ID > iCloud > Advanced Data Protection
60 - Apple ID \> Personal Information \> Communication Preferences 60 - Apple ID > Personal Information > Communication Preferences
61 - App Privacy Report 61 - App Privacy Report
62 - Location Services only for Camera, Find My, UDisc, & WiFiman 62 - Location Services only for Camera, Find My, UDisc, & WiFiman
63 (`While Using`) 63 (`While Using`)
64 - Safari \> Prevent Cross-Site Tracking 64 - Safari > Prevent Cross-Site Tracking
65 - Safari \> Hide IP Address 65 - Safari > Hide IP Address
66 - Safari \> Advanced \> Advanced Tracking and Fingerprinting 66 - Safari > Advanced > Advanced Tracking and Fingerprinting
67 Protection 67 Protection
68 68
69## Native Apps 69## Native Apps
@@ -92,7 +92,7 @@ Here's the baseline I start with:
92 92
93### Music 93### Music
94 94
95- [Apple Music](https://apps.apple.com/us/app/apple-music/id1108187390) (`*`) - Apple\'s native music streaming app 95- [Apple Music](https://apps.apple.com/us/app/apple-music/id1108187390) (`*`) - Apple's native music streaming app
96- [Plexamp](https://apps.apple.com/us/app/plexamp/id1500797510) (`*`) - Top-notch music app for your Plex Media Server, with a neural network that provides excellent radio/shuffle suggestions 96- [Plexamp](https://apps.apple.com/us/app/plexamp/id1500797510) (`*`) - Top-notch music app for your Plex Media Server, with a neural network that provides excellent radio/shuffle suggestions
97 97
98### News 98### News
@@ -109,7 +109,7 @@ Here's the baseline I start with:
109- [beorg](https://apps.apple.com/us/app/beorg-to-do-list-agenda/id1238649962) - An org-mode editor, outline, and scheduler with paid extensions 109- [beorg](https://apps.apple.com/us/app/beorg-to-do-list-agenda/id1238649962) - An org-mode editor, outline, and scheduler with paid extensions
110- [Bitwarden](https://apps.apple.com/us/app/bitwarden-password-manager/id1137397744) (`*`) - An open source password manager 110- [Bitwarden](https://apps.apple.com/us/app/bitwarden-password-manager/id1137397744) (`*`) - An open source password manager
111- [Cryptomator](https://apps.apple.com/us/app/cryptomator/id1560822163) - A cross-platform encryption program 111- [Cryptomator](https://apps.apple.com/us/app/cryptomator/id1560822163) - A cross-platform encryption program
112- [Obsidian](https://apps.apple.com/us/app/obsidian-connected-notes/id1557175442) (`*`) - A nice Markdown-based editor based on a \"vault\" structure. Offers a paid sync solution and community extensions 112- [Obsidian](https://apps.apple.com/us/app/obsidian-connected-notes/id1557175442) (`*`) - A nice Markdown-based editor based on a "vault" structure. Offers a paid sync solution and community extensions
113- [Strongbox](https://apps.apple.com/us/app/strongbox-password-manager/id897283731) - Keepass password manager for iOS & macOS 113- [Strongbox](https://apps.apple.com/us/app/strongbox-password-manager/id897283731) - Keepass password manager for iOS & macOS
114- [UniFi Network](https://apps.apple.com/us/app/unifi/id1057750338) - View and manage most UniFi Network settings 114- [UniFi Network](https://apps.apple.com/us/app/unifi/id1057750338) - View and manage most UniFi Network settings
115 115
@@ -130,7 +130,7 @@ Here's the baseline I start with:
130 130
131### Sports 131### Sports
132 132
133- [Apple Sports](https://apps.apple.com/us/app/apple-sports/id6446788829) - Apple\'s new sports app - lacks notifications and live events 133- [Apple Sports](https://apps.apple.com/us/app/apple-sports/id6446788829) - Apple's new sports app - lacks notifications and live events
134- [UDisc](https://apps.apple.com/us/app/udisc-disc-golf/id1072228953) - Disc golf course maps, score cards, and more 134- [UDisc](https://apps.apple.com/us/app/udisc-disc-golf/id1072228953) - Disc golf course maps, score cards, and more
135 135
136### Utilities 136### Utilities
content/wiki/macos.md +2 −2
@@ -92,7 +92,7 @@ echo "yabai configuration loaded.."
92 92
93### Communications 93### Communications
94 94
95- [Element](https://element.io/) (`*`) - Matrix\'s default GUI client 95- [Element](https://element.io/) (`*`) - Matrix's default GUI client
96- [gomuks](https://github.com/tulir/gomuks) - A terminal based Matrix client 96- [gomuks](https://github.com/tulir/gomuks) - A terminal based Matrix client
97- [Thunderbird](https://www.thunderbird.net/) (`*`) - An open source email client by Mozilla 97- [Thunderbird](https://www.thunderbird.net/) (`*`) - An open source email client by Mozilla
98- [Signal](https://signal.org/) (`*`) - A simple, powerful, and secure messenger 98- [Signal](https://signal.org/) (`*`) - A simple, powerful, and secure messenger
@@ -103,7 +103,7 @@ echo "yabai configuration loaded.."
103 - [open-webui](https://github.com/open-webui/open-webui) - User-friendly WebUI for LLMs 103 - [open-webui](https://github.com/open-webui/open-webui) - User-friendly WebUI for LLMs
104- [iTerm2](https://iterm2.com/) (`*`) - The best terminal for macOS, hands down 104- [iTerm2](https://iterm2.com/) (`*`) - The best terminal for macOS, hands down
105- [Podman Desktop](https://podman-desktop.io/) (`*`) - Open source tool for containers and Kubernetes 105- [Podman Desktop](https://podman-desktop.io/) (`*`) - Open source tool for containers and Kubernetes
106- [Xcode](https://developer.apple.com/xcode/) - Apple\'s IDE 106- [Xcode](https://developer.apple.com/xcode/) - Apple's IDE
107- [zsh](https://en.wikipedia.org/wiki/Z_shell) (`*`) - My shell preference due to its plugin and theme community 107- [zsh](https://en.wikipedia.org/wiki/Z_shell) (`*`) - My shell preference due to its plugin and theme community
108 - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) - Fish-like autosuggestions for zsh 108 - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) - Fish-like autosuggestions for zsh
109 - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) - Fish shell like syntax highlighting for Zsh 109 - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) - Fish shell like syntax highlighting for Zsh