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.
2828
2929## Tasks
3030
31- [ ] Format all blog posts
32 - [ ] 2018
33 - [ ] 2019
34 - [ ] 2020
35 - [ ] 2021
36 - [ ] 2022
37 - [ ] 2023
38 - [ ] 2024
31- [x] Format all blog posts
32 - [x] 2018
33 - [x] 2019
34 - [x] 2020
35 - [x] 2021
36 - [x] 2022
37 - [x] 2023
38 - [x] 2024
39- [ ] Add descriptions to blog posts
3940- [ ] 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
77
88# Basic AES
99
10If you\'re not familiar with encryption techniques,
10If you're not familiar with encryption techniques,
1111[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) is the
12**Advanced Encryption Standard**. This specification was established by
13the National Institute of Standards and Technology, sub-selected from
14the Rijndael family of ciphers (128, 192, and 256 bits) in 2001.
15Furthering its popularity and status, the US government chose AES as
16their default encryption method for top-secret data, removing the
17previous standard which had been in place since 1977.
18
19AES has proven to be an extremely safe encryption method, with 7-round
20and 8-round attacks making no material improvements since the release of
21this encryption standard almost two decades ago.
22
23> Though many papers have been published on the cryptanalysis of AES,
24> the fastest single-key attacks on round-reduced AES variants \[20,
25> 33\] so far are only slightly more powerful than those proposed 10
26> years ago \[23,24\].
12**Advanced Encryption Standard**. This specification was established by the
13National Institute of Standards and Technology, sub-selected from the Rijndael
14family of ciphers (128, 192, and 256 bits) in 2001. Furthering its popularity
15and status, the US government chose AES as their default encryption method for
16top-secret data, removing the previous standard which had been in place since
171977.
18
19AES has proven to be an extremely safe encryption method, with 7-round and
208-round attacks making no material improvements since the release of this
21encryption standard almost two decades ago.
22
23> Though many papers have been published on the cryptanalysis of AES, the
24> fastest single-key attacks on round-reduced AES variants [20, 33] so far are
25> only slightly more powerful than those proposed 10 years ago [23,24].
2726>
28> - [Bogdonav, et
29> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf)
27> - [Bogdonav, et
28> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf)
3029
3130# How Secure is AES?
3231
33In theory, AES-256 is non-crackable due to the massive number of
34combinations that can be produced. However, AES-128 is no longer
35recommended as a viable implementation to protect important data.
32In theory, AES-256 is non-crackable due to the massive number of combinations
33that can be produced. However, AES-128 is no longer recommended as a viable
34implementation to protect important data.
3635
3736A semi-short [comic
3837strip](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html)
39from Moserware quickly explains AES for the public to understand.
40Basically AES encrypts the data by obscuring the relationship between
41the data and the encrypted data. Additionally, this method spreads the
42message out. Lastly, the key produced by AES is the secret to decrypting
43it. Someone may know the method of AES, but without the key, they are
44powerless.
45
46To obscure and spread the data out, AES creates a
47substitution-permutation network. Wikipedia has a wonderful [example of
48an SP
38from Moserware quickly explains AES for the public to understand. Basically AES
39encrypts the data by obscuring the relationship between the data and the
40encrypted data. Additionally, this method spreads the message out. Lastly, the
41key produced by AES is the secret to decrypting it. Someone may know the method
42of AES, but without the key, they are powerless.
43
44To obscure and spread the data out, AES creates a substitution-permutation
45network. Wikipedia has a wonderful [example of an SP
4946network](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
51the unique key) to substitute the bits with another block of bits. Then,
52a P box will permutate, or rearrange, the bits. This is done over and
53over, with the key being derived from the last round. For AES, the key
54size specifies the number of transformation rounds: 10, 12, and 14
55rounds for 128-bit, 192-bit, and 256-bit keys, respectively.
47available. This network sends the data through a set of S boxes (using the
48unique key) to substitute the bits with another block of bits. Then, a P box
49will permutate, or rearrange, the bits. This is done over and over, with the key
50being derived from the last round. For AES, the key size specifies the number of
51transformation rounds: 10, 12, and 14 rounds for 128-bit, 192-bit, and 256-bit
52keys, respectively.
5653
5754# The Process
5855
591. \*KeyExpansion=: Using [Rijndael\'s key
60 schedule](https://en.m.wikipedia.org/wiki/Advanced_Encryption_Standard),
61 the keys are dynamically generated.
622. **AddRoundKey**: Each byte of the data is combined with this key
63 using bitwise xor.
643. **SubBytes**: This is followed by the substitution of each byte of
65 data.
664. **ShiftRows**: Then, the final three rows are shifted a certain
67 number of steps, dictated by the cipher.
685. **MixColumns**: After the rows have been shifted, the columns are
69 mixed and combined.
70
71This process does not necessarily stop after one full round. Steps 2
72through 5 will repeat for the number of rounds specified by the key.
73However, the final round excludes the MixColumns step. As you can see,
74this is a fairly complex process. One must have a solid understanding of
75general mathematic principles to fully understand how the sequence works
76(and to even attempt to find a weakness).
77
78According to research done by Bogdanov et al., it would take billions of
79years to brute force a 126-bit key with current hardware. Additionally,
80this brute force attack would require storing 2^88^ bits of data!
81However, there are a few different attacks that have been used to show
82vulnerabilities with the use of this technology. Side-channel attacks
83use inadvertent leaks of data from the hardware or software, which can
84allow attackers to obtain the key or run programs on a user\'s hardware.
85
86Please note that this is not something you should run out and try to
87implement in your `Hello, World!` app after only a few hours
88of research. While AES (basically all encryption methods) is extremely
89efficient in what it does, it takes a lot of time and patience to
90understand. If you\'re looking for something which currently implements
91AES, check out the [Legion of the Bouncy
561. **KeyExpansion**: Using [Rijndael's key
57 schedule](https://en.m.wikipedia.org/wiki/Advanced_Encryption_Standard), the
58 keys are dynamically generated.
592. **AddRoundKey**: Each byte of the data is combined with this key using
60 bitwise xor.
613. **SubBytes**: This is followed by the substitution of each byte of data.
624. **ShiftRows**: Then, the final three rows are shifted a certain number of
63 steps, dictated by the cipher.
645. **MixColumns**: After the rows have been shifted, the columns are mixed and
65 combined.
66
67This process does not necessarily stop after one full round. Steps 2 through 5
68will repeat for the number of rounds specified by the key. However, the final
69round excludes the MixColumns step. As you can see, this is a fairly complex
70process. One must have a solid understanding of general mathematic principles to
71fully understand how the sequence works (and to even attempt to find a
72weakness).
73
74According to research done by Bogdanov et al., it would take billions of years
75to brute force a 126-bit key with current hardware. Additionally, this brute
76force attack would require storing 2^88^ bits of data! However, there are a few
77different attacks that have been used to show vulnerabilities with the use of
78this technology. Side-channel attacks use inadvertent leaks of data from the
79hardware or software, which can allow attackers to obtain the key or run
80programs on a user's hardware.
81
82Please note that this is not something you should run out and try to implement
83in your `Hello, World!` app after only a few hours of research. While AES
84(basically all encryption methods) is extremely efficient in what it does, it
85takes a lot of time and patience to understand. If you're looking for something
86which currently implements AES, check out the [Legion of the Bouncy
9287Castle](https://www.bouncycastle.org/documentation.html) for Java
9388implementations of cryptographic algorithms.
9489
9590# Why Does Encryption Matter?
9691
97There are limitless reasons to enable encryption at-rest or in-transit
98for various aspects of your digital life. You can research specific
99examples, such as [Australia passes new law to thwart strong
92There are limitless reasons to enable encryption at-rest or in-transit for
93various aspects of your digital life. You can research specific examples, such
94as [Australia passes new law to thwart strong
10095encryption](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
102encryption, where feasible:
103
1041. Privacy is a human right and is recognized as a national right in
105 some countries (e.g., [US Fourth
106 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)).
1072. \"Why not?\" Encryption rarely affects performance or speed, so
108 there\'s usually not a reason to avoid it in the first place.
1093. Your digital identity and activity (texts, emails, phone calls,
110 online accounts, etc.) are extremely valuable and can result in
111 terrible consequences, such as identity theft, if leaked to other
112 parties. Encrypting this data prevents such leaks from ruining
113 lives.
1144. Wiping or factory-resetting does not actually wipe all data from the
115 storage device. There are methods to read data from the physical
116 disks/boards inside devices.
1175. Corporations, governments, and other nefarious groups/individuals
118 are actively looking for ways to collect personal information about
119 anyone they can. If someone\'s data is unencrypted, that person may
120 become a target due to the ease of data collection.
96However, I will simply list a few basic reasons to always enable encryption,
97where feasible:
98
991. Privacy is a human right and is recognized as a national right in some
100 countries (e.g., [US Fourth
101 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)).
1022. "Why not?" Encryption rarely affects performance or speed, so there's
103 usually not a reason to avoid it in the first place.
1043. Your digital identity and activity (texts, emails, phone calls, online
105 accounts, etc.) are extremely valuable and can result in terrible
106 consequences, such as identity theft, if leaked to other parties. Encrypting
107 this data prevents such leaks from ruining lives.
1084. Wiping or factory-resetting does not actually wipe all data from the storage
109 device. There are methods to read data from the physical disks/boards inside
110 devices.
1115. Corporations, governments, and other nefarious groups/individuals are
112 actively looking for ways to collect personal information about anyone they
113 can. If someone's data is unencrypted, that person may become a target due
114 to the ease of data collection.
121115
122116​**Read More:**
123117
124- [Federal Information Processing Standards Publication
125 197](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf)
118- [Federal Information Processing Standards Publication
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
77
88# A Brief Introduction
99
10[C++](https://en.wikipedia.org/wiki/C%2B%2B) is a general-purpose
11programming language with object-oriented, generic, and functional
12features in addition to facilities for low-level memory manipulation.
10[C++](https://en.wikipedia.org/wiki/C%2B%2B) is a general-purpose programming
11language with object-oriented, generic, and functional features in addition to
12facilities for low-level memory manipulation.
1313
14The source code, shown in the snippet below, must be compiled before it
15can be executed. There are many steps and intricacies to the compilation
16process, and this post was a personal exercise to learn and remember as
17much information as I can.
14The source code, shown in the snippet below, must be compiled before it can be
15executed. There are many steps and intricacies to the compilation process, and
16this post was a personal exercise to learn and remember as much information as I
17can.
1818
1919``` cpp
2020#include <iostream>
@@ -29,56 +29,52 @@ int main()
2929
3030### An Overview
3131
32Compiling C++ projects is a frustrating task most days. Seemingly
33nonexistent errors keeping your program from successfully compiling can
34be annoying (especially since you know you wrote it perfectly the first
35time, right?).
32Compiling C++ projects is a frustrating task most days. Seemingly nonexistent
33errors keeping your program from successfully compiling can be annoying
34(especially since you know you wrote it perfectly the first time, right?).
3635
37I\'m learning more and more about C++ these days and decided to write
38this concept down so that I can cement it even further in my own head.
39However, C++ is not the only compiled language. Check out [the Wikipedia
40entry for compiled
41languages](https://en.wikipedia.org/wiki/Compiled_language) for more
42examples of compiled languages.
36I'm learning more and more about C++ these days and decided to write this
37concept down so that I can cement it even further in my own head. However, C++
38is not the only compiled language. Check out [the Wikipedia entry for compiled
39languages](https://en.wikipedia.org/wiki/Compiled_language) for more examples of
40compiled languages.
4341
44I\'ll start with a wonderful, graphical way to conceptualize the C++
45compiler. View [The C++ Compilation
42I'll start with a wonderful, graphical way to conceptualize the C++ compiler.
43View [The C++ Compilation
4644Process](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
48explanation. The goal of the compilation process is to take the C++ code
49and produce a shared library, dynamic library, or an executable file.
45by Kurt MacMahon, an NIU professor, to see the graphic and an explanation. The
46goal of the compilation process is to take the C++ code and produce a shared
47library, dynamic library, or an executable file.
5048
5149## Compilation Phases
5250
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
5452compiling C++ code.
5553
5654### Step 1
5755
58The first step is to expand the source code file to meet all
59dependencies. The C++ preprocessor includes the code from all the header
60files, such as `#include
61<iostream>`. Now, what does that mean? The previous example
62includes the `iostream` header. This tells the computer that
63you want to use the `iostream` standard library, which
64contains classes and functions written in the core language. This
65specific header allows you to manipulate input/output streams. After all
66this, you\'ll end up which a temporary file that contains the expanded
56The first step is to expand the source code file to meet all dependencies. The
57C++ preprocessor includes the code from all the header files, such as `#include
58<iostream>`. Now, what does that mean? The previous example includes the
59`iostream` header. This tells the computer that you want to use the `iostream`
60standard library, which contains classes and functions written in the core
61language. This specific header allows you to manipulate input/output streams.
62After all this, you'll end up which a temporary file that contains the expanded
6763source code.
6864
69In the example of the C++ code above, the `iostream` class
70would be included in the expanded code.
65In the example of the C++ code above, the `iostream` class would be included in
66the expanded code.
7167
7268### Step 2
7369
74After the code is expanded, the compiler comes into play. The compiler
75takes the C++ code and converts this code into the assembly language,
76understood by the platform. You can see this in action if you head over
77to the [GodBolt Compiler Explorer](https://godbolt.org), which shows C++
78being converted into assembly dynamically.
70After the code is expanded, the compiler comes into play. The compiler takes the
71C++ code and converts this code into the assembly language, understood by the
72platform. You can see this in action if you head over to the [GodBolt Compiler
73Explorer](https://godbolt.org), which shows C++ being converted into assembly
74dynamically.
7975
80For example, the `Hello, world!` code snippet above compiles
81into the following assembly code:
76For example, the `Hello, world!` code snippet above compiles into the following
77assembly code:
8278
8379``` asm
8480.LC0:
@@ -124,17 +120,17 @@ _GLOBAL__sub_I_main:
124120
125121### Step 3
126122
127Third, the assembly code generated by the compiler is assembled into the
128object code for the platform. Essentially, this is when the compiler
129takes the assembly code and assembles it into machine code in a binary
130format. After researching this online, I figured out that a lot of
131compilers will allow you to stop compilation at this step. This would be
132useful for compiling each source code file separately. This saves time
133later if a single file changes; only that file needs to be recompiled.
123Third, the assembly code generated by the compiler is assembled into the object
124code for the platform. Essentially, this is when the compiler takes the assembly
125code and assembles it into machine code in a binary format. After researching
126this online, I figured out that a lot of compilers will allow you to stop
127compilation at this step. This would be useful for compiling each source code
128file separately. This saves time later if a single file changes; only that file
129needs to be recompiled.
134130
135131### Step 4
136132
137Finally, the object code file generated by the assembler is linked
138together with the object code files for any library functions used to
139produce a shared library, dynamic library, or an executable file. It
140replaces all references to undefined symbols with the correct addresses.
133Finally, the object code file generated by the assembler is linked together with
134the object code files for any library functions used to produce a shared
135library, dynamic library, or an executable file. It replaces all references to
136undefined symbols with the correct addresses.
content/blog/2019-01-07-useful-css.md +54 −64
@@ -7,36 +7,32 @@ draft = false
77
88# Introduction to CSS
99
10[CSS](https://en.wikipedia.org/wiki/CSS), the language used to markup
11HTML code and make it \"pretty\", is one of the most effective ways to
12increase the attractiveness of a website. It can also lead to increased
13user engagement, retention, and satisfaction. In fact, there are whole
14career fields are dedicated to the improvement of user experiences,
15known as UI design and UX design.
16
17Some web developers are used to the common CSS properties, such as
18element sizing, fonts, colors, etc., but are not as well versed in
19less-used properties and values such as `flexbox`,
20`clip-path`, and `transform`. This article will
10[CSS](https://en.wikipedia.org/wiki/CSS), the language used to markup HTML code
11and make it "pretty", is one of the most effective ways to increase the
12attractiveness of a website. It can also lead to increased user engagement,
13retention, and satisfaction. In fact, there are whole career fields are
14dedicated to the improvement of user experiences, known as UI design and UX
15design.
16
17Some web developers are used to the common CSS properties, such as element
18sizing, fonts, colors, etc., but are not as well versed in less-used properties
19and values such as `flexbox`, `clip-path`, and `transform`. This article will
2120provide some insight into the less-used and unique CSS properties.
2221
2322# CSS Variables
2423
25The first topic today is CSS variables. Variables are not often used by
26smaller developers. CSS variables allow you to give your website a
27well-defined structure, where you can easily reuse CSS properties
28throughout the project.
24The first topic today is CSS variables. Variables are not often used by smaller
25developers. CSS variables allow you to give your website a well-defined
26structure, where you can easily reuse CSS properties throughout the project.
2927
30You can use variables to define things, such as color palettes. Then,
31you can use these colors for backgrounds anywhere else in the HTML. This
32could be extended, where extra variables could be defined for
33`primary-text`, `quoted-text`, etc. Variables can
34also be used to define spacing (e.g. `32px` or
35`2rem`), which can then be applied to margins, padding, font
36sizes, and more.
28You can use variables to define things, such as color palettes. Then, you can
29use these colors for backgrounds anywhere else in the HTML. This could be
30extended, where extra variables could be defined for `primary-text`,
31`quoted-text`, etc. Variables can also be used to define spacing (e.g. `32px` or
32`2rem`), which can then be applied to margins, padding, font sizes, and more.
3733
38For example, here are some variables defined at the root of the website,
39which allows for any subsequent CSS rules to use those variables:
34For example, here are some variables defined at the root of the website, which
35allows for any subsequent CSS rules to use those variables:
4036
4137``` css
4238:root {
@@ -52,23 +48,22 @@ body {
5248
5349# CSS Box Shadows
5450
55Box shadows were once my mortal enemy. No matter how hard I tried, I
56just couldn\'t get them to work how I wanted. Because of this, my
57favorite discovery has been CSSMatic\'s [box shadow
58generator](https://www.cssmatic.com/box-shadow). It provides an
59excellent tool to generate box shadows using their simple sliders.
60Surprisingly, this is the reason I learned how box shadows work! You can
61use the sliders and watch how the CSS code changes in the image that is
62displayed. Through this, you should understand that the basic structure
63for box shadows is:
51Box shadows were once my mortal enemy. No matter how hard I tried, I just
52couldn't get them to work how I wanted. Because of this, my favorite discovery
53has been CSSMatic's [box shadow
54generator](https://www.cssmatic.com/box-shadow). It provides an excellent tool
55to generate box shadows using their simple sliders. Surprisingly, this is the
56reason I learned how box shadows work! You can use the sliders and watch how the
57CSS code changes in the image that is displayed. Through this, you should
58understand that the basic structure for box shadows is:
6459
6560``` css
6661box-shadow: inset horizontal vertical blur spread color;
6762```
6863
69Now, let\'s look at some basic examples! You can copy and paste the
70following code into a site like CodePen or your own HTML files. Feel
71free to play around with the code, experiment, and learn.
64Now, let's look at some basic examples! You can copy and paste the following
65code into a site like CodePen or your own HTML files. Feel free to play around
66with the code, experiment, and learn.
7267
7368**Box Shadow #1**
7469
@@ -124,22 +119,20 @@ free to play around with the code, experiment, and learn.
124119}
125120```
126121
127Try these box shadows out on your own and see how changing each shadow
128value works.
122Try these box shadows out on your own and see how changing each shadow value
123works.
129124
130125# CSS Flexbox
131126
132Now, let\'s move on to the best part of this article: flexbox. The
133flexbox is by far my favorite new toy. I originally stumbled across this
134solution after looking for more efficient ways of centering content
135horizontally AND vertically. I had used a few hack-ish methods before,
136but flexbox throws those out the window. The best part of it all is that
137flexbox is *dead simple*.
127Now, let's move on to the best part of this article: flexbox. The flexbox is by
128far my favorite new toy. I originally stumbled across this solution after
129looking for more efficient ways of centering content horizontally AND
130vertically. I had used a few hack-ish methods before, but flexbox throws those
131out the window. The best part of it all is that flexbox is *dead simple*.
138132
139Flexbox pertains to the parent div of any element. You want the parent
140to be the flexbox in which items are arranged to use the flex methods.
141It\'s easier to see this in action that explained, so let\'s see an
142example.
133Flexbox pertains to the parent div of any element. You want the parent to be the
134flexbox in which items are arranged to use the flex methods. It's easier to see
135this in action that explained, so let's see an example.
143136
144137**Flexbox**
145138
@@ -174,27 +167,24 @@ example.
174167}
175168```
176169
177You may notice that we no longer need to use the `top`
178property for the `h3` elements in our code. This is because
179we set the display box to be a flex container for the small boxes, AND
180we made the small boxes flex containers for their elements (the h3
181tags). Flex boxes can be nested like this to center content that is
182inside centered content.
170You may notice that we no longer need to use the `top` property for the `h3`
171elements in our code. This is because we set the display box to be a flex
172container for the small boxes, AND we made the small boxes flex containers for
173their elements (the h3 tags). Flex boxes can be nested like this to center
174content that is inside centered content.
183175
184For the example above, we designated the `justify-content`
185property to be `flex-start` so that the boxes stack from the
186left side of the screen. This property can be changed to
187`center` to make the boxes appear in the center of the
188screen.
176For the example above, we designated the `justify-content` property to be
177`flex-start` so that the boxes stack from the left side of the screen. This
178property can be changed to `center` to make the boxes appear in the center of
179the screen.
189180
190181For an interactive example, [check out this
191182CodePen](https://codepen.io/LandonSchropp/pen/KpzzGo) from
192[LandonScropp](https://codepen.io/LandonSchropp/). Resize the window
193with dice to see how they collapse and re-align.
183[LandonScropp](https://codepen.io/LandonSchropp/). Resize the window with dice
184to see how they collapse and re-align.
194185
195186# Even More CSS
196187
197188For more inspiration, you can visit [CodePen](https://www.codepen.io),
198[Dribbble](https://dribbble.com), or [UI
199Movement](https://uimovement.com) to browse the collections of many
200amazing web designers.
189[Dribbble](https://dribbble.com), or [UI Movement](https://uimovement.com) to
190browse the collections of many amazing web designers.
content/blog/2019-09-09-audit-analytics.md +154 −172
@@ -7,150 +7,139 @@ draft = false
77
88# What Are Data Analytics?
99
10A quick aside before I dive into this post: `data analytics`
11is a vague term that has become popular in recent years. Think of a
12`data analytic` as the output of any data analysis you
13perform. For example, a pivot table or a pie chart could be a data
14analytic.
15
16[Data analysis](https://en.wikipedia.org/wiki/Data_analysis) is a
17process that utilizes statistics and other mathematical methods to
18discover useful information within datasets. This involves examining,
19cleaning, transforming, and modeling data so that you can use the data
20to support an opinion, create more useful viewpoints, and gain knowledge
21to implement into audit planning or risk assessments.
22
23One of the common mistakes that managers (and anyone new to the process)
24make is assuming that everything involved with this process is \"data
25analytics\". In fact, data analytics are only a small part of the
26process.
27
28See **Figure 1\*** for a more accurate representation of where data
29analysis sits within the full process. This means that data analysis
30does not include querying or extracting data, selecting samples, or
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.
10A quick aside before I dive into this post: `data analytics` is a vague term
11that has become popular in recent years. Think of a `data analytic` as the
12output of any data analysis you perform. For example, a pivot table or a pie
13chart could be a data analytic.
14
15[Data analysis](https://en.wikipedia.org/wiki/Data_analysis) is a process that
16utilizes statistics and other mathematical methods to discover useful
17information within datasets. This involves examining, cleaning, transforming,
18and modeling data so that you can use the data to support an opinion, create
19more useful viewpoints, and gain knowledge to implement into audit planning or
20risk assessments.
21
22One of the common mistakes that managers (and anyone new to the process) make is
23assuming that everything involved with this process is "data analytics". In
24fact, data analytics are only a small part of the process.
25
26See **Figure 1** for a more accurate representation of where data analysis
27sits within the full process. This means that data analysis does not include
28querying or extracting data, selecting samples, or performing audit tests. These
29steps can be necessary for an audit (and may even be performed by the same
30associates), but they are not data analytics.
3431
3532![The Intelligence
3633Cycle](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/intelligence_cycle-min.png)
3734
3835# Current Use of Analytics in Auditing
3936
40While data analysis has been an integral part of most businesses and
41departments for the better part of the last century, only recently have
42internal audit functions been adopting this practice. The internal audit
43function works exclusively to provide assurance and consulting services
44to the business areas within the firm (except for internal auditing
45firms who are hired by different companies to perform their roles).
46
47> Internal Auditing helps an organization accomplish its objectives by
48> bringing a systematic, disciplined approach to evaluate and improve
49> the effectiveness of risk management, control and governance
50> processes.
37While data analysis has been an integral part of most businesses and departments
38for the better part of the last century, only recently have internal audit
39functions been adopting this practice. The internal audit function works
40exclusively to provide assurance and consulting services to the business areas
41within the firm (except for internal auditing firms who are hired by different
42companies to perform their roles).
43
44> Internal Auditing helps an organization accomplish its objectives by bringing
45> a systematic, disciplined approach to evaluate and improve the effectiveness
46> of risk management, control and governance processes.
5147>
52> - The IIA\'s Definition of Internal Audit
53
54Part of the blame for the slow adoption of data analysis can be
55attributed to the fact that internal auditing is strongly based on
56tradition and following the precedents set by previous auditors.
57However, there can be no progress without auditors who are willing to
58break the mold and test new audit techniques. In fact, as of 2018, [only
5963% of internal audit departments currently utilize data
48> - The IIA's Definition of Internal Audit
49
50Part of the blame for the slow adoption of data analysis can be attributed to
51the fact that internal auditing is strongly based on tradition and following the
52precedents set by previous auditors. However, there can be no progress without
53auditors who are willing to break the mold and test new audit techniques. In
54fact, as of 2018, [only 63% of internal audit departments currently utilize data
6055analytics](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
62have never been part of an audit that would not have benefited from data
63analytics.
56in North America. This number should be as close as possible to 100%. I have
57never been part of an audit that would not have benefited from data analytics.
6458
65So, how do internal audit functions remedy this situation? It\'s
66definitely not as easy as walking into work on Monday and telling your
67Chief Audit Executive that you\'re going to start implementing analytics
68in the next audit. You need a plan and a system to make the analysis
69process as effective as possible.
59So, how do internal audit functions remedy this situation? It's definitely not
60as easy as walking into work on Monday and telling your Chief Audit Executive
61that you're going to start implementing analytics in the next audit. You need a
62plan and a system to make the analysis process as effective as possible.
7063
7164# The DELTA Model
7265
7366One of the easiest ways to experiment with data analytics and gain an
74understanding of the processes is to implement them within your own
75department. But how do we do this if we\'ve never worked with analysis
76before? One of the most common places to start is to research some data
77analysis models currently available. For this post, we\'ll take a look
78at the DELTA model. You can take a look at **\*\*\*Figure 2\*\*\*\***
79for a quick overview of the model.
80
81The DELTA model sets a few guidelines for areas wanting to implement
82data analytics so that the results can be as comprehensive as possible:
83
84- **Data**: Must be clean, accessible, and (usually) unique.
85- **Enterprise-Wide Focus**: Key data systems and analytical resources
86 must be available for use (by the Internal Audit Function).
87- **Leaders**: Must promote a data analytics approach and show the
88 value of analytical results.
89- **Targets**: Must be set for key areas and risks that the analytics
90 can be compared against (KPIs).
91- **Analysts**: There must be auditors willing and able to perform
92 data analytics or else the system cannot be sustained.
67understanding of the processes is to implement them within your own department.
68But how do we do this if we've never worked with analysis before? One of the
69most common places to start is to research some data analysis models currently
70available. For this post, we'll take a look at the DELTA model. You can take a
71look at **Figure 2** for a quick overview of the model.
72
73The DELTA model sets a few guidelines for areas wanting to implement data
74analytics so that the results can be as comprehensive as possible:
75
76- **Data**: Must be clean, accessible, and (usually) unique.
77- **Enterprise-Wide Focus**: Key data systems and analytical resources must be
78 available for use (by the Internal Audit Function).
79- **Leaders**: Must promote a data analytics approach and show the value of
80 analytical results.
81- **Targets**: Must be set for key areas and risks that the analytics can be
82 compared against (KPIs).
83- **Analysts**: There must be auditors willing and able to perform data
84 analytics or else the system cannot be sustained.
9385
9486![The Delta
9587Model](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/delta-min.png)
9688
9789# Finding the Proper KPIs
9890
99Once the Internal Audit Function has decided that they want to start
100using data analytics internally and have ensured they\'re properly set
101up to do so, they need to figure out what they will be testing against.
102Key Performance Indicators (KPIs) are qualitative or quantitative
103factors that can be evaluated and assessed to determine if the
104department is performing well, usually compared to historical or
105industry benchmarks. Once KPIs have been agreed upon and set, auditors
106can use data analytics to assess and report on these KPIs. This allows
107the person performing the analytics the freedom to express opinions on
108the results, whereas the results are ambiguous if no KPIs exist.
109
110It should be noted that tracking KPIs in the department can help ensure
111you have a rigorous Quality Assurance and Improvement Program (QAIP) in
112accordance with some applicable standards, such as IPPF Standard 1300.
113
114> The chief audit executive must develop and maintain a quality
115> assurance and improvement program that covers all aspects of the
116> internal audit activity.
91Once the Internal Audit Function has decided that they want to start using data
92analytics internally and have ensured they're properly set up to do so, they
93need to figure out what they will be testing against. Key Performance Indicators
94(KPIs) are qualitative or quantitative factors that can be evaluated and
95assessed to determine if the department is performing well, usually compared to
96historical or industry benchmarks. Once KPIs have been agreed upon and set,
97auditors can use data analytics to assess and report on these KPIs. This allows
98the person performing the analytics the freedom to express opinions on the
99results, whereas the results are ambiguous if no KPIs exist.
100
101It should be noted that tracking KPIs in the department can help ensure you have
102a rigorous Quality Assurance and Improvement Program (QAIP) in accordance with
103some applicable standards, such as IPPF Standard 1300.
104
105> The chief audit executive must develop and maintain a quality assurance and
106> improvement program that covers all aspects of the internal audit activity.
117107>
118108> - IPPF Standard 1300
119109
120110Additionally, IPPF Standard 2060 discusses reporting:
121111
122> The chief audit executive must report periodically to senior
123> management and the board on the internal audit activity\'s purpose,
124> authority, responsibility, and performance relative to its plan and on
125> its conformance with the Code of Ethics and the Standards. Reporting
126> must also include significant risk and control issues, including fraud
127> risks, governance issues, and other matters that require the attention
128> of senior management and/or the board.
112> The chief audit executive must report periodically to senior management and
113> the board on the internal audit activity's purpose, authority,
114> responsibility, and performance relative to its plan and on its conformance
115> with the Code of Ethics and the Standards. Reporting must also include
116> significant risk and control issues, including fraud risks, governance issues,
117> and other matters that require the attention of senior management and/or the
118> board.
129119>
130120> - IPPF Standard 2060
131121
132The hardest part of finding KPIs is to determine which KPIs are
133appropriate for your department. Since every department is different and
134has different goals, KPIs will vary drastically between companies. To
135give you an idea of where to look, here are some ideas I came up with
136when discussing the topic with a few colleagues.
122The hardest part of finding KPIs is to determine which KPIs are appropriate for
123your department. Since every department is different and has different goals,
124KPIs will vary drastically between companies. To give you an idea of where to
125look, here are some ideas I came up with when discussing the topic with a few
126colleagues.
137127
138128- Efficiency/Budgeting:
139 - Audit hours to staff utilization ratio (annual hours divided by
140 total annual work hours).
129 - Audit hours to staff utilization ratio (annual hours divided by total
130 annual work hours).
141131 - Audit hours compared to the number of audits completed.
142 - Time between audit steps or to complete the whole audit. E.g.,
143 time from fieldwork completion to audit report issuance.
132 - Time between audit steps or to complete the whole audit. E.g., time from
133 fieldwork completion to audit report issuance.
144134- Reputation:
145 - The frequency that management has requested the services of the
146 IAF.
147 - Management, audit committee, or external audit satisfaction
148 survey results.
149 - Education, experience, certifications, tenure, and training of
150 the auditors on staff.
135 - The frequency that management has requested the services of the IAF.
136 - Management, audit committee, or external audit satisfaction survey
137 results.
138 - Education, experience, certifications, tenure, and training of the
139 auditors on staff.
151140- Quality:
152 - Number and frequency of audit findings. Assign monetary or
153 numerical values, if possible.
141 - Number and frequency of audit findings. Assign monetary or numerical
142 values, if possible.
154143 - Percentage of recommendations issued and implemented.
155144- Planning:
156145 - Percentage or number of key risks audited per year or per audit.
@@ -158,65 +147,59 @@ when discussing the topic with a few colleagues.
158147
159148# Data Analysis Tools
160149
161Finally, to be able to analyze and report on the data analysis, auditors
162need to evaluate the tools at their disposal. There are many options
163available, but a few of the most common ones can easily get the job
164done. For example, almost every auditor already has access to Microsoft
165Excel. Excel is more powerful than most people give it credit for and
166can accomplish a lot of basic statistics without much work. If you
167don\'t know a lot about statistics but still want to see some of the
168more basic results, Excel is a great option.
169
170To perform more in-depth statistical analysis or to explore large
171datasets that Excel cannot handle, auditors will need to explore other
172options. The big three that have had a lot of success in recent years
173are Python, R, and ACL. ACL can be used as either a graphical tool
174(point and click) or as a scripting tool, where the auditor must write
175the scripts manually. Python and the R-language are solely scripting
176languages.
177
178The general trend in the data analytics environment is that if the tool
179allows you to do everything by clicking buttons or dragging elements,
180you won\'t be able to fully utilize the analytics you need. The most
181robust solutions are created by those who understand how to write the
182scripts manually. It should be noted that as the utility of a tool
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.
150Finally, to be able to analyze and report on the data analysis, auditors need to
151evaluate the tools at their disposal. There are many options available, but a
152few of the most common ones can easily get the job done. For example, almost
153every auditor already has access to Microsoft Excel. Excel is more powerful than
154most people give it credit for and can accomplish a lot of basic statistics
155without much work. If you don't know a lot about statistics but still want to
156see some of the more basic results, Excel is a great option.
157
158To perform more in-depth statistical analysis or to explore large datasets that
159Excel cannot handle, auditors will need to explore other options. The big three
160that have had a lot of success in recent years are Python, R, and ACL. ACL can
161be used as either a graphical tool (point and click) or as a scripting tool,
162where the auditor must write the scripts manually. Python and the R-language are
163solely scripting languages.
164
165The general trend in the data analytics environment is that if the tool allows
166you to do everything by clicking buttons or dragging elements, you won't be
167able to fully utilize the analytics you need. The most robust solutions are
168created by those who understand how to write the scripts manually. It should be
169noted that as the utility of a tool increases, it usually means that the
170learning curve for that tool will also be higher. It will take auditors longer
171to learn how to utilize Python, R, or ACL versus learning how to utilize Excel.
186172
187173# Visualization
188174
189Once an auditor has finally found the right data, KPIs, and tools, they
190must report these results so that actions can be taken. Performing
191in-depth data analysis is only useful if the results are understood by
192the audiences of the data. The best way to create this understanding is
193to visualize the results of the data. Let\'s take a look at some of the
194best options to visualize and report the results you\'ve found.
195
196Some of the most popular commercial tools for visualization are
197Microsoft PowerBI and Tableau Desktop. However, other tools exist such
198as JMP, Plotly, Qlikview, Alteryx, or D3. Some require commercial
199licenses while others are simply free to use. For corporate data, you
200may want to make sure that the tool does not communicate any of the data
201outside the company (such as cloud storage). I won\'t be going into
202depth on any of these tools since visualization is largely a subjective
203and creative experience, but remember to constantly explore new options
204as you repeat the process.
205
206Lastly, let\'s take a look at an example of data visualization. This
207example comes from a [blog post written by Kushal
175Once an auditor has finally found the right data, KPIs, and tools, they must
176report these results so that actions can be taken. Performing in-depth data
177analysis is only useful if the results are understood by the audiences of the
178data. The best way to create this understanding is to visualize the results of
179the data. Let's take a look at some of the best options to visualize and report
180the results you've found.
181
182Some of the most popular commercial tools for visualization are Microsoft
183PowerBI and Tableau Desktop. However, other tools exist such as JMP, Plotly,
184Qlikview, Alteryx, or D3. Some require commercial licenses while others are
185simply free to use. For corporate data, you may want to make sure that the tool
186does not communicate any of the data outside the company (such as cloud
187storage). I won't be going into depth on any of these tools since visualization
188is largely a subjective and creative experience, but remember to constantly
189explore new options as you repeat the process.
190
191Lastly, let's take a look at an example of data visualization. This example
192comes from a [blog post written by Kushal
208193Chakrabarti](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
210experience. **Figure 3\*** shows us an easy-to-digest picture of the
211data. We can quickly tell that only about 12.5% of entry-level jobs
212don\'t require experience.
213
214This is the kind of result that easily describes the data for you.
215However, make sure to include an explanation of what the results mean.
216Don\'t let the reader assume what the data means, especially if it
217relates to a complex subject. *Tell a story* about the data and why the
218results matter. For example, **Figure 4\*** shows a part of the
219explanation the author gives to illustrate his point.
194in 2018 about the percent of entry-level US jobs that require experience.
195**Figure 3** shows us an easy-to-digest picture of the data. We can quickly
196tell that only about 12.5% of entry-level jobs don't require experience.
197
198This is the kind of result that easily describes the data for you. However, make
199sure to include an explanation of what the results mean. Don't let the reader
200assume what the data means, especially if it relates to a complex subject. *Tell
201a story* about the data and why the results matter. For example, **Figure 4**
202shows a part of the explanation the author gives to illustrate his point.
220203
221204![Entry-Level
222205Visualization](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
226209
227210# Wrap-Up
228211
229While this is not an all-encompassing program that you can just adopt
230into your department, it should be enough to get anyone started on the
231process of understanding and implementing data analytics. Always
232remember to continue learning and exploring new options as your
233processes grow and evolve.
212While this is not an all-encompassing program that you can just adopt into your
213department, it should be enough to get anyone started on the process of
214understanding and implementing data analytics. Always remember to continue
215learning and exploring new options as your processes grow and evolve.
content/blog/2019-12-03-the-ansoff-matrix.md +87 −96
@@ -7,38 +7,35 @@ draft = false
77
88# Overview
99
10As the world of business evolves, managers must approach business
11planning and strategy with a contemporary mindset. According to Dess,
12McNamara, Eisner, and Lee, managers must be willing to adapt to the
13modern business environment by going beyond \"\'incremental
14management\', whereby they view their job as making a series of small,
15minor changes to improve the efficiency of the firm\'s
16operations\"(2019).
17
18One reason that strategic management is crucial is because most
19businesses that fail in the United States each year fail due to a lack
20of strategic focus or direction(2019). The rate of failure for
21businesses with poor strategies shows that strategic planning and
22management are crucial to a business\'s strength and longevity,
23injecting the critical factors of growth and direction into a company\'s
24business plan.
25
26One of the most significant strategic planning and management frameworks
27that companies can use is the [Ansoff
28Matrix](https://en.wikipedia.org/wiki/Ansoff_matrix). While this
29framework has unique purposes and use-cases, it can effectively help an
30organization grow and compete. Specifically, the Ansoff matrix is one of
31the most effective frameworks for companies who want to focus on
32increasing sales revenue or profitability(2019).
33
34This framework uses a two-by-two figure to show the four strategic
35options for companies to use in this framework: market penetration,
36market development, product development, and diversification (see
37**Figure 1**). The x-axis of the matrix focuses on the firm\'s markets
38and also determines if the firm is looking to enter new markets or
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.
10As the world of business evolves, managers must approach business planning and
11strategy with a contemporary mindset. According to Dess, McNamara, Eisner, and
12Lee, managers must be willing to adapt to the modern business environment by
13going beyond "'incremental management', whereby they view their job as making
14a series of small, minor changes to improve the efficiency of the firm's
15operations"(2019).
16
17One reason that strategic management is crucial is because most businesses that
18fail in the United States each year fail due to a lack of strategic focus or
19direction(2019). The rate of failure for businesses with poor strategies shows
20that strategic planning and management are crucial to a business's strength and
21longevity, injecting the critical factors of growth and direction into a
22company's business plan.
23
24One of the most significant strategic planning and management frameworks that
25companies can use is the [Ansoff
26Matrix](https://en.wikipedia.org/wiki/Ansoff_matrix). While this framework has
27unique purposes and use-cases, it can effectively help an organization grow and
28compete. Specifically, the Ansoff matrix is one of the most effective frameworks
29for companies who want to focus on increasing sales revenue or
30profitability(2019).
31
32This framework uses a two-by-two figure to show the four strategic options for
33companies to use in this framework: market penetration, market development,
34product development, and diversification (see **Figure 1**). The x-axis of the
35matrix focuses on the firm's markets and also determines if the firm is looking
36to enter new markets or innovate in its current markets. The y-axis of the
37matrix focuses on the firm's products and determines if the firm wants to
38pursue strategies around their existing products or explore new products.
4239
4340![The Ansoff Matrix by JaisonAbeySabu, Own work, CC BY-SA
44413.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.
4744
4845## Market Penetration
4946
50The most straightforward strategy in the Ansoff matrix is to focus on
51existing products in existing markets, also known as market
52penetration(2019). Companies such as Coca-Cola have used market
53penetration successfully by investing a lot of money to get further
54value out of their current markets. Coca-Cola does this by introducing
55new features such as Christmas-themed bottles, personal names on the
56bottles, and other marketing schemes.
47The most straightforward strategy in the Ansoff matrix is to focus on existing
48products in existing markets, also known as market penetration(2019). Companies
49such as Coca-Cola have used market penetration successfully by investing a lot
50of money to get further value out of their current markets. Coca-Cola does this
51by introducing new features such as Christmas-themed bottles, personal names on
52the bottles, and other marketing schemes.
5753
5854## Market Development
5955
60Market development extends existing products into new markets in an
61attempt to increase the number of buyers. One interesting way that
62Coca-Cola used this strategy comes from the stigma that Diet Coke is a
63woman\'s drink(2019). Coca-Cola introduced Coca-Cola Zero, which
64contained the same nutritional content as Diet Coke, but was packaged in
65a dark black can to appear more \"manly\"(2019).
56Market development extends existing products into new markets in an attempt to
57increase the number of buyers. One interesting way that Coca-Cola used this
58strategy comes from the stigma that Diet Coke is a woman's drink(2019).
59Coca-Cola introduced Coca-Cola Zero, which contained the same nutritional
60content as Diet Coke, but was packaged in a dark black can to appear more
61"manly"(2019).
6662
6763## Product Development
6864
69Product development uses existing markets to introduce new products so
70that the firm can better meet customer needs(2019). The extreme end of
71diversification is home to companies such as Johnson & Johnson, a
72healthcare company that has developed a business portfolio of more than
7360,000 different products(2019). Johnson & Johnson\'s dedication to
74continuous diversification has led them to a balance sheet rating of
75\"AAA\", industry recognition for diversification, and increases in
76their investor dividends for 57 consecutive years(2019).
65Product development uses existing markets to introduce new products so that the
66firm can better meet customer needs(2019). The extreme end of diversification is
67home to companies such as Johnson & Johnson, a healthcare company that has
68developed a business portfolio of more than 60,000 different products(2019).
69Johnson & Johnson's dedication to continuous diversification has led them to a
70balance sheet rating of "AAA", industry recognition for diversification, and
71increases in their investor dividends for 57 consecutive years(2019).
7772
7873## Related Diversification
7974
80Diversification, the final strategy of the Ansoff Matrix, is more
81difficult than the others since it involves exploring both new markets
82and new products. Related diversification is a diversification strategy
83that closely relates to the firm\'s core business. Coca-Cola\'s best
84example of related diversification is its acquisition of Glaceau and
85Vitamin Water, which expanded their drinking lines of business(2019).
75Diversification, the final strategy of the Ansoff Matrix, is more difficult than
76the others since it involves exploring both new markets and new products.
77Related diversification is a diversification strategy that closely relates to
78the firm's core business. Coca-Cola's best example of related diversification
79is its acquisition of Glaceau and Vitamin Water, which expanded their drinking
80lines of business(2019).
8681
8782## Unrelated Diversification
8883
89Unrelated diversification is a diversification strategy that does not
90really relate to the firm\'s core business but still diversifies their
91business portfolio. A good example of this would be a coffee company who
92has decided to enter the market for bicycle sales. The main purpose of
93this strategy is to an extremely diverse company that will not go
94bankrupt if one market goes through difficult times. However, this
95requires a lot of independent skills and heavy investments since the
96company most likely cannot easily transfer knowledge between the markets
97they compete in.
84Unrelated diversification is a diversification strategy that does not really
85relate to the firm's core business but still diversifies their business
86portfolio. A good example of this would be a coffee company who has decided to
87enter the market for bicycle sales. The main purpose of this strategy is to an
88extremely diverse company that will not go bankrupt if one market goes through
89difficult times. However, this requires a lot of independent skills and heavy
90investments since the company most likely cannot easily transfer knowledge
91between the markets they compete in.
9892
9993# Requirements for Success
10094
101To use the Ansoff Matrix framework, managers need to formulate corporate
102goals and objectives. Without goals and direction, management frameworks
103do not present much practical utility. Further, the Ansoff Matrix
104requires the managers involved to make tactical decisions and create a
105path for the company to take toward their goals. Lastly, both the Ansoff
106Matrix needs to consider both internal and external perspectives
107throughout the strategy formulation process.
108
109One interesting probability is that companies will be using multiple
110strategic planning and management frameworks at the same time. While
111this may sound like it could crowd the management process, there are
112numerous reasons to do so. For example, the Ansoff Matrix and the
113Balanced Scorecard are relatively popular, and they cover entirely
114different parts of a company\'s strategy. Using the results from the
115Balanced Scorecard could inform a company of the potential product and
116market demands, such as from customer or supplier survey results, to
117help the company determine which Ansoff Matrix strategy to pursue.
118However, a combined approach at this level would require mature
119frameworks and focused managers who are able to strategize at a high
120level.
121
122Lastly, it should be noted that the author of the Ansoff matrix, Igor
123Ansoff, often used the term [paralysis by
124analysis](https://en.wikipedia.org/wiki/Analysis_paralysis) to explain
125the mistake of companies who overuse analysis and spend too much time
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.
95To use the Ansoff Matrix framework, managers need to formulate corporate goals
96and objectives. Without goals and direction, management frameworks do not
97present much practical utility. Further, the Ansoff Matrix requires the managers
98involved to make tactical decisions and create a path for the company to take
99toward their goals. Lastly, both the Ansoff Matrix needs to consider both
100internal and external perspectives throughout the strategy formulation process.
101
102One interesting probability is that companies will be using multiple strategic
103planning and management frameworks at the same time. While this may sound like
104it could crowd the management process, there are numerous reasons to do so. For
105example, the Ansoff Matrix and the Balanced Scorecard are relatively popular,
106and they cover entirely different parts of a company's strategy. Using the
107results from the Balanced Scorecard could inform a company of the potential
108product and market demands, such as from customer or supplier survey results, to
109help the company determine which Ansoff Matrix strategy to pursue. However, a
110combined approach at this level would require mature frameworks and focused
111managers who are able to strategize at a high level.
112
113Lastly, it should be noted that the author of the Ansoff matrix, Igor Ansoff,
114often used the term [paralysis by
115analysis](https://en.wikipedia.org/wiki/Analysis_paralysis) to explain the
116mistake of companies who overuse analysis and spend too much time planning.
117Companies need to understand the utility of a strategic management framework
118while ensuring that the company is poised to execute as efficiently as they have
119planned.
content/blog/2019-12-16-password-security.md +85 −95
@@ -9,119 +9,109 @@ draft = false
99
1010## Why Does It Matter?
1111
12Information security, including passwords and identities, has become one
13of the most important digital highlights of the last decade. With
14[billions of people affected by data breaches each
12Information security, including passwords and identities, has become one of the
13most important digital highlights of the last decade. With [billions of people
14affected by data breaches each
1515year](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
17systems. If you think you\'ve been part of a breach, or you want to
18check and see, you can use [Have I Been
19Pwned](https://haveibeenpwned.com/) to see if your email has been
20involved in any public breaches. Remember that there\'s a possibility
21that a company experienced a breach and did not report it to anyone.
16there's a greater need to introduce strong information security systems. If you
17think you've been part of a breach, or you want to check and see, you can use
18[Have I Been Pwned](https://haveibeenpwned.com/) to see if your email has been
19involved in any public breaches. Remember that there's a possibility that a
20company experienced a breach and did not report it to anyone.
2221
2322## How Do I Protect Myself?
2423
25The first place to start with any personal security check-up is to
26gather a list of all the different websites, apps, or programs that
27require you to have login credentials. Optionally, once you know where
28your information is being stored, you can sort the list from the
29most-important items such as banks or government logins to less
30important items such as your favorite meme site. You will want to ensure
31that your critical logins are secure before getting to the others.
24The first place to start with any personal security check-up is to gather a list
25of all the different websites, apps, or programs that require you to have login
26credentials. Optionally, once you know where your information is being stored,
27you can sort the list from the most-important items such as banks or government
28logins to less important items such as your favorite meme site. You will want to
29ensure that your critical logins are secure before getting to the others.
3230
3331Once you think you have a good idea of all your different authentication
3432methods, I recommend using a password manager such as
35[Bitwarden](https://bitwarden.com/). Using a password manager allows you
36to automatically save your logins, create randomized passwords, and
37transfer passwords across devices. However, you\'ll need to memorize
38your \"vault password\" that allows you to open the password manager.
39It\'s important to make this something hard to guess since it would
40allow anyone who has it to access every password you\'ve stored in
41there.
33[Bitwarden](https://bitwarden.com/). Using a password manager allows you to
34automatically save your logins, create randomized passwords, and transfer
35passwords across devices. However, you'll need to memorize your "vault
36password" that allows you to open the password manager. It's important to make
37this something hard to guess since it would allow anyone who has it to access
38every password you've stored in there.
4239
4340Personally, I recommend using a
4441[passphrase](https://en.wikipedia.org/wiki/Passphrase) instead of a
45[password](https://en.wikipedia.org/wiki/Password) for your vault
46password. Instead of using a string of characters (whether random or
47simple), use a phrase and add in symbols and a number. For example, your
48vault password could be `Racing-Alphabet-Gourd-Parrot3`. Swap
49the symbols out for whichever symbol you want, move the number around,
50and fine-tune the passphrase until you are confident that you can
51remember it whenever necessary.
52
53Once you\'ve stored your passwords, make sure you continually check up
54on your account and make sure you aren\'t following bad password
55practices. Krebs on Security has a great [blog post on password
56recommendations](https://krebsonsecurity.com/password-dos-and-donts/).
57Any time that a data breach happens, make sure you check to see if you
58were included, and if you need to reset any account passwords.
42[password](https://en.wikipedia.org/wiki/Password) for your vault password.
43Instead of using a string of characters (whether random or simple), use a phrase
44and add in symbols and a number. For example, your vault password could be
45`Racing-Alphabet-Gourd-Parrot3`. Swap the symbols out for whichever symbol you
46want, move the number around, and fine-tune the passphrase until you are
47confident that you can remember it whenever necessary.
48
49Once you've stored your passwords, make sure you continually check up on your
50account and make sure you aren't following bad password practices. Krebs on
51Security has a great [blog post on password
52recommendations](https://krebsonsecurity.com/password-dos-and-donts/). Any time
53that a data breach happens, make sure you check to see if you were included, and
54if you need to reset any account passwords.
5955
6056# Developers
6157
6258## What Are the Basic Requirements?
6359
64When developing any password-protected application, there are a few
65basic rules that anyone should follow even if they do not follow any
66official guidelines such as NIST. The foremost practice is to require
67users to use passwords that are at least 8 characters and cannot easily
68be guessed. This sounds extremely simple, but it requires quite a few
69different strategies. First, the application should check the potential
70passwords against a dictionary of insecure passwords such
71`password`, `1234abc`, or
72`application_name`.
73
74Next, the application should offer guidance on the strength of passwords
75being entered during enrollment. Further, NIST officially recommends
76**not\*** implementing any composition rules that make passwords hard to
77remember (e.g. passwords with letters, numbers, and special characters)
78and instead encouraging the use of long pass phrases which can include
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.
60When developing any password-protected application, there are a few basic rules
61that anyone should follow even if they do not follow any official guidelines
62such as NIST. The foremost practice is to require users to use passwords that
63are at least 8 characters and cannot easily be guessed. This sounds extremely
64simple, but it requires quite a few different strategies. First, the application
65should check the potential passwords against a dictionary of insecure passwords
66such `password`, `1234abc`, or `application_name`.
67
68Next, the application should offer guidance on the strength of passwords being
69entered during enrollment. Further, NIST officially recommends **not**
70implementing any composition rules that make passwords hard to remember (e.g.
71passwords with letters, numbers, and special characters) and instead encouraging
72the use of long pass phrases which can include spaces. It should be noted that
73to be able to keep spaces within passwords, all unicode characters should be
74supported, and passwords should not be truncated.
8275
8376## What Does NIST Recommend?
8477
8578The National Institute of Standards and Technology
86([NIST](https://www.nist.gov)) in the US Department of Commerce
87regularly publishes information around information security and digital
88identity guidelines. Recently, NIST published [Special Publication
89800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html): Digital
90Identity Guidelines and Authentication and Lifecycle Management.
91
92> A Memorized Secret authenticator - commonly referred to as a password
93> or, if numeric, a PIN - is a secret value intended to be chosen and
94> memorized by the user. Memorized secrets need to be of sufficient
95> complexity and secrecy that it would be impractical for an attacker to
96> guess or otherwise discover the correct secret value. A memorized
97> secret is something you know.
79([NIST](https://www.nist.gov)) in the US Department of Commerce regularly
80publishes information around information security and digital identity
81guidelines. Recently, NIST published [Special Publication
82800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html): Digital Identity
83Guidelines and Authentication and Lifecycle Management.
84
85> A Memorized Secret authenticator - commonly referred to as a password or, if
86> numeric, a PIN - is a secret value intended to be chosen and memorized by the
87> user. Memorized secrets need to be of sufficient complexity and secrecy that
88> it would be impractical for an attacker to guess or otherwise discover the
89> correct secret value. A memorized secret is something you know.
9890>
99> - NIST Special Publication 800-63B
100
101NIST offers a lot of guidance on passwords, but I\'m going to highlight
102just a few of the important factors:
103
104- Require passwords to be a minimum of 8 characters (6 characters if
105 randomly generated and be generated using an approved random bit
106 generator).
107- Compare potential passwords against a list that contains values
108 known to be commonly-used, expected, or compromised.
109- Offer guidance on password strength, such as a strength meter.
110- Implement a rate-limiting mechanism to limit the number of failed
111 authentication attempts for each user account.
112- Do not require composition rules for passwords and do not require
113 passwords to be changed periodically (unless compromised).
114- Allow pasting of user identification and passwords to facilitate the
115 use of password managers.
116- Allow users to view the password as it is being entered.
117- Use secure forms of communication and storage, including salting and
118 hashing passwords using a one-way key derivation function.
119
120NIST offers further guidance on other devices that require specific
121security policies, querying for passwords, and more. All the information
122discussed so far comes from [NIST
123SP800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html) but NIST
124offers a lot of information on digital identities, enrollment, identity
125proofing, authentication, lifecycle management, federation, and
126assertions in the total [NIST SP800-63 Digital Identity
91> - NIST Special Publication 800-63B
92
93NIST offers a lot of guidance on passwords, but I'm going to highlight just a
94few of the important factors:
95
96- Require passwords to be a minimum of 8 characters (6 characters if randomly
97 generated and be generated using an approved random bit generator).
98- Compare potential passwords against a list that contains values known to be
99 commonly-used, expected, or compromised.
100- Offer guidance on password strength, such as a strength meter.
101- Implement a rate-limiting mechanism to limit the number of failed
102 authentication attempts for each user account.
103- Do not require composition rules for passwords and do not require passwords to
104 be changed periodically (unless compromised).
105- Allow pasting of user identification and passwords to facilitate the use of
106 password managers.
107- Allow users to view the password as it is being entered.
108- Use secure forms of communication and storage, including salting and hashing
109 passwords using a one-way key derivation function.
110
111NIST offers further guidance on other devices that require specific security
112policies, querying for passwords, and more. All the information discussed so far
113comes from [NIST SP800-63b](https://pages.nist.gov/800-63-3/sp800-63b.html) but
114NIST offers a lot of information on digital identities, enrollment, identity
115proofing, authentication, lifecycle management, federation, and assertions in
116the total [NIST SP800-63 Digital Identity
127117Guidelines](https://pages.nist.gov/800-63-3/).
content/blog/2020-01-25-linux-software.md +72 −87
@@ -12,32 +12,31 @@ draft = false
1212![Etcher
1313Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/etcher.png)
1414
15[Etcher](https://www.balena.io/etcher/) is a quick and easy way to burn
16ISO images to CDs and USB devices. There are two different ways you can
17install this program. First, you can navigate to the [official
18website](https://www.balena.io/etcher/) and download the AppImage file,
19which can run without installation.
15[Etcher](https://www.balena.io/etcher/) is a quick and easy way to burn ISO
16images to CDs and USB devices. There are two different ways you can install this
17program. First, you can navigate to the [official
18website](https://www.balena.io/etcher/) and download the AppImage file, which
19can run without installation.
2020
21However, AppImage files are not executable by default, so you\'ll either
22need to right-click to open the properties of the file and click the
23\"Allow executing file as program\" box in the Permissions tab or use
24the following command:
21However, AppImage files are not executable by default, so you'll either need to
22right-click to open the properties of the file and click the "Allow executing
23file as program" box in the Permissions tab or use the following command:
2524
2625```sh
2726chmod u+x FILE_NAME
2827```
2928
30If you don\'t like AppImage files or just prefer repositories, you can
31use the following commands to add the author\'s repository and install
32it through the command-line only.
29If you don't like AppImage files or just prefer repositories, you can use the
30following commands to add the author's repository and install it through the
31command-line only.
3332
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:
3534
3635```sh
3736echo "deb https://deb.etcher.io stable etcher" | sudo tee /etc/apt/sources.list.d/balena-etcher.list
3837```
3938
40Next, add the application keys to Ubuntu\'s keyring:
39Next, add the application keys to Ubuntu's keyring:
4140
4241```sh
4342sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61
@@ -49,8 +48,7 @@ Finally, update the repositories and install the app.
4948sudo apt update && sudo apt install balena-etcher-electron
5049```
5150
52Using Arch, Manjaro, or another distro using the AUR? Use this command
53instead:
51Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
5452
5553```sh
5654sudo pacman -S etcher
@@ -61,12 +59,11 @@ sudo pacman -S etcher
6159![Atom
6260Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/atom.png)
6361
64[Atom](https://atom.io) is the self-proclaimed \"hackable text editor
65for the 21st century\". This text editor is made by GitHub, [now owned
66by
62[Atom](https://atom.io) is the self-proclaimed "hackable text editor for the
6321st century". This text editor is made by GitHub, [now owned by
6764Microsoft](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
69abilities of the app.
65and has some of the best add-ons available to customize the layout and abilities
66of the app.
7067
7168First, add the Atom repository to your sources.
7269
@@ -80,25 +77,24 @@ Next, update your package listings and install atom.
8077sudo apt update && sudo apt install atom
8178```
8279
83If you have issues updating your packages with the Atom repository,
84you\'ll need to use the snap package described below instead of the
85repository. To remove the repository we just added, use this command:
80If you have issues updating your packages with the Atom repository, you'll need
81to use the snap package described below instead of the repository. To remove the
82repository we just added, use this command:
8683
8784```sh
8885sudo add-apt-repository -r ppa:webupd8team/atom
8986```
9087
91You can also install Atom as a snap package, but it must be installed
92with the `--classic` flag. A [full explanation is
88You can also install Atom as a snap package, but it must be installed with the
89`--classic` flag. A [full explanation is
9390available](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.
9592
9693```sh
9794snap install atom --classic
9895```
9996
100Using Arch, Manjaro, or another distro using the AUR? Use this command
101instead:
97Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
10298
10399```sh
104100sudo pacman -S atom
@@ -109,28 +105,25 @@ sudo pacman -S atom
109105![Visual Studio Code
110106Code](https://img.cleberg.net/blog/20200125-the-best-linux-software/vscode.png)
111107
112[Visual Studio Code](https://code.visualstudio.com) is yet another
113fantastic choice for programming on Linux, especially if you need those
114extra add-ons to spice up your late-night coding sessions. The theme
115used in the screenshot is
116[Mars](https://marketplace.visualstudio.com/items?itemName=EliverLara.mars)
117by theme creator [Eliver Lara](https://github.com/EliverLara), who makes
118a ton of great themes for VS Code, Atom, and various Linux desktop
119environments.
120
121To install VS Code, you\'ll need to download the `.deb` file
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:
108[Visual Studio Code](https://code.visualstudio.com) is yet another fantastic
109choice for programming on Linux, especially if you need those extra add-ons to
110spice up your late-night coding sessions. The theme used in the screenshot is
111[Mars](https://marketplace.visualstudio.com/items?itemName=EliverLara.mars) by
112theme creator [Eliver Lara](https://github.com/EliverLara), who makes a ton of
113great themes for VS Code, Atom, and various Linux desktop environments.
114
115To install VS Code, you'll need to download the `.deb` file from the official
116website. Once you've downloaded the file, either double-click it to install
117through the Software Center or run the following command:
125118
126119```sh
127120sudo dpkg -i FILE_NAME.deb
128121```
129122
130You can also install VS Code as a snap package, but it must be installed
131with the `--classic` flag. A [full explanation is
123You can also install VS Code as a snap package, but it must be installed with
124the `--classic` flag. A [full explanation is
132125available](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.
134127
135128```sh
136129snap install code --classic
@@ -148,19 +141,18 @@ sudo pacman -S yay binutils make gcc pkg-config fakeroot yay -S visual-studio-co
148141![Gnome Tweaks
149142Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/gnome-tweaks.png)
150143
151[Gnome Tweaks](https://gitlab.gnome.org/GNOME/gnome-tweaks) is the
152ultimate tool to use if you want to customize your GNOME desktop
153environment. This is how you can switch application themes (GTK), shell
154themes, icons, fonts, and more. To install GNOME Tweaks on Ubuntu, you
155just need to install the official package.
144[Gnome Tweaks](https://gitlab.gnome.org/GNOME/gnome-tweaks) is the ultimate tool
145to use if you want to customize your GNOME desktop environment. This is how you
146can switch application themes (GTK), shell themes, icons, fonts, and more. To
147install GNOME Tweaks on Ubuntu, you just need to install the official package.
156148
157149```sh
158150sudo apt install gnome-tweaks
159151```
160152
161If you\'ve installed Manjaro or Arch with Gnome, you should have the
162tweak tool pre-installed. If you\'re on Fedora, this tool is available
163as an official package:
153If you've installed Manjaro or Arch with Gnome, you should have the tweak tool
154pre-installed. If you're on Fedora, this tool is available as an official
155package:
164156
165157```sh
166158sudo dnf install gnome-tweaks
@@ -171,22 +163,20 @@ sudo dnf install gnome-tweaks
171163![Steam
172164Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png)
173165
174[Steam](https://steampowered.com) is one of the most popular gaming
175libraries for computers and is one of the main reasons that many people
176have been able to switch to Linux in recent years, thanks to Steam
177Proton, which makes it easier to play games not officially created for
178Linux platforms.
166[Steam](https://steampowered.com) is one of the most popular gaming libraries
167for computers and is one of the main reasons that many people have been able to
168switch to Linux in recent years, thanks to Steam Proton, which makes it easier
169to play games not officially created for Linux platforms.
179170
180To install Steam on Ubuntu, you just need to install the official
181package.
171To install Steam on Ubuntu, you just need to install the official package.
182172
183173```sh
184174sudo apt install steam-installer
185175```
186176
187For Arch-based systems, you\'ll simply need to install the
188`steam` package. However, this requires that you enable the
189`multilib` source. To do so, use the following command:
177For Arch-based systems, you'll simply need to install the `steam` package.
178However, this requires that you enable the `multilib` source. To do so, use the
179following command:
190180
191181```sh
192182sudo nano /etc/pacman.conf
@@ -220,27 +210,26 @@ Here.](./2020-01-26-steam-on-ntfs-drives.html)
220210![Neofetch
221211Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/neofetch.png)
222212
223[Neofetch](https://github.com/dylanaraps/neofetch) is a customizable
224tool used in the command-line to show system information. This is
225exceptionally useful if you want to see your system\'s information
226quickly without the clutter of some resource-heavy GUI apps.
213[Neofetch](https://github.com/dylanaraps/neofetch) is a customizable tool used
214in the command-line to show system information. This is exceptionally useful if
215you want to see your system's information quickly without the clutter of some
216resource-heavy GUI apps.
227217
228This is an official package if you\'re running Ubuntu 17.04 or later, so
229simply use the following command:
218This is an official package if you're running Ubuntu 17.04 or later, so simply
219use the following command:
230220
231221```sh
232222sudo apt install neofetch
233223```
234224
235If you\'re running Ubuntu 16.10 or earlier, you\'ll have to use a series
236of commands:
225If you're running Ubuntu 16.10 or earlier, you'll have to use a series of
226commands:
237227
238228```sh
239229sudo add-apt-repository ppa:dawidd0811/neofetch; sudo apt update; sudo apt install neofetch
240230```
241231
242Using Arch, Manjaro, or another distro using the AUR? Use this command
243instead:
232Using Arch, Manjaro, or another distro using the AUR? Use this command instead:
244233
245234```sh
246235sudo pacman -S neofetch
@@ -251,31 +240,27 @@ sudo pacman -S neofetch
251240![yt-dlp
252241Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/yt-dlp.png)
253242
254[yt-dlp](https://github.com/yt-dlp/yt-dlp) is an extremely handy
255command-line tool that allows you to download video or audio files from
256various websites, such as YouTube. There are a ton of different options
257when running this package, so be sure to run `yt-dlp --help`
258first to look through everything you can do (or give up and search for
259the best config online).
243[yt-dlp](https://github.com/yt-dlp/yt-dlp) is an extremely handy command-line
244tool that allows you to download video or audio files from various websites,
245such as YouTube. There are a ton of different options when running this package,
246so be sure to run `yt-dlp --help` first to look through everything you can do
247(or give up and search for the best config online).
260248
261While this shouldn\'t be a problem for most users, yt-dlp requires
262Python 2.6, 2.7, or 3.2+ to work correctly, so install Python if you
263don\'t have it already. You can check to see if you have Python
264installed by running:
249While this shouldn't be a problem for most users, yt-dlp requires Python 2.6,
2502.7, or 3.2+ to work correctly, so install Python if you don't have it already.
251You can check to see if you have Python installed by running:
265252
266253```sh
267254python -V
268255```
269256
270To get the youtube-dl package, simply curl the URL and output the
271results.
257To get the youtube-dl package, simply curl the URL and output the results.
272258
273259```sh
274260sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
275261```
276262
277Finally, make the file executable so that it can be run from the
278command-line.
263Finally, make the file executable so that it can be run from the command-line.
279264
280265```sh
281266sudo 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
1010![Steam
1111Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.png)
1212
13If you want to see how to install Steam on Linux, see my other post:
14[Linux Software](../linux-software/).
13If you want to see how to install Steam on Linux, see my other post: [Linux
14Software](../linux-software/).
1515
16Are you having trouble launching games, even though they\'ve installed
17correctly? This may happen if you\'re storing your games on an
18NTFS-formatted drive. This shouldn\'t be an issue if you\'re storing
19your games on the same drive that Steam is on, but some gamers prefer to
20put Steam on their main drive and game files on another SSD or HDD.
16Are you having trouble launching games, even though they've installed
17correctly? This may happen if you're storing your games on an NTFS-formatted
18drive. This shouldn't be an issue if you're storing your games on the same
19drive that Steam is on, but some gamers prefer to put Steam on their main drive
20and game files on another SSD or HDD.
2121
22To fix this problem, you\'ll need to try a few things. First, you\'ll
23need to install the `ntfs-3g` package, which is meant for
24better interoperability with Linux.
22To fix this problem, you'll need to try a few things. First, you'll need to
23install the `ntfs-3g` package, which is meant for better interoperability with
24Linux.
2525
2626```sh
2727sudo apt install ntfs-3g
2828```
2929
30Next, you should set up the `/etc/fstab` file to
31automatically mount your drives on boot. To automatically mount your
32drives when the computer boots up, you\'ll have to create the folders
33you want to mount your drive to first. I store mine in the
34`/mnt` folder using names that I\'ll recognize, but you can
35create your folders wherever you want.
30Next, you should set up the `/etc/fstab` file to automatically mount your drives
31on boot. To automatically mount your drives when the computer boots up, you'll
32have to create the folders you want to mount your drive to first. I store mine
33in the `/mnt` folder using names that I'll recognize, but you can create your
34folders wherever you want.
3635
3736```sh
3837mkdir /path/to/folder
@@ -44,28 +43,27 @@ For example:
4443mkdir /mnt/steam_library
4544```
4645
47To automatically mount drives upon system boot, you will need to collect
48a few items. The UUID is the identification number connected to
49whichever drive you\'re using to store Steam games.
46To automatically mount drives upon system boot, you will need to collect a few
47items. The UUID is the identification number connected to whichever drive
48you're using to store Steam games.
5049
51Drives are usually labeled similar to `/dev/nvme0n1p1` or
52`/dev/sda1`, so you\'ll need to find the line in the output
53of the command below that correlates to your drive and copy the UUID
54over to the `/etc/fstab` file.
50Drives are usually labeled similar to `/dev/nvme0n1p1` or `/dev/sda1`, so
51you'll need to find the line in the output of the command below that correlates
52to your drive and copy the UUID over to the `/etc/fstab` file.
5553
5654```sh
5755sudo blkid | grep UUID=
5856```
5957
60Next, you\'ll need your `uid` and `gid`. To find
61these, run the following command:
58Next, you'll need your `uid` and `gid`. To find these, run the following
59command:
6260
6361```sh
6462id -u && id -g
6563```
6664
67Now that you have collected the necessary information, open the
68`/etc/fstab` file:
65Now that you have collected the necessary information, open the `/etc/fstab`
66file:
6967
7068```sh
7169sudo nano /etc/fstab
@@ -78,9 +76,8 @@ Each drive you want to mount on boot should have its own line in the
7876UUID=B64E53824E5339F7 /mnt/steam_library ntfs-3g uid=1000,gid=1000 0 0
7977```
8078
81Now all you need to do is unmount your drive and re-mount it. You can
82unmount the drive by doing this (be sure to use the correct drive name
83here):
79Now all you need to do is unmount your drive and re-mount it. You can unmount
80the drive by doing this (be sure to use the correct drive name here):
8481
8582```sh
8683sudo umount /dev/sdxX
@@ -92,6 +89,6 @@ You can re-mount all your drives by executing the following:
9289sudo mount -a
9390```
9491
95If you don\'t know what your drive name is, or you\'re nervous about
96unmounting and re-mounting, simply reboot your computer, and it will be
97done for you automatically.
92If you don't know what your drive name is, or you're nervous about unmounting
93and re-mounting, simply reboot your computer, and it will be done for you
94automatically.
content/blog/2020-02-09-cryptography-basics.md +135 −148
@@ -7,174 +7,161 @@ draft = false
77
88# Similar Article Available
99
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
1111Encryption](../aes-encryption/).
1212
1313# What is Cryptography?
1414
15In layman\'s terms, cryptography is a process that can change data from
16a readable format into an unreadable format (and vice-versa) through a
17series of processes and secrets. More technically, this is the Internet
18Security Glossary\'s definition:
19
20> \[Cryptography is\] the mathematical science that deals with
21> transforming data to render its meaning unintelligible (i.e., to hide
22> its semantic content), prevent its undetected alteration, or prevent
23> its unauthorized use. If the transformation is reversible,
24> cryptography also deals with restoring encrypted data to an
25> intelligible form.
15In layman's terms, cryptography is a process that can change data from a
16readable format into an unreadable format (and vice-versa) through a series of
17processes and secrets. More technically, this is the Internet Security
18Glossary's definition:
19
20> [Cryptography is] the mathematical science that deals with transforming data
21> to render its meaning unintelligible (i.e., to hide its semantic content),
22> prevent its undetected alteration, or prevent its unauthorized use. If the
23> transformation is reversible, cryptography also deals with restoring encrypted
24> data to an intelligible form.
2625>
27> - [Internet Security Glossary
28> (2000)](https://tools.ietf.org/html/rfc2828)
26> - [Internet Security Glossary (2000)](https://tools.ietf.org/html/rfc2828)
2927
30Cryptography cannot offer protection against the loss of data; it simply
31offers encryption methods to protect data at-rest and data in-traffic.
32At a high-level, encrypted is when plaintext data is encrypted to
33ciphertext (a secure form of text that cannot be understood unless
34decrypted back to plaintext). The encryption process is completed
35through the use of a mathematical function that utilizes one or more
36values called keys to encrypt or decrypt the data.
28Cryptography cannot offer protection against the loss of data; it simply offers
29encryption methods to protect data at-rest and data in-traffic. At a high-level,
30encrypted is when plaintext data is encrypted to ciphertext (a secure form of
31text that cannot be understood unless decrypted back to plaintext). The
32encryption process is completed through the use of a mathematical function that
33utilizes one or more values called keys to encrypt or decrypt the data.
3734
3835# Key Elements of Cryptographic Systems
3936
40To create or evaluate a cryptographic system, you need to know the
41essential pieces to the system:
42
43- **Encryption Algorithm (Primitive):\*** A mathematical process that
44 encrypts and decrypts data.
45- **Encryption Key:\*** A string of bits used within the encryption
46 algorithm as the secret that allows successful encryption or
47 decryption of data.
48- **Key Length (Size):\*** The maximum number of bits within the
49 encryption key. It\'s important to remember that key size is
50 regulated in many countries.
51- **Message Digest:\*** A smaller, fixed-size bit string version of
52 the original message. This is practically infeasible to reverse,
53 which is why it\'s commonly used to verify integrity.
37To create or evaluate a cryptographic system, you need to know the essential
38pieces to the system:
39
40- **Encryption Algorithm (Primitive):** A mathematical process that encrypts
41 and decrypts data.
42- **Encryption Key:** A string of bits used within the encryption algorithm as
43 the secret that allows successful encryption or decryption of data.
44- **Key Length (Size):** The maximum number of bits within the encryption key.
45 It's important to remember that key size is regulated in many countries.
46- **Message Digest:** A smaller, fixed-size bit string version of the original
47 message. This is practically infeasible to reverse, which is why it's
48 commonly used to verify integrity.
5449
5550# Symmetric Systems (Secret Key Cryptography)
5651
57Symmetric cryptography utilizes a secret, bidirectional key to perform
58both encryption and decryption of the data. The most common
59implementation of symmetric cryptography is the Advanced Encryption
60Standard, which uses keys that are 128 bits to 256 bits in size. This
61standard came after the National Institute of Standards and Technology
62(NIST) decided to retire the Data Encryption Standard (DES) in 2001.
63
64Since brute force attacks strongly correlate with key length, the 56-bit
65key length of DES was considered insecure after it was publicly broken
66in under 24 hours. However, there is a modern implementation of DES
67called Triple DES where the DES method is applied three times to each
68data block.
69
70The main advantages to symmetric systems are the ease of use, since only
71one key is required for both encryption and decryption, and the
72simplicity of the algorithms. This helps with bulk data encryption that
73may unnecessarily waste time and power using asymmetric systems.
74
75However, symmetric systems have disadvantages to keep in mind. Since the
76key is private, it can be difficult to safely distribute keys to
77communication partners. Additionally, the key cannot be used to sign
78messages since it\'s necessary to keep the key private.
52Symmetric cryptography utilizes a secret, bidirectional key to perform both
53encryption and decryption of the data. The most common implementation of
54symmetric cryptography is the Advanced Encryption Standard, which uses keys that
55are 128 bits to 256 bits in size. This standard came after the National
56Institute of Standards and Technology (NIST) decided to retire the Data
57Encryption Standard (DES) in 2001.
58
59Since brute force attacks strongly correlate with key length, the 56-bit key
60length of DES was considered insecure after it was publicly broken in under 24
61hours. However, there is a modern implementation of DES called Triple DES where
62the DES method is applied three times to each data block.
63
64The main advantages to symmetric systems are the ease of use, since only one key
65is required for both encryption and decryption, and the simplicity of the
66algorithms. This helps with bulk data encryption that may unnecessarily waste
67time and power using asymmetric systems.
68
69However, symmetric systems have disadvantages to keep in mind. Since the key is
70private, it can be difficult to safely distribute keys to communication
71partners. Additionally, the key cannot be used to sign messages since it's
72necessary to keep the key private.
7973
8074# Asymmetric Systems (Public Key Cryptography)
8175
82Asymmetric cryptography utilizes two keys within the system: a secret
83key that is privately-held and a public key that can be distributed
84freely. The interesting aspect of asymmetric cryptography is that either
85key can be used to encrypt the data, there\'s no rule that dictates
86which key must be used for encryption. Once one key is used to encrypt
87the data, only the other key can be used to decrypt the data. This means
88that if the private key encrypts the data, only the public key can
89decrypt the data.
90
91An advantage of this system is that if you successfully decrypt data
92using one of the keys, you can be sure of the sender since only the
93other key could have encrypted the data.
94
95One of the major implementations of an asymmetric system is a digital
96signature. A digital signature can be generated using the sender\'s
97private key, or a one-way hash function and is used to provide assurance
98for the integrity and authenticity of the message. A couple common
99message digest algorithms are SHA-256 and SHA-512, which securely
100compress data and produce a 128-bit message digest.
101
102It should be noted that man-in-the-middle attacks are one of the risks
103with digital signatures and public keys. To combat this, applications
104often use a public key infrastructure (PKI) to independently
105authenticate the validity of signatures and keys.
76Asymmetric cryptography utilizes two keys within the system: a secret key that
77is privately-held and a public key that can be distributed freely. The
78interesting aspect of asymmetric cryptography is that either key can be used to
79encrypt the data, there's no rule that dictates which key must be used for
80encryption. Once one key is used to encrypt the data, only the other key can be
81used to decrypt the data. This means that if the private key encrypts the data,
82only the public key can decrypt the data.
83
84An advantage of this system is that if you successfully decrypt data using one
85of the keys, you can be sure of the sender since only the other key could have
86encrypted the data.
87
88One of the major implementations of an asymmetric system is a digital signature.
89A digital signature can be generated using the sender's private key, or a
90one-way hash function and is used to provide assurance for the integrity and
91authenticity of the message. A couple common message digest algorithms are
92SHA-256 and SHA-512, which securely compress data and produce a 128-bit message
93digest.
94
95It should be noted that man-in-the-middle attacks are one of the risks with
96digital signatures and public keys. To combat this, applications often use a
97public key infrastructure (PKI) to independently authenticate the validity of
98signatures and keys.
10699
107100Due to the large key size and [inefficient mathematical
108functions](https://crypto.stackexchange.com/a/591) of asymmetric
109encryption, elliptical curve cryptography (ECC) is often used to
110increase security while using fewer resources.
101functions](https://crypto.stackexchange.com/a/591) of asymmetric encryption,
102elliptical curve cryptography (ECC) is often used to increase security while
103using fewer resources.
111104
112105# Applications of Cryptographic Systems
113106
114There are quite a few implementations of cryptographic systems around
115the world. Here are a few popular examples:
116
117**Transport Layer Security (TLS):\*** One of the most famous
118cryptographic solutions created is TLS, a session-layered or
119connection-layered internet protocol that allows for secure
120communications between browsers and servers. Using handshakes, peer
121negotiation, and authentication allows TLS to prevent eavesdropping and
122malicious transformation of data. The major reason for TLS popularity is
123that a major vulnerability was found in the SSL protocol in 2014.
124Instead of SSL, TLS can be used with HTTP to form HTTPS and is the
125preferred method for modern web development due to its increased
126security.
127
128**Secure Hypertext Transfer Protocol (HTTPS):\*** An application layer
129protocol that allows for secure transport of data between servers and
130web clients. One of the unique parts of HTTPS is that it uses a secured
131port number instead of the default web port address.
132
133**Virtual Private Network (VPN):\*** VPNs are made to securely extend a
134private network across public networks by utilizing an encrypted layered
135tunneling protocol paired with an authentication method, such as
136usernames and passwords. This technology originally allowed remote
137employees to access their company\'s data but have evolved into one of
138the top choices for anyone who wishes to mask their sensitive personal
139data.
140
141**Internet Protocol Security (IPSec):\*** This protocol suite
142facilitates communication between two or more hosts or subnets by
143authenticating and encrypting the data packets. IPSec is used in a lot
144of VPNs to establish the VPN connection through the transport and tunnel
145mode encryption methods. IPSec encrypts just the data portion of packets
146in the transport methods, but it encrypts both the data and headers in
147the tunnel method (introducing an additional header for authentication).
148
149**Secure Shell (SSH):\*** SSH is another network protocol used to
150protect network services by authenticating users through a secure
151channel. This protocol is often used for command-line (shell) functions
152such as remote shell commands, logins, and file transfers.
153
154**Kerberos:\*** Developed by MIT, Kerberos is a computer-network
155authentication protocol that works on the basis of tickets to allow
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).
107There are quite a few implementations of cryptographic systems around the world.
108Here are a few popular examples:
109
110**Transport Layer Security (TLS):** One of the most famous cryptographic
111solutions created is TLS, a session-layered or connection-layered internet
112protocol that allows for secure communications between browsers and servers.
113Using handshakes, peer negotiation, and authentication allows TLS to prevent
114eavesdropping and malicious transformation of data. The major reason for TLS
115popularity is that 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
117method for modern web development due to its increased security.
118
119**Secure Hypertext Transfer Protocol (HTTPS):** An application layer protocol
120that allows for secure transport of data between servers and web clients. One of
121the unique parts of HTTPS is that it uses a secured port number instead of the
122default web port address.
123
124**Virtual Private Network (VPN):** VPNs are made to securely extend a private
125network across public networks by utilizing an encrypted layered tunneling
126protocol paired with an authentication method, such as usernames and passwords.
127This technology originally allowed remote employees to access their company's
128data but have evolved into one of the top choices for anyone who wishes to mask
129their sensitive personal data.
130
131**Internet Protocol Security (IPSec):** This protocol suite facilitates
132communication between two or more hosts or subnets by authenticating and
133encrypting the data packets. IPSec is used in a lot of VPNs to establish the VPN
134connection through the transport and tunnel mode encryption methods. IPSec
135encrypts just the data portion of packets in the transport methods, but it
136encrypts both the data and headers in the tunnel method (introducing an
137additional header for authentication).
138
139**Secure Shell (SSH):** SSH is another network protocol used to protect
140network services by authenticating users through a secure channel. This protocol
141is often used for command-line (shell) functions such as remote shell commands,
142logins, and file transfers.
143
144**Kerberos:** Developed by MIT, Kerberos is a computer-network authentication
145protocol that works on the basis of tickets to allow nodes communicating over a
146non-secure network to prove their identity to one another securely. This is most
147commonly used in business environments when used as the authentication and
148encryption method for Windows Active Directory (AD).
160149
161150# Cybersecurity Controls
162151
163If you\'re someone who needs solutions on how to control risks
164associated with utilizing a crytograhpic system, start with a few basic
165controls:
166
167- **Policies:\*** A policy on the use of cryptographic controls for
168 protection of information is implemented and is in accordance with
169 organizational objectives.
170- **Key management:\*** A policy on the use, protection and lifetime
171 of cryptographic keys is implemented through the entire application
172 lifecycle.
173- **Key size:\*** The organization has researched the optimal key size
174 for their purposes, considering national laws, required processing
175 power, and longevity of the solution.
176- **Algorithm selection:\*** Implemented algorithms are sufficiently
177 appropriate for the business of the organization, robust, and align
178 with recommended guidelines.
179- **Protocol configuration:\*** Protocols have been reviewed and
180 configured suitable to the purpose of the business.
152If you're someone who needs solutions on how to control risks associated with
153utilizing a crytograhpic system, start with a few basic controls:
154
155- **Policies:** A policy on the use of cryptographic controls for protection
156 of information is implemented and is in accordance with organizational
157 objectives.
158- **Key management:** A policy on the use, protection and lifetime of
159 cryptographic keys is implemented through the entire application lifecycle.
160- **Key size:** The organization has researched the optimal key size for their
161 purposes, considering national laws, required processing power, and longevity
162 of the solution.
163- **Algorithm selection:** Implemented algorithms are sufficiently appropriate
164 for the business of the organization, robust, and align with recommended
165 guidelines.
166- **Protocol configuration:** Protocols have been reviewed and configured
167 suitable to the purpose of the business.
content/blog/2020-03-25-session-messenger.md +64 −69
@@ -7,67 +7,65 @@ draft = false
77
88# Privacy Warning
99
10The company behind Session (Loki Foundation) is from Australia. If you
11didn\'t know, Australia has introduced
10The company behind Session (Loki Foundation) is from Australia. If you didn't
11know, Australia has introduced
1212[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
14access into applications. For more information, read my article on [AES
13mandating companies comply with government requests to build backdoor access
14into applications. For more information, read my article on [AES
1515Encryption](./2020-01-25-aes-encryption.html).
1616
1717# About Session
1818
19[Session](https://getsession.org) is a private, cross-platform messaging
20app from the [Loki Foundation](https://loki.foundation). As someone who
21has spent years looking for quality alternatives to major messaging
22apps, I was excited when I first heard about Session. Reading through
23[Session\'s white paper](https://arxiv.org/pdf/2002.04609.pdf), you can
24learn the technologies behind the Session app. Part of the security of
25Session comes from the Signal protocol, which was forked as the origin
26of Session.
19[Session](https://getsession.org) is a private, cross-platform messaging app
20from the [Loki Foundation](https://loki.foundation). As someone who has spent
21years looking for quality alternatives to major messaging apps, I was excited
22when I first heard about Session. Reading through [Session's white
23paper](https://arxiv.org/pdf/2002.04609.pdf), you can learn the technologies
24behind the Session app. Part of the security of Session comes from the Signal
25protocol, which was forked as the origin of Session.
2726
28> Session is an end-to-end encrypted messenger that removes sensitive
29> metadata collection, and is designed for people who want privacy and
30> freedom from any forms of surveillance.
27> Session is an end-to-end encrypted messenger that removes sensitive metadata
28> collection, and is designed for people who want privacy and freedom from any
29> forms of surveillance.
3130
3231In general, this app promises security through end-to-end encryption,
33decentralized onion routing, and private identities. The biggest change
34that the Loki Foundation has made to the Signal protocol is removing the
35need for a phone number. Instead, a random identification string is
36generated for any session you create. This means you can create a new
37session for each device if you want to, or link new devices with your
38ID.
32decentralized onion routing, and private identities. The biggest change that the
33Loki Foundation has made to the Signal protocol is removing the need for a phone
34number. Instead, a random identification string is generated for any session you
35create. This means you can create a new session for each device if you want to,
36or link new devices with your ID.
3937
40Since Session\'s website and white paper describe the details of
41Session\'s security, I\'m going to focus on using the app in this post.
38Since Session's website and white paper describe the details of Session's
39security, I'm going to focus on using the app in this post.
4240
4341# Features
4442
45Since most people are looking for an alternative to a popular chat app,
46I am going to list out the features that Session has so that you are
47able to determine if the app would suit your needs:
48
49- Multiple device linking (via QR code or ID)
50- App locking via device screen lock, password, or fingerprint
51- Screenshot blocking
52- Incognito keyboard
53- Read receipts and typing indicators
54- Mobile notification customization
55- Old message deletion and conversation limit
56- Backups
57- Recovery phrase
58- Account deletion, including ID, messages, sessions, and contacts
43Since most people are looking for an alternative to a popular chat app, I am
44going to list out the features that Session has so that you are able to
45determine if the app would suit your needs:
46
47- Multiple device linking (via QR code or ID)
48- App locking via device screen lock, password, or fingerprint
49- Screenshot blocking
50- Incognito keyboard
51- Read receipts and typing indicators
52- Mobile notification customization
53- Old message deletion and conversation limit
54- Backups
55- Recovery phrase
56- Account deletion, including ID, messages, sessions, and contacts
5957
6058# Downloads
6159
62I have tested this app on Ubuntu 19.10, Android 10, macOS Monterey, and
63iOS 15. All apps have worked well without many issues.
60I have tested this app on Ubuntu 19.10, Android 10, macOS Monterey, and iOS 15.
61All apps have worked well without many issues.
6462
65Below is a brief overview of the Session app on Linux. To get this app,
66you\'ll need to go to the [Downloads](https://getsession.org/download/)
67page and click to link to the operating system you\'re using.
63Below is a brief overview of the Session app on Linux. To get this app, you'll
64need to go to the [Downloads](https://getsession.org/download/) page and click
65to link to the operating system you're using.
6866
69For Linux, it will download an AppImage that you\'ll need to enable with
70the following command:
67For Linux, it will download an AppImage that you'll need to enable with the
68following command:
7169
7270```sh
7371sudo 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
7876
7977# Creating an Account
8078
81Once you\'ve installed the app, simply run the app and create your
82unique Session ID. It will look something like this:
79Once you've installed the app, simply run the app and create your unique
80Session ID. It will look something like this:
8381`05af1835afdd63c947b47705867501d6373f486aa1ae05b1f2f3fcd24570eba608`.
8482
85You\'ll need to set a display name and, optionally, a password. If you
86set a password, you will need to enter it every time you open the app.
83You'll need to set a display name and, optionally, a password. If you set a
84password, you will need to enter it every time you open the app.
8785
8886![Session Login
8987(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/
9694
9795# Start Messaging
9896
99Once you\'ve created your account and set up your profile details, the
100next step is to start messaging other people. To do so, you\'ll need to
101share your Session ID with other people. From this point, it\'s fairly
102straightforward and acts like any other messaging app, so I won\'t dive
103into much detail here.
97Once you've created your account and set up your profile details, the next step
98is to start messaging other people. To do so, you'll need to share your Session
99ID with other people. From this point, it's fairly straightforward and acts
100like any other messaging app, so I won't dive into much detail here.
104101
105102## macOS
106103
107104![macOS
108105Conversations](https://img.cleberg.net/blog/20200325-session-private-messenger/session_macos_conversations.png)
109106
110One key feature to note is that the desktop application now provides a
111helpful pop-up box explaining the process that Session uses to hide your
112IP address:
107One key feature to note is that the desktop application now provides a helpful
108pop-up box explaining the process that Session uses to hide your IP address:
113109
114110![IP Address Help
115111Box](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ip.png)
116112
117113## iOS
118114
119The mobile app is quite simple and effective, giving you all the
120standard mobile messaging options you\'d expect.
115The mobile app is quite simple and effective, giving you all the standard mobile
116messaging options you'd expect.
121117
122118![iOS
123119App](https://img.cleberg.net/blog/20200325-session-private-messenger/session_ios.png)
124120
125121# Potential Issues
126122
127I\'ve discovered one annoying issue that would prevent from using this
128app regularly. On a mobile device, there have been issues with receiving
129messages on time. Even with battery optimization disabled and no network
130restrictions, Session notifications sometimes do not display until I
131open the app or the conversation itself and wait a few moments. This is
132actually one of the reasons I stopped using Signal (this seems fixed as
133of my updates in 2021/2022, so I wouldn\'t worry about this issue
134anymore).
135
136Looking for another messenger instead of Session? I recommend Signal,
137Matrix, and IRC.
123I've discovered one annoying issue that would prevent from using this app
124regularly. On a mobile device, there have been issues with receiving messages on
125time. Even with battery optimization disabled and no network restrictions,
126Session notifications sometimes do not display until I open the app or the
127conversation itself and wait a few moments. This is actually one of the reasons
128I stopped using Signal (this seems fixed as of my updates in 2021/2022, so I
129wouldn't worry about this issue anymore).
130
131Looking for another messenger instead of Session? I recommend Signal, Matrix,
132and IRC.
content/blog/2020-05-03-homelab.md +87 −98
@@ -7,16 +7,15 @@ draft = false
77
88# What is a Homelab?
99
10Starting as a developer, I have largely stayed away from hardware-based
11hobbies (other than building a gaming desktop). However, as the
12quarantine for COVID-19 stretches out further and further, I found
13myself bored and in search of new hobbies. After spending the last few
14months browsing the [r/homelab](https://www.reddit.com/r/homelab/)
15subreddit, I decided it was time to jump in and try things out for
16myself.
10Starting as a developer, I have largely stayed away from hardware-based hobbies
11(other than building a gaming desktop). However, as the quarantine for COVID-19
12stretches out further and further, I found myself bored and in search of new
13hobbies. After spending the last few months browsing the
14[r/homelab](https://www.reddit.com/r/homelab/) subreddit, I decided it was time
15to jump in and try things out for myself.
1716
18Since I am a beginner and just recently graduated from college,
19everything I\'ve done so far in my homelab is fairly low-budget.
17Since I am a beginner and just recently graduated from college, everything I've
18done so far in my homelab is fairly low-budget.
2019
2120# Hardware
2221
@@ -26,141 +25,131 @@ Diagram](https://img.cleberg.net/blog/20200503-homelab/homelab-min.png)
2625### Raspberry Pi 4
2726
2827Luckily, I had actually purchased a [Raspberry Pi
294](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) before
30the quarantine started so that I could try to keep Plex Media Center
31running, even while my desktop computer was turned off. I started here,
32using the Pi to hold Plex and Pi-hole until I grew tired with the slow
33performance.
284](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) before the
29quarantine started so that I could try to keep Plex Media Center running, even
30while my desktop computer was turned off. I started here, using the Pi to hold
31Plex and Pi-hole until I grew tired with the slow performance.
3432
3533Here are the specifications for the Pi 4:
3634
37- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz
38- 4GB LPDDR4-3200 SDRAM
39- Gigabit Ethernet
40- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode)
41- 64 GB MicroSD Card
35- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz
36- 4GB LPDDR4-3200 SDRAM
37- Gigabit Ethernet
38- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode)
39- 64 GB MicroSD Card
4240
4341## Dell Optiplex 5040
4442
45Since I wasn\'t happy with the Pi as my main server, I turned to
46Craigslist. I know a lot of other homelabbers use Ebay, but I can\'t
47seem to ever trust it enough to purchase items on there. So I used
48Craigslist and found a Dell Optiplex 5040 desktop computer on sale for
49\$90. While this computer might be underpowered, it was one of the few
50computers under \$100 that was available during quarantine.
43Since I wasn't happy with the Pi as my main server, I turned to Craigslist. I
44know a lot of other homelabbers use Ebay, but I can't seem to ever trust it
45enough to purchase items on there. So I used Craigslist and found a Dell
46Optiplex 5040 desktop computer on sale for $90. While this computer might be
47underpowered, it was one of the few computers under $100 that was available
48during quarantine.
5149
5250Here are the specifications for the Dell Optiplex 5040:
5351
54- Intel Core i3 6100
55- 8GB RAM DDR3
56- Intel HD Graphics
57- Gigabit Ethernet
58- 500GB Hard Drive
52- Intel Core i3 6100
53- 8GB RAM DDR3
54- Intel HD Graphics
55- Gigabit Ethernet
56- 500GB Hard Drive
5957
60While this hardware would be awful for a work computer or a gaming rig,
61it turned out to be wonderful for my server purposes. The only
62limitation I have found so far is the CPU. The i3-6100 only has enough
63power for a single 4k video transcode at a time. I haven\'t tested more
64than three 1080p streams at a time, but the maximum amount of streams
65I\'ve ever actually used is two.
58While this hardware would be awful for a work computer or a gaming rig, it
59turned out to be wonderful for my server purposes. The only limitation I have
60found so far is the CPU. The i3-6100 only has enough power for a single 4k video
61transcode at a time. I haven't tested more than three 1080p streams at a time,
62but the maximum amount of streams I've ever actually used is two.
6663
6764## WD easystore 10TB & 8TB
6865
69Application storage and temporary files are stored on the internal hard
70drive of the server, but all media files (movies, tv, games, books, etc)
71are stored externally on my WD easystore hard drive. Creating auto-boot
72configurations in the `/etc/fstab` file on my server allows
73the hard drives to automatically mount whenever I need to restart my
74server.
66Application storage and temporary files are stored on the internal hard drive of
67the server, but all media files (movies, tv, games, books, etc) are stored
68externally on my WD easystore hard drive. Creating auto-boot configurations in
69the `/etc/fstab` file on my server allows the hard drives to automatically mount
70whenever I need to restart my server.
7571
76> Update: In March 2022, I shucked the hard drives out of their external
77> cases, put some Kapton tape on the third power pin to prevent power
78> shutdowns, and stuck them inside my server tower using internal SATA
79> cables.
72> Update: In March 2022, I shucked the hard drives out of their external cases,
73> put some Kapton tape on the third power pin to prevent power shutdowns, and
74> stuck them inside my server tower using internal SATA cables.
8075
8176## Netgear Unmanaged Switch
8277
83To manage all the ethernet cords used by my homelab, my desktop, and my
84living room media center, I purchased an 8-port gigabit ethernet switch
85for \$50 at my local computer store. This is probably much more than I
86should have spent on an unmanaged switch, but I am comfortable with the
87choice.
78To manage all the ethernet cords used by my homelab, my desktop, and my living
79room media center, I purchased an 8-port gigabit ethernet switch for $50 at my
80local computer store. This is probably much more than I should have spent on an
81unmanaged switch, but I am comfortable with the choice.
8882
8983## TP-Link Managed Switch
9084
91Since I use the unmanaged switch to group all living room devices
92together, I use the managed switch to configure VLANs and secure my
93network.
85Since I use the unmanaged switch to group all living room devices together, I
86use the managed switch to configure VLANs and secure my network.
9487
9588## Arris TM1602A Modem & Sagecom Fast 5280 Router
9689
97My default modem and router, provided by my ISP, are fairly standard.
98The Arris modem supports DOCSIS 3.0, which is something that I
99definitely wanted as a minimum. The Sagecom router is also standard, no
100fancy bells or whistles. However, it does support DHCP and DHCPv6, which
101is something you can use to route all household traffic through a
102pi-hole or firewall.
90My default modem and router, provided by my ISP, are fairly standard. The Arris
91modem supports DOCSIS 3.0, which is something that I definitely wanted as a
92minimum. The Sagecom router is also standard, no fancy bells or whistles.
93However, it does support DHCP and DHCPv6, which is something you can use to
94route all household traffic through a pi-hole or firewall.
10395
10496## TP-Link EAP
10597
106In order to gain better control over the network, I use my own wireless
107access point instead of the one included in the Sagecom router above.
108Now I can control and organize all of my ethernet connections through
109the VLANs on the managed switch and wireless connections through the
110VLANS on the EAP.
98In order to gain better control over the network, I use my own wireless access
99point instead of the one included in the Sagecom router above. Now I can control
100and organize all of my ethernet connections through the VLANs on the managed
101switch and wireless connections through the VLANS on the EAP.
111102
112103## Generic Printer
113104
114The last piece to my homelab is a standard wireless printer. Nothing
115special here.
105The last piece to my homelab is a standard wireless printer. Nothing special
106here.
116107
117108# Software
118109
119110## Ubuntu Server 20.04
120111
121While the 20.04 version of Ubuntu was just released, I always like to
122experiment with new features (and I don\'t mind breaking my system - it
123just gives me more experience learning how to fix things). So, I have
124Ubuntu Server 20.04 installed on the Dell Optiplex server and Ubuntu
125Server 19.10 installed on the Raspberry Pi. Once I find an acceptable
126use for the Pi, I will most likely switch the operating system.
112While the 20.04 version of Ubuntu was just released, I always like to experiment
113with new features (and I don't mind breaking my system - it just gives me more
114experience learning how to fix things). So, I have Ubuntu Server 20.04 installed
115on the Dell Optiplex server and Ubuntu Server 19.10 installed on the Raspberry
116Pi. Once I find an acceptable use for the Pi, I will most likely switch the
117operating system.
127118
128119## Docker
129120
130I am *very* new to Docker, but I have had a lot of fun playing with it
131so far. Docker is used to create containers that can hold all the
132contents of a system without interfering with other software on the same
133system. So far, I have successfully installed pi-hole, GitLab, Gogs, and
134Nextcloud in containers. However, I opted to delete all of those so that
135I can reconfigure them more professionally at a later time.
121I am *very* new to Docker, but I have had a lot of fun playing with it so far.
122Docker is used to create containers that can hold all the contents of a system
123without interfering with other software on the same system. So far, I have
124successfully installed pi-hole, GitLab, Gogs, and Nextcloud in containers.
125However, I opted to delete all of those so that I can reconfigure them more
126professionally at a later time.
136127
137128## Plex Media Server
138129
139Plex is a media center software that allows you to organize your movies,
140TV shows, music, photos, and videos automatically. It will even download
141metadata for you so that you can easily browse these collections.
130Plex is a media center software that allows you to organize your movies, TV
131shows, music, photos, and videos automatically. It will even download metadata
132for you so that you can easily browse these collections.
142133
143134## Pi-hole
144135
145Pi-hole is an alternative ad-blocker that runs at the DNS level,
146allowing you to block traffic when it hits your network, so that you can
147reject any traffic you deem to be bad. Pi-hole uses blacklists and
148whitelists to decide which traffic block and, luckily, there are a lot
149of pre-made lists out there on Reddit, GitHub, etc.
136Pi-hole is an alternative ad-blocker that runs at the DNS level, allowing you to
137block traffic when it hits your network, so that you can reject any traffic you
138deem to be bad. Pi-hole uses blacklists and whitelists to decide which traffic
139block and, luckily, there are a lot of pre-made lists out there on Reddit,
140GitHub, etc.
150141
151142## Nextcloud
152143
153While I had trouble with the Docker version of Nextcloud, I was very
154successful when setting up the snap version. Using this, I was able to
155map Nextcloud to a subdomain of a domain I own in Namecheap.
156Additionally, Nextcloud has an integration with Let\'s Encrypt that
157allows me to issue certificates automatically to any new domain I
158authorize.
144While I had trouble with the Docker version of Nextcloud, I was very successful
145when setting up the snap version. Using this, I was able to map Nextcloud to a
146subdomain of a domain I own in Namecheap. Additionally, Nextcloud has an
147integration with Let's Encrypt that allows me to issue certificates
148automatically to any new domain I authorize.
159149
160150## Webmin
161151
162To monitor my servers, and the processes running on them, I use the
163Webmin dashboard. This was fairly painless to set up, and I currently
164access it straight through the server\'s IP address. In the future, I
165will be looking to configure Webmin to use a custom domain just like
166Nextcloud.
152To monitor my servers, and the processes running on them, I use the Webmin
153dashboard. This was fairly painless to set up, and I currently access it
154straight through the server's IP address. In the future, I will be looking to
155configure Webmin to use a custom domain just like Nextcloud.
content/blog/2020-05-19-customizing-ubuntu.md +89 −100
@@ -7,20 +7,20 @@ draft = false
77
88# More Information
99
10For inspiration on designing your \*nix computer, check out the
10For inspiration on designing your *nix computer, check out the
1111[r/unixporn](https://libredd.it/r/unixporn) subreddit!
1212
1313# Customizing Ubuntu
1414
15New to Linux and want to add a personal touch to your machine? One of
16the best perks of Linux is that it is **extremely\*** customizable. You
17can change the styles of the windows, shell (status bars/docks), icons,
18fonts, terminals, and more.
15New to Linux and want to add a personal touch to your machine? One of the best
16perks of Linux is that it is **extremely** customizable. You can change the
17styles of the windows, shell (status bars/docks), icons, fonts, terminals, and
18more.
1919
20In this post, I\'m going to go through customization on Ubuntu 20.04
21(GNOME) since most new users tend to choose Ubuntu-based distros. If
22you\'ve found a way to install Arch with i3-gaps, I\'m assuming you know
23how to find more advanced tutorials out there on customizations.
20In this post, I'm going to go through customization on Ubuntu 20.04 (GNOME)
21since most new users tend to choose Ubuntu-based distros. If you've found a way
22to install Arch with i3-gaps, I'm assuming you know how to find more advanced
23tutorials out there on customizations.
2424
2525## Required Tools
2626
@@ -28,61 +28,55 @@ how to find more advanced tutorials out there on customizations.
2828Tweaks](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-tweaks-min.png)
2929
3030Ubuntu 20.04 ships with the default desktop environment
31[Gnome](https://www.gnome.org/), which includes the handy
32`gnome-tweaks` tool to quickly change designs. To install
33this, just open your terminal and enter the following command:
31[Gnome](https://www.gnome.org/), which includes the handy `gnome-tweaks` tool to
32quickly change designs. To install this, just open your terminal and enter the
33following command:
3434
3535```sh
3636sudo apt install gnome-tweaks
3737```
3838
39After you\'ve finished installing the tool, simply launch the Tweaks
40application, and you\'ll be able to access the various customization
41options available by default on Ubuntu. You might even like some of the
42pre-installed options.
39After you've finished installing the tool, simply launch the Tweaks
40application, and you'll be able to access the various customization options
41available by default on Ubuntu. You might even like some of the pre-installed
42options.
4343
4444## GNOME Application Themes
4545
46To change the themes applied to applications in GNOME, you will need to
47change the Applications dropdown in the Appearance section of Tweaks. To
48add more themes, you will have to find your preferred theme online and
49follow the steps below to have it show up in the Tweaks tool. While you
50may find themes anywhere, one of the most popular sites for GNOME themes
51is [gnome-look.org](https://www.gnome-look.org/). This website contains
52themes for applications, shells, icons, and cursors.
46To change the themes applied to applications in GNOME, you will need to change
47the Applications dropdown in the Appearance section of Tweaks. To add more
48themes, you will have to find your preferred theme online and follow the steps
49below to have it show up in the Tweaks tool. While you may find themes anywhere,
50one of the most popular sites for GNOME themes is
51[gnome-look.org](https://www.gnome-look.org/). This website contains themes for
52applications, shells, icons, and cursors.
5353
5454Steps to import themes into Tweaks:
5555
561. Download the theme.
572. These files are usually compressed (.zip, .tar.gz, .tar.xz), so you
58 will need to extract the contents. This is easiest when opening the
59 file explorer, right-clicking the compressed file, and choosing
60 \"Extract here.\"
613. Move the theme folder to `/usr/share/themes/`. You can do
62 so with the following command:
63 `sudo mv theme-folder/ /usr/share/themes/`.
64 - Icons and cursors will be moved to the
65 `/usr/share/icons/` folder.
66 - Fonts will be moved to the `/usr/share/fonts/` folder
67 Alternatively, you can move them to the
68 `/usr/share/fonts/opentype/` or
69 `/usr/share/fonts/opentype/` folders, if you have a
70 specific font type.
714. Close tweaks if it is open. Re-open Tweaks and your new theme will
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:
561. Download the theme.
572. These files are usually compressed (.zip, .tar.gz, .tar.xz), so you will need
58 to extract the contents. This is easiest when opening the file explorer,
59 right-clicking the compressed file, and choosing "Extract here."
603. Move the theme folder to `/usr/share/themes/`. You can do so with the
61 following command: `sudo mv theme-folder/ /usr/share/themes/`.
62 - Icons and cursors will be moved to the `/usr/share/icons/` folder.
63 - Fonts will be moved to the `/usr/share/fonts/` folder Alternatively, you
64 can move them to the `/usr/share/fonts/opentype/` or
65 `/usr/share/fonts/opentype/` folders, if you have a specific font type.
664. Close tweaks if it is open. Re-open Tweaks and your new theme will be
67 available in the Applications dropdown in the Appearance section of Tweaks.
68
69If the theme is not showing up after you've moved it into the themes folder,
70you may have uncompressed the folder into a sub-folder. You can check this by
71entering the theme folder and listing the contents:
7872
7973```sh
8074cd /usr/share/themes/Mojave-Dark && ls -la
8175```
8276
83This is an example of what the contents of your theme folder should look
84like. If you just see another folder there, you should move that folder
85up into the `/usr/share/themes/` folder.
77This is an example of what the contents of your theme folder should look like.
78If you just see another folder there, you should move that folder up into the
79`/usr/share/themes/` folder.
8680
8781```sh
8882cinnamon 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
9084
9185## GNOME Shell Themes
9286
93To change the appearance of the title bar, default dock, app menu, and
94other parts of the GNOME shell, you\'ll need to install the [user
95themes](https://extensions.gnome.org/extension/19/user-themes/)
96extension on [Gnome Extensions](https://extensions.gnome.org/). To be
97able to install extensions, you will first need to install the browser
98extension that the website instructs you to. See this screenshot for the
99blue box with a link to the extension.
87To change the appearance of the title bar, default dock, app menu, and other
88parts of the GNOME shell, you'll need to install the [user
89themes](https://extensions.gnome.org/extension/19/user-themes/) extension on
90[Gnome Extensions](https://extensions.gnome.org/). To be able to install
91extensions, you will first need to install the browser extension that the
92website instructs you to. See this screenshot for the blue box with a link to
93the extension.
10094
10195![Gnome
10296Extensions](https://img.cleberg.net/blog/20200519-customizing-ubuntu/gnome-extensions-min.png)
10397
104After the browser extension is installed, you will need to install the
105native host connector:
98After the browser extension is installed, you will need to install the native
99host connector:
106100
107101```sh
108102sudo apt install chrome-gnome-shell
109103```
110104
111105Finally, you can go the [user
112themes](https://extensions.gnome.org/extension/19/user-themes/)
113extension page and click the installation button. This will enable the
114Shell option in Tweaks. Now you can move shell themes to the
115`/usr/share/themes` directory, using the same steps mentioned
116in the previous section, and enable the new theme in Tweaks.
106themes](https://extensions.gnome.org/extension/19/user-themes/) extension page
107and click the installation button. This will enable the Shell option in Tweaks.
108Now you can move shell themes to the `/usr/share/themes` directory, using the
109same steps mentioned in the previous section, and enable the new theme in
110Tweaks.
117111
118112## Icons & Cursors
119113
120Icons and cursors are installed exactly the same way, so I\'m grouping
121these together in this post. Both of these items will need to follow the
122same process as installing themes, except you will want to move your
123font folders to the `/usr/share/icons/` directory instead.
114Icons and cursors are installed exactly the same way, so I'm grouping these
115together in this post. Both of these items will need to follow the same process
116as installing themes, except you will want to move your font folders to the
117`/usr/share/icons/` directory instead.
124118
125119## Fonts
126120
127Fonts are one of the overlooked parts of customization, but a good font
128can make the whole screen look different. For example, I have installed
129the [IBM Plex](https://github.com/IBM/plex/releases) fonts on my system.
130This follows the same process as installing themes, except you will want
131to move your font folders to the `/usr/share/fonts/`
132directory instead.
121Fonts are one of the overlooked parts of customization, but a good font can make
122the whole screen look different. For example, I have installed the [IBM
123Plex](https://github.com/IBM/plex/releases) fonts on my system. This follows the
124same process as installing themes, except you will want to move your font
125folders to the `/usr/share/fonts/` directory instead.
133126
134127## Terminal
135128
136If you spend a lot of time typing commands, you know how important the
137style and functionality of the terminal is. After spending a lot of time
138using the default GNOME terminal with [unix
139shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), I decided to
140try some different options. I ended up choosing
129If you spend a lot of time typing commands, you know how important the style and
130functionality of the terminal is. After spending a lot of time using the default
131GNOME terminal with [unix
132shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), I decided to try some
133different options. I ended up choosing
141134[Terminator](https://terminator-gtk3.readthedocs.io/en/latest/) with
142135[zsh](https://en.wikipedia.org/wiki/Z_shell).
143136
144Terminator is great if you need to open multiple terminals at one time
145by simply right-clicking and splitting the screen into as many terminals
146as you want. While this project hasn\'t been updated in a while, [it is
147coming under new
148development](https://github.com/gnome-terminator/terminator/issues/1).
149However, this terminal is great and I haven\'t experienced any errors
150yet.
137Terminator is great if you need to open multiple terminals at one time by simply
138right-clicking and splitting the screen into as many terminals as you want.
139While this project hasn't been updated in a while, [it is coming under new
140development](https://github.com/gnome-terminator/terminator/issues/1). However,
141this terminal is great and I haven't experienced any errors yet.
151142
152For the shell choice, I decided to choose zsh after trying it out on a
153fresh Manjaro installation. Zsh is great if you like to change the
154themes of your terminal, include icons, or add plugins.
143For the shell choice, I decided to choose zsh after trying it out on a fresh
144Manjaro installation. Zsh is great if you like to change the themes of your
145terminal, include icons, or add plugins.
155146
156147The desktop uses the
157[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)
158to suggest past commands as you type. In addition, it suggests
159corrections if you misspell a command. Lastly, it uses the
160`af-magic` theme, which adds dashed lines between commands,
161moving the user@host tag to the right side of the terminal, and changes
162the colors. There are plenty of plugins and themes to choose from. Just
163figure out what you like and add it to your `~/.zshrc` file!
148[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) to
149suggest past commands as you type. In addition, it suggests corrections if you
150misspell a command. Lastly, it uses the `af-magic` theme, which adds dashed
151lines between commands, moving the user@host tag to the right side of the
152terminal, and changes the colors. There are plenty of plugins and themes to
153choose from. Just figure out what you like and add it to your `~/.zshrc` file!
164154
165155### Steps to Replicate My Terminal
166156
@@ -194,10 +184,9 @@ To install zsh-autosuggestions via Oh My Zsh:
194184git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
195185```
196186
197Then, add the following plugin wording to your `~/.zshrc`
198file (the default config usually has the `git` plugin
199activated, so just add any other plugins to the parentheses separated by
200a space):
187Then, add the following plugin wording to your `~/.zshrc` file (the default
188config usually has the `git` plugin activated, so just add any other plugins to
189the parentheses separated by a space):
201190
202191```sh
203192nano ~/.zshrc
@@ -207,5 +196,5 @@ nano ~/.zshrc
207196plugins=(git zsh-autosuggestions)
208197```
209198
210Finally, you need to log out of your computer and log back in so your
211user shell can refresh.
199Finally, you need to log out of your computer and log back in so your user shell
200can refresh.
content/blog/2020-07-20-video-game-sales.md +31 −32
@@ -8,26 +8,25 @@ draft = false
88# Background Information
99
1010This dataset (obtained from
11[Kaggle](https://www.kaggle.com/gregorut/videogamesales/data)) contains
12a list of video games with sales greater than 100,000 copies. It was
13generated by a scrape of vgchartz.com.
11[Kaggle](https://www.kaggle.com/gregorut/videogamesales/data)) contains a list
12of video games with sales greater than 100,000 copies. It was generated by a
13scrape of vgchartz.com.
1414
1515Fields include:
1616
17- Rank: Ranking of overall sales
18- Name: The game name
19- Platform: Platform of the game release (i.e. PC,PS4, etc.)
20- Year: Year of the game\'s release
21- Genre: Genre of the game
22- Publisher: Publisher of the game
23- NA~Sales~: Sales in North America (in millions)
24- EU~Sales~: Sales in Europe (in millions)
25- JP~Sales~: Sales in Japan (in millions)
26- Other~Sales~: Sales in the rest of the world (in millions)
27- Global~Sales~: Total worldwide sales.
28
29There are 16,598 records. 2 records were dropped due to incomplete
30information.
17- Rank: Ranking of overall sales
18- Name: The game name
19- Platform: Platform of the game release (i.e. PC,PS4, etc.)
20- Year: Year of the game's release
21- Genre: Genre of the game
22- Publisher: Publisher of the game
23- NA~Sales~: Sales in North America (in millions)
24- EU~Sales~: Sales in Europe (in millions)
25- JP~Sales~: Sales in Japan (in millions)
26- Other~Sales~: Sales in the rest of the world (in millions)
27- Global~Sales~: Total worldwide sales.
28
29There are 16,598 records. 2 records were dropped due to incomplete information.
3130
3231# Import the Data
3332
@@ -166,18 +165,18 @@ Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/0
166165
167166# Discussion
168167
169The purpose of exploring datasets is to ask questions, answer questions,
170and discover intelligence that can be used to inform decision-making.
171So, what have we found in this dataset?
172
173Today we simply explored a publicly-available dataset to see what kind
174of information it contained. During that exploration, we found that
175video game sales peaked in 2006. That peak was largely due to Nintendo,
176who sold the top 5 games in 2006 and has a number of games in the top-10
177list for the years 1980-2020. Additionally, the top four platforms by
178global sales (Wii, NES, GB, DS) are owned by Nintendo.
179
180We didn\'t explore everything this dataset has to offer, but we can tell
181from a brief analysis that Nintendo seems to rule sales in the video
182gaming world. Further analysis could provide insight into which genres,
183regions, publishers, or world events are correlated with sales.
168The purpose of exploring datasets is to ask questions, answer questions, and
169discover intelligence that can be used to inform decision-making. So, what have
170we found in this dataset?
171
172Today we simply explored a publicly-available dataset to see what kind of
173information it contained. During that exploration, we found that video game
174sales peaked in 2006. That peak was largely due to Nintendo, who sold the top 5
175games in 2006 and has a number of games in the top-10 list for the years
1761980-2020. Additionally, the top four platforms by global sales (Wii, NES, GB,
177DS) are owned by Nintendo.
178
179We didn't explore everything this dataset has to offer, but we can tell from a
180brief analysis that Nintendo seems to rule sales in the video gaming world.
181Further analysis could provide insight into which genres, regions, publishers,
182or world events are correlated with sales.
content/blog/2020-07-26-business-analysis.md +63 −69
@@ -7,24 +7,24 @@ draft = false
77
88# Background Information
99
10This project aims to help investors learn more about a random city in
11order to determine optimal locations for business investments. The data
12used in this project was obtained using Foursquare\'s developer API.
10This project aims to help investors learn more about a random city in order to
11determine optimal locations for business investments. The data used in this
12project was obtained using Foursquare's developer API.
1313
1414Fields include:
1515
16- Venue Name
17- Venue Category
18- Venue Latitude
19- Venue Longitude
16- Venue Name
17- Venue Category
18- Venue Latitude
19- Venue Longitude
2020
21There are 232 records found using the center of Lincoln as the area of
22interest with a radius of 10,000.
21There are 232 records found using the center of Lincoln as the area of interest
22with a radius of 10,000.
2323
2424# Import the Data
2525
26The first step is the simplest: import the applicable libraries. We will
27be using the libraries below for this project.
26The first step is the simplest: import the applicable libraries. We will be
27using the libraries below for this project.
2828
2929``` python
3030# Import the Python libraries we will be using
@@ -37,10 +37,10 @@ from pandas.io.json import json_normalize
3737from sklearn.cluster import KMeans
3838```
3939
40To begin our analysis, we need to import the data for this project. The
41data we are using in this project comes directly from the Foursquare
42API. The first step is to get the latitude and longitude of the city
43being studied (Lincoln, NE) and setting up the folium map.
40To begin our analysis, we need to import the data for this project. The data we
41are using in this project comes directly from the Foursquare API. The first step
42is to get the latitude and longitude of the city being studied (Lincoln, NE) and
43setting up the folium map.
4444
4545``` python
4646# Define the latitude and longitude, then map the results
@@ -54,11 +54,11 @@ map_LNK
5454![Blank
5555Map](https://img.cleberg.net/blog/20200726-ibm-data-science/01_blank_map-min.png)
5656
57Now that we have defined our city and created the map, we need to go get
58the business data. The Foursquare API will limit the results to 100 per
59API call, so we use our first API call below to determine the total
60results that Foursquare has found. Since the total results are 232, we
61perform the API fetching process three times (100 + 100 + 32 = 232).
57Now that we have defined our city and created the map, we need to go get the
58business data. The Foursquare API will limit the results to 100 per API call, so
59we use our first API call below to determine the total results that Foursquare
60has found. Since the total results are 232, we perform the API fetching process
61three times (100 + 100 + 32 = 232).
6262
6363``` python
6464# Foursquare API credentials
@@ -122,13 +122,12 @@ results3 = requests.get(url3).json()
122122
123123# Clean the Data
124124
125Now that we have our data in three separate dataframes, we need to
126combine them into a single dataframe and make sure to reset the index so
127that we have a unique ID for each business. The
128`get~categorytype~` function below will pull the categories
129and name from each business\'s entry in the Foursquare data
130automatically. Once all the data has been labeled and combined, the
131results are stored in the `nearby_venues` dataframe.
125Now that we have our data in three separate dataframes, we need to combine them
126into a single dataframe and make sure to reset the index so that we have a
127unique ID for each business. The `get~categorytype~` function below will pull
128the categories and name from each business's entry in the Foursquare data
129automatically. Once all the data has been labeled and combined, the results are
130stored in the `nearby_venues` dataframe.
132131
133132``` python
134133# 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
200199
201200# Visualize the Data
202201
203We now have a complete, clean data set. The next step is to visualize
204this data onto the map we created earlier. We will be using folium\'s
205`CircleMarker()` function to do this.
202We now have a complete, clean data set. The next step is to visualize this data
203onto the map we created earlier. We will be using folium's `CircleMarker()`
204function to do this.
206205
207206``` python
208207# add markers to map
@@ -227,15 +226,14 @@ map](https://img.cleberg.net/blog/20200726-ibm-data-science/03_data_map-min.png)
227226
228227# Clustering: *k-means*
229228
230To cluster the data, we will be using the *k-means* algorithm. This
231algorithm is iterative and will automatically make sure that data points
232in each cluster are as close as possible to each other, while being as
233far as possible away from other clusters.
229To cluster the data, we will be using the *k-means* algorithm. This algorithm is
230iterative and will automatically make sure that data points in each cluster are
231as close as possible to each other, while being as far as possible away from
232other clusters.
234233
235However, we first have to figure out how many clusters to use (defined
236as the variable *\'k\'*). To do so, we will use the next two functions
237to calculate the sum of squares within clusters and then return the
238optimal number of clusters.
234However, we first have to figure out how many clusters to use (defined as the
235variable *'k'*). To do so, we will use the next two functions to calculate the
236sum of squares within clusters and then return the optimal number of clusters.
239237
240238``` python
241239# This function will return the sum of squares found in the data
@@ -273,9 +271,9 @@ def optimal_number_of_clusters(wcss):
273271n = optimal_number_of_clusters(sum_of_squares)
274272```
275273
276Now that we have found that our optimal number of clusters is six, we
277need to perform k-means clustering. When this clustering occurs, each
278business is assigned a cluster number from 0 to 5 in the dataframe.
274Now that we have found that our optimal number of clusters is six, we need to
275perform k-means clustering. When this clustering occurs, each business is
276assigned a cluster number from 0 to 5 in the dataframe.
279277
280278``` python
281279# set number of clusters equal to the optimal number
@@ -288,9 +286,8 @@ kmeans = KMeans(n_clusters=kclusters, random_state=0).fit(cluster_df)
288286nearby_venues.insert(0, 'Cluster Labels', kmeans.labels_)
289287```
290288
291Success! We now have a dataframe with clean business data, along with a
292cluster number for each business. Now let\'s map the data using six
293different colors.
289Success! We now have a dataframe with clean business data, along with a cluster
290number for each business. Now let's map the data using six different colors.
294291
295292``` python
296293# create map with clusters
@@ -318,12 +315,11 @@ Map](https://img.cleberg.net/blog/20200726-ibm-data-science/04_clusters-min.png)
318315
319316# Investigate Clusters
320317
321Now that we have figured out our clusters, let\'s do a little more
322analysis to provide more insight into the clusters. With the information
323below, we can see which clusters are more popular for businesses and
324which are less popular. The results below show us that clusters 0
325through 3 are popular, while clusters 4 and 5 are not very popular at
326all.
318Now that we have figured out our clusters, let's do a little more analysis to
319provide more insight into the clusters. With the information below, we can see
320which clusters are more popular for businesses and which are less popular. The
321results below show us that clusters 0 through 3 are popular, while clusters 4
322and 5 are not very popular at all.
327323
328324``` python
329325# Show how many venues are in each cluster
@@ -337,9 +333,9 @@ for x in range(0,6):
337333![Venues per
338334Cluster](https://img.cleberg.net/blog/20200726-ibm-data-science/05_venues_per_cluster-min.png)
339335
340Our last piece of analysis is to summarize the categories of businesses
341within each cluster. With these results, we can clearly see that
342restaurants, coffee shops, and grocery stores are the most popular.
336Our last piece of analysis is to summarize the categories of businesses within
337each cluster. With these results, we can clearly see that restaurants, coffee
338shops, and grocery stores are the most popular.
343339
344340``` python
345341# 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):
371367
372368# Discussion
373369
374In this project, we gathered location data for Lincoln, Nebraska, USA
375and clustered the data using the k-means algorithm in order to identify
376the unique clusters of businesses in Lincoln. Through these actions, we
377found that there are six unique business clusters in Lincoln and that
378two of the clusters are likely unsuitable for investors. The remaining
379four clusters have a variety of businesses, but are largely dominated by
380restaurants and grocery stores.
381
382Using this project, investors can now make more informed decisions when
383deciding the location and category of business in which to invest.
384
385Further studies may involve other attributes for business locations,
386such as population density, average wealth across the city, or crime
387rates. In addition, further studies may include additional location data
388and businesses by utilizing multiple sources, such as Google Maps and
389OpenStreetMap.
370In this project, we gathered location data for Lincoln, Nebraska, USA and
371clustered the data using the k-means algorithm in order to identify the unique
372clusters of businesses in Lincoln. Through these actions, we found that there
373are six unique business clusters in Lincoln and that two of the clusters are
374likely unsuitable for investors. The remaining four clusters have a variety of
375businesses, but are largely dominated by restaurants and grocery stores.
376
377Using this project, investors can now make more informed decisions when deciding
378the location and category of business in which to invest.
379
380Further studies may involve other attributes for business locations, such as
381population density, average wealth across the city, or crime rates. In addition,
382further studies may include additional location data and businesses by utilizing
383multiple sources, such as Google Maps and OpenStreetMap.
content/blog/2020-08-22-redirect-github-pages.md +53 −66
@@ -9,18 +9,17 @@ draft = false
99
1010## Step 1
1111
12Add a new file CNAME to your GitHub Pages repository containing only one
13line: your top-level domain name. E.g.: `example.com`
12Add a new file CNAME to your GitHub Pages repository containing only one line:
13your top-level domain name. E.g.: `example.com`
1414
1515## Step 2
1616
17\[Optional\] but highly recommended
17[Optional] but highly recommended
1818
192.1: Remove all other top-level records (prefixed with @) of type A from
20your DNS configuration.
192.1: Remove all other top-level records (prefixed with @) of type A from your
20DNS configuration.
2121
222.2: Remove a CNAME record for the second-level domain www if it is
23present.
222.2: Remove a CNAME record for the second-level domain www if it is present.
2423
2524## Step 3
2625
@@ -34,70 +33,61 @@ Add these 5 entries to the very top of your DNS configuration:
3433www CNAME your_github_username.github.io.
3534```
3635
37Replace `your_github_username` with your actual GitHub
38username.
36Replace `your_github_username` with your actual GitHub username.
3937
4038## Step 4
4139
42Wait for your DNS changes to propagate. DNS changes aren\'t effective
40Wait for your DNS changes to propagate. DNS changes aren't effective
4341immediately. They can take up to a full day to propagate.
4442
4543# Long answer
4644
47This issue has two sides. One is the DNS configuration itself. Another
48one is the way GitHub Pages will forward HTTP requests.
45This issue has two sides. One is the DNS configuration itself. Another one is
46the way GitHub Pages will forward HTTP requests.
4947
50We need to know a few things to understand what GitHub is trying to say
51in their documentation.
48We need to know a few things to understand what GitHub is trying to say in their
49documentation.
5250
5351## DNS Entry Types
5452
5553There are two types of DNS records which interest us: CNAME and A.
5654
57`A` is also known as `Apex` or sometimes as
58`root entry`. It forwards requests to a specified fixed IP
59address. `CNAME` entry forwards requests to a specified URL
60(actual valid plain text URL, not an IP address).
55`A` is also known as `Apex` or sometimes as `root entry`. It forwards requests
56to a specified fixed IP address. `CNAME` entry forwards requests to a specified
57URL (actual valid plain text URL, not an IP address).
6158
6259## DNS Load balancing
6360
64GitHub has one central URL address which accepts all DNS requests for
65GitHub Pages: `http://username.github.io`. That URL is
66resolved to different IP addresses based on your geographical location.
67Website hosted on GitHub Pages is a simple collection of
68`HTML`, `CSS` and `JS` files. GitHub
69distributes these files to different servers across the globe. So that
70when your browser sends a request from Europe, it receives data from a
71server in Europe. The same is valid for the requests from Asia and the
72USA.
61GitHub has one central URL address which accepts all DNS requests for GitHub
62Pages: `http://username.github.io`. That URL is resolved to different IP
63addresses based on your geographical location. Website hosted on GitHub Pages is
64a simple collection of `HTML`, `CSS` and `JS` files. GitHub distributes these
65files to different servers across the globe. So that when your browser sends a
66request from Europe, it receives data from a server in Europe. The same is valid
67for the requests from Asia and the USA.
7368
7469## What GitHub is trying to say
7570
76Since `A` records in DNS must contain IP addresses, and they
77must be either `185.199.108.153` or
78`185.199.109.153` or `185.199.110.153` or
79`185.199.111.153`, there is no way to forward requests to a
80server located somewhere in Europe or Asia. Your website hosted at
81GitHub Pages will be downloaded from a central GitHub Pages server.
82There is a minor risk that if GitHub Pages DNS servers
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
71Since `A` records in DNS must contain IP addresses, and they must be either
72`185.199.108.153` or `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
74somewhere in Europe or Asia. Your website hosted at GitHub Pages will be
75downloaded from a central GitHub Pages server. There is a minor risk that if
76GitHub Pages DNS servers (`x.x.x.153`) are down for some reason, all custom
77domains which use fixed GitHub Pages IP addresses will not be accessible (their
8578DNS requests will not be resolvable).
8679
87That is why GitHub strongly suggests to either use a second-level domain
88for your GitHub Pages (e.g. `blog.example.com`) or use a DNS
89service provider that supports a record type `ALIAS` that
90acts as `A` record but forwards request to a URL address
91(e.g. `username.github.io`) instead of a fixed IP address.
80That is why GitHub strongly suggests to either use a second-level domain for
81your GitHub Pages (e.g. `blog.example.com`) or use a DNS service provider that
82supports a record type `ALIAS` that acts as `A` record but forwards request to a
83URL address (e.g. `username.github.io`) instead of a fixed IP address.
9284
9385## How GitHub Pages treats HTTP requests
9486
95After a DNS request for `your_github_username.github.io` is
96resolved into an IP address, e.g. `185.199.108.153` your
97browser sends an HTTP request to that server with an HTTP header
98`Host`. Below are `curl` examples that load the
99same website (these examples might not work if you are behind a proxy
100server):
87After a DNS request for `your_github_username.github.io` is resolved into an IP
88address, e.g. `185.199.108.153` your browser sends an HTTP request to that
89server with an HTTP header `Host`. Below are `curl` examples that load the same
90website (these examples might not work if you are behind a proxy server):
10191
10292```sh
10393curl --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/
10797
10898This way GitHub Pages servers know which user website to serve.
10999
110> GitHub Pages server will automatically redirect HTTP requests to the
111> top-level domain if your `CNAME` file contains
112> `example.com` but `www.example.com` is
100> GitHub Pages server will automatically redirect HTTP requests to the top-level
101> domain if your `CNAME` file contains `example.com` but `www.example.com` is
113102> requested.
114103>
115> The same is valid if your `CNAME` file contains
116> `www.example.com` but the header `Host` in the
117> `HTTP` request contains `example.com`.
104> The same is valid if your `CNAME` file contains `www.example.com` but the
105> header `Host` in the `HTTP` request contains `example.com`.
118106
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?
120108
121109Quote from the GitHub Pages documentation:
122110
123> Warning: Do not create a CNAME record for your custom apex domain!
124> Doing so may cause issues with other services, such as email, on that
125> domain.
111> Warning: Do not create a CNAME record for your custom apex domain! Doing so
112> may cause issues with other services, such as email, on that domain.
126113
127114## References:
128115
1291. [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)
1312. [My custom domain isn\'t
132 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
134 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
136 subdomain (e.g. 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)
1161. [Setting up a custom domain with GitHub
117 Pages](https://docs.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site)
1182. [My custom domain isn't
119 working](https://docs.github.com/en/github/working-with-github-pages/troubleshooting-custom-domains-and-github-pages)
1203. [Cannot access my GitHub Pages website by IP
121 Address](https://serverfault.com/questions/589370/cannot-access-my-github-pages-website-by-ip-address)
1224. [How do I set up GitHub Pages to redirect DNS requests from a subdomain (e.g.
123 www) to the top-level domain (TLD, Apex
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
77
88# Introduction
99
10When creating websites that will allow users to create accounts, the
11developer always needs to consider the proper authentication flow for
12their app. For example, some developers will utilize an API for
13authentication, some will use OAuth, and some may just use their own
14simple database.
10When creating websites that will allow users to create accounts, the developer
11always needs to consider the proper authentication flow for their app. For
12example, some developers will utilize an API for authentication, some will use
13OAuth, and some may just use their own simple database.
1514
16For those using pre-built libraries, authentication may simply be a
17problem of copying and pasting the code from their library\'s
18documentation. For example, here\'s the code I use to authenticate users
19with the Tumblr OAuth API for my Tumblr client, Vox Populi:
15For those using pre-built libraries, authentication may simply be a problem of
16copying and pasting the code from their library's documentation. For example,
17here's the code I use to authenticate users with the Tumblr OAuth API for my
18Tumblr client, Vox Populi:
2019
2120``` php
2221// Start the session
@@ -41,24 +40,23 @@ $client = new Tumblr\API\Client(
4140);
4241```
4342
44However, developers creating authentication flows from scratch will need
45to think carefully about when to make sure a web page will check the
46user\'s authenticity.
43However, developers creating authentication flows from scratch will need to
44think carefully about when to make sure a web page will check the user's
45authenticity.
4746
48In this article, we\'re going to look at a simple authentication flow
49using a MySQL database and PHP.
47In this article, we're going to look at a simple authentication flow using a
48MySQL database and PHP.
5049
5150# Creating User Accounts
5251
53The beginning to any type of user authentication is to create a user
54account. This process can take many formats, but the simplest is to
55accept user input from a form (e.g., username and password) and send it
56over to your database. For example, here\'s a snippet that shows how to
57get username and password parameters that would come when a user submits
58a form to your PHP script.
52The beginning to any type of user authentication is to create a user account.
53This process can take many formats, but the simplest is to accept user input
54from a form (e.g., username and password) and send it over to your database. For
55example, here's a snippet that shows how to get username and password
56parameters that would come when a user submits a form to your PHP script.
5957
60**Note**: Ensure that your password column is large enough to hold the
61hashed value (at least 60 characters or longer).
58**Note**: Ensure that your password column is large enough to hold the hashed
59value (at least 60 characters or longer).
6260
6361``` php
6462// Get the values from the URL
@@ -97,9 +95,9 @@ $conn->close();
9795
9896## Validate Returning Users
9997
100To be able to verify that a returning user has a valid username and
101password in your database is as simple as having users fill out a form
102and comparing their inputs to your database.
98To be able to verify that a returning user has a valid username and password in
99your database is as simple as having users fill out a form and comparing their
100inputs to your database.
103101
104102``` php
105103// Query the database for username and password
@@ -116,24 +114,23 @@ if(password_verify($password_input, $hashed_password)) {
116114
117115# Storing Authentication State
118116
119Once you\'ve created the user\'s account, now you\'re ready to
120initialize the user\'s session. **You will need to do this on every page
121you load while the user is logged in.\*** To do so, simply enter the
122following code snippet:
117Once you've created the user's account, now you're ready to initialize the
118user's session. **You will need to do this on every page you load while the
119user is logged in.** To do so, simply enter the following code snippet:
123120
124121``` php
125122session_start();
126123```
127124
128Once you\'ve initialized the session, the next step is to store the
129session in a cookie so that you can access it later.
125Once you've initialized the session, the next step is to store the session in a
126cookie so that you can access it later.
130127
131128``` php
132129setcookie(session_name());
133130```
134131
135Now that the session name has been stored, you\'ll be able to check if
136there\'s an active session whenever you load a page.
132Now that the session name has been stored, you'll be able to check if there's
133an active session whenever you load a page.
137134
138135``` php
139136if(isset(session_name())) {
@@ -143,9 +140,9 @@ if(isset(session_name())) {
143140
144141## Removing User Authentication
145142
146The next logical step is to give your users the option to log out once
147they are done using your application. This can be tricky in PHP since a
148few of the standard ways do not always work.
143The next logical step is to give your users the option to log out once they are
144done using your application. This can be tricky in PHP since a few of the
145standard ways do not always work.
149146
150147``` php
151148// Initialize the session.
@@ -183,14 +180,13 @@ die();
183180
184181# Wrapping Up
185182
186Now you should be ready to begin your authentication programming with
187PHP. You can create user accounts, create sessions for users across
188different pages of your site, and then destroy the user data when
189they\'re ready to leave.
183Now you should be ready to begin your authentication programming with PHP. You
184can create user accounts, create sessions for users across different pages of
185your site, and then destroy the user data when they're ready to leave.
190186
191187For more information on this subject, I recommend reading the [PHP
192Documentation](https://www.php.net/). Specifically, you may want to look
193at [HTTP Authentication with
188Documentation](https://www.php.net/). Specifically, you may want to look at
189[HTTP Authentication with
194190PHP](https://www.php.net/manual/en/features.http-auth.php), [session
195191handling](https://www.php.net/manual/en/book.session.php), and
196192[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
77
88# What is IBM Watson?
99
10If you\'ve never heard of [Watson](https://www.ibm.com/watson), this
11service is a suite of enterprise-ready AI services, applications, and
12tooling provided by IBM. Watson contains quite a few useful tools for
13data scientists and students, including the subject of this post today:
14visual recognition.
15
16If you\'d like to view the official documentation for the Visual
17Recognition API, visit the [API
10If you've never heard of [Watson](https://www.ibm.com/watson), this service is
11a suite of enterprise-ready AI services, applications, and tooling provided by
12IBM. Watson contains quite a few useful tools for data scientists and students,
13including the subject of this post today: visual recognition.
14
15If you'd like to view the official documentation for the Visual Recognition
16API, visit the [API
1817Docs](https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?code=python).
1918
2019# Prerequisites
2120
22To be able to use Watson Visual Recognition, you\'ll need the following:
23
241. Create a free account on [IBM Watson
25 Studio](https://www.ibm.com/cloud/watson-studio).
262. Add the [Watson Visual
27 Recognition](https://www.ibm.com/cloud/watson-visual-recognition)
28 service to your IBM Watson account.
293. Get your API key and URL. To do this, first go to the [profile
30 dashboard](https://dataplatform.cloud.ibm.com/home2?context=cpdaas)
31 for your IBM account and click on the Watson Visual Recognition
32 service you created. This will be listed in the section titled
33 **Your services**. Then click the **Credentials\*** tab and open the
34 **Auto-generated credentials\*** dropdown. Copy your API key and URL
35 so that you can use them in the Python script later.
364. **\[Optional\]\*** While not required, you can also create the
37 Jupyter Notebook for this project right inside [Watson
38 Studio](https://www.ibm.com/cloud/watson-studio). Watson Studio will
39 save your notebooks inside an organized project and allow you to use
40 their other integrated products, such as storage containers, AI
41 models, documentation, external sharing, etc.
21To be able to use Watson Visual Recognition, you'll need the following:
22
231. Create a free account on [IBM Watson
24 Studio](https://www.ibm.com/cloud/watson-studio).
252. Add the [Watson Visual
26 Recognition](https://www.ibm.com/cloud/watson-visual-recognition) service to
27 your IBM Watson account.
283. Get your API key and URL. To do this, first go to the [profile
29 dashboard](https://dataplatform.cloud.ibm.com/home2?context=cpdaas) for your
30 IBM account and click on the Watson Visual Recognition service you created.
31 This will be listed in the section titled **Your services**. Then click the
32 **Credentials** tab and open the **Auto-generated credentials** dropdown.
33 Copy your API key and URL so that you can use them in the Python script
34 later.
354. **[Optional]** While not required, you can also create the Jupyter Notebook
36 for this project right inside [Watson
37 Studio](https://www.ibm.com/cloud/watson-studio). Watson Studio will save
38 your notebooks inside an organized project and allow you to use their other
39 integrated products, such as storage containers, AI models, documentation,
40 external sharing, etc.
4241
4342# Calling the IBM Watson Visual Recognition API
4443
45Okay, now let\'s get started.
44Okay, now let's get started.
4645
4746To begin, we need to install the proper Python package for IBM Watson.
4847
@@ -50,8 +49,8 @@ To begin, we need to install the proper Python package for IBM Watson.
5049pip install --upgrade --user "ibm-watson>=4.5.0"
5150```
5251
53Next, we need to specify the API key, version, and URL given to us when
54we created the Watson Visual Recognition service.
52Next, we need to specify the API key, version, and URL given to us when we
53created the Watson Visual Recognition service.
5554
5655``` python
5756apikey = "<your-apikey>"
@@ -59,7 +58,7 @@ version = "2018-03-19"
5958url = "<your-url>"
6059```
6160
62Now, let\'s import the necessary libraries and authenticate our service.
61Now, let's import the necessary libraries and authenticate our service.
6362
6463``` python
6564import json
@@ -75,16 +74,15 @@ visual_recognition = VisualRecognitionV3(
7574visual_recognition.set_service_url(url)
7675```
7776
78**\[Optional\]** If you\'d like to tell the API not to use any data to
79improve their products, set the following header.
77**[Optional]** If you'd like to tell the API not to use any data to improve
78their products, set the following header.
8079
8180``` python
8281visual_recognition.set_default_headers({'x-watson-learning-opt-out': "true"})
8382```
8483
85Now we have our API all set and ready to go. For this example, I\'m
86going to include a `dict` of photos to load as we test out
87the API.
84Now we have our API all set and ready to go. For this example, I'm going to
85include a `dict` of photos to load as we test out the API.
8886
8987``` python
9088data = [
@@ -115,14 +113,14 @@ data = [
115113]
116114```
117115
118Now that we\'ve set up our libraries and have the photos ready, let\'s
119create a loop to call the API for each image. The code below shows a
120loop that calls the URL of each image and sends it to the API,
121requesting results with at least 60% confidence. The results are output
122to the console with dotted lines separating each section.
116Now that we've set up our libraries and have the photos ready, let's create a
117loop to call the API for each image. The code below shows a loop that calls the
118URL of each image and sends it to the API, requesting results with at least 60%
119confidence. The results are output to the console with dotted lines separating
120each section.
123121
124In the case of an API error, the codes and explanations are output to
125the console.
122In the case of an API error, the codes and explanations are output to the
123console.
126124
127125``` python
128126from ibm_watson import ApiException
@@ -149,23 +147,22 @@ except ApiException as ex:
149147
150148# The Results
151149
152Here we can see the full result set of our function above. If you view
153each of the URLs that we sent to the API, you\'ll be able to see that it
154was remarkably accurate. To be fair, these are clear high-resolution,
155clear photos shot with a professional camera. In reality, you will most
156likely be processing images that are lower quality and may have a lot of
157noise in the photo.
150Here we can see the full result set of our function above. If you view each of
151the URLs that we sent to the API, you'll be able to see that it was remarkably
152accurate. To be fair, these are clear high-resolution, clear photos shot with a
153professional camera. In reality, you will most likely be processing images that
154are lower quality and may have a lot of noise in the photo.
158155
159However, we can clearly see the benefit of being able to call this API
160instead of attempting to write our own image recognition function. Each
161of the classifications returned was a fair description of the image.
156However, we can clearly see the benefit of being able to call this API instead
157of attempting to write our own image recognition function. Each of the
158classifications returned was a fair description of the image.
162159
163If you wanted to restrict the results to those that are at least 90%
164confident or greater, you would simply adjust the `threshold`
165in the `visual_recognition.classify()` function.
160If you wanted to restrict the results to those that are at least 90% confident
161or greater, you would simply adjust the `threshold` in the
162`visual_recognition.classify()` function.
166163
167When your program runs, it should show the output below for each photo
168you provide.
164When your program runs, it should show the output below for each photo you
165provide.
169166
170167``` txt
171168----------------------------------------------------------------
@@ -184,22 +181,19 @@ greenishness color ( 0.975 )
184181
185182# Discussion
186183
187Now, this was a very minimal implementation of the API. We simply
188supplied some images and looked to see how accurate the results were.
189However, you could implement this type of API into many machine learning
190(ML) models.
191
192For example, you could be working for a company that scans their
193warehouses or inventory using drones. Would you want to pay employees to
194sit there and watch drone footage all day in order to identify or count
195things in the video? Probably not. Instead, you could use a
196classification system similar to this one in order to train your machine
197learning model to correctly identify items that the drones show through
198video. More specifically, you could have your machine learning model
199watch a drone fly over a field of sheep in order to count how many sheep
200are living in that field.
201
202There are many ways to implement machine learning functionality, but
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.
184Now, this was a very minimal implementation of the API. We simply supplied some
185images and looked to see how accurate the results were. However, you could
186implement this type of API into many machine learning (ML) models.
187
188For example, you could be working for a company that scans their warehouses or
189inventory using drones. Would you want to pay employees to sit there and watch
190drone footage all day in order to identify or count things in the video?
191Probably not. Instead, you could use a classification system similar to this one
192in order to train your machine learning model to correctly identify items that
193the drones show through video. More specifically, you could have your machine
194learning model watch a drone fly over a field of sheep in order to count how
195many sheep are living in that field.
196
197There are many ways to implement machine learning functionality, but hopefully
198this post helped inspire some deeper thought about the tools that can help
199propel us further into the future of machine learning and AI.
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-
1010
1111# Definitions
1212
13One of the many reasons that Internal Audit needs such thorough
14explaining to non-auditors is that Internal Audit can serve many
15purposes, depending on the organization\'s size and needs. However, the
16Institute of Internal Auditors (IIA) defines Internal Auditing as:
17
18> Internal auditing is an independent, objective assurance and
19> consulting activity designed to add value and improve an
20> organization\'s operations. It helps an organization accomplish its
21> objectives by bringing a systematic, disciplined approach to evaluate
22> and improve the effectiveness of risk management, control, and
23> governance processes.
24
25However, this definition uses quite a few terms that aren\'t clear
26unless the reader already has a solid understanding of the auditing
27profession. To further explain, the following is a list of definitions
28that can help supplement understanding of internal auditing.
13One of the many reasons that Internal Audit needs such thorough explaining to
14non-auditors is that Internal Audit can serve many purposes, depending on the
15organization's size and needs. However, the Institute of Internal Auditors
16(IIA) defines Internal Auditing as:
17
18> Internal auditing is an independent, objective assurance and consulting
19> activity designed to add value and improve an organization's operations. It
20> helps an organization accomplish its objectives by bringing a systematic,
21> disciplined approach to evaluate and improve the effectiveness of risk
22> management, control, and governance processes.
23
24However, this definition uses quite a few terms that aren't clear unless the
25reader already has a solid understanding of the auditing profession. To further
26explain, the following is a list of definitions that can help supplement
27understanding of internal auditing.
2928
3029## Independent
3130
32Independence is the freedom from conditions that threaten the ability of
33the internal audit activity to carry out internal audit responsibilities
34in an unbiased manner. To achieve the degree of independence necessary
35to effectively carry out the responsibilities of the internal audit
36activity, the chief audit executive has direct and unrestricted access
37to senior management and the board. This can be achieved through a
38dual-reporting relationship. Threats to independence must be managed at
39the individual auditor, engagement, functional, and organizational
40levels.
31Independence is the freedom from conditions that threaten the ability of the
32internal audit activity to carry out internal audit responsibilities in an
33unbiased manner. To achieve the degree of independence necessary to effectively
34carry out the responsibilities of the internal audit activity, the chief audit
35executive has direct and unrestricted access to senior management and the board.
36This can be achieved through a dual-reporting relationship. Threats to
37independence must be managed at the individual auditor, engagement, functional,
38and organizational levels.
4139
4240## Objective
4341
44Objectivity is an unbiased mental attitude that allows internal auditors
45to perform engagements in such a manner that they believe in their work
46product and that no quality compromises are made. Objectivity requires
47that internal auditors do not subordinate their judgment on audit
48matters to others. Threats to objectivity must be managed at the
49individual auditor, engagement, functional, and organizational levels.
42Objectivity is an unbiased mental attitude that allows internal auditors to
43perform engagements in such a manner that they believe in their work product and
44that no quality compromises are made. Objectivity requires that internal
45auditors do not subordinate their judgment on audit matters to others. Threats
46to objectivity must be managed at the individual auditor, engagement,
47functional, and organizational levels.
5048
5149## Assurance
5250
53Assurance services involve the internal auditor\'s objective assessment
54of evidence to provide opinions or conclusions regarding an entity,
55operation, function, process, system, or other subject matters. The
56internal auditor determines the nature and scope of an assurance
57engagement. Generally, three parties are participants in assurance
58services: (1) the person or group directly involved with the entity,
59operation, function, process, system, or other subject - (the process
60owner), (2) the person or group making the assessment - (the internal
61auditor), and (3) the person or group using the assessment - (the user).
51Assurance services involve the internal auditor's objective assessment of
52evidence to provide opinions or conclusions regarding an entity, operation,
53function, process, system, or other subject matters. The internal auditor
54determines the nature and scope of an assurance engagement. Generally, three
55parties are participants in assurance services: (1) the person or group directly
56involved with the entity, operation, function, process, system, or other subject
57- (the process owner), (2) the person or group making the assessment - (the
58internal auditor), and (3) the person or group using the assessment - (the
59user).
6260
6361## Consulting
6462
65Consulting services are advisory in nature and are generally performed
66at the specific request of an engagement client. The nature and scope of
67the consulting engagement are subject to agreement with the engagement
68client. Consulting services generally involve two parties: (1) the
69person or group offering the advice (the internal auditor), and (2) the
70person or group seeking and receiving the advice (the engagement
71client). When performing consulting services, the internal auditor
72should maintain objectivity and not assume management responsibility.
63Consulting services are advisory in nature and are generally performed at the
64specific request of an engagement client. The nature and scope of the consulting
65engagement are subject to agreement with the engagement client. Consulting
66services generally involve two parties: (1) the person or group offering the
67advice (the internal auditor), and (2) the person or group seeking and receiving
68the advice (the engagement client). When performing consulting services, the
69internal auditor should maintain objectivity and not assume management
70responsibility.
7371
7472## Governance, Risk Management, & Compliance (GRC)
7573
@@ -78,187 +76,173 @@ reliably achieve objectives, address uncertainty and act with integrity.
7876
7977# Audit Charter & Standards
8078
81First, it\'s important to note that not every organization needs
82internal auditors. In fact, it\'s unwise for an organization to hire
83internal auditors unless they have regulatory requirements for auditing
84and have the capital to support the department. Internal audit is a cost
85center that can only affect revenue indirectly.
86
87Once an organization determines the need for internal assurance
88services, they will hire a Chief Audit Executive and create the audit
89charter. This charter is a document, approved by the company\'s
90governing body, that will define internal audit\'s purpose, authority,
91responsibility, and position within the organization. Fortunately, the
92IIA has model charters available to IIA members for those developing or
93improving their charter.
94
95Beyond the charter and organizational documents, internal auditors
96follow a few different standards in order to perform their job. First is
97the International Professional Practices Framework (IPPF) by the IIA,
98which is the model of standards for internal auditing. In addition,
99ISACA\'s Information Technology Assurance Framework (ITAF) helps guide
100auditors in reference to information technology (IT) compliance and
101assurance. Finally, additional standards such as FASB, GAAP, and
102industry-specific standards are used when performing internal audit
103work.
79First, it's important to note that not every organization needs internal
80auditors. In fact, it's unwise for an organization to hire internal auditors
81unless they have regulatory requirements for auditing and have the capital to
82support the department. Internal audit is a cost center that can only affect
83revenue indirectly.
84
85Once an organization determines the need for internal assurance services, they
86will hire a Chief Audit Executive and create the audit charter. This charter is
87a document, approved by the company's governing body, that will define internal
88audit's purpose, authority, responsibility, and position within the
89organization. Fortunately, the IIA has model charters available to IIA members
90for those developing or improving their charter.
91
92Beyond the charter and organizational documents, internal auditors follow a few
93different standards in order to perform their job. First is the International
94Professional Practices Framework (IPPF) by the IIA, which is the model of
95standards for internal auditing. In addition, ISACA's Information Technology
96Assurance Framework (ITAF) helps guide auditors in reference to information
97technology (IT) compliance and assurance. Finally, additional standards such as
98FASB, GAAP, and industry-specific standards are used when performing internal
99audit work.
104100
105101# Three Lines of Defense
106102
107[The IIA](https://theiia.org) released the original Three Lines of
108Defense model in 2013, but have released an updated version in 2020.
109Here is what the Three Lines of Defense model has historically looked
110like:
103[The IIA](https://theiia.org) released the original Three Lines of Defense model
104in 2013, but have released an updated version in 2020. Here is what the Three
105Lines of Defense model has historically looked like:
111106
112107![2013 Three Lines of Defense
113108Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/three_lines_model.png)
114109
115I won\'t go into depth about the changes made to the model in this
116article. Instead, let\'s take a look at the most current model.
110I won't go into depth about the changes made to the model in this article.
111Instead, let's take a look at the most current model.
117112
118113![2020 Three Lines of Defense
119114Model](https://img.cleberg.net/blog/20200922-what-is-internal-audit/updated_three_lines_model.png)
120115
121116The updated model forgets the strict idea of areas performing their own
122functions or line of defense. Instead of talking about management, risk,
123and internal audit as 1-2-3, the new model creates a more fluid and
124cooperative model.
125
126Looking at this model from an auditing perspective shows us that
127auditors will need to align, communicate, and collaborate with
128management, including business area managers and chief officers, as well
129as reporting to the governing body. The governing body will instruct
130internal audit *functionally* on their goals and track their progress
131periodically.
132
133However, the internal audit department will report *administratively* to
134a chief officer in the company for the purposes of collaboration,
135direction, and assistance with the business. Note that in most
136situations, the governing body is the audit committee on the company\'s
137board of directors.
138
139The result of this structure is that internal audit is an independent
140and objective function that can provide assurance over the topics they
141audit.
117functions or line of defense. Instead of talking about management, risk, and
118internal audit as 1-2-3, the new model creates a more fluid and cooperative
119model.
120
121Looking at this model from an auditing perspective shows us that auditors will
122need to align, communicate, and collaborate with management, including business
123area managers and chief officers, as well as reporting to the governing body.
124The governing body will instruct internal audit *functionally* on their goals
125and track their progress periodically.
126
127However, the internal audit department will report *administratively* to a chief
128officer in the company for the purposes of collaboration, direction, and
129assistance with the business. Note that in most situations, the governing body
130is the audit committee on the company's board of directors.
131
132The result of this structure is that internal audit is an independent and
133objective function that can provide assurance over the topics they audit.
142134
143135# Audit Process
144136
145A normal audit will generally follow the same process, regardless of the
146topic. However, certain special projects or abnormal business areas may
147call for changes to the audit process. The audit process is not set in
148stone, it\'s simply a set of best practices so that audits can be
149performed consistently.
137A normal audit will generally follow the same process, regardless of the topic.
138However, certain special projects or abnormal business areas may call for
139changes to the audit process. The audit process is not set in stone, it's
140simply a set of best practices so that audits can be performed consistently.
150141
151142![The Internal Audit
152143Process](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-audit-process.jpg)
153144
154While different organizations may tweak the process, it will generally
155follow this flow:
145While different organizations may tweak the process, it will generally follow
146this flow:
156147
157148## 1. Risk Assessment
158149
159150The risk assessment part of the process has historically been performed
160annually, but many organizations have moved to performing this process
161much more frequently. In fact, some organizations are moving to an agile
162approach that can take new risks into the risk assessment and
163re-prioritize risk areas on-the-go. To perform a risk assessment,
164leaders in internal audit will research industry risks, consult with
165business leaders around the company, and perform analyses on company
166data.
151annually, but many organizations have moved to performing this process much more
152frequently. In fact, some organizations are moving to an agile approach that can
153take new risks into the risk assessment and re-prioritize risk areas on-the-go.
154To perform a risk assessment, leaders in internal audit will research industry
155risks, consult with business leaders around the company, and perform analyses on
156company data.
167157
168158Once a risk assessment has been documented, the audit department has a
169prioritized list of risks that can be audited. This is usually in the
170form of auditable entities, such as business areas or departments.
159prioritized list of risks that can be audited. This is usually in the form of
160auditable entities, such as business areas or departments.
171161
172162## 2. Planning
173163
174During the planning phase of an audit, auditors will meet with the
175business area to discuss the various processes, controls, and risks
176applicable to the business. This helps the auditors determine the scope
177limits for the audit, as well as timing and subject-matter experts.
178Certain documents will be created in this phase that will be used to
179keep the audit on-track an in-scope as it goes forward.
164During the planning phase of an audit, auditors will meet with the business area
165to discuss the various processes, controls, and risks applicable to the
166business. This helps the auditors determine the scope limits for the audit, as
167well as timing and subject-matter experts. Certain documents will be created in
168this phase that will be used to keep the audit on-track an in-scope as it goes
169forward.
180170
181171## 3. Testing
182172
183The testing phase, also known as fieldwork or execution, is where
184internal auditors will take the information they\'ve discovered and test
185it against regulations, industry standards, company rules, best
186practices, as well as validating that any processes are complete and
187accurate. For example, an audit of HR would most likely examine
188processes such as employee on-boarding, employee termination, security
189of personally identifiable information (PII), or the IT systems involved
190in these processes. Company standards would be examined and compared
191against how the processes are actually being performed day-to-day, as
192well as compared against regulations such as the Equal Employment
193Opportunity (EEO), American with Disabilities Act, and National Labor
194Relations Act.
173The testing phase, also known as fieldwork or execution, is where internal
174auditors will take the information they've discovered and test it against
175regulations, industry standards, company rules, best practices, as well as
176validating that any processes are complete and accurate. For example, an audit
177of HR would most likely examine processes such as employee on-boarding, employee
178termination, security of personally identifiable information (PII), or the IT
179systems involved in these processes. Company standards would be examined and
180compared against how the processes are actually being performed day-to-day, as
181well as compared against regulations such as the Equal Employment Opportunity
182(EEO), American with Disabilities Act, and National Labor Relations Act.
195183
196184## 4. Reporting
197185
198Once all the tests have been completed, the audit will enter the
199reporting phase. This is when the audit team will conclude on the
200evidence they\'ve collected, interviews they\'ve held, and any opinions
201they\'ve formed on the controls in place. A summary of the audit
202findings, conclusions, and specific recommendations are officially
203communicated to the client through a draft report. Clients have the
204opportunity to respond to the report and submit an action plan and time
205frame. These responses become part of the final report which is
206distributed to the appropriate level of administration.
186Once all the tests have been completed, the audit will enter the reporting
187phase. This is when the audit team will conclude on the evidence they've
188collected, interviews they've held, and any opinions they've formed on the
189controls in place. A summary of the audit findings, conclusions, and specific
190recommendations are officially communicated to the client through a draft
191report. Clients have the opportunity to respond to the report and submit an
192action plan and time frame. These responses become part of the final report
193which is distributed to the appropriate level of administration.
207194
208195## 5. Follow-Up
209196
210After audits have been completed and management has formed action plans
211and time frames for audit issues, internal audit will follow up once
212that due date has arrived. In most cases, the follow-up will simply
213consist of a meeting to discuss how the action plan has been completed
214and to request documentation to prove it.
197After audits have been completed and management has formed action plans and time
198frames for audit issues, internal audit will follow up once that due date has
199arrived. In most cases, the follow-up will simply consist of a meeting to
200discuss how the action plan has been completed and to request documentation to
201prove it.
215202
216203# Audit Department Structure
217204
218205While an internal audit department is most often thought of as a team of
219206full-time employees, there are actually many different ways in which a
220department can be structured. As the world becomes more digital and
221fast-paced, outsourcing has become a more attractive option for some
222organizations. Internal audit can be fully outsourced or partially
223outsourced, allowing for flexibility in cases where turnover is high.
224
225In addition, departments can implement a rotational model. This allows
226for interested employees around the organization to rotate into the
227internal audit department for a period of time, allowing them to obtain
228knowledge of risks and controls and allowing the internal audit team to
229obtain more business area knowledge. This program is popular in very
230large organizations, but organizations tend to rotate lower-level audit
231staff instead of managers. This helps prevent any significant knowledge
232loss as auditors rotate out to business areas.
207department can be structured. As the world becomes more digital and fast-paced,
208outsourcing has become a more attractive option for some organizations. Internal
209audit can be fully outsourced or partially outsourced, allowing for flexibility
210in cases where turnover is high.
211
212In addition, departments can implement a rotational model. This allows for
213interested employees around the organization to rotate into the internal audit
214department for a period of time, allowing them to obtain knowledge of risks and
215controls and allowing the internal audit team to obtain more business area
216knowledge. This program is popular in very large organizations, but
217organizations tend to rotate lower-level audit staff instead of managers. This
218helps prevent any significant knowledge loss as auditors rotate out to business
219areas.
233220
234221# Consulting
235222
236Consulting is not an easy task at any organization, especially for a
237department that can have negative perceptions within the organization as
238the \"compliance police.\" However, once an internal audit department
239has delivered value to organization, adding consulting to their suite of
240services is a smart move. In most cases, Internal Audit can insert
241themselves into a consulting role without affecting the process of
242project management at the company. This means that internal audit can
243add objective assurance and opinions to business areas as they develop
244new processes, instead of coming in periodically to audit an area and
245file issues that could have been fixed at the beginning.
223Consulting is not an easy task at any organization, especially for a department
224that can have negative perceptions within the organization as the "compliance
225police." However, once an internal audit department has delivered value to
226organization, adding consulting to their suite of services is a smart move. In
227most cases, Internal Audit can insert themselves into a consulting role without
228affecting the process of project management at the company. This means that
229internal audit can add objective assurance and opinions to business areas as
230they develop new processes, instead of coming in periodically to audit an area
231and file issues that could have been fixed at the beginning.
246232
247233# Data Science & Data Analytics
248234
249235![Data Science Skill
250236Set](https://img.cleberg.net/blog/20200922-what-is-internal-audit/data-science-skillset.png)
251237
252One major piece of the internal audit function in the modern world is
253data science. While the process is data science, most auditors will
254refer to anything in this realm as data analytics. Hot topics such as
255robotic process automation (RPA), machine learning (ML), and data mining
256have taken over the auditing world in recent years. These technologies
257have been immensely helpful with increasing the effectiveness and
258efficiency of auditors.
259
260For example, mundane and repetitive tasks can be automated in order for
261auditors to make more room in their schedules for labor-intensive work.
262Further, auditors will need to adapt technologies like machine learning
263in order to extract more value from the data they\'re using to form
264conclusions.
238One major piece of the internal audit function in the modern world is data
239science. While the process is data science, most auditors will refer to anything
240in this realm as data analytics. Hot topics such as robotic process automation
241(RPA), machine learning (ML), and data mining have taken over the auditing world
242in recent years. These technologies have been immensely helpful with increasing
243the effectiveness and efficiency of auditors.
244
245For example, mundane and repetitive tasks can be automated in order for auditors
246to make more room in their schedules for labor-intensive work. Further, auditors
247will need to adapt technologies like machine learning in order to extract more
248value from the data they're using to form conclusions.
content/blog/2020-09-25-happiness-map.md +46 −49
@@ -8,28 +8,28 @@ draft = false
88# Background Information
99
1010The dataset (obtained from
11[Kaggle](https://www.kaggle.com/unsdsn/world-happiness)) used in this
12article contains a list of countries around the world, their happiness
13rankings and scores, as well as other national scoring measures.
11[Kaggle](https://www.kaggle.com/unsdsn/world-happiness)) used in this article
12contains a list of countries around the world, their happiness rankings and
13scores, as well as other national scoring measures.
1414
1515Fields include:
1616
17- Overall rank
18- Country or region
19- GDP per capita
20- Social support
21- Healthy life expectancy
22- Freedom to make life choices
23- Generosity
24- Perceptions of corruption
17- Overall rank
18- Country or region
19- GDP per capita
20- Social support
21- Healthy life expectancy
22- Freedom to make life choices
23- Generosity
24- Perceptions of corruption
2525
26There are 156 records. Since there are \~195 countries in the world, we
27can see that around 40 countries will be missing from this dataset.
26There are 156 records. Since there are ~195 countries in the world, we can see
27that around 40 countries will be missing from this dataset.
2828
2929# Install Packages
3030
31As always, run the `install` command for all packages needed
32to perform analysis.
31As always, run the `install` command for all packages needed to perform
32analysis.
3333
3434``` python
3535!pip install folium geopandas matplotlib numpy pandas
@@ -38,9 +38,9 @@ to perform analysis.
3838# Import the Data
3939
4040We only need a couple packages to create a choropleth map. We will use
41[Folium](https://python-visualization.github.io/folium/), which provides
42map visualizations in Python. We will also use geopandas and pandas to
43wrangle our data before we put it on a map.
41[Folium](https://python-visualization.github.io/folium/), which provides map
42visualizations in Python. We will also use geopandas and pandas to wrangle our
43data before we put it on a map.
4444
4545``` python
4646# Import the necessary Python packages
@@ -49,14 +49,14 @@ import geopandas as gpd
4949import pandas as pd
5050```
5151
52To get anything to show up on a map, we need a file that will specify
53the boundaries of each country. Luckily, GeoJSON files exist (for free!)
54on the internet. To get the boundaries of every country in the world, we
55will use the GeoJSON link shown below.
52To get anything to show up on a map, we need a file that will specify the
53boundaries of each country. Luckily, GeoJSON files exist (for free!) on the
54internet. To get the boundaries of every country in the world, we will use the
55GeoJSON link shown below.
5656
57GeoPandas will take this data and load it into a dataframe so that we
58can easily match it to the data we\'re trying to analyze. Let\'s look at
59the GeoJSON dataframe:
57GeoPandas will take this data and load it into a dataframe so that we can easily
58match it to the data we're trying to analyze. Let's look at the GeoJSON
59dataframe:
6060
6161``` python
6262# Load the GeoJSON data with geopandas
@@ -67,9 +67,9 @@ geo_data.head()
6767![GeoJSON
6868Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/geojson_df.png)
6969
70Next, let\'s load the data from the Kaggle dataset. I\'ve downloaded
71this file, so update the file path if you have it somewhere else. After
72loading, let\'s take a look at this dataframe:
70Next, let's load the data from the Kaggle dataset. I've downloaded this file,
71so update the file path if you have it somewhere else. After loading, let's
72take a look at this dataframe:
7373
7474``` python
7575# Load the world happiness data with pandas
@@ -82,12 +82,11 @@ Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/happiness_
8282
8383# Clean the Data
8484
85Some countries need to be renamed, or they will be lost when you merge
86the happiness and GeoJSON dataframes. This is something I discovered
87when the map below showed empty countries. I searched both data frames
88for the missing countries to see the naming differences. Any countries
89that do not have records in the `happy_data` df will not show
90up on the map.
85Some countries need to be renamed, or they will be lost when you merge the
86happiness and GeoJSON dataframes. This is something I discovered when the map
87below showed empty countries. I searched both data frames for the missing
88countries to see the naming differences. Any countries that do not have records
89in the `happy_data` df will not show up on the map.
9190
9291``` python
9392# Rename some countries to match our GeoJSON data
@@ -112,11 +111,11 @@ happy_data.at[democratic_congo_index, 'Country or region'] = 'Democratic Republi
112111# Merge the Data
113112
114113Now 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
116need to call the `.merge()` function.
114happiness data. Since we've stored them both in dataframes, we just need to
115call the `.merge()` function.
117116
118We will also rename a couple columns, just so that they\'re a little
119easier to use when we create the map.
117We will also rename a couple columns, just so that they're a little easier to
118use when we create the map.
120119
121120``` python
122121# 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.
133132# Create the Map
134133
135134The 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
137object. The important part is to remember to reference the merged
138dataframe for our GeoJSON data and value data. The columns specify which
139geo data and value data to use.
135simplest way to find the center of the map and create a Folium map object. The
136important part is to remember to reference the merged dataframe for our GeoJSON
137data and value data. The columns specify which geo data and value data to use.
140138
141139``` python
142140# Assign centroids to map
@@ -164,17 +162,16 @@ folium.Choropleth(
164162).add_to(world_map)
165163```
166164
167Let\'s look at the resulting map.
165Let's look at the resulting map.
168166
169167![Choropleth
170168Map](https://img.cleberg.net/blog/20200925-world-choropleth-map/map.png)
171169
172170# Create a Tooltip on Hover
173171
174Now that we have a map set up, we could stop. However, I want to add a
175tooltip so that I can see more information about each country. The
176`tooltip_data` code below will show a popup on hover with all
177the data fields shown.
172Now that we have a map set up, we could stop. However, I want to add a tooltip
173so that I can see more information about each country. The `tooltip_data` code
174below will show a popup on hover with all the data fields shown.
178175
179176``` python
180177 # Adding labels to map
@@ -219,8 +216,8 @@ folium.LayerControl().add_to(world_map)
219216world_map
220217```
221218
222The final image below will show you what the tooltip looks like whenever
223you hover over a country.
219The final image below will show you what the tooltip looks like whenever you
220hover over a country.
224221
225222![Choropleth Map
226223Tooltip](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
77
88# Perfect is the Enemy of Good
99
10As the saying goes, \"the best is the enemy of the good.\" As we strive
11for perfection, we often fail to realize the implications of such an
12undertaking. Attempting to reach perfection is often unrealistic. Even
13worse, it can get in the way of achieving a good outcome. In certain
14situations, we try so hard to achieve the ideal solution that we have
15burned the bridges that would have allowed us to reach a lesser yet
16still superb solution.
17
18Philosophers throughout history have inspected this plight from many
19viewpoints. Greek mythology speaks of the [golden
20mean](https://en.wikipedia.org/wiki/Golden_mean_(philosophy)), which
21uses the story of Icarus to illustrate that sometimes \"the middle
22course\" is the best solution. In this story, Daedalus, a famous artist
23of his time, built feathered wings for himself and his son so that they
24might escape the clutches of King Minos. Daedalus warns his beloved son
25whom he loved so much to \"fly the middle course\", between the sea
26spray and the sun\'s heat. Icarus did not heed his father; he flew up
27and up until the sun melted the wax off his wings. For not heeding the
28middle course, he fell into the sea and drowned.
10As the saying goes, "the best is the enemy of the good." As we strive for
11perfection, we often fail to realize the implications of such an undertaking.
12Attempting to reach perfection is often unrealistic. Even worse, it can get in
13the way of achieving a good outcome. In certain situations, we try so hard to
14achieve the ideal solution that we have burned the bridges that would have
15allowed us to reach a lesser yet still superb solution.
16
17Philosophers throughout history have inspected this plight from many viewpoints.
18Greek mythology speaks of the [golden
19mean](https://en.wikipedia.org/wiki/Golden_mean_(philosophy)), which uses the
20story of Icarus to illustrate that sometimes "the middle course" is the best
21solution. In this story, Daedalus, a famous artist of his time, built feathered
22wings for himself and his son so that they might escape the clutches of King
23Minos. Daedalus warns his beloved son whom he loved so much to "fly the middle
24course", between the sea spray and the sun's heat. Icarus did not heed his
25father; he flew up and up until the sun melted the wax off his wings. For not
26heeding the middle course, he fell into the sea and drowned.
2927
3028More recently, management scholars have explored the [Pareto
31principle](https://en.wikipedia.org/wiki/Pareto_principle) and found
32that as we increase the frequency of something, or strive to perform
33actions to achieve some form of perfection, we run into [diminishing
29principle](https://en.wikipedia.org/wiki/Pareto_principle) and found that as we
30increase the frequency of something, or strive to perform actions to achieve
31some form of perfection, we run into [diminishing
3432returns](https://en.wikipedia.org/wiki/Diminishing_returns).
3533
3634Even further, Harold Demsetz is noted as coining the term [the Nirvana
37fallacy](https://en.wikipedia.org/wiki/Nirvana_fallacy) in 1969, which
38shows the fallacy of comparing actual things with unrealistic, idealized
39alternatives. This is another trap that we may fall into, where we are
40constantly thinking of the ultimate solutions to problems, when
41something more realistic needs to be considered.
42
43Over and over throughout history, we\'ve found that perfection is often
44unrealistic and unachievable. However, we push ourselves and our peers
45to \"give 100%\" or \"go the extra mile,\" while it may be that the
46better course is to give a valuable level of effort while considering
47the effects of further effort on the outcome. Working harder does not
48always help us achieve loftier goals.
49
50This has presented itself to me most recently during my time studying at
51my university. I was anxious and feeling the stresses of my courses,
52career, and personal life for quite a while, which was greatly affecting
53how well I was doing at school and my level of effort at work. One day,
54I happened to be talking to my father when he said something simple that
55hit home:
56
57> All you can do is show up and do your best. Worrying about the
58> outcomes won\'t affect the outcome itself.
35fallacy](https://en.wikipedia.org/wiki/Nirvana_fallacy) in 1969, which shows the
36fallacy of comparing actual things with unrealistic, idealized alternatives.
37This is another trap that we may fall into, where we are constantly thinking of
38the ultimate solutions to problems, when something more realistic needs to be
39considered.
40
41Over and over throughout history, we've found that perfection is often
42unrealistic and unachievable. However, we push ourselves and our peers to "give
43100%" or "go the extra mile," while it may be that the better course is to
44give a valuable level of effort while considering the effects of further effort
45on the outcome. Working harder does not always help us achieve loftier goals.
46
47This has presented itself to me most recently during my time studying at my
48university. I was anxious and feeling the stresses of my courses, career, and
49personal life for quite a while, which was greatly affecting how well I was
50doing at school and my level of effort at work. One day, I happened to be
51talking to my father when he said something simple that hit home:
52
53> All you can do is show up and do your best. Worrying about the outcomes won't
54> affect the outcome itself.
5955
6056The thought was extremely straightforward and uncomplicated, yet it was
61something that I had lost sight of during my stress-filled years at
62school. Ever since then, I\'ve found myself pausing and remembering that
63quote every time I get anxious or stressed. It helps to stop and think
64\"Can I do anything to affect the outcome, or am I simply worrying over
65something I can\'t change?\"
66
67# When Mediocrity Isn\'t Enough
68
69One problem with the philosophies presented in this post is that they
70are implemented far too often in situations where mediocrity simply
71isn\'t adequate. For example, let\'s take a look at digital user data,
72specifically personally-identifiable information (PII). As a
73cybersecurity auditor in the United States, I have found that most
74companies are concerned more with compliance than any actual safeguards
75over the privacy or protection of user data. Other than companies who
76have built their reputation on privacy and security, most companies will
77use [satisficing](https://en.wikipedia.org/wiki/Satisficing) as their
78primary decision-making strategy around user data.
79
80> Satisficing is a decision-making strategy or cognitive heuristic that
81> entails searching through the available alternatives until an
82> acceptability threshold is met.
83
84This means that each decision will be met with certain possible
85solutions until one of the solutions meets their minimum acceptable
86standards. For companies that deal with user data, the
87minimum-acceptable standards come from three areas:
88
891. Laws and regulations
902. Competitive pressure
913. Risk of monetary or reputation loss
92
93Working with project management or auditing, the primary concern here is
94the risk of legal ramifications. Since the primary risk comes from laws
95and regulations, companies will require that any project that involves
96user data must follow all the rules of those laws so that the company
97can protect itself from fines or other penalties.
98
99Following this, companies will consider best practices in order to place
100itself in a competitive position (e.g. Google vs. Apple) and review any
101recent or ongoing litigation against companies regarding user data. In a
102perfect company, management would then consider the ethical
103responsibilities of their organization and discuss their
104responsibilities over things like personally-identifiable information.
105
106However, as we mentioned above, most companies follow the idea of
107satisficing, which states that they have met the minimum acceptable
108standards and can now move on to other decisions. Modern business
109culture in the United States dictates that profits are the golden
110measure of how well a company or manager is performing, so we often
111don\'t think about our responsibilities beyond these basic standards.
112
113Not all situations demand excellence, but I believe that applying any
114philosophy as a broad stroke across one\'s life can be a mistake. We
115must be able to think critically about what we are doing as we do it and
116ask ourselves a few questions. Have I done everything I can in this
117situation? Is mediocrity an acceptable outcome, or should we strive for
118perfection, even if we can\'t attain it?
57something that I had lost sight of during my stress-filled years at school. Ever
58since then, I've found myself pausing and remembering that quote every time I
59get anxious or stressed. It helps to stop and think "Can I do anything to
60affect the outcome, or am I simply worrying over something I can't change?"
61
62# When Mediocrity Isn't Enough
63
64One problem with the philosophies presented in this post is that they are
65implemented far too often in situations where mediocrity simply isn't adequate.
66For example, let's take a look at digital user data, specifically
67personally-identifiable information (PII). As a cybersecurity auditor in the
68United States, I have found that most companies are concerned more with
69compliance than any actual safeguards over the privacy or protection of user
70data. Other than companies who have built their reputation on privacy and
71security, most companies will use
72[satisficing](https://en.wikipedia.org/wiki/Satisficing) as their primary
73decision-making strategy around user data.
74
75> Satisficing is a decision-making strategy or cognitive heuristic that entails
76> searching through the available alternatives until an acceptability threshold
77> is met.
78
79This means that each decision will be met with certain possible solutions until
80one of the solutions meets their minimum acceptable standards. For companies
81that deal with user data, the minimum-acceptable standards come from three
82areas:
83
841. Laws and regulations
852. Competitive pressure
863. Risk of monetary or reputation loss
87
88Working with project management or auditing, the primary concern here is the
89risk of legal ramifications. Since the primary risk comes from laws and
90regulations, companies will require that any project that involves user data
91must follow all the rules of those laws so that the company can protect itself
92from fines or other penalties.
93
94Following this, companies will consider best practices in order to place itself
95in a competitive position (e.g. Google vs. Apple) and review any recent or
96ongoing litigation against companies regarding user data. In a perfect company,
97management would then consider the ethical responsibilities of their
98organization and discuss their responsibilities over things like
99personally-identifiable information.
100
101However, as we mentioned above, most companies follow the idea of satisficing,
102which states that they have met the minimum acceptable standards and can now
103move on to other decisions. Modern business culture in the United States
104dictates that profits are the golden measure of how well a company or manager is
105performing, so we often don't think about our responsibilities beyond these
106basic standards.
107
108Not all situations demand excellence, but I believe that applying any philosophy
109as a broad stroke across one's life can be a mistake. We must be able to think
110critically about what we are doing as we do it and ask ourselves a few
111questions. Have I done everything I can in this situation? Is mediocrity an
112acceptable outcome, or should we strive for perfection, even if we can't attain
113it?
119114
120115Taking a few moments to think critically throughout our day, as we make
121116decisions, 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
77
88# A Brief History
99
10As a form of continuous learning and entertainment, I\'ve been running a
11handful of websites since 2016 when I took my first programming courses
12in college. I maintain one main website, the place I consider the
13official website to represent me. Under this site, I have a handful of
14subdirectories and subdomains.
15
16One of the parts I\'ve enjoyed the most about web development is the
17aspect of designing an identity for a web page and working to find
18exciting ways to display the site\'s content. Inevitably, this means
19I\'ve changed the designs for my websites more times than I could
20possibly count. Since I don\'t really host anything on my main webpage
21that\'s vital, it allows me the freedom to change things as inspiration
22strikes.
23
24Historically, I\'ve relied on core utilities for spacing, components,
25and layouts from [Bootstrap](https://getbootstrap.com) and added custom
26CSS for fonts, accents, colors, and other items. I also tend to create
27sites with no border radius on items, visible borders, and content that
28takes up the entire screen (using whitespace inside components instead
29of whitespace around my components).
10As a form of continuous learning and entertainment, I've been running a handful
11of websites since 2016 when I took my first programming courses in college. I
12maintain one main website, the place I consider the official website to
13represent me. Under this site, I have a handful of subdirectories and
14subdomains.
15
16One of the parts I've enjoyed the most about web development is the aspect of
17designing an identity for a web page and working to find exciting ways to
18display the site's content. Inevitably, this means I've changed the designs
19for my websites more times than I could possibly count. Since I don't really
20host anything on my main webpage that's vital, it allows me the freedom to
21change things as inspiration strikes.
22
23Historically, I've relied on core utilities for spacing, components, and
24layouts from [Bootstrap](https://getbootstrap.com) and added custom CSS for
25fonts, accents, colors, and other items. I also tend to create sites with no
26border radius on items, visible borders, and content that takes up the entire
27screen (using whitespace inside components instead of whitespace around my
28components).
3029
3130# The Redesign Process
3231
33About a week ago, I found myself wishing for a new design yet again. The
34prior design was largely inspired by IBM\'s [Carbon Design
35System](https://www.carbondesignsystem.com) and relied on jQuery,
36Bootstrap, along with some compressed
37[.webp](https://en.wikipedia.org/wiki/WebP) images.
32About a week ago, I found myself wishing for a new design yet again. The prior
33design was largely inspired by IBM's [Carbon Design
34System](https://www.carbondesignsystem.com) and relied on jQuery, Bootstrap,
35along with some compressed [.webp](https://en.wikipedia.org/wiki/WebP) images.
3836
39To anyone who knows my preferences toward web design - and even in my
40personal life - it should be no surprise that I immediately started
41looking for inspiration on minimalism. While there are some decent
42minimalistic designs on sites like
37To anyone who knows my preferences toward web design - and even in my personal
38life - it should be no surprise that I immediately started looking for
39inspiration on minimalism. While there are some decent minimalistic designs on
40sites like
4341[Dribbble](https://dribbble.com/search/shots/popular/web-design?q=minimalism),
4442people seem to mostly discuss [brutalist web
45design](https://brutalist-web.design) when you ask about minimalism.
46While brutalist web design doesn\'t have to be minimal, it often is.
47
48I suppose, in a way, I did create a brutalist website since my HTML is
49semantic and accessible, hyperlinks are colored and underlined, and all
50native browser functions like scrolling and the back button work as
51expected. However, I didn\'t think about brutalism while designing these
52sites.
53
54The new design followed a simple design process. I walked through the
55screens on my blog and asked myself: \"Is this element necessary for a
56user?\" This allowed me to first start by removing all javascript, which
57had the sole purpose of allowing users to open a collapsed navbar on
58mobile. Replacing the collapsible navbar allowed me to remove both
59jQuery and Bootstrap\'s javascript.
60
61Next, I removed things like author names (since I\'m literally the only
62person who will ever write on this site), multiple ways to click on a
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.
43design](https://brutalist-web.design) when you ask about minimalism. While
44brutalist web design doesn't have to be minimal, it often is.
45
46I suppose, in a way, I did create a brutalist website since my HTML is semantic
47and accessible, hyperlinks are colored and underlined, and all native browser
48functions like scrolling and the back button work as expected. However, I
49didn't think about brutalism while designing these sites.
50
51The new design followed a simple design process. I walked through the screens on
52my blog and asked myself: "Is this element necessary for a user?" This allowed
53me to first start by removing all javascript, which had the sole purpose of
54allowing users to open a collapsed navbar on mobile. Replacing the collapsible
55navbar allowed me to remove both jQuery and Bootstrap's javascript.
56
57Next, I removed things like author names (since I'm literally the only person
58who will ever write on this site), multiple ways to click on a blog post card,
59blog post descriptions, and the scroll-to-top button. It also helped to move all
60categories to a single page, rather than have each category on its own page.
6661
6762The final big piece to finish the
68\"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)\"-like
69part of my process was to remove Bootstrap CSS in its entirety. However,
70this meant pulling out a few very useful classes, such as
71`.img-fluid` and the default font stacks to keep in my custom
72CSS.
73
74After removing all the unnecessary pieces, I was finally able to
75reorganize my content and add a very small amount of custom CSS to make
76everything pretty. This took a brief amount of time, effectively just
77consisting of me converting `<div>` tags into things like
78`<ul>` lists and choosing accent colors.
63"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)"-like
64part of my process was to remove Bootstrap CSS in its entirety. However, this
65meant pulling out a few very useful classes, such as `.img-fluid` and the
66default font stacks to keep in my custom CSS.
67
68After removing all the unnecessary pieces, I was finally able to reorganize my
69content and add a very small amount of custom CSS to make everything pretty.
70This took a brief amount of time, effectively just consisting of me converting
71`<div>` tags into things like `<ul>` lists and choosing accent colors.
7972
8073# The Results
8174
8275## Reflection
8376
8477So, what did all of this reorganizing do to my webpages? Well, first, my
85websites are now **ridiculously fast**. Since the prior designs were
86also minimal and didn\'t have many images, they measured up in
87Firefox\'s Network Monitor around 300 KB - 600KB. After making the
88changes, my main site is at 5 KB transferred (22 KB total), and my blog
89is at 6.5 KB transferred (13 KB total). **That means the redesigned
90pages are less than 2% the size of the old designs.**
91
92Google Lighthouse ranks the new webpage as 100 in performance,
93accessibility, and best practices, with SEO at 92 since they think tap
94targets are not sized appropriately for mobile users. First contextual
95paints of the pages are under 0.8 seconds with 0 ms of blocking time.
96However, the blog subdomain ranks at 100 for all four categories! First
97contextual paints of the blog homepage are under 1.0 seconds with 0 ms
98of blocking time, due to the fact that the CSS for my blog is within a
99separate CSS file, and the CSS for my main website is simply embedded in
100the HTML file.
101
102Now that everything is complete, I can confidently say I\'m happy with
103the result and proud to look at the fastest set of websites I\'ve
104created so far.
78websites are now **ridiculously fast**. Since the prior designs were also
79minimal and didn't have many images, they measured up in Firefox's Network
80Monitor around 300 KB - 600KB. After making the changes, my main site is at 5 KB
81transferred (22 KB total), and my blog is at 6.5 KB transferred (13 KB total).
82**That means the redesigned pages are less than 2% the size of the old
83designs.**
84
85Google Lighthouse ranks the new webpage as 100 in performance, accessibility,
86and best practices, with SEO at 92 since they think tap targets are not sized
87appropriately for mobile users. First contextual paints of the pages are under
880.8 seconds with 0 ms of blocking time. However, the blog subdomain ranks at 100
89for all four categories! First contextual paints of the blog homepage are under
901.0 seconds with 0 ms of blocking time, due to the fact that the CSS for my blog
91is within a separate CSS file, and the CSS for my main website is simply
92embedded in the HTML file.
93
94Now that everything is complete, I can confidently say I'm happy with the
95result and proud to look at the fastest set of websites I've created so far.
content/blog/2020-12-28-neon-drive.md +48 −51
@@ -7,51 +7,49 @@ draft = false
77
88# Game Description
99
10[Neon Drive](https://store.steampowered.com/app/433910/Neon_Drive/)
11presents itself as a simple arcade-style game inspired by the arcade
12race games of the 1980s, yet it has managed to take up hours of my life
13without much effort. The game description, directly from the Steam page,
14is intriguing enough to entice anyone who\'s been looking for a good
15arcade racing game:
10[Neon Drive](https://store.steampowered.com/app/433910/Neon_Drive/) presents
11itself as a simple arcade-style game inspired by the arcade race games of the
121980s, yet it has managed to take up hours of my life without much effort. The
13game description, directly from the Steam page, is intriguing enough to entice
14anyone who's been looking for a good arcade racing game:
1615
17> Neon Drive is a slick retro-futuristic arcade game that will make your
18> brain melt. You\'ve been warned. From beautiful cityscapes and ocean
19> roads to exploding enemy spaceships, Neon Drive has it all.
16> Neon Drive is a slick retro-futuristic arcade game that will make your brain
17> melt. You've been warned. From beautiful cityscapes and ocean roads to
18> exploding enemy spaceships, Neon Drive has it all.
2019
2120# Gameplay
2221
2322The game holds true to the
24[retro-futurism](https://en.wikipedia.org/wiki/Retrofuturism) style,
25including chrome female robots, pixelated arcade machines, and
23[retro-futurism](https://en.wikipedia.org/wiki/Retrofuturism) style, including
24chrome female robots, pixelated arcade machines, and
2625[outrun](https://teddit.net/r/outrun/) aesthetics.
2726
28Each level of the game is shown as a separate arcade machine. Each
29arcade machine lets you play on Normal, Hard, Insane, Practice, and Free
30Run. To beat each arcade, you must reach the end of the level without
31crashing your car into the various obstacles on the course. Basic levels
32let you move left or right to avoid blocks in the road. Later levels put
33you through other tests, such as dodging traffic or blasting asteroids.
27Each level of the game is shown as a separate arcade machine. Each arcade
28machine lets you play on Normal, Hard, Insane, Practice, and Free Run. To beat
29each arcade, you must reach the end of the level without crashing your car into
30the various obstacles on the course. Basic levels let you move left or right to
31avoid blocks in the road. Later levels put you through other tests, such as
32dodging traffic or blasting asteroids.
3433
35The game uses synthwave music to keep you on track to make the correct
36moves by timing the beats of the songs to the correct moves on the
37screen. It reminds me of the early Guitar Hero games, as well as mobile
38apps like VOEZ - repetition and staying on-beat is the only way to win.
34The game uses synthwave music to keep you on track to make the correct moves by
35timing the beats of the songs to the correct moves on the screen. It reminds me
36of the early Guitar Hero games, as well as mobile apps like VOEZ - repetition
37and staying on-beat is the only way to win.
3938
4039# In-Game Screenshots
4140
42Taking a look at the main menu, you can see that Neon Drive plays into
43every stereotype you can think of around retro-futuristic, synthwave
44arcades (in a good way).
41Taking a look at the main menu, you can see that Neon Drive plays into every
42stereotype you can think of around retro-futuristic, synthwave arcades (in a
43good way).
4544
4645![Neon Drive
4746Menu](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_menu.png)
4847
49Once you get into the first level, we see that the choice of car fits
50right in with the stereotypical cars of the 80s, like the
48Once you get into the first level, we see that the choice of car fits right in
49with the stereotypical cars of the 80s, like the
5150[DeLorean](https://en.wikipedia.org/wiki/DMC_DeLorean) or the [Ferrari
52F40](https://en.wikipedia.org/wiki/Ferrari_F40). Each new level comes
53with new color schemes and cars, so you should never get tired of the
54aesthetic.
51F40](https://en.wikipedia.org/wiki/Ferrari_F40). Each new level comes with new
52color schemes and cars, so you should never get tired of the aesthetic.
5553
5654![Neon Drive
5755Race](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:
6159![Level
62602](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_level_2.png)
6361
64If you\'re the competitive type and getting 100% on all arcade machines
65isn\'t enough, there are leaderboards for the regular part of the game,
66and the endurance game mode.
62If you're the competitive type and getting 100% on all arcade machines isn't
63enough, there are leaderboards for the regular part of the game, and the
64endurance game mode.
6765
6866![Leaderboard](https://img.cleberg.net/blog/20201228-neon-drive/neon_drive_leaderboard.png)
6967
7068# Other Suggestions
7169
72Neon Drive sits nicely within the well-founded cult genre of Outrun.
73Other games that I\'ve enjoyed in this same spectrum are:
70Neon Drive sits nicely within the well-founded cult genre of Outrun. Other games
71that I've enjoyed in this same spectrum are:
7472
75- [Far Cry 3: Blood
73- [Far Cry 3: Blood
7674 Dragon](https://store.steampowered.com/app/233270/Far_Cry_3__Blood_Dragon/)
77- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/)
78- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/)
75- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/)
76- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/)
7977
80Although these games aren\'t necessarily in the same genre, they do have
81aspects that place them close enough to interest gamers that enjoyed
82Neon Drive:
78Although these games aren't necessarily in the same genre, they do have aspects
79that place them close enough to interest gamers that enjoyed Neon Drive:
8380
84- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/)
85- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/)
86- [Need for Speed:
81- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/)
82- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/)
83- [Need for Speed:
8784 Heat](https://store.steampowered.com/app/1222680/Need_for_Speed_Heat/)
88- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/)
89
90Of course, if all you really care about is the arcade aspect of these
91games, you can check out the [Atari
92Vault](https://store.steampowered.com/app/400020/Atari_Vault/) or any of
93the other classic games sold on Steam by companies like Namco, Atari.
94For something like Nintendo, you\'d have to settle for buying used
95classic consoles or delve into the world of emulation.
85- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/)
86
87Of course, if all you really care about is the arcade aspect of these games, you
88can check out the [Atari
89Vault](https://store.steampowered.com/app/400020/Atari_Vault/) or any of the
90other classic games sold on Steam by companies like Namco, Atari. For something
91like Nintendo, you'd have to settle for buying used classic consoles or delve
92into the world of emulation.
content/blog/2020-12-29-zork.md +59 −68
@@ -7,34 +7,33 @@ draft = false
77
88# Download (Free)
99
10Before we get into the game itself, you should know that you can
11download Zork for free from Infocom\'s [download
12page](http://infocom-if.org/downloads/downloads.html). So feel free to
13boot it up and take a ride back to the 1980s with this masterpiece.
10Before we get into the game itself, you should know that you can download Zork
11for free from Infocom's [download
12page](http://infocom-if.org/downloads/downloads.html). So feel free to boot it
13up and take a ride back to the 1980s with this masterpiece.
1414
1515# Game Description
1616
1717Zork is an interactive, text-based computer game originally released in
181980. This series, split into three separate games, introduced a robust
19and sophisticated text parser to gamers. People were largely used to the
20simple commands used in the popular game [Colossal Cave
21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but
22Zork allowed users to send more complex commands that included
23prepositions and conjunctions.
24
25Zork tracks your score as you explore the map, find tools, and collect
26trophy items (e.g., a jewel-encrusted egg). When you place your trophy
27items in the trophy case found in the Living Room area, you gain score
28points. Collecting the Twenty Treasures of Zork and placing them within
29the trophy case wins the game. However, you must explore the map, solve
30puzzles, and avoid being eaten by a grue to collect these treasures.
181980. This series, split into three separate games, introduced a robust and
19sophisticated text parser to gamers. People were largely used to the simple
20commands used in the popular game [Colossal Cave
21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but Zork
22allowed users to send more complex commands that included prepositions and
23conjunctions.
24
25Zork tracks your score as you explore the map, find tools, and collect trophy
26items (e.g., a jewel-encrusted egg). When you place your trophy items in the
27trophy case found in the Living Room area, you gain score points. Collecting the
28Twenty Treasures of Zork and placing them within the trophy case wins the game.
29However, you must explore the map, solve puzzles, and avoid being eaten by a
30grue to collect these treasures.
3131
3232# The Map
3333
34Since Zork is a vast and complex game, it helps to have a map as you
35explore and collect your trophies. However, if you want to play the game
36as it was truly intended, you should try to play it without using the
37map.
34Since Zork is a vast and complex game, it helps to have a map as you explore and
35collect your trophies. However, if you want to play the game as it was truly
36intended, you should try to play it without using the map.
3837
3938![Zork Map](https://img.cleberg.net/blog/20201229-zork/zork_map.png)
4039
@@ -42,55 +41,47 @@ map.
4241
4342# In-Game Screenshots
4443
45After playing the game (for the first time ever) for several weeks
46around 2014, I was finally able to beat the game with some online help
47to find the last couple items. As I was writing this post, I installed
48the game again to grab some screenshots to show off the true glory of
49this game. As noted in [Jimmy Maher\'s
50playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/), the
51original Zork games looked quite a bit different due to the older
52hardware of computers like the Apple II and multiple bug fixes that
53Infocom pushed out after the game\'s initial release. My play-through
54uses the [Zork
55Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/)
56version, which utilizes DOSBox on Windows.
57
58The first screenshot here shows the introductory information, which
59doesn\'t include instructions of any kind for the player. If you
60haven\'t played text adventures before, try to use simple commands like
61\"go west,\" \"look around,\" or \"hit troll with elvish sword.\"
62
63![Zork Screen, pt.
641](https://img.cleberg.net/blog/20201229-zork/zork_01.png)
65
66In this second screenshot, we see the player has entered the house and
67found the trophy case in the living room. The lantern and sword in this
68room allow the player to explore dark areas and attack enemies. If you
69don\'t use the lantern, you won\'t be able to see anything in dark
70areas, and you may be eaten by a grue.
71
72![Zork Screen, pt.
732](https://img.cleberg.net/blog/20201229-zork/zork_02.png)
74
75Finally, we see that the player has found the first treasure: a
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)
44After playing the game (for the first time ever) for several weeks around 2014,
45I was finally able to beat the game with some online help to find the last
46couple items. As I was writing this post, I installed the game again to grab
47some screenshots to show off the true glory of this game. As noted in [Jimmy
48Maher's playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/),
49the original Zork games looked quite a bit different due to the older hardware
50of computers like the Apple II and multiple bug fixes that Infocom pushed out
51after the game's initial release. My play-through uses the [Zork
52Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/) version,
53which utilizes DOSBox on Windows.
54
55The first screenshot here shows the introductory information, which doesn't
56include instructions of any kind for the player. If you haven't played text
57adventures before, try to use simple commands like "go west," "look around,"
58or "hit troll with elvish sword."
59
60![Zork Screen, pt. 1](https://img.cleberg.net/blog/20201229-zork/zork_01.png)
61
62In this second screenshot, we see the player has entered the house and found the
63trophy case in the living room. The lantern and sword in this room allow the
64player to explore dark areas and attack enemies. If you don't use the lantern,
65you won't be able to see anything in dark areas, and you may be eaten by a
66grue.
67
68![Zork Screen, pt. 2](https://img.cleberg.net/blog/20201229-zork/zork_02.png)
69
70Finally, we see that the player has found the first treasure: a jewel-encrusted
71egg. These treasures can be taken back to the house and placed in the trophy
72case or carried until you feel like you want to put things away.
73
74![Zork Screen, pt 3.](https://img.cleberg.net/blog/20201229-zork/zork_03.png)
8275
8376# Conclusion
8477
85It\'s been quite a few years since I first played Zork, but I clearly
86remember the late nights and bloodshot eyes that helped me find all the
87treasures. This game is well worth the time and effort, even though the
88text-based aspect may be off-putting to gamers who didn\'t have to grow
89up playing games without graphics. However, I believe that the strategy
90and skills learned in early video games like Zork can actually help you,
91even when playing newer games.
78It's been quite a few years since I first played Zork, but I clearly remember
79the late nights and bloodshot eyes that helped me find all the treasures. This
80game is well worth the time and effort, even though the text-based aspect may be
81off-putting to gamers who didn't have to grow up playing games without
82graphics. However, I believe that the strategy and skills learned in early video
83games like Zork can actually help you, even when playing newer games.
9284
9385If you do decide to play Zork, you can download Zork I, II, and III from
94Infocom\'s [download
95page](http://infocom-if.org/downloads/downloads.html) for free or search
96the internet for an online version.
86Infocom's [download page](http://infocom-if.org/downloads/downloads.html) for
87free or search the internet for an online version.
content/blog/2021-01-01-seum.md +51 −58
@@ -8,86 +8,79 @@ draft = false
88# Game Description
99
1010[SEUM: Speedrunners from
11Hell](https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/)
12is an incredibly fast-paced mashup of a puzzle game and a free-running
13game. Created by [Pine Studio](https://pinestudio.co) in early 2016 and
14first released as a [demo on
11Hell](https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/) is
12an incredibly fast-paced mashup of a puzzle game and a free-running game.
13Created by [Pine Studio](https://pinestudio.co) in early 2016 and first released
14as a [demo on
1515GameJolt](https://gamejolt.com/games/seum-speedrunners-from-hell-demo/154868),
16this game was successfully green-lit on Steam and has amassed a cult
17following on multiple consoles.
16this game was successfully green-lit on Steam and has amassed a cult following
17on multiple consoles.
1818
19Here\'s the game description straight from the developers:
19Here's the game description straight from the developers:
2020
21> Like a bastard child of Quake 3 and Super Meat Boy, SEUM: Speedrunners
22> from Hell is truly hardcore and focuses on speed and fast reaction.
21> Like a bastard child of Quake 3 and Super Meat Boy, SEUM: Speedrunners from
22> Hell is truly hardcore and focuses on speed and fast reaction.
2323
2424# Story
2525
26SEUM does a great job setting the stage when you open the game for the
27first time, playing an animated video in the form of comic book images.
28You see Marty, the protagonist, sitting around drinking his beer as
29Satan busts down the door, cuts his hand off, and steals all his beer
30and bacon. As Satan is leaving, Marty whips a vinyl record across the
31room and cuts off one of Satan\'s hands. This hand is what allows you to
32use all the powers in the game.
26SEUM does a great job setting the stage when you open the game for the first
27time, playing an animated video in the form of comic book images. You see Marty,
28the protagonist, sitting around drinking his beer as Satan busts down the door,
29cuts his hand off, and steals all his beer and bacon. As Satan is leaving, Marty
30whips a vinyl record across the room and cuts off one of Satan's hands. This
31hand is what allows you to use all the powers in the game.
3332
34Check out the screenshot below for one of the first panels of the
35storyline:
33Check out the screenshot below for one of the first panels of the storyline:
3634
3735![SEUM Story](https://img.cleberg.net/blog/20210101-seum/seum_story.png)
3836
3937# Gameplay
4038
41To accomplish each level, you will need to get to the final blue portal
42under a certain time limit. You can beat a level by getting to the
43portal before the time meter runs out or \"Dominate\" a level by beating
44it within a shorter time limit (noted by a bright red/orange color in
45the time meter).
46
47The portal is usually set behind locked gates, protected by dangerous
48defenses, or in hard-to-reach places. To reach the portal, you\'ll need
49to go through any existing orange portals, light all yellow beacons,
50avoid things like fireballs and blades, or use any satanic power orbs
51lying around. These special abilities include:
52
53- Gravity
54- Teleport
55- Rewind
56- Spawn platform
57- Roar (DLC)
58- Rocket (DLC)
59- Shadow world (DLC)
60
61For the main storyline, there are nine floors to beat. Each floor
62contains nine regular levels, one boss level, and one bonus level;
63although you don\'t technically need to beat all levels to advance to
64the next floor.
65
66![SEUM Floor
67Menu](https://img.cleberg.net/blog/20210101-seum/seum_floor.png)
39To accomplish each level, you will need to get to the final blue portal under a
40certain time limit. You can beat a level by getting to the portal before the
41time meter runs out or "Dominate" a level by beating it within a shorter time
42limit (noted by a bright red/orange color in the time meter).
43
44The portal is usually set behind locked gates, protected by dangerous defenses,
45or in hard-to-reach places. To reach the portal, you'll need to go through any
46existing orange portals, light all yellow beacons, avoid things like fireballs
47and blades, or use any satanic power orbs lying around. These special abilities
48include:
49
50- Gravity
51- Teleport
52- Rewind
53- Spawn platform
54- Roar (DLC)
55- Rocket (DLC)
56- Shadow world (DLC)
57
58For the main storyline, there are nine floors to beat. Each floor contains nine
59regular levels, one boss level, and one bonus level; although you don't
60technically need to beat all levels to advance to the next floor.
61
62![SEUM Floor Menu](https://img.cleberg.net/blog/20210101-seum/seum_floor.png)
6863
6964# In-Game Screenshots
7065
71The main menu gives you plenty of options for tuning your system,
72playing main levels, playing the DLC, or exploring the other game modes.
66The main menu gives you plenty of options for tuning your system, playing main
67levels, playing the DLC, or exploring the other game modes.
7368
74![SEUM Main
75Menu](https://img.cleberg.net/blog/20210101-seum/seum_menu.png)
69![SEUM Main Menu](https://img.cleberg.net/blog/20210101-seum/seum_menu.png)
7670
77Once you enter a level, you can look around and strategize before
78starting. Clicking any button will start the menu, and you\'ll have to
79restart if you die. One of the great things about SEUM is that it has
80great keyboard shortcuts. You can quickly smash `R` to
81restart the level or `M` to return to the level menu.
71Once you enter a level, you can look around and strategize before starting.
72Clicking any button will start the menu, and you'll have to restart if you die.
73One of the great things about SEUM is that it has great keyboard shortcuts. You
74can quickly smash `R` to restart the level or `M` to return to the level menu.
8275
8376![SEUM Level](https://img.cleberg.net/blog/20210101-seum/seum_level.png)
8477
85Once you\'re able to win a level, you\'ll see the high scores and can
86watch replays of the best scores.
78Once you're able to win a level, you'll see the high scores and can watch
79replays of the best scores.
8780
8881![SEUM Win](https://img.cleberg.net/blog/20210101-seum/seum_win.png)
8982
90Each regular level contains a beer in a disguised location that may take
91some out-of-the-box thinking.
83Each regular level contains a beer in a disguised location that may take some
84out-of-the-box thinking.
9285
9386![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
77
88# What is the Fediverse?
99
10The fediverse is a federated universe of servers commonly used for
11sharing content, like social media. So, instead of having to rely on a
12single organization to run the server (e.g. Facebook), the fediverse is
13a giant collection of servers across the world, owned by many people and
14organizations.
15
16Take a look at this depiction of a federated network. Each server in
17this photo is owned and run by different administrators/owners.
18Federated networks are best explained as email servers: you have an
19email account that exists on a server (e.g. Outlook), your friend has an
20account on a different server (e.g. GMail), and another friend has an
21account on a third server (e.g. ProtonMail). All three of you can talk
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
10The fediverse is a federated universe of servers commonly used for sharing
11content, like social media. So, instead of having to rely on a single
12organization to run the server (e.g. Facebook), the fediverse is a giant
13collection of servers across the world, owned by many people and organizations.
14
15Take a look at this depiction of a federated network. Each server in this photo
16is owned and run by different administrators/owners. Federated networks are best
17explained as email servers: you have an email account that exists on a server
18(e.g. Outlook), your friend has an account on a different server (e.g. GMail),
19and another friend has an account on a third server (e.g. ProtonMail). All three
20of you can talk and communicate back and forth without having to be on the same
21server. However, responsible email admins are there to set rules and control the
2422traffic going in/out of the server.
2523
2624![Federated services
2725diagram](https://img.cleberg.net/blog/20210104-a-simple-guide-to-the-fediverse/federated-example.svg)
2826
29The main objective of this architecture is to decentralize the control
30within the internet connections. For example, if you run your own
31Mastodon instance, you and your users can\'t be censored or impacted in
32any way by authorities of another Mastodon instance. Some users have
33praised these features due to recent criticism of popular social media
34websites that may be over-censoring their users.
35
36This 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
38I create a Mastodon instance and get a ton of users to sign up, I can
39shut the server down at any time. That means you\'re at risk of losing
40the content you\'ve created unless you back it up, or the server backs
41it up for you. Also, depending on the software used (e.g. Mastodon,
42Pixelfed, etc.), censorship may still be an issue if the server admins
43decide they want to censor their users. Now, censorship isn\'t always a
44bad thing and can even benefit the community as a whole, but you\'ll
45want to determine which servers align with your idea of proper
46censorship.
47
48However, these are risks that we take when we sign up for any online
49platform. Whatever your reason is for trying out federated social
50networks, they are part of the future of the internet. However, the
51popularity of these services is still yet to be determined, especially
52with the increased difficulty understanding and signing up for these
53platforms. Perhaps increased regulation and litigation against current
54social media sites will push more users into the fediverse.
27The main objective of this architecture is to decentralize the control within
28the internet connections. For example, if you run your own Mastodon instance,
29you and your users can't be censored or impacted in any way by authorities of
30another Mastodon instance. Some users have praised these features due to recent
31criticism of popular social media websites that may be over-censoring their
32users.
33
34This strategy is great for making sure control of the social web isn't
35controlled by a single organization, but it also has some downsides. If I create
36a Mastodon instance and get a ton of users to sign up, I can shut the server
37down at any time. That means you're at risk of losing the content you've
38created unless you back it up, or the server backs it up for you. Also,
39depending on the software used (e.g. Mastodon, Pixelfed, etc.), censorship may
40still be an issue if the server admins decide they want to censor their users.
41Now, censorship isn't always a bad thing and can even benefit the community as
42a whole, but you'll want to determine which servers align with your idea of
43proper censorship.
44
45However, these are risks that we take when we sign up for any online platform.
46Whatever your reason is for trying out federated social networks, they are part
47of the future of the internet. However, the popularity of these services is
48still yet to be determined, especially with the increased difficulty
49understanding and signing up for these platforms. Perhaps increased regulation
50and litigation against current social media sites will push more users into the
51fediverse.
5552
5653# Federated Alternatives to Popular Sites
5754
58The list below is a small guide that will show you federated
59alternatives to current popular websites. There are many more out there,
60so go and explore: you might just find the perfect home.
55The list below is a small guide that will show you federated alternatives to
56current popular websites. There are many more out there, so go and explore: you
57might just find the perfect home.
6158
6259## Reddit
6360
64- [Lemmy](https://lemmy.ml/instances)
61- [Lemmy](https://lemmy.ml/instances)
6562
6663## Twitter/Facebook/Tumblr
6764
68- [Mastodon](https://joinmastodon.org)
69- [Diaspora](https://diasporafoundation.org)
70- [Friendica](https://friendi.ca)
71- [GNU Social](https://gnusocial.network)
72- [Pleroma](https://pleroma.social)
65- [Mastodon](https://joinmastodon.org)
66- [Diaspora](https://diasporafoundation.org)
67- [Friendica](https://friendi.ca)
68- [GNU Social](https://gnusocial.network)
69- [Pleroma](https://pleroma.social)
7370
7471## Instagram
7572
76- [Pixelfed](https://pixelfed.org)
73- [Pixelfed](https://pixelfed.org)
7774
7875## Slack/Discord
7976
80- [Matrix](https://element.io)
77- [Matrix](https://element.io)
8178
8279## Youtube/Vimeo
8380
84- [Peertube](https://joinpeertube.org)
81- [Peertube](https://joinpeertube.org)
8582
8683## Spotify/Soundcloud
8784
88- [Funkwhale](https://funkwhale.audio)
85- [Funkwhale](https://funkwhale.audio)
8986
9087## Podcasting
9188
92- [Pubcast](https://pubcast.pub)
89- [Pubcast](https://pubcast.pub)
9390
9491## Medium/Blogger
9592
96- [WriteFreely](https://writefreely.org)
93- [WriteFreely](https://writefreely.org)
9794
9895# Get Started
9996
100The best way to get started is to simply sign up and learn as you go. If
101you\'re comfortable signing up through a Mastodon, Pleroma, or Friendica
102server, here is [a list of themed
103servers](https://fediverse.party/en/portal/servers) to choose from. If
104you\'re looking for something else, try a web search for a federated
97The best way to get started is to simply sign up and learn as you go. If you're
98comfortable signing up through a Mastodon, Pleroma, or Friendica server, here is
99[a list of themed servers](https://fediverse.party/en/portal/servers) to choose
100from. If you're looking for something else, try a web search for a federated
105101alternative to your favorite sites.
106102
107103Find 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
77
88# Uncomplicated Firewall
99
10Uncomplicated Firewall, also known as ufw, is a convenient and
11beginner-friendly way to enforce OS-level firewall rules. For those who
12are hosting servers or any device that is accessible to the world (i.e.,
13by public IP or domain name), it\'s critical that a firewall is properly
14implemented and active.
15
16Ufw is available by default in all Ubuntu installations after 8.04 LTS.
17For other distributions, you can look to install ufw or check if there
18are alternative firewalls installed already. There are usually
19alternatives available, such as Fedora\'s `firewall` and the
20package available on most distributions: `iptables`. Ufw is
21considered a beginner-friendly front-end to iptables.
22
23[Gufw](https://gufw.org) is available as a graphical user interface
24(GUI) application for users who are uncomfortable setting up a firewall
25through a terminal.
10Uncomplicated Firewall, also known as ufw, is a convenient and beginner-friendly
11way to enforce OS-level firewall rules. For those who are hosting servers or any
12device that is accessible to the world (i.e., by public IP or domain name),
13it's critical that a firewall is properly implemented and active.
14
15Ufw is available by default in all Ubuntu installations after 8.04 LTS. For
16other distributions, you can look to install ufw or check if there are
17alternative firewalls installed already. There are usually alternatives
18available, such as Fedora's `firewall` and the package available on most
19distributions: `iptables`. Ufw is considered a beginner-friendly front-end to
20iptables.
21
22[Gufw](https://gufw.org) is available as a graphical user interface (GUI)
23application for users who are uncomfortable setting up a firewall through a
24terminal.
2625
2726![Gufw
2827Screenshot](https://img.cleberg.net/blog/20210107-secure-your-network-with-the-uncomplicated-firewall/gufw.png)
2928
3029# Getting Help
3130
32If you need help figuring out commands, remember that you can run the
33`--help` flag to get a list of options.
31If you need help figuring out commands, remember that you can run the `--help`
32flag to get a list of options.
3433
3534```sh
3635sudo ufw --help
@@ -38,20 +37,19 @@ sudo ufw --help
3837
3938# Set Default State
4039
41The proper way to run a firewall is to set a strict default state and
42slowly open up ports that you want to allow. This helps prevent anything
43malicious from slipping through the cracks. The following command
44prevents all incoming traffic (other than the rules we specify later),
45but you can also set this for outgoing connections, if necessary.
40The proper way to run a firewall is to set a strict default state and slowly
41open up ports that you want to allow. This helps prevent anything malicious from
42slipping through the cracks. The following command prevents all incoming traffic
43(other than the rules we specify later), but you can also set this for outgoing
44connections, if necessary.
4645
4746```sh
4847sudo ufw default deny incoming
4948```
5049
51You should also allow outgoing traffic if you want to allow the device
52to communicate back to you or other parties. For example, media servers
53like Plex need to be able to send out data related to streaming the
54media.
50You should also allow outgoing traffic if you want to allow the device to
51communicate back to you or other parties. For example, media servers like Plex
52need to be able to send out data related to streaming the media.
5553
5654```sh
5755sudo ufw default allow outgoing
@@ -59,24 +57,23 @@ sudo ufw default allow outgoing
5957
6058# Adding Port Rules
6159
62Now that we\'ve disabled all incoming traffic by default, we need to
63open up some ports (or else no traffic would be able to come in). If you
64need to be able to `ssh` into the machine, you\'ll need to
65open up port 22.
60Now that we've disabled all incoming traffic by default, we need to open up
61some ports (or else no traffic would be able to come in). If you need to be able
62to `ssh` into the machine, you'll need to open up port 22.
6663
6764```sh
6865sudo ufw allow 22
6966```
7067
71You can also issue more restrictive rules. The following rule will allow
72`ssh` connections only from machines on the local subnet.
68You can also issue more restrictive rules. The following rule will allow `ssh`
69connections only from machines on the local subnet.
7370
7471```sh
7572sudo ufw allow proto tcp from 192.168.0.0/24 to any port 22
7673```
7774
78If you need to set a rule that isn\'t tcp, just append your connection
79type to the end of the rule.
75If you need to set a rule that isn't tcp, just append your connection type to
76the end of the rule.
8077
8178```sh
8279sudo ufw allow 1900/udp
@@ -99,8 +96,7 @@ sudo reboot now
9996
10097# Checking Status
10198
102Now that the firewall is enabled, let\'s check and see what the rules
103look like.
99Now that the firewall is enabled, let's check and see what the rules look like.
104100
105101```sh
106102sudo ufw status numbered
@@ -117,9 +113,9 @@ Status: active
117113
118114# Deleting Rules
119115
120If you need to delete a rule, you need to know the number associated
121with that rule. Let\'s delete the first rule in the table above. You\'ll
122be asked to confirm the deletion as part of this process.
116If you need to delete a rule, you need to know the number associated with that
117rule. Let's delete the first rule in the table above. You'll be asked to
118confirm the deletion as part of this process.
123119
124120```sh
125121sudo ufw delete 1
@@ -127,11 +123,10 @@ sudo ufw delete 1
127123
128124# Managing App Rules
129125
130Luckily, there\'s a convenient way for installed applications to create
131files that ufw can easily implement so that you don\'t have to search
132and find which ports your application requires. To see if your device
133has any applications with pre-installed ufw rules, execute the following
134command:
126Luckily, there's a convenient way for installed applications to create files
127that ufw can easily implement so that you don't have to search and find which
128ports your application requires. To see if your device has any applications with
129pre-installed ufw rules, execute the following command:
135130
136131```sh
137132sudo ufw app list
@@ -148,14 +143,14 @@ Available applications:
148143 plexmediaserver-dlna
149144```
150145
151If you want to get more information on a specific app rule, use the
152`info` command.
146If you want to get more information on a specific app rule, use the `info`
147command.
153148
154149```sh
155150sudo ufw app info plexmediaserver-dlna
156151```
157152
158You\'ll get a blurb of info back like this:
153You'll get a blurb of info back like this:
159154
160155``` txt
161156Profile: plexmediaserver-dlna
@@ -167,8 +162,8 @@ Ports:
167162 32469/tcp
168163```
169164
170You can add or delete app rules the same way that you\'d add or delete
171specific port rules.
165You can add or delete app rules the same way that you'd add or delete specific
166port rules.
172167
173168```sh
174169sudo ufw allow plexmediaserver-dlna
@@ -180,12 +175,12 @@ sudo ufw delete RULE|NUM
180175
181176# Creating App Rules
182177
183If you\'d like to create you own app rule, you\'ll need to create a file
184in the `/etc/ufw/applications.d` directory. Within the file
185you create, you need to make sure the content is properly formatted.
178If you'd like to create you own app rule, you'll need to create a file in the
179`/etc/ufw/applications.d` directory. Within the file you create, you need to
180make sure the content is properly formatted.
186181
187For example, here are the contents my `plexmediaserver` file,
188which creates three distinct app rules for ufw:
182For example, here are the contents my `plexmediaserver` file, which creates
183three distinct app rules for ufw:
189184
190185``` config
191186[plexmediaserver]
@@ -204,8 +199,8 @@ description=The Plex Media Server (with additional DLNA capability)
204199ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp
205200```
206201
207So, if I wanted to create a custom app rule called \"mycustomrule,\"
208I\'d create a file and add my content like this:
202So, if I wanted to create a custom app rule called "mycustomrule," I'd create
203a file and add my content like this:
209204
210205```sh
211206sudo nano /etc/ufw/applications.d/mycustomrule
content/blog/2021-02-19-macos.md +79 −92
@@ -7,79 +7,74 @@ draft = false
77
88# Diving into macOS
99
10After spending nearly 15 years working with Windows and 8 years on
11Linux, I have experienced macOS for the first time. By chance, my spouse
12happened to buy a new MacBook and gifted me their 2013 model. Of course,
13I still consider my Linux desktop to be my daily driver and keep Windows
14around for gaming needs, but over the past week I\'ve found myself using
15the MacBook more and more for things that don\'t require gaming specs or
16advanced dev tools.
10After spending nearly 15 years working with Windows and 8 years on Linux, I have
11experienced macOS for the first time. By chance, my spouse happened to buy a new
12MacBook and gifted me their 2013 model. Of course, I still consider my Linux
13desktop to be my daily driver and keep Windows around for gaming needs, but over
14the past week I've found myself using the MacBook more and more for things that
15don't require gaming specs or advanced dev tools.
1716
1817# Initial Thoughts
1918
20Before I move on to the technical aspects of my set-up, I want to take
21some time and express my thoughts on the overall OS.
19Before I move on to the technical aspects of my set-up, I want to take some time
20and express my thoughts on the overall OS.
2221
2322![macOS
2423Desktop](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/macos-desktop.png)
2524
26As expected, the initial computer setup is a breeze with Mac\'s guided
27GUI installer.
28
29The desktop itself reminds me of GNOME more than anything else I\'ve
30seen: even Pantheon from [ElementaryOS](https://elementary.io/), which
31people commonly refer to as the closest Linux distro to macOS. The
32desktop toolbar is great and far surpasses the utility of the GNOME
33toolbar due to the fact that the extensions and icons *actually work*. I
34launch macOS and immediately see my shortcuts for Tresorit, Bitwarden,
35and Mullvad pop up as the computer loads.
36
37Even further, the app dock is very useful and will be yet another
38familiarity for GNOME users. I know many people like panels instead of
39docks, but I\'ve always found docks to have a more pleasing UI. However,
40I had to disable the \"Show recent applications in Dock\" preference; I
41can\'t stand items taking up precious screen space if I\'m not currently
42using them. On that same note, it\'s taking me some time to get use to
43the fact that I have to manually quit an app or else it will still stay
44open/active in the dock, even if I\'ve closed out all windows for that
45app (e.g. Firefox).
46
47Overall, I\'m having a lot of fun and for users who spend a large
48majority of their time performing basic tasks like web browsing,
49writing, watching media, etc., macOS is a fantastic option.
25As expected, the initial computer setup is a breeze with Mac's guided GUI
26installer.
27
28The desktop itself reminds me of GNOME more than anything else I've seen: even
29Pantheon from [ElementaryOS](https://elementary.io/), which people commonly
30refer to as the closest Linux distro to macOS. The desktop toolbar is great and
31far surpasses the utility of the GNOME toolbar due to the fact that the
32extensions and icons *actually work*. I launch macOS and immediately see my
33shortcuts for Tresorit, Bitwarden, and Mullvad pop up as the computer loads.
34
35Even further, the app dock is very useful and will be yet another familiarity
36for GNOME users. I know many people like panels instead of docks, but I've
37always found docks to have a more pleasing UI. However, I had to disable the
38"Show recent applications in Dock" preference; I can't stand items taking up
39precious screen space if I'm not currently using them. On that same note, it's
40taking me some time to get use to the fact that I have to manually quit an app
41or else it will still stay open/active in the dock, even if I've closed out all
42windows for that app (e.g. Firefox).
43
44Overall, I'm having a lot of fun and for users who spend a large majority of
45their time performing basic tasks like web browsing, writing, watching media,
46etc., macOS is a fantastic option.
5047
5148The 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
53set up on Fedora, Ubuntu, etc.
49environment to make me feel more at-home, similar to the environments I set up
50on Fedora, Ubuntu, etc.
5451
5552# Making it Feel Like Home
5653
57If you\'re someone who uses Linux primarily, no doubt your first thought
58when booting macOS will be the same as mine was: \"Where is the terminal
59and how do I set up my favorite utilities?\"
54If you're someone who uses Linux primarily, no doubt your first thought when
55booting macOS will be the same as mine was: "Where is the terminal and how do I
56set up my favorite utilities?"
6057
61Luckily, macOS hasn\'t completely hidden away the development tools from
62the average user. You can easily find the Terminal app in the Launchpad
63area, but it\'s probably not what you\'re used to. I was surprised (and
64happy) to see that the default shell is `zsh`, the shell I
65use on all of my Linux distros. However, the commands are not the same -
66even the ones you may think are native to the shell. Commands like
67`dir` do not exist, so other native commands like
68`ls -la` or `pwd` are more useful here.
58Luckily, macOS hasn't completely hidden away the development tools from the
59average user. You can easily find the Terminal app in the Launchpad area, but
60it's probably not what you're used to. I was surprised (and happy) to see that
61the default shell is `zsh`, the shell I use on all of my Linux distros. However,
62the commands are not the same - even the ones you may think are native to the
63shell. Commands like `dir` do not exist, so other native commands like `ls -la`
64or `pwd` are more useful here.
6965
70With only a few minutes of installing and tweaking a few packages, I was
71able to recreate a terminal environment that I feel very comfortable
72using. See the image below for a preview of the iTerm2 app with a split
73view between my macOS desktop shell and an SSH session into my server.
66With only a few minutes of installing and tweaking a few packages, I was able to
67recreate a terminal environment that I feel very comfortable using. See the
68image below for a preview of the iTerm2 app with a split view between my macOS
69desktop shell and an SSH session into my server.
7470
7571![iTerm2](https://img.cleberg.net/blog/20210219-macos-testing-out-a-new-os/iterm2.png)
7672
7773# Xcode
7874
79My first step was to search the web for any hints on how to get
80`zsh` back up to the state I like, with extensions, themes,
81etc. My first step was to install the CLI tools for
82[Xcode](https://developer.apple.com/xcode/), Apple\'s suite of
75My first step was to search the web for any hints on how to get `zsh` back up to
76the state I like, with extensions, themes, etc. My first step was to install the
77CLI tools for [Xcode](https://developer.apple.com/xcode/), Apple's suite of
8378development tools.
8479
8580```sh
@@ -92,8 +87,8 @@ sudo xcode-select --install
9287
9388# Homebrew
9489
95Next up is to install [Homebrew](https://brew.sh), a nifty package
96manager for macOS.
90Next up is to install [Homebrew](https://brew.sh), a nifty package manager for
91macOS.
9792
9893```sh
9994/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:
107102Failed during: /usr/local/bin/brew update --force --quiet
108103```
109104
110I found that the following permission modification worked like a charm.
111However, I noted that some users online discussed the fact that this
112solution may not work if your system has multiple users who use
113Homebrew.
105I found that the following permission modification worked like a charm. However,
106I noted that some users online discussed the fact that this solution may not
107work if your system has multiple users who use Homebrew.
114108
115109```sh
116110sudo chown -R $(whoami) $(brew --prefix)/*
@@ -128,17 +122,16 @@ brew cleanup
128122
129123# iTerm2
130124
131Now that I\'ve installed the basic utilities for development, I moved
132onto installing iTerm2, a much better terminal than the default.
125Now that I've installed the basic utilities for development, I moved onto
126installing iTerm2, a much better terminal than the default.
133127
134128```sh
135129brew install --cask iterm2
136130```
137131
138I also used the `Make iTerm2 Default Term` and
139`Install Shell Integration` options in the iTerm2 application
140menu to make sure I don\'t run into any issues later on with different
141terminals.
132I also used the `Make iTerm2 Default Term` and `Install Shell Integration`
133options in the iTerm2 application menu to make sure I don't run into any issues
134later on with different terminals.
142135
143136We will also install `zsh` so we can use it in iTerm2.
144137
@@ -148,9 +141,9 @@ brew install zsh
148141
149142# Oh-My-Zsh
150143
151I\'ve shown the great aspects of [Oh My Zsh](https://ohmyz.sh) in other
152blog posts, so I\'ll skip over that speech for now. Simply install it
153and run an update.
144I've shown the great aspects of [Oh My Zsh](https://ohmyz.sh) in other blog
145posts, so I'll skip over that speech for now. Simply install it and run an
146update.
154147
155148```sh
156149sh -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
160153omz update
161154```
162155
163Finally, restart the iTerm2 application to ensure all changes go into
164effect.
156Finally, restart the iTerm2 application to ensure all changes go into effect.
165157
166158# Oh-My-Zsh Themes
167159
168Let\'s change the theme of the terminal to make it a little more
169friendly.
160Let's change the theme of the terminal to make it a little more friendly.
170161
171162```sh
172163open ~/.zshrc
173164```
174165
175The third section of this file should contain a line like the code
176below. Change that theme to [any theme you
177want](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes), save the file,
178and exit.
166The third section of this file should contain a line like the code below. Change
167that theme to [any theme you
168want](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes), save the file, and exit.
179169
180170```sh
181171ZSH_THEME="af-magic"
182172```
183173
184After changing the `.zshrc` file, you\'ll need to close your
185terminal and re-open it to see the changes. Optionally, just open a new
186tab if you\'re using iTerm2, and you\'ll see the new shell config.
174After changing the `.zshrc` file, you'll need to close your terminal and
175re-open it to see the changes. Optionally, just open a new tab if you're using
176iTerm2, and you'll see the new shell config.
187177
188178# Oh-My-Zsh Plugins
189179
190Of course, my customization of `zsh` would not be complete
191without
192[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions).
193This will bring up commands you\'ve run in the past as you type them.
194For example, if you\'ve run `ssh user@192.168.1.99` before,
195the terminal will show this command as soon as you start typing it (e.g.
196`zsh u`), and you can hit the right arrow to autocomplete the
197command.
180Of course, my customization of `zsh` would not be complete without
181[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions). This
182will bring up commands you've run in the past as you type them. For example, if
183you've run `ssh user@192.168.1.99` before, the terminal will show this command
184as soon as you start typing it (e.g. `zsh u`), and you can hit the right arrow
185to autocomplete the command.
198186
199187```sh
200188git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
@@ -209,7 +197,6 @@ open ~/.zshrc
209197plugins=(git zsh-autosuggestions)
210198```
211199
212Remember: After changing the `.zshrc` file, you\'ll need to
213close your terminal and re-open it to see the changes. Optionally, just
214open a new tab if you\'re using iTerm2, and you\'ll see the new shell
215config.
200Remember: After changing the `.zshrc` file, you'll need to close your terminal
201and re-open it to see the changes. Optionally, just open a new tab if you're
202using iTerm2, and you'll see the new shell config.
content/blog/2021-03-19-clone-github-repos.md +30 −35
@@ -7,29 +7,27 @@ draft = false
77
88# Cloning from GitHub
99
10If you\'re like me and use a lot of different devices (and sometimes
11decide to just wipe your device and start with a new OS), you probably
12know the pain of cloning all your old code repositories down to your
13local file system.
10If you're like me and use a lot of different devices (and sometimes decide to
11just wipe your device and start with a new OS), you probably know the pain of
12cloning all your old code repositories down to your local file system.
1413
15If you\'re using GitHub, you can easily clone all of your code back down
16in just seconds. First, create a bash script. I do so by opening a new
17file in `nano`, but you can use `gedit`,
18`vim`, or something else:
14If you're using GitHub, you can easily clone all of your code back down in just
15seconds. First, create a bash script. I do so by opening a new file in `nano`,
16but you can use `gedit`, `vim`, or something else:
1917
2018```sh
2119nano clone_github_repos.sh
2220```
2321
24Next, paste in the following information. Note that you can replace the
25word `users` in the first line with `orgs` and
26type an organization\'s name instead of a user\'s name.
22Next, paste in the following information. Note that you can replace the word
23`users` in the first line with `orgs` and type an organization's name instead
24of a user's name.
2725
2826```sh
2927CNTX=users; NAME=YOUR-USERNAME; PAGE=1
3028curl "https://api.github.com/$CNTX/$NAME/repos?page=$PAGE&per_page=100" |
3129 grep -e 'git_url*' |
32 cut -d \" -f 4 |
30 cut -d " -f 4 |
3331 xargs -L1 git clone
3432```
3533
@@ -47,12 +45,12 @@ Now you can run the script and should see the cloning process begin.
4745
4846# Cloning from Sourcehut
4947
50I haven\'t fully figured out how to directly incorporate Sourcehut\'s
51GraphQL API into a bash script yet, so this one will take two steps.
48I haven't fully figured out how to directly incorporate Sourcehut's GraphQL
49API into a bash script yet, so this one will take two steps.
5250
5351First, log-in to Sourcehut and go to their [GraphQL playground for
54Git](https://git.sr.ht/graphql). Next, paste the following query into
55the left box:
52Git](https://git.sr.ht/graphql). Next, paste the following query into the left
53box:
5654
5755```sh
5856query {
@@ -68,24 +66,22 @@ query {
6866}
6967```
7068
71The output on the right side will give you an object of all your
72repositories. Just grab that text and remove all the characters such as
73quotation marks and curly brackets. You will need a single-line list of
74space-separated values for the next step.
69The output on the right side will give you an object of all your repositories.
70Just grab that text and remove all the characters such as quotation marks and
71curly brackets. You will need a single-line list of space-separated values for
72the next step.
7573
76Now let\'s create the bash script:
74Now let's create the bash script:
7775
7876```sh
7977nano clone_sourcehut_repos.sh
8078```
8179
82Next, paste the following bash script in with the list of repositories
83you obtained above and replace `your-username` with your
84username.
80Next, paste the following bash script in with the list of repositories you
81obtained above and replace `your-username` with your username.
8582
86Note that this uses the SSH-based Git cloning method (e.g.
87`git@git...`), so you\'ll need to ensure you have set up
88Sourcehut with your SSH key.
83Note that this uses the SSH-based Git cloning method (e.g. `git@git...`), so
84you'll need to ensure you have set up Sourcehut with your SSH key.
8985
9086```sh
9187repos=(repo1 repo2 repo3)
@@ -112,19 +108,18 @@ Now you can run the script and should see the cloning process begin.
112108
113109# Moving Repositories to a New Host
114110
115Now that you have all of your code repositories cloned to your local
116computer, you may want to change the remote host (e.g., moving from
117GitHub to GitLab). To do this, let\'s create another bash script:
111Now that you have all of your code repositories cloned to your local computer,
112you may want to change the remote host (e.g., moving from GitHub to GitLab). To
113do this, let's create another bash script:
118114
119115```sh
120116nano change_remote_urls.sh
121117```
122118
123Past the following information and be sure to change the URL information
124to whichever host you are moving to. For this example, I am looping
125through all of my cloned GitHub directories and changing them to
126Sourcehut (e.g. `<YOUR_NEW_REMOTE_URL>` -\>
127`git@git.sr.ht:~myusername`).
119Past the following information and be sure to change the URL information to
120whichever host you are moving to. For this example, I am looping through all of
121my cloned GitHub directories and changing them to Sourcehut (e.g.
122`<YOUR_NEW_REMOTE_URL>` -> `git@git.sr.ht:~myusername`).
128123
129124```sh
130125# List all sub-directories in the current directory
content/blog/2021-03-28-gemini-capsule.md +67 −78
@@ -7,23 +7,20 @@ draft = false
77
88# What is Gemini?
99
10[Gemini](https://gemini.circumlunar.space/) is an internet protocol
11introduced in June 2019 as an alternative to HTTP(S) or Gopher. In
12layman\'s terms, it\'s an alternative way to browse sites (called
13capsules) that requires a special browser. Since Gemini is not
14standardized as an internet standard, normal web browsers won\'t be able
15to load a Gemini capsule. Instead, you\'ll need to use [a
16Gemini-specific
17browser](https://gemini.%20circumlunar.space/clients.html).
10[Gemini](https://gemini.circumlunar.space/) is an internet protocol introduced
11in June 2019 as an alternative to HTTP(S) or Gopher. In layman's terms, it's
12an alternative way to browse sites (called capsules) that requires a special
13browser. Since Gemini is not standardized as an internet standard, normal web
14browsers won't be able to load a Gemini capsule. Instead, you'll need to use
15[a Gemini-specific browser](https://gemini.%20circumlunar.space/clients.html).
1816
1917The content found within a Gemini page is called
2018[Gemtext](https://gemini.circumlunar.space/docs/cheatsheet.gmi) and is
21*extremely* basic (on purpose). Gemini only processes the text, no media
22content like images. However, you\'re able to style 3 levels of
23headings, regular text, links (which will display on their own line),
24quotes, and an unordered list.
19*extremely* basic (on purpose). Gemini only processes the text, no media content
20like images. However, you're able to style 3 levels of headings, regular text,
21links (which will display on their own line), quotes, and an unordered list.
2522
26Here\'s a complete listing of valid Gemtext:
23Here's a complete listing of valid Gemtext:
2724
2825``` txt
2926# Heading 1
@@ -46,79 +43,72 @@ My List:
4643
4744### Free Option
4845
49There are probably numerous websites that allow you to create your
50personal Gemini capsule, but I\'m going to focus on the two sites that I
51have personally tested. The first option below, Midnight Pub, allows you
52to create/edit any Gemini files you want in your account. This is
53essentially a GUI option with a built-in text box for editing. The
54second option below, Sourcehut, allows you to use a Git repository and
55automatic build process to deploy your personal Gemini capsule every
56time you push a commit.
46There are probably numerous websites that allow you to create your personal
47Gemini capsule, but I'm going to focus on the two sites that I have personally
48tested. The first option below, Midnight Pub, allows you to create/edit any
49Gemini files you want in your account. This is essentially a GUI option with a
50built-in text box for editing. The second option below, Sourcehut, allows you to
51use a Git repository and automatic build process to deploy your personal Gemini
52capsule every time you push a commit.
5753
5854## Midnight Pub - Beginner Friendly
5955
60[Midnight Pub](https://midnight.pub/) is a small, virtual community
61meant to reflect the atmosphere of wandering into a small alley pub. The
62site is built in Gemtext and has a server-side process to convert
63Gemtext to HTML if someone loads the site in an HTTP(S) browser.
56[Midnight Pub](https://midnight.pub/) is a small, virtual community meant to
57reflect the atmosphere of wandering into a small alley pub. The site is built in
58Gemtext and has a server-side process to convert Gemtext to HTML if someone
59loads the site in an HTTP(S) browser.
6460
65To create an account, you\'ll need to email the owner of the website to
66obtain a key. You can find their email on the Midnight Pub homepage.
67Once registered, head to [your account](https://midnight.pub/account)
68and select [manage site](https://midnight.pub/site). This is the screen
69where you can upload or create any files to be displayed on the
70internet.
61To create an account, you'll need to email the owner of the website to obtain a
62key. You can find their email on the Midnight Pub homepage. Once registered,
63head to [your account](https://midnight.pub/account) and select [manage
64site](https://midnight.pub/site). This is the screen where you can upload or
65create any files to be displayed on the internet.
7166
72For example, I\'ve created both an HTML file and a Gemini file. Remember
73that Gemini is automatically converted to HTML on the Pub, so you don\'t
74need an HTML version. For example, I created an HTML version to add in
75some extra styling.
67For example, I've created both an HTML file and a Gemini file. Remember that
68Gemini is automatically converted to HTML on the Pub, so you don't need an HTML
69version. For example, I created an HTML version to add in some extra styling.
7670
77All you need to do is create a page like `index.gmi` and use
78your Gemini browser to head over to your-username.midnight.pub to see
79the result.
71All you need to do is create a page like `index.gmi` and use your Gemini browser
72to head over to your-username.midnight.pub to see the result.
8073
81That\'s all there is to it! Easy enough, right? Let\'s check out a more
82advanced version in the next section.
74That's all there is to it! Easy enough, right? Let's check out a more advanced
75version in the next section.
8376
8477# Paid Option
8578
86As of 2021, Sourcehut has decided to require users to have a paid
87account in order to utilize their automated build system. For now, paid
88accounts can be as low as \$2/month.
79As of 2021, Sourcehut has decided to require users to have a paid account in
80order to utilize their automated build system. For now, paid accounts can be as
81low as $2/month.
8982
9083## Sourcehut
9184
92[Sourcehut](https://sourcehut.org/) is a collection of software
93development tools, but mostly surrounds their hosted Git repository
94service. Simply put, it\'s a minimal and more private alternative to
95services like GitHub.
85[Sourcehut](https://sourcehut.org/) is a collection of software development
86tools, but mostly surrounds their hosted Git repository service. Simply put,
87it's a minimal and more private alternative to services like GitHub.
9688
97This walkthrough is more advanced and involves things like Git, SSH, the
98command line. If you don\'t think you know enough to do this, check out
99my walkthrough on creating a Gemini capsule for the Midnight Pub
100instead.
89This walkthrough is more advanced and involves things like Git, SSH, the command
90line. If you don't think you know enough to do this, check out my walkthrough
91on creating a Gemini capsule for the Midnight Pub instead.
10192
102The first thing you\'ll need to do is create an SSH key pair, if you
103don\'t already have one on your system. Once created, grab the contents
104of `id_rsa.pub` and add it to your Sourcehut account
105settings - this will allow you to push and pull code changes without
106using a username/password.
93The first thing you'll need to do is create an SSH key pair, if you don't
94already have one on your system. Once created, grab the contents of `id_rsa.pub`
95and add it to your Sourcehut account settings - this will allow you to push and
96pull code changes without using a username/password.
10797
10898```sh
10999ssh keygen
110100```
111101
112Next up, let\'s create a repository with the proper name so that the
113Sourcehut build system will know we want them to host a website for us.
114Use the following format exactly:
102Next up, let's create a repository with the proper name so that the Sourcehut
103build system will know we want them to host a website for us. Use the following
104format exactly:
115105
116106```sh
117107mkdir your-username.srht.site && cd your-username.srht.site
118108```
119109
120Now that we\'ve created the repo, let\'s initialize Git and add the
121proper remote URL.
110Now that we've created the repo, let's initialize Git and add the proper
111remote URL.
122112
123113```sh
124114git init
@@ -128,14 +118,14 @@ git init
128118git remote add origin git@git.sr.ht:~your-username/your-username.srht.site
129119```
130120
131Now that our repository is set up and configured, we will need to create
132at least two files:
121Now that our repository is set up and configured, we will need to create at
122least two files:
133123
134- `index.gmi`
135- `.build.yml`
124- `index.gmi`
125- `.build.yml`
136126
137For your `.build.yml` file, use the following content and be
138sure to update the `site` line with your username!
127For your `.build.yml` file, use the following content and be sure to update the
128`site` line with your username!
139129
140130``` yaml
141131image: alpine/latest
@@ -150,11 +140,11 @@ tasks:
150140 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI
151141```
152142
153For the `index.gmi` file, put whatever you want in there and
154save it. You could even just copy and paste the Gemtext cheatsheet.
143For the `index.gmi` file, put whatever you want in there and save it. You could
144even just copy and paste the Gemtext cheatsheet.
155145
156If you want to serve both HTML and Gemini files from this repository,
157just add a second command to the `upload` section:
146If you want to serve both HTML and Gemini files from this repository, just add a
147second command to the `upload` section:
158148
159149``` yaml
160150- upload: |
@@ -168,19 +158,18 @@ Lastly, commit your changes and push them to the remote repo.
168158git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD
169159```
170160
171If you\'ve successfully created the files with the proper format,
172you\'ll see the terminal print a message that lets you know where the
173automatic build is taking place. For example, here\'s what the terminal
174tells me:
161If you've successfully created the files with the proper format, you'll see
162the terminal print a message that lets you know where the automatic build is
163taking place. For example, here's what the terminal tells me:
175164
176165```sh
177166remote: Build started:
178167remote: https://builds.sr.ht/~user/job/689803 [.build.yml]
179168```
180169
181Now 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.
183Take a look at the image below for my Sourcehut Gemini capsule.
170Now that you've properly built your Sourcehut page, you can browse to
171your-username.srht.site in a Gemini browser and view the final results. Take a
172look at the image below for my Sourcehut Gemini capsule.
184173
185174![Gemini page on the amfora
186175browser](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
77
88# Overview
99
10When it comes to an aesthetic that originated primarily online, there
11tends to be a lot of confusion around what falls into each specific
12genre. This post discusses Vaporwave and Outrun, which have become
13almost synonymous in the minds of those online who aren\'t hardcore into
14these genres of media. More specifically, Outrun is largely an unknown
15term while all aesthetics in these two genres are usually attributed to
16Vaporwave. For example, take a look at the image search results for
17Vaporwave: the results include **a lot\*** of Outrun-themed images.
18You\'ll find a similar trend almost everywhere.
10When it comes to an aesthetic that originated primarily online, there tends to
11be a lot of confusion around what falls into each specific genre. This post
12discusses Vaporwave and Outrun, which have become almost synonymous in the minds
13of those online who aren't hardcore into these genres of media. More
14specifically, Outrun is largely an unknown term while all aesthetics in these
15two genres are usually attributed to Vaporwave. For example, take a look at the
16image search results for Vaporwave: the results include **a lot** of
17Outrun-themed images. You'll find a similar trend almost everywhere.
1918
2019![Vaporwave Search
2120Results](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
2524![Macintosh Plus Album
2625Cover](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/macintosh-plus.png)
2726
28Okay, so what is Vaporwave? I\'m going to just copy-and-paste some
29general info from the Wikipedia article on
30[Vaporwave](https://en.wikipedia.org/wiki/Vaporwave), so that I\'m not
31repeating everything you can already search for online:
32
33> Vaporwave is a microgenre of electronic music, a visual art style, and
34> an Internet meme that emerged in the early 2010s. It is defined partly
35> by its slowed-down, chopped and screwed samples of smooth jazz,
36> elevator, R&B, and lounge music from the 1980s and 1990s. The
37> surrounding subculture is sometimes associated with an ambiguous or
38> satirical take on consumer capitalism and pop culture, and tends to be
39> characterized by a nostalgic or surrealist engagement with the popular
40> entertainment, technology and advertising of previous decades.
41> Visually, it incorporates early Internet imagery, late 1990s web
42> design, glitch art, anime, 3D-rendered objects, and cyberpunk tropes
43> in its cover artwork and music videos.
44
45This is an excellent summary, and it helps address my point here: there
46are specific aspects that make Vaporwave unique:
27Okay, so what is Vaporwave? I'm going to just copy-and-paste some general info
28from the Wikipedia article on
29[Vaporwave](https://en.wikipedia.org/wiki/Vaporwave), so that I'm not repeating
30everything you can already search for online:
31
32> Vaporwave is a microgenre of electronic music, a visual art style, and an
33> Internet meme that emerged in the early 2010s. It is defined partly by its
34> slowed-down, chopped and screwed samples of smooth jazz, elevator, R&B, and
35> lounge music from the 1980s and 1990s. The surrounding subculture is sometimes
36> associated with an ambiguous or satirical take on consumer capitalism and pop
37> culture, and tends to be characterized by a nostalgic or surrealist engagement
38> with the popular entertainment, technology and advertising of previous
39> decades. Visually, it incorporates early Internet imagery, late 1990s web
40> design, glitch art, anime, 3D-rendered objects, and cyberpunk tropes in its
41> cover artwork and music videos.
42
43This is an excellent summary, and it helps address my point here: there are
44specific aspects that make Vaporwave unique:
4745
4846## Time Frame
4947
50The time frame for references, logos, etc. focuses mostly on the 1990s
51in Vaporwave. You\'ll see old school Pepsi logos, Microsoft 95 screens,
52tropical plants, classic marble sculptures, and many references from
53Japan\'s influence in the 90s.
48The time frame for references, logos, etc. focuses mostly on the 1990s in
49Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, tropical
50plants, classic marble sculptures, and many references from Japan's influence
51in the 90s.
5452
5553## Art
5654
57The color scheme is generally a soft, light palette that uses pastel
58colors. The backdrop will often be in a light-pink or teal blue.
55The color scheme is generally a soft, light palette that uses pastel colors. The
56backdrop will often be in a light-pink or teal blue.
5957
6058## Music
6159
62The musical genre of Vaporwave incorporates soft tunes, lounge music,
63and sound effects that will make the listener reminisce of the 90s. The
64sounds of the genre are generally slower-paced and calming. The major
65breakthrough artist for Vaporwave was [Macintosh
66Plus](https://en.wikipedia.org/wiki/Vektroid), who released the album
67[Floral
68Shoppe](https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete)
69in 2011. Another more recent example is the artist
70[sadbert](https://sadbert.bandcamp.com/), whose latest album
71incorporates the upbeat tones of the 1999 Dilbert TV series.
72
73Notice that Vaporwave doesn\'t include things like racing cars,
74futuristic technology, chrome, or the deep orange/purple color scheme.
75Vaporwave is a focus on the idyllic state of the world when technology
76was becoming common in households, a reality that we have already
77experienced. Focus on the most aesthetically-pleasing parts of that past
78is a large part of Vaporwave.
60The musical genre of Vaporwave incorporates soft tunes, lounge music, and sound
61effects that will make the listener reminisce of the 90s. The sounds of the
62genre are generally slower-paced and calming. The major breakthrough artist for
63Vaporwave was [Macintosh Plus](https://en.wikipedia.org/wiki/Vektroid), who
64released the album [Floral
65Shoppe](https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete) in
662011. Another more recent example is the artist
67[sadbert](https://sadbert.bandcamp.com/), whose latest album incorporates the
68upbeat tones of the 1999 Dilbert TV series.
69
70Notice that Vaporwave doesn't include things like racing cars, futuristic
71technology, chrome, or the deep orange/purple color scheme. Vaporwave is a focus
72on the idyllic state of the world when technology was becoming common in
73households, a reality that we have already experienced. Focus on the most
74aesthetically-pleasing parts of that past is a large part of Vaporwave.
7975
8076# Outrun
8177
8278![Outrun](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/outrun.png)
8379
84Now, let\'s get to Outrun. This one is a little trickier since the genre
85has largely been lumped under the Vaporwave title for so long. However,
86it stems from the [Synthwave](https://en.wikipedia.org/wiki/Synthwave)
87music genre and is likely named after the 1986 racer game, [Out
80Now, let's get to Outrun. This one is a little trickier since the genre has
81largely been lumped under the Vaporwave title for so long. However, it stems
82from the [Synthwave](https://en.wikipedia.org/wiki/Synthwave) music genre and is
83likely named after the 1986 racer game, [Out
8884Run](https://en.wikipedia.org/wiki/Out_Run).
8985
9086## Time Frame
9187
92Outrun can be thought of as a retro-futuristic aesthetic born from the
931980s.
88Outrun can be thought of as a retro-futuristic aesthetic born from the 1980s.
9489
9590## Art
9691
97The color scheme uses a very dark color palette with the main colors
98being deep oranges, blues, and purples. Red edges are common around
99objects in Outrun art. The background of the Outrun aesthetic is almost
100always a neon grid like you\'d expect to see in Tron or a 1980s arcade
101machine.
92The color scheme uses a very dark color palette with the main colors being deep
93oranges, blues, and purples. Red edges are common around objects in Outrun art.
94The background of the Outrun aesthetic is almost always a neon grid like you'd
95expect to see in Tron or a 1980s arcade machine.
10296
103Classic sports cars, chrome robots, computer generated graphics and
104fonts, and the occasional use of rain or palm trees can be found in
105Outrun art.
97Classic sports cars, chrome robots, computer generated graphics and fonts, and
98the occasional use of rain or palm trees can be found in Outrun art.
10699
107100## Music
108101
109This aesthetic has a more aggressive and fast-paced style of music,
110which tends to match the subject of the art in this aesthetic.
102This aesthetic has a more aggressive and fast-paced style of music, which tends
103to match the subject of the art in this aesthetic.
111104
112Outrun enthusiasts love what people in the 1980s thought the future
113would look like. Take a look at a common video game discussed in Outrun
114circles, Far Cry 3: Blood Dragon:
105Outrun enthusiasts love what people in the 1980s thought the future would look
106like. Take a look at a common video game discussed in Outrun circles, Far Cry 3:
107Blood Dragon:
115108
116109![Fry Cry 3: Blood
117110Dragon](https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/far-cry.png)
118111
119Another example that doesn\'t force the color scheme as hard as some
120online art does is Kung Fury:
112Another example that doesn't force the color scheme as hard as some online art
113does is Kung Fury:
121114
122115![Kung
123116Fury](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
127120
128121# Conclusion
129122
130While Vaporwave and Outrun share similarities, they are two distinct
131aesthetics with many important distinctions. Someone who enjoys one may
132not necessarily enjoy the other, so it\'s important to make sure we
133properly describe the aesthetic we\'re looking for.
123While Vaporwave and Outrun share similarities, they are two distinct aesthetics
124with many important distinctions. Someone who enjoys one may not necessarily
125enjoy the other, so it's important to make sure we properly describe the
126aesthetic we're looking for.
content/blog/2021-03-30-vps-web-server.md +162 −183
@@ -7,105 +7,96 @@ draft = false
77
88# Shared Hosting vs. VPS
99
10Choosing a place to host a website is one of the most confusing
11decisions for beginner web developers. Even for experienced web devs,
12choosing between different forms of web hosting can be a daunting
13choice.
14
15First, let\'s take a look at [shared web
16hosting](https://en.wikipedia.org/wiki/Shared_web_hosting_service).
17Shared web hosting is a product where you are purchasing a small piece
18of a web server that is being shared between many websites. As a result,
19the cost of shared hosting is extremely low. You won\'t have access to
20the server itself, which means you can\'t install your own software on
21the server, such as Docker. Usually, you are simply allowed to connect
22your domains to the server, set up domain security, and other small
23utilities.
10Choosing a place to host a website is one of the most confusing decisions for
11beginner web developers. Even for experienced web devs, choosing between
12different forms of web hosting can be a daunting choice.
13
14First, let's take a look at [shared web
15hosting](https://en.wikipedia.org/wiki/Shared_web_hosting_service). Shared web
16hosting is a product where you are purchasing a small piece of a web server that
17is being shared between many websites. As a result, the cost of shared hosting
18is extremely low. You won't have access to the server itself, which means you
19can't install your own software on the server, such as Docker. Usually, you are
20simply allowed to connect your domains to the server, set up domain security,
21and other small utilities.
2422
2523In contrast, a [virtual private
26server](https://en.wikipedia.org/wiki/Virtual_private_server) (VPS) is a
27virtual machine that replicates the environment of having a dedicated
28server to yourself. You are able to control the virtual server\'s host
29names, base file system, package manager, etc. Another great upside of a
30VPS is that since it\'s virtual, the company providing the VPS can
31dynamically increase the disk size, RAM size, or number of CPUs at any
32time. However, the virtual server is still physically located on a
33server that is shared between multiple virtual servers.
34
35The choice between shared hosting and VPS mostly depends on your skill
36level with system administration. If you\'re comforting working on a
37server that is mostly left up to you (or you\'re willing to learn), then
38a VPS is usually a better option. However, shared hosting is a fantastic
39option for people who don\'t want to have to learn how to manage their
40server.
24server](https://en.wikipedia.org/wiki/Virtual_private_server) (VPS) is a virtual
25machine that replicates the environment of having a dedicated server to
26yourself. You are able to control the virtual server's host names, base file
27system, package manager, etc. Another great upside of a VPS is that since it's
28virtual, the company providing the VPS can dynamically increase the disk size,
29RAM size, or number of CPUs at any time. However, the virtual server is still
30physically located on a server that is shared between multiple virtual servers.
31
32The choice between shared hosting and VPS mostly depends on your skill level
33with system administration. If you're comforting working on a server that is
34mostly left up to you (or you're willing to learn), then a VPS is usually a
35better option. However, shared hosting is a fantastic option for people who
36don't want to have to learn how to manage their server.
4137
4238# My Situation
4339
44I had used shared hosting for approximately 5 years before trying my
45first VPS. I manage a homelab and have had success running a server and
46performing typical sysadmin duties, but I was still hesitant to get a
47VPS. One fear was that I always struggled to properly set up the
48networking part of a server - DNS and hostname configurations were not
49my friend.
40I had used shared hosting for approximately 5 years before trying my first VPS.
41I manage a homelab and have had success running a server and performing typical
42sysadmin duties, but I was still hesitant to get a VPS. One fear was that I
43always struggled to properly set up the networking part of a server - DNS and
44hostname configurations were not my friend.
5045
5146As a little bit of background, I originally used
52[Siteground](https://www.siteground.com) for my initially shared hosting
53and stayed on that platform for at least a year. However, the UI was
54clunky, and I didn\'t like how they handled certain technical aspects,
55so I switched to [Namecheap](https://www.namecheap.com). Namecheap was
56great because it is the service I primarily use for purchasing domain
57names, which made it incredibly easy to link them to my hosting service.
58However, it was still mediocre shared hosting, and Namecheap is
59notorious for not letting you use [Let\'s
60Encrypt](https://letsencrypt.org) to obtain free SSL/TLS certificates;
61Namecheap wants to make you purchase certificates through their store.
62
63Finally, I settled down with [iWebFusion](https://www.iwebfusion.net)
64for about the last year of my shared hosting. This service was pretty
65great, came with free SSL/TLS, and I never had any complaints.
66
67However, I finally grew tired of not being able to install software on
68my own web server. I wanted to be able to try out things like
69[Postmill](https://postmill.xyz) or [Matrix](https://matrix.org). This
70is possible with a VPS, so I decided to grab a new domain name to try it
71out.
47[Siteground](https://www.siteground.com) for my initially shared hosting and
48stayed on that platform for at least a year. However, the UI was clunky, and I
49didn't like how they handled certain technical aspects, so I switched to
50[Namecheap](https://www.namecheap.com). Namecheap was great because it is the
51service I primarily use for purchasing domain names, which made it incredibly
52easy to link them to my hosting service. However, it was still mediocre shared
53hosting, and Namecheap is notorious for not letting you use [Let's
54Encrypt](https://letsencrypt.org) to obtain free SSL/TLS certificates; Namecheap
55wants to make you purchase certificates through their store.
56
57Finally, I settled down with [iWebFusion](https://www.iwebfusion.net) for about
58the last year of my shared hosting. This service was pretty great, came with
59free SSL/TLS, and I never had any complaints.
60
61However, I finally grew tired of not being able to install software on my own
62web server. I wanted to be able to try out things like
63[Postmill](https://postmill.xyz) or [Matrix](https://matrix.org). This is
64possible with a VPS, so I decided to grab a new domain name to try it out.
7265
7366# Getting Started: Buying a VPS
7467
75The first step to moving over to a VPS is (you guessed it): finding a
76VPS provider. For my VPSs, I use [1984](https://1984hosting.com) and
77prefer their services much more than any alternative, due to their
78location (Iceland), their [privacy
79policy](https://1984hosting.com/GDPR/), their respect for GDPR, and the
68The first step to moving over to a VPS is (you guessed it): finding a VPS
69provider. For my VPSs, I use [1984](https://1984hosting.com) and prefer their
70services much more than any alternative, due to their location (Iceland), their
71[privacy policy](https://1984hosting.com/GDPR/), their respect for GDPR, and the
8072ability to remain anonymous if you pay in Bitcoin or Monero.
8173
82[Njalla](https://njal.la) is another good, privacy-oriented option for
83VPS services.
74[Njalla](https://njal.la) is another good, privacy-oriented option for VPS
75services.
8476
85You\'ll have to decide what specifications you want on your VPS. For me,
86I only build and deploy low-resource HTML, PHP, and Python websites.
87This means I can survive on the smallest VPS: 1 CPU, 1GB of RAM, and
8825GB SSD for \$5.00 per month.
77You'll have to decide what specifications you want on your VPS. For me, I only
78build and deploy low-resource HTML, PHP, and Python websites. This means I can
79survive on the smallest VPS: 1 CPU, 1GB of RAM, and 25GB SSD for $5.00 per
80month.
8981
90As noted above, the great thing about a VPS is you can request your
91provider to increase the resources at any time.
82As noted above, the great thing about a VPS is you can request your provider to
83increase the resources at any time.
9284
9385# Configuring DNS Settings
9486
95Okay, so now let\'s get into some actual work that has to be done to get
96content moved from a shared host to a VPS. At this point, I\'m assuming
97you have a shared host with website content that you can still access,
98and you\'ve purchased a new VPS and can SSH into that server.
87Okay, so now let's get into some actual work that has to be done to get content
88moved from a shared host to a VPS. At this point, I'm assuming you have a
89shared host with website content that you can still access, and you've
90purchased a new VPS and can SSH into that server.
9991
100The first change is minor, but it should be done immediately in order to
101get things moving: DNS settings. Go to wherever your DNS settings are
102handled. If your shared host also managed your DNS settings, you\'ll
103need to first move that DNS over to your new VPS provider. For me, I
104route my DNS through [Gandi](https://www.gandi.net).
92The first change is minor, but it should be done immediately in order to get
93things moving: DNS settings. Go to wherever your DNS settings are handled. If
94your shared host also managed your DNS settings, you'll need to first move that
95DNS over to your new VPS provider. For me, I route my DNS through
96[Gandi](https://www.gandi.net).
10597
106Once you know where your DNS settings are, go ahead and update the
107`A` records to match the public IP address of your VPS. For
108example:
98Once you know where your DNS settings are, go ahead and update the `A` records
99to match the public IP address of your VPS. For example:
109100
110101``` txt
111102A example.com xxx.xxx.xxx.xxx
@@ -113,37 +104,36 @@ A subdomain xxx.xxx.xxx.xxx
113104CNAME www example.com.
114105```
115106
116If you have any other records that require updates, such as MX or TXT
117records for a mail server, be sure to update those accordingly.
118Personally, I don\'t host my own mail server. I route all mail on my
119custom domains to [Migadu](https://www.migadu.com). Hosting your own
120email server can become complex quickly and is not for beginners.
107If you have any other records that require updates, such as MX or TXT records
108for a mail server, be sure to update those accordingly. Personally, I don't
109host my own mail server. I route all mail on my custom domains to
110[Migadu](https://www.migadu.com). Hosting your own email server can become
111complex quickly and is not for beginners.
121112
122DNS changes can take up to 48 hours to propagate, so be sure to give it
123some time before assuming you\'ve made an error.
113DNS changes can take up to 48 hours to propagate, so be sure to give it some
114time before assuming you've made an error.
124115
125116# Server Updates and Packages
126117
127Now that the DNS settings have been changed, let\'s set up our server
128while we wait for the DNS to propagate. First up is to ssh into your
129server. If you\'ve signed up with a service like DigitalOcean, you can
130add your SSH key to your account and to your VPS droplet so that you
131don\'t need a password in order to SSH.
118Now that the DNS settings have been changed, let's set up our server while we
119wait for the DNS to propagate. First up is to ssh into your server. If you've
120signed up with a service like DigitalOcean, you can add your SSH key to your
121account and to your VPS droplet so that you don't need a password in order to
122SSH.
132123
133124```sh
134125ssh root@xxx.xxx.xxx.xxx
135126```
136127
137The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache
138web server. If you\'re working on a different operating system (OS) or
139want a different web server, such as Nginx, you\'ll have to use
140different commands to set it up.
128The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache web
129server. If you're working on a different operating system (OS) or want a
130different web server, such as Nginx, you'll have to use different commands to
131set it up.
141132
142First, let\'s update and upgrade our server.
133First, let's update and upgrade our server.
143134
144**NOTE:** Since we have logged in to the server as `root` for
145now, we don\'t need to use the `sudo` modifier before our
146commands.
135**NOTE:** Since we have logged in to the server as `root` for now, we don't
136need to use the `sudo` modifier before our commands.
147137
148138```sh
149139apt update && apt upgrade -y
@@ -151,11 +141,11 @@ apt update && apt upgrade -y
151141
152142# Create A User Account
153143
154While being able to use `root` can be beneficial at times,
155you shouldn\'t use `root` unless you have to.
144While being able to use `root` can be beneficial at times, you shouldn't use
145`root` unless you have to.
156146
157So let\'s set up a new user in our system. The `-m` option
158below tells the OS to create a home directory for the new user.
147So let's set up a new user in our system. The `-m` option below tells the OS to
148create a home directory for the new user.
159149
160150```sh
161151adduser USERNAME
@@ -167,41 +157,40 @@ Now, create a password for that user.
167157passwd USERNAME
168158```
169159
170Finally, add the user to the sudoers file, so they can perform
171priveleged commands.
160Finally, add the user to the sudoers file, so they can perform priveleged
161commands.
172162
173163```sh
174164usermod -a -G sudo USERNAME
175165```
176166
177If you are using SSH keys and not passwords, you\'ll need to copy your
178SSH key from your local machine to the VPS. If you haven\'t disabled
179password-based SSH yet, the easiest way to do this is
180`ssh-copy-id` from your local computer (not from the VPS):
167If you are using SSH keys and not passwords, you'll need to copy your SSH key
168from your local machine to the VPS. If you haven't disabled password-based SSH
169yet, the easiest way to do this is `ssh-copy-id` from your local computer (not
170from the VPS):
181171
182172```sh
183173ssh-copy-id testuser@xxx.xxx.xxx.xxx
184174```
185175
186If you\'ve disabled password-based SSH, you\'ll need to manually copy
187your SSH key into the `~/.ssh/authorized_keys` file.
176If you've disabled password-based SSH, you'll need to manually copy your SSH
177key into the `~/.ssh/authorized_keys` file.
188178
189179# Install Software
190180
191Our goal here is to host a web server, so the next step is to install
192the Apache web server and any other packages we need.
181Our goal here is to host a web server, so the next step is to install the Apache
182web server and any other packages we need.
193183
194From this point on, I will be logged in as a user (not
195`root`) and will need to use the `sudo` modifier
196for most commands.
184From this point on, I will be logged in as a user (not `root`) and will need to
185use the `sudo` modifier for most commands.
197186
198187```sh
199188sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
200189sudo apt install apache2
201190```
202191
203If you need other language support, such as PHP, you\'ll need to install
204that too.
192If you need other language support, such as PHP, you'll need to install that
193too.
205194
206195```sh
207196sudo apt install libapache2-mod-php php-dom
@@ -211,20 +200,18 @@ sudo systemctl restart apache2
211200
212201# Website Files & Folders
213202
214Next up is to create the directories for the domain(s) we want to be
215hosted on this web server.
203Next up is to create the directories for the domain(s) we want to be hosted on
204this web server.
216205
217206```sh
218207cd /var/www
219208sudo mkdir example.com
220209```
221210
222We have a folder for `example.com` now, so let\'s add an
223`index.html` file and put it within a specific
224`public_html` folder. You don\'t need this
225`public_html` if you don\'t want it, but it helps with
226organizing items related to `example.com` that you don\'t
227want to publish to the internet.
211We have a folder for `example.com` now, so let's add an `index.html` file and
212put it within a specific `public_html` folder. You don't need this
213`public_html` if you don't want it, but it helps with organizing items related
214to `example.com` that you don't want to publish to the internet.
228215
229216```sh
230217cd example.com
@@ -232,8 +219,8 @@ sudo mkdir public_html && cd public_html
232219sudo nano index.html
233220```
234221
235You can put anything you want in this `index.html` file. If
236you can\'t think of anything, paste this in there:
222You can put anything you want in this `index.html` file. If you can't think of
223anything, paste this in there:
237224
238225``` html
239226<!DOCTYPE html>
@@ -249,10 +236,9 @@ you can\'t think of anything, paste this in there:
249236</html>
250237```
251238
252If you want something to be served at
253`example.com/page01/file.txt`, you\'ll have to create the
254`page01` directory under the `example.com`
255directory. For example:
239If you want something to be served at `example.com/page01/file.txt`, you'll
240have to create the `page01` directory under the `example.com` directory. For
241example:
256242
257243```sh
258244cd /var/www/example.com/public_html
@@ -262,9 +248,9 @@ sudo nano file.txt
262248
263249# Apache Configuration
264250
265Now, let\'s set up the files that will tell the server where to find the
266files for `example.com`. We will copy the default
267configuration file and create our own.
251Now, let's set up the files that will tell the server where to find the files
252for `example.com`. We will copy the default configuration file and create our
253own.
268254
269255```sh
270256cd /etc/apache2/sites-available
@@ -272,9 +258,8 @@ sudo cp 000-default.conf example.com.conf
272258sudo nano example.com.conf
273259```
274260
275This configuration file will have a few default lines, but you\'ll need
276to edit it to look similar to this (settings may change based on your
277personal needs):
261This configuration file will have a few default lines, but you'll need to edit
262it to look similar to this (settings may change based on your personal needs):
278263
279264``` config
280265<VirtualHost *:80>
@@ -296,35 +281,33 @@ sudo a2dissite 000-default.conf
296281sudo systemctl reload apache2
297282```
298283
299You can always run a test to make sure no errors or warnings are found
300in your configuration files.
284You can always run a test to make sure no errors or warnings are found in your
285configuration files.
301286
302287```sh
303288sudo apache2ctl configtest
304289```
305290
306Now, restart the web server entirely. After this, you should be able to
307browse to `http://example.com` and see the HTML content you
308provided earlier. Note that SSL/TLS has not been enabled yet, so you
309won\'t be able to use the secure version yet
310(`https://example.com`).
291Now, restart the web server entirely. After this, you should be able to browse
292to `http://example.com` and see the HTML content you provided earlier. Note that
293SSL/TLS has not been enabled yet, so you won't be able to use the secure
294version yet (`https://example.com`).
311295
312296```sh
313297sudo systemctl restart apache2
314298```
315299
316You can repeat this for as many websites as you need. Just create the
317domain folders in `/var/www/`, add the configuration file,
318enable the configuration, and restart `apache2`.
300You can repeat this for as many websites as you need. Just create the domain
301folders in `/var/www/`, add the configuration file, enable the configuration,
302and restart `apache2`.
319303
320304# SSL/TLS Certificates: Serve Websites Over HTTPS
321305
322In order to serve secure content, you\'ll need to obtain SSL/TLS
323certificates. Luckily, there\'s a free tool called
324[Certbot](https://certbot.eff.org) that helps us with the process.
306In order to serve secure content, you'll need to obtain SSL/TLS certificates.
307Luckily, there's a free tool called [Certbot](https://certbot.eff.org) that
308helps us with the process.
325309
326The first step is to install `snapd` and `core`
327for Ubuntu.
310The first step is to install `snapd` and `core` for Ubuntu.
328311
329312```sh
330313sudo apt install snapd
@@ -338,8 +321,7 @@ Next, install the `certbot` snap package.
338321sudo snap install --classic certbot
339322```
340323
341Execute the following command to ensure that the `certbot`
342command can be run.
324Execute the following command to ensure that the `certbot` command can be run.
343325
344326```sh
345327sudo ln -s /snap/bin/certbot /usr/bin/certbot
@@ -347,10 +329,10 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
347329
348330Finally, you can run `certbot` one of two ways:
349331
3501. run it and let it alter your Apache configuration files
351 automatically to enable HTTPS redirects.
3522. run it and only allow it to create certificates. You\'ll need to
353 manually alter the config files to enable HTTPS redirects.
3321. run it and let it alter your Apache configuration files automatically to
333 enable HTTPS redirects.
3342. run it and only allow it to create certificates. You'll need to manually
335 alter the config files to enable HTTPS redirects.
354336
355337Run certbot and allow automatic config changes:
356338
@@ -358,18 +340,16 @@ Run certbot and allow automatic config changes:
358340sudo certbot --apache
359341```
360342
361Run certbot for certificates only and don\'t allow it to alter config
362files:
343Run certbot for certificates only and don't allow it to alter config files:
363344
364345```sh
365346sudo certbot certonly --apache
366347```
367348
368The Certbot packages on your system come with a cron job or systemd
369timer that will renew your certificates automatically before they
370expire. You will not need to run Certbot again unless you change your
371configuration. You can test automatic renewal for your certificates by
372running this command:
349The Certbot packages on your system come with a cron job or systemd timer that
350will renew your certificates automatically before they expire. You will not need
351to run Certbot again unless you change your configuration. You can test
352automatic renewal for your certificates by running this command:
373353
374354```sh
375355sudo certbot renew --dry-run
@@ -379,13 +359,13 @@ Now, test your domains by going to `https://example.com`.
379359
380360# Firewall Security
381361
382To enable better security on your server, you\'ll need to enable a basic
383firewall. For Ubuntu, we\'ll use [the uncomplicated
362To enable better security on your server, you'll need to enable a basic
363firewall. For Ubuntu, we'll use [the uncomplicated
384364firewall](../secure-your-network-with-the-uncomplicated-firewall/).
385365
386Now, add the following rules to the firewall allow SSH, Apache, and
387HTTP(S) connections. If you need to, you can enable different ports for
388specifics applications, SFTP, etc.
366Now, add the following rules to the firewall allow SSH, Apache, and HTTP(S)
367connections. If you need to, you can enable different ports for specifics
368applications, SFTP, etc.
389369
390370```sh
391371sudo ufw default deny incoming
@@ -395,7 +375,7 @@ sudo ufw allow Apache
395375sudo ufw allow proto tcp from any to any port 80,443
396376```
397377
398Once you\'ve added all the rules you need, enable the firewall.
378Once you've added all the rules you need, enable the firewall.
399379
400380```sh
401381sudo ufw enable
@@ -403,16 +383,15 @@ sudo ufw enable
403383
404384# Troubleshooting
405385
406If you run into any issues during your VPS set-up, be sure to walk back
407through your actions and make sure you didn\'t miss any steps.
386If you run into any issues during your VPS set-up, be sure to walk back through
387your actions and make sure you didn't miss any steps.
408388
409Many websites have fantastic guides to setting up various web servers.
410This is one of the areas [where DigitalOcean
411shines](https://www.digitalocean.%20com/community/tutorials). For
412simpler or more Linux-oriented questions, I suggest using \[Linuxize\]
389Many websites have fantastic guides to setting up various web servers. This is
390one of the areas [where DigitalOcean
391shines](https://www.digitalocean.%20com/community/tutorials). For simpler or
392more Linux-oriented questions, I suggest using [Linuxize]
413393(<https://linuxize.com>).
414394
415If you\'re getting certain errors (e.g.
416`500 Internal Server Error`) and need to debug locally, you
417can view the `access.log` and `error.log` files in
418the `/var/log/apache/` directory.
395If you're getting certain errors (e.g. `500 Internal Server Error`) and need to
396debug locally, you can view the `access.log` and `error.log` files in the
397`/var/log/apache/` directory.
content/blog/2021-04-17-gemini-server.md +36 −40
@@ -7,28 +7,27 @@ draft = false
77
88# Similar Article Available
99
10To read more about Gemini and ways to test out this new protocol without
11your own server, see my previous post [Launching a Gemini
10To read more about Gemini and ways to test out this new protocol without your
11own server, see my previous post [Launching a Gemini
1212Capsule](../launching-a-gemini-capsule/).
1313
1414# Preparation
1515
16This guide assumes you have access to a server accessible to the world
17through a public IP address and that you own a domain name used for this
18Gemini capsule.
16This guide assumes you have access to a server accessible to the world through a
17public IP address and that you own a domain name used for this Gemini capsule.
1918
2019# Getting Started with Agate
2120
2221We 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
24little time and maintenance to get it running.
22tutorial. This is a basic Gemini server written in Rust. It takes very little
23time and maintenance to get it running.
2524
2625# Install Dependencies
2726
28First, you will need to install the Rust package for your system. On
29Ubuntu, use the following commands (remember to use `sudo` if
30you are not the root user). The Rust installation will give you options
31to customize the installation; I used the default installation options.
27First, you will need to install the Rust package for your system. On Ubuntu, use
28the following commands (remember to use `sudo` if you are not the root user).
29The Rust installation will give you options to customize the installation; I
30used the default installation options.
3231
3332```sh
3433sudo apt update && sudo apt upgrade -y
@@ -41,15 +40,14 @@ Remember to configure your shell with the new configuration:
4140source $HOME/.cargo/env
4241```
4342
44Before we install agate, make sure you have the `gcc` package
45installed:
43Before we install agate, make sure you have the `gcc` package installed:
4644
4745```sh
4846sudo apt install gcc
4947```
5048
51Next, you\'ll need to install the agate executable with Rust\'s Cargo
52package maintainer:
49Next, you'll need to install the agate executable with Rust's Cargo package
50maintainer:
5351
5452```sh
5553cargo install agate
@@ -57,18 +55,17 @@ cargo install agate
5755
5856# Create Symlinks
5957
60Once Cargo has finished installing all the required packages, symlink
61the executable to your \$PATH.
58Once Cargo has finished installing all the required packages, symlink the
59executable to your $PATH.
6260
6361```sh
6462sudo ln -s $HOME/.cargo/bin/agate /usr/local/bin/agate
6563```
6664
67# Using Agate\'s Built-In Installation Tool
65# Using Agate's Built-In Installation Tool
6866
69If you\'re running Ubuntu or Debian, use the Debian installation script
70found in Agate\'s GitHub repository, under the `tools/debian`
71folder.
67If you're running Ubuntu or Debian, use the Debian installation script found in
68Agate's GitHub repository, under the `tools/debian` folder.
7269
7370```sh
7471git clone https://github.com/mbrubeck/agate
@@ -78,11 +75,10 @@ sudo ./install.sh
7875
7976# Configure the Gemini Service
8077
81We have a little more to do, but since this script tries to immediately
82run the service, it will likely fail with an exit code. Let\'s add our
83finishing touches. Edit the following file and replace the hostname with
84your desired URL. You can also change the directory where content will
85be served.
78We have a little more to do, but since this script tries to immediately run the
79service, it will likely fail with an exit code. Let's add our finishing
80touches. Edit the following file and replace the hostname with your desired URL.
81You can also change the directory where content will be served.
8682
8783```sh
8884sudo nano /etc/systemd/system/gemini.service
@@ -101,8 +97,8 @@ WorkingDirectory=/var/gemini/
10197ExecStart=agate --hostname gemini.example.com --lang en
10298```
10399
104Since we\'ve altered the systemd configuration files, we have to reload
105the daemon. Let\'s do that, restart our service, and check its status.
100Since we've altered the systemd configuration files, we have to reload the
101daemon. Let's do that, restart our service, and check its status.
106102
107103```sh
108104sudo systemctl daemon-reload
@@ -112,8 +108,8 @@ sudo systemctl status gemini.service
112108
113109# Fixing Systemd Errors
114110
115If you\'re still getting errors, the installation process may not have
116properly enabled the gemini service. Fix it with the following commands.
111If you're still getting errors, the installation process may not have properly
112enabled the gemini service. Fix it with the following commands.
117113
118114```sh
119115sudo systemctl enable gemini.service
@@ -123,9 +119,9 @@ sudo systemctl status gemini.service
123119
124120# Firewall Rules
125121
126Great! Our server is now functional and running. The first consideration
127now is that you need to be able to access port 1965 on the server. If
128you have a firewall enabled, you\'ll need to open that port up.
122Great! Our server is now functional and running. The first consideration now is
123that you need to be able to access port 1965 on the server. If you have a
124firewall enabled, you'll need to open that port up.
129125
130126```sh
131127sudo ufw allow 1965
@@ -134,19 +130,19 @@ sudo ufw reload
134130
135131# Creating Content
136132
137Let\'s create the Gemini capsule. Note that wherever you set the
138WorkingDirectory variable to earlier, Agate will expect you to put your
139Gemini capsule contents in a sub-folder called \"content.\" So, I place
140my files in \"/var/gmi/content.\" I\'m going to create that folder now
141and put a file in there.
133Let's create the Gemini capsule. Note that wherever you set the
134WorkingDirectory variable to earlier, Agate will expect you to put your Gemini
135capsule contents in a sub-folder called "content." So, I place my files in
136"/var/gmi/content." I'm going to create that folder now and put a file in
137there.
142138
143139```sh
144140sudo mkdir /var/gemini/content
145141sudo nano /var/gemini/content/index.gmi
146142```
147143
148You can put whatever you want in the \"index.gmi\" file, just make sure
149it\'s valid Gemtext.
144You can put whatever you want in the "index.gmi" file, just make sure it's
145valid Gemtext.
150146
151147# The Results
152148
content/blog/2021-04-23-php-comment-system.md +89 −105
@@ -7,85 +7,78 @@ draft = false
77
88# The Terrible-ness of Commenting Systems
99
10The current state of affairs regarding interactive comment systems is,
11well, terrible. It is especially awful if you\'re a privacy conscious
12person who does not generally load third-party scripts or frames on the
13websites you visit.
10The current state of affairs regarding interactive comment systems is, well,
11terrible. It is especially awful if you're a privacy conscious person who does
12not generally load third-party scripts or frames on the websites you visit.
1413
15Even further, many comment systems are charging exorbitant fees for
16something that should be standard.
14Even further, many comment systems are charging exorbitant fees for something
15that should be standard.
1716
1817Of course, there are some really terrible options:
1918
20- Facebook Comments
21- Discourse
19- Facebook Comments
20- Discourse
2221
23There are some options that are better but still use too many scripts,
24frames, or social integrations on your web page that could impact some
25users:
22There are some options that are better but still use too many scripts, frames,
23or social integrations on your web page that could impact some users:
2624
27- Disqus
28- Isso
29- Remark42
25- Disqus
26- Isso
27- Remark42
3028
31Lastly, I looked into a few unique ways of generating blog comments,
32such as using Twitter threads or GitHub issues to automatically post
33issues. However, these both rely on external third-party sites that I
34don\'t currently use.
29Lastly, I looked into a few unique ways of generating blog comments, such as
30using Twitter threads or GitHub issues to automatically post issues. However,
31these both rely on external third-party sites that I don't currently use.
3532
3633# Stay Static with Server-Side Comments
3734
38The main issue for my personal use-case is that my blog is completely,
39100% static. I use PHP on the back-end but website visitors only see
40HTML and a single CSS file. No external javascript and no embedded
41frames.
42
43So, how do we keep a site static and still allow users to interact with
44blog posts? The key actually pretty simple - I\'m already using PHP, so
45why not rely on the classic HTML `<form>` and a PHP script to
46save the comments somewhere? As it turns out, this was a perfect
47solution for me.
48
49The second issue for my personal use-case is that I am trying to keep
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
35The main issue for my personal use-case is that my blog is completely, 100%
36static. I use PHP on the back-end but website visitors only see HTML and a
37single CSS file. No external javascript and no embedded frames.
38
39So, how do we keep a site static and still allow users to interact with blog
40posts? The key actually pretty simple - I'm already using PHP, so why not rely
41on the classic HTML `<form>` and a PHP script to save the comments somewhere? As
42it turns out, this was a perfect solution for me.
43
44The second issue for my personal use-case is that I am trying to keep the
45contents of my website accessible over time, as described by @brandur, in his
46post entitled [Blog with Markdown + Git, and degrade gracefully through
5347time](https://brandur.org/fragments/graceful-degradation-time) .
5448
55This means I cannot rely on a database for comments, since I do not rely
56on a database for any other part of my websites.
49This means I cannot rely on a database for comments, since I do not rely on a
50database for any other part of my websites.
5751
58I blog in plain Markdown files, commit all articles to Git, and ensure
59that future readers will be able to see the source data long after I\'m
60gone, or the website has gone offline. However, I still haven\'t
61committed any images served on my blog to Git, as I\'m not entirely sold
62on Git LFS yet - for now, images can be found at
63[img.cleberg.net](https://img.cleberg.net).
52I blog in plain Markdown files, commit all articles to Git, and ensure that
53future readers will be able to see the source data long after I'm gone, or the
54website has gone offline. However, I still haven't committed any images served
55on my blog to Git, as I'm not entirely sold on Git LFS yet - for now, images
56can be found at [img.cleberg.net](https://img.cleberg.net).
6457
65Saving my comments back to the Git repository ensures that another
66aspect of my site will degrade gracefully.
58Saving my comments back to the Git repository ensures that another aspect of my
59site will degrade gracefully.
6760
6861# Create a Comment Form
6962
70Okay, let\'s get started. The first step is to create an HTML form that
71users can see and utilize to submit comments. This is fairly easy and
72can be changed depending on your personal preferences.
63Okay, let's get started. The first step is to create an HTML form that users
64can see and utilize to submit comments. This is fairly easy and can be changed
65depending on your personal preferences.
7366
74Take a look at the code block below for the form I currently use. Note
75that `<current-url>` is replaced automatically in PHP with
76the current post\'s URL, so that my PHP script used later will know
77which blog post the comment is related to.
67Take a look at the code block below for the form I currently use. Note that
68`<current-url>` is replaced automatically in PHP with the current post's URL,
69so that my PHP script used later will know which blog post the comment is
70related to.
7871
7972The form contains the following structure:
8073
811. `<form>` - This is the form and will determine which PHP
82 script to send the comment to.
832. `<section hidden>` - This section is hidden from the user
84 and is used to ensure that we know which blog post sent the comment.
853. `<section>` Display Name (Optional) - Used to accept a
86 display name, if entered.
874. `<section>` Comment (Required) - Used to accept the
88 user\'s full comment. Markdown is allowed.
741. `<form>` - This is the form and will determine which PHP script to send the
75 comment to.
762. `<section hidden>` - This section is hidden from the user and is used to
77 ensure that we know which blog post sent the comment.
783. `<section>` Display Name (Optional) - Used to accept a display name, if
79 entered.
804. `<section>` Comment (Required) - Used to accept the user's full comment.
81 Markdown is allowed.
89825. `<button>` - A button to submit the form.
9083
9184``` html
@@ -132,13 +125,12 @@ The form contains the following structure:
132125
133126# Handle Comments via POST
134127
135Now that we have a form and can submit comments, we need to create a PHP
136script so that the server can fetch the comment data and save it. Make
137sure your PHP script name matches the name you entered in the
138`action` field in your form.
128Now that we have a form and can submit comments, we need to create a PHP script
129so that the server can fetch the comment data and save it. Make sure your PHP
130script name matches the name you entered in the `action` field in your form.
139131
140See the code block below for the contents of my `comment.php`
141script. We perform the following tasks in this script:
132See the code block below for the contents of my `comment.php` script. We perform
133the following tasks in this script:
142134
1431351. Grab the POST data from the HTML form.
1441362. Sanitize the comment data with `htmlentities`.
@@ -146,12 +138,11 @@ script. We perform the following tasks in this script:
1461384. Create a PHP object that combines all of this data.
1471395. Check if our destination file `comments.json` exists.
1481406. 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
150 will exit with an error. You can alter this to ensure it creates the
151 script, but my source code includes the file by default, so it will
152 always exist.
1538. Finally, send the user back to the `#comments` section of
154 the blog post they just read.
1417. If the `comments.json` file does not exist, the script will exit with an
142 error. You can alter this to ensure it creates the script, but my source
143 code includes the file by default, so it will always exist.
1448. Finally, send the user back to the `#comments` section of the blog post they
145 just read.
155146
156147``` php
157148// Get the content sent from the comment form
@@ -190,9 +181,9 @@ if (file_exists($file_name)) {
190181header('Location: ' . $post_url . '#comments');
191182```
192183
193If you\'re using Apache, make sure the `www-data` user on
194your server has the correct permissions to your website directory or
195else it will not be able to write to `comments.json`.
184If you're using Apache, make sure the `www-data` user on your server has the
185correct permissions to your website directory or else it will not be able to
186write to `comments.json`.
196187
197188```sh
198189chgrp -R www-data /path/to/website/
@@ -201,18 +192,15 @@ chmod -R g+w comments.json
201192
202193# Display User Comments
203194
204Now that we can submit comments, and they are saved to the
205`comments.json` file, let\'s make sure we can show those
206comments in each blog post.
195Now that we can submit comments, and they are saved to the `comments.json` file,
196let's make sure we can show those comments in each blog post.
207197
208The code block below shows the function I use to decode my
209`comments.json` file, check if the comments apply to the
210current post, and then display them.
198The code block below shows the function I use to decode my `comments.json` file,
199check if the comments apply to the current post, and then display them.
211200
212This piece of code should **really\*** be inside a function (or at least
213in an organized PHP workflow). Don\'t just copy-and-paste and expect it
214to work. You need to at least supply a `$query` variable
215depending on the page visited.
201This piece of code should **really** be inside a function (or at least in an
202organized PHP workflow). Don't just copy-and-paste and expect it to work. You
203need to at least supply a `$query` variable depending on the page visited.
216204
217205``` php
218206$query = 'your-blog-post.html';
@@ -248,30 +236,26 @@ foreach ($comments as $comment) {
248236echo $comment_section;
249237```
250238
251# Bonus: Create a \'Recent Comments\' Page
239# Bonus: Create a 'Recent Comments' Page
252240
253Finally, the last part of my current system is to create a Recent
254Comments page so that I can easily check-in on my blog and moderate any
255spam. As an alternative, you could use PHP\'s `mail()`
256function to email you for each blog comment.
241Finally, the last part of my current system is to create a Recent Comments page
242so that I can easily check-in on my blog and moderate any spam. As an
243alternative, you could use PHP's `mail()` function to email you for each blog
244comment.
257245
258The code to do this is literally the same code as the previous section,
259I just make sure it is printed when someone visits
260`https://example.com/comments/`.
246The code to do this is literally the same code as the previous section, I just
247make sure it is printed when someone visits `https://example.com/comments/`.
261248
262249# Possible Enhancements
263250
264This comment system is by no means a fully-developed system. I have
265noted a few possible enhancements here that I may implement in the
266future:
267
268- Create a secure moderator page with user authentication at
269 `https://blog.example.com/mod/`. This page could have the
270 option to edit or delete any comment found in
271 `comments.json`.
272- Create a temporary file, such as `pending_comments.json`,
273 that will store newly-submitted comments and won\'t display on blog
274 posts until approved by a moderator.
275- Create a `/modlog/` page with a chronological log,
276 showing which moderator approved which comments and why certain
277 comments were rejected.
251This comment system is by no means a fully-developed system. I have noted a few
252possible enhancements here that I may implement in the future:
253
254- Create a secure moderator page with user authentication at
255 `https://blog.example.com/mod/`. This page could have the option to edit or
256 delete any comment found in `comments.json`.
257- Create a temporary file, such as `pending_comments.json`, that will store
258 newly-submitted comments and won't display on blog posts until approved by a
259 moderator.
260- Create a `/modlog/` page with a chronological log, showing which moderator
261 approved which comments and why certain comments were rejected.
content/blog/2021-04-28-photography.md +42 −47
@@ -7,67 +7,62 @@ draft = false
77
88# Why Photography?
99
10I\'ve often wondered why photography is as enticing as it is. You can
11see billions of people around the world taking photographs every single
12moment of the day. New technology often boasts about their photographic
13capabilities, especially smartphones. I would even assume that we live
14in a world where there is never a moment in which a photograph is not
15being taken somewhere on Earth.
10I've often wondered why photography is as enticing as it is. You can see
11billions of people around the world taking photographs every single moment of
12the day. New technology often boasts about their photographic capabilities,
13especially smartphones. I would even assume that we live in a world where there
14is never a moment in which a photograph is not being taken somewhere on Earth.
1615
17As for myself, I would simply say that I enjoy preserving a memory in
18physical (or digital) form. I\'ve never had the best memory when it
19comes to recalling details of places and people gone by, so it helps to
20have a frame of reference lying around.
16As for myself, I would simply say that I enjoy preserving a memory in physical
17(or digital) form. I've never had the best memory when it comes to recalling
18details of places and people gone by, so it helps to have a frame of reference
19lying around.
2120
22Regardless of the reason, I think most people would agree that you
23simply cannot have too many hobbies.
21Regardless of the reason, I think most people would agree that you simply cannot
22have too many hobbies.
2423
2524# Older Cameras
2625
27I started playing around with the idea of photography when my family
28purchased a Fujifilm camera for family-specific events. I don\'t recall
29the specific model, but I do recall it was a point-and-shoot camera
30without an interchangeable lens. However, it was of great value to
31someone, like myself, who couldn\'t afford any other camera. I took
32about 10,000 shots with that camera over a 3-5 year span. Most notably,
33all of my trips to California were documented through this camera.
26I started playing around with the idea of photography when my family purchased a
27Fujifilm camera for family-specific events. I don't recall the specific model,
28but I do recall it was a point-and-shoot camera without an interchangeable lens.
29However, it was of great value to someone, like myself, who couldn't afford any
30other camera. I took about 10,000 shots with that camera over a 3-5 year span.
31Most notably, all of my trips to California were documented through this camera.
3432
35When possible, I would borrow my sister\'s camera, which is a Sony
36SLT-A58. This camera was great and allowed for some of my best early
37shots, especially those taken in Utah\'s and Nevada\'s parks.
33When possible, I would borrow my sister's camera, which is a Sony SLT-A58. This
34camera was great and allowed for some of my best early shots, especially those
35taken in Utah's and Nevada's parks.
3836
3937# My Current Kit
4038
41I\'ve finally come to a point in my life where I have the disposable
42income to invest in a solid photography kit. I played around with the
43idea of a lot of different cameras, different types, new vs used, etc.
44Finally, I settled on the [Sony α7
45III](https://en.wikipedia.org/wiki/Sony_%CE%B17_III). This camera is
46mirror-less and uses a full-frame image sensor at 24 megapixels. I
47don\'t create large prints, and I am mostly focused on preserving
48memories in high quality for the next 5-10 years with this camera, so
49the specifications here are just perfect for me.
39I've finally come to a point in my life where I have the disposable income to
40invest in a solid photography kit. I played around with the idea of a lot of
41different cameras, different types, new vs used, etc. Finally, I settled on the
42[Sony α7 III](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
44large prints, and I am mostly focused on preserving memories in high quality for
45the next 5-10 years with this camera, so the specifications here are just
46perfect for me.
5047
5148For lenses, I decided to buy two lenses that could carry me through most
5249situations:
5350
54- [Vario-Tessar T\*\* FE 24-70 mm F4 ZA
55 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z)
56- [Tamron 70-300mm f4.5-6.3 Di III
57 RXD](https://www.tamron-usa.com/product/lenses/a047.html)
51- [Vario-Tessar T** FE 24-70 mm F4 ZA
52 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z)
53- [Tamron 70-300mm f4.5-6.3 Di III
54 RXD](https://www.tamron-usa.com/product/lenses/a047.html)
5855
5956In addition, I grabbed a couple [HGX Prime
6067mm](https://www.promaster.com/Product/6725) protection filters for the
61lenses.
5767mm](https://www.promaster.com/Product/6725) protection filters for the lenses.
6258
63As I delve further into photography and pick up more skills, I will most
64likely go back and grab a lens with a higher f-stop value, such as
65f/1.8. I toyed with the idea of grabbing a 50 mm at `f/1.8`,
66but decided to keep things in a reasonable price range instead.
59As I delve further into photography and pick up more skills, I will most likely
60go back and grab a lens with a higher f-stop value, such as f/1.8. I toyed with
61the idea of grabbing a 50 mm at `f/1.8`, but decided to keep things in a
62reasonable price range instead.
6763
68Finally, I made sure to buy a photography-specific backpack with a rain
69guard, and the zipper on the back panel, to protect the equipment while
70wearing the bag. If you\'ve ever had to haul around a DSLR (or camera of
71similar heft) in a bag that only has a shoulder strap, you\'ll know the
72pain it can cause. Putting all my equipment in a backpack was an easy
73decision.
64Finally, I made sure to buy a photography-specific backpack with a rain guard,
65and the zipper on the back panel, to protect the equipment while wearing the
66bag. If you've ever had to haul around a DSLR (or camera of similar heft) in a
67bag that only has a shoulder strap, you'll know the pain it can cause. Putting
68all my equipment in a backpack was an easy decision.
content/blog/2021-05-30-changing-git-authors.md +12 −12
@@ -7,25 +7,25 @@ draft = false
77
88# Changing Git Author/Email Based on Previously Committed Email
99
10Here\'s the dilemma: You\'ve been committing changes to your git
11repository with an incorrect name or email (or multiple repositories),
12and now you want to fix it. Luckily, there\'s a semi-reliable way to fix
13that. While I have never experienced issues with this method, some
14people have warned that it can mess with historical hashes and integrity
15of commits, so use this method only if you\'re okay accepting that risk.
10Here's the dilemma: You've been committing changes to your git repository with
11an incorrect name or email (or multiple repositories), and now you want to fix
12it. Luckily, there's a semi-reliable way to fix that. While I have never
13experienced issues with this method, some people have warned that it can mess
14with historical hashes and integrity of commits, so use this method only if
15you're okay accepting that risk.
1616
17Okay, let\'s create the bash script:
17Okay, let's create the bash script:
1818
1919```sh
2020nano change_git_authors.sh
2121```
2222
23The following information can be pasted directly into your bash script.
24The only changes you need to make are to the following variables:
23The following information can be pasted directly into your bash script. The only
24changes you need to make are to the following variables:
2525
26- `OLD_EMAIL`
27- `CORRECT_NAME`
28- `CORRECT_EMAIL`
26- `OLD_EMAIL`
27- `CORRECT_NAME`
28- `CORRECT_EMAIL`
2929
3030```sh
3131#!/bin/sh
content/blog/2021-07-15-delete-gitlab-repos.md +21 −22
@@ -7,31 +7,31 @@ draft = false
77
88# Background
99
10Have you ever used GitLab to host your source code, moved to a different
11host, and wanted to delete everything from your GitLab account? Well,
12this post covers any scenario where you would want to delete all
13repositories from your GitLab account.
10Have you ever used GitLab to host your source code, moved to a different host,
11and wanted to delete everything from your GitLab account? Well, this post covers
12any scenario where you would want to delete all repositories from your GitLab
13account.
1414
15For me, I currently maintain around 30 repositories and don\'t like to
16manually delete them whenever I switch host. GitHub has a few different
17tools online to delete all repositories for you, but I have not found
18anything similar for GitLab, so I needed an alternative solution.
15For me, I currently maintain around 30 repositories and don't like to manually
16delete them whenever I switch host. GitHub has a few different tools online to
17delete all repositories for you, but I have not found anything similar for
18GitLab, so I needed an alternative solution.
1919
2020# Use a Python Script
2121
2222## Requirements
2323
24Before we look at the script, make sure you know your GitLab username.
25Next, [create an authorization
26token](https://gitlab.com/-/profile/personal_access_tokens) so that the
27Python script can delete your repositories. Don\'t lose this token or
28else you\'ll need to create a new one.
24Before we look at the script, make sure you know your GitLab username. Next,
25[create an authorization
26token](https://gitlab.com/-/profile/personal_access_tokens) so that the Python
27script can delete your repositories. Don't lose this token or else you'll need
28to create a new one.
2929
3030## Create the Script
3131
32To run a Python script, you must first create it. Open a terminal and
33enter the following commands in whichever directory you prefer to store
34the script. You can do the same things in a file manager if you prefer.
32To run a Python script, you must first create it. Open a terminal and enter the
33following commands in whichever directory you prefer to store the script. You
34can do the same things in a file manager if you prefer.
3535
3636```sh
3737mkdir delete-gitlab
@@ -103,13 +103,12 @@ if __name__ == "__main__":
103103 main()
104104```
105105
106Now that you have the proper information, replace `{user-id}`
107with your GitLab username and `{auth-token}` with the
108authorization token you created earlier.
106Now that you have the proper information, replace `{user-id}` with your GitLab
107username and `{auth-token}` with the authorization token you created earlier.
109108
110Finally, simply run the script and watch the output. You can also use
111PyCharm Community Edition to edit and run the Python script if you
112don\'t want to work in a terminal.
109Finally, simply run the script and watch the output. You can also use PyCharm
110Community Edition to edit and run the Python script if you don't want to work
111in a terminal.
113112
114113```sh
115114python3 main.py
content/blog/2021-08-25-audit-sampling.md +92 −101
@@ -8,44 +8,43 @@ draft = false
88# Introduction
99
1010For anyone who is familiar with internal auditing, external auditing, or
11consulting, you will understand how tedious audit testing can become
12when you are required to test large swaths of data. When we cannot
13establish an automated means of testing an entire population, we
14generate samples to represent the population of data. This helps ensure
15we can have a small enough data pool to test and that our results still
16represent the population.
17
18However, sampling data within the world of audit still seems to confuse
19quite a lot of people. While some audit-focused tools have introduced
20sampling functionality (e.g. Wdesk), many audit departments and firms
21cannot use software like this due to certain constraints, such as the
22team\'s budget or knowledge. Here is where this article comes in: we\'re
23going to use [Python](https://www.python.org), a free and open-source
24programming language, to generate random samples from a dataset in order
25to suffice numerous audit situations.
11consulting, you will understand how tedious audit testing can become when you
12are required to test large swaths of data. When we cannot establish an automated
13means of testing an entire population, we generate samples to represent the
14population of data. This helps ensure we can have a small enough data pool to
15test and that our results still represent the population.
16
17However, sampling data within the world of audit still seems to confuse quite a
18lot of people. While some audit-focused tools have introduced sampling
19functionality (e.g. Wdesk), many audit departments and firms cannot use software
20like this due to certain constraints, such as the team's budget or knowledge.
21Here is where this article comes in: we're going to use
22[Python](https://www.python.org), a free and open-source programming language,
23to generate random samples from a dataset in order to suffice numerous audit
24situations.
2625
2726# Audit Requirements for Sampling
2827
29Before we get into the details of how to sample with Python, I want to
30make sure I discuss the different requirements that auditors may have of
31samples used within their projects.
28Before we get into the details of how to sample with Python, I want to make sure
29I discuss the different requirements that auditors may have of samples used
30within their projects.
3231
3332## Randomness
3433
35First, let\'s discuss randomness. When testing out new technology to
36help assist with audit sampling, you need to understand exactly how your
37samples are being generated. For example, if the underlying function is
38just picking every 57th element from a list, that\'s not truly random;
39it\'s a systematic form of sampling. Luckily, since Python is
40open-source, we have access to its codebase. Through this blog post, I
41will be using the [pandas](https://pandas.pydata.org) module in order to
42generate the random samples. More specifically, I will be using the
34First, let's discuss randomness. When testing out new technology to help assist
35with audit sampling, you need to understand exactly how your samples are being
36generated. For example, if the underlying function is just picking every 57th
37element from a list, that's not truly random; it's a systematic form of
38sampling. Luckily, since Python is open-source, we have access to its codebase.
39Through this blog post, I will be using the [pandas](https://pandas.pydata.org)
40module in order to generate the random samples. More specifically, I will be
41using the
4342[pandas.DataFrame.sample](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html)
4443function provided by Pandas.
4544
46Now that you know what you\'re using, you can always check out the code
47behind `pandas.DataFrame.sample`. This function does a lot of
48work, but we really only care about the following snippets of code:
45Now that you know what you're using, you can always check out the code behind
46`pandas.DataFrame.sample`. This function does a lot of work, but we really only
47care about the following snippets of code:
4948
5049``` python
5150# Process random_state argument
@@ -61,67 +60,59 @@ result.index = ibase.default_index(len(result))
6160return result
6261```
6362
64The block of code above shows you that if you assign a
65`random_state` argument when you run the function, that will
66be used as a seed number in the random generation and will allow you to
67reproduce a sample, given that nothing else changes. This is critical to
68the posterity of audit work. After all, how can you say your audit
69process is adequately documented if the next person can\'t run the code
70and get the same sample? The final piece here on randomness is to look
71at the
72[choice](https://docs.%20python.org/3/library/random.html#random.choice)
73function used above. This is the crux of the generation and can also be
74examined for more detailed analysis on its reliability. As far as
75auditing goes, we will trust that these functions are mathematically
76random.
63The block of code above shows you that if you assign a `random_state` argument
64when you run the function, that will be used as a seed number in the random
65generation and will allow you to reproduce a sample, given that nothing else
66changes. This is critical to the posterity of audit work. After all, how can you
67say your audit process is adequately documented if the next person can't run
68the code and 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)
70function used above. This is the crux of the generation and can also be examined
71for more detailed analysis on its reliability. As far as auditing goes, we will
72trust that these functions are mathematically random.
7773
7874## Sample Sizes
7975
80As mentioned in the intro, sampling is only an effective method of
81auditing when it truly represents the entire population. While some
82audit departments or firms may consider certain judgmental sample sizes
83to be adequate, you may need to rely on statistically-significant
84confidence levels of sample testing at certain points. I will
85demonstrate both here. For statistically-significant confidence levels,
86most people will assume a 90% - 99% confidence level. In order to
87actually calculate the correct sample size, it is best to use
88statistical tools due to the tedious math work required. For example,
89for a population of 1000, and a 90% confidence level that no more than
905% of the items are nonconforming, you would sample 45 items.
91
92However, in my personal experience, many audit departments and firms do
93not use statistical sampling. Most people use a predetermined, often
94proprietary, table that will instruct auditors which sample sizes to
95choose. This allows for uniform testing and reduces overall workload.
96See the table below for a common implementation of sample sizes:
76As mentioned in the intro, sampling is only an effective method of auditing when
77it truly represents the entire population. While some audit departments or firms
78may consider certain judgmental sample sizes to be adequate, you may need to
79rely on statistically-significant confidence levels of sample testing at certain
80points. I will demonstrate both here. For statistically-significant confidence
81levels, most people will assume a 90% - 99% confidence level. In order to
82actually calculate the correct sample size, it is best to use statistical tools
83due to the tedious math work required. For example, for a population of 1000,
84and a 90% confidence level that no more than 5% of the items are nonconforming,
85you would sample 45 items.
86
87However, in my personal experience, many audit departments and firms do not use
88statistical sampling. Most people use a predetermined, often proprietary, table
89that will instruct auditors which sample sizes to choose. This allows for
90uniform testing and reduces overall workload. See the table below for a common
91implementation of sample sizes:
9792
9893 Control Frequency Sample Size - High Risk Sample Size - Low Risk
9994 ------------------- ------------------------- ------------------------
100 More Than Daily 40 25
101 Daily 40 25
102 Weekly 12 5
103 Monthly 5 3
104 Quarterly 2 2
105 Semi-Annually 1 1
106 Annually 1 1
107 Ad-hoc 1 1
95 More Than Daily 40 25 Daily 40
96 25 Weekly 12 5 Monthly 5
97 3 Quarterly 2 2 Semi-Annually 1
98 1 Annually 1 1 Ad-hoc 1
99 1
108100
109101### Sampling with Python & Pandas
110102
111In this section, I am going to cover a few basic audit situations that
112require sampling. While some situations may require more effort, the
113syntax, organization, and intellect used remain largely the same. If
114you\'ve never used Python before, note that lines starting with a
115\'`#`\' symbol are called comments, and they will be skipped
116by Python. I highly recommend taking a quick tutorial online to
117understand the basics of Python if any of the code below is confusing to
118you.
103In this section, I am going to cover a few basic audit situations that require
104sampling. While some situations may require more effort, the syntax,
105organization, and intellect used remain largely the same. If you've never used
106Python before, note that lines starting with a '`#`' symbol are called
107comments, and they will be skipped by Python. I highly recommend taking a quick
108tutorial online to understand the basics of Python if any of the code below is
109confusing to you.
119110
120111## Simple Random Sample
121112
122First, let\'s look at a simple, random sample. The code block below will
123import the `pandas` module, load a data file, sample the
124data, and export the sample to a file.
113First, let's look at a simple, random sample. The code block below will import
114the `pandas` module, load a data file, sample the data, and export the sample to
115a file.
125116
126117``` python
127118# Import the Pandas module
@@ -145,8 +136,8 @@ sample.to_excel(file_output)
145136
146137## Simple Random Sample: Using Multiple Input Files
147138
148Now that we\'ve created a simple sample, let\'s create a sample from
149multiple files.
139Now that we've created a simple sample, let's create a sample from multiple
140files.
150141
151142``` python
152143# Import the Pandas module
@@ -179,9 +170,9 @@ sample.to_excel(file_output)
179170
180171## Stratified Random Sample
181172
182Well, what if you need to sample distinct parts of a single file? For
183example, let\'s write some code to separate our data by \"Region\" and
184sample those regions independently.
173Well, what if you need to sample distinct parts of a single file? For example,
174let's write some code to separate our data by "Region" and sample those
175regions independently.
185176
186177``` python
187178# Import the Pandas module
@@ -213,10 +204,10 @@ sample.to_excel(file_output)
213204
214205## Stratified Systematic Sample
215206
216This next example is quite useful if you need audit coverage over a
217certain time period. This code will generate samples for each month in
218the data and combine them all together at the end. Obviously, this code
219can be modified to stratify by something other than months, if needed.
207This next example is quite useful if you need audit coverage over a certain time
208period. This code will generate samples for each month in the data and combine
209them all together at the end. Obviously, this code can be modified to stratify
210by something other than months, if needed.
220211
221212``` python
222213# Import the Pandas module
@@ -262,17 +253,17 @@ sample.to_excel(file_output)
262253
263254### Documenting the Results
264255
265Once you\'ve generated a proper sample, there are a few things left to
266do in order to properly ensure your process is reproducible.
267
2681. Document the sample. Make sure the resulting file is readable and
269 includes the documentation listed in the next bullet.
2702. Include documentation around the data source, extraction techniques,
271 any modifications made to the data, and be sure to include a copy of
272 the script itself.
2733. Whenever possible, perform a completeness and accuracy test to
274 ensure your sample is coming from a complete and accurate
275 population. To ensure completeness, compare the record count from
276 the data source to the record count loaded into Python. To ensure
277 accuracy, test a small sample against the source data (e.g., test 5
278 sales against the database to see if the details are accurate).
256Once you've generated a proper sample, there are a few things left to do in
257order to properly ensure your process is reproducible.
258
2591. Document the sample. Make sure the resulting file is readable and includes
260 the documentation listed in the next bullet.
2612. Include documentation around the data source, extraction techniques, any
262 modifications made to the data, and be sure to include a copy of the script
263 itself.
2643. Whenever possible, perform a completeness and accuracy test to ensure your
265 sample is coming from a complete and accurate population. To ensure
266 completeness, compare the record count from the data source to the record
267 count loaded into Python. To ensure accuracy, test a small sample against the
268 source data (e.g., test 5 sales against the database to see if the details
269 are accurate).
content/blog/2021-10-09-apache-redirect.md +22 −24
@@ -7,26 +7,25 @@ draft = false
77
88# The Problem
99
10After recently switching static site generators (SSG), my blog URLs
11changed with no option to preserve the classic `.html`
12extension at the end of my blog post URLs.
10After recently switching static site generators (SSG), my blog URLs changed with
11no option to preserve the classic `.html` extension at the end of my blog post
12URLs.
1313
14I really disliked using my old SSG ([Jekyll](https://jekyllrb.com)) and
15prefer my new tool ([Zola](https://www.getzola.org)) much more, so I was
16determined to figure out a way to get the proper redirect set up so that
17people who find my posts online aren\'t constantly met by 404 errors.
14I really disliked using my old SSG ([Jekyll](https://jekyllrb.com)) and prefer
15my new tool ([Zola](https://www.getzola.org)) much more, so I was determined to
16figure out a way to get the proper redirect set up so that people who find my
17posts online aren't constantly met by 404 errors.
1818
1919# The Solution
2020
2121To solve this problem, I really needed to solve two pieces:
2222
231. Redirect all blog post URL requests from
24 `/blog/some-post.html` to `/blog/some-post/`.
252. Ensure that no other `.html` files are redirected, such
26 as `index.html`.
231. Redirect all blog post URL requests from `/blog/some-post.html` to
24 `/blog/some-post/`.
252. Ensure that no other `.html` files are redirected, such as `index.html`.
2726
28After *a lot* of tweaking and testing, I believe I have finally found
29the solution. The solution is shown below.
27After *a lot* of tweaking and testing, I believe I have finally found the
28solution. The solution is shown below.
3029
3130``` conf
3231RewriteEngine On
@@ -34,14 +33,13 @@ RewriteCond %{REQUEST_URI} !\index.html$ [NC]
3433RewriteRule ^(.*).html$ https://example.com/$1 [R=301,L]
3534```
3635
37This piece of code in the Apache `.conf` or
38`.htaccess` file will do the following:
39
401. Turn on the RewriteEngine so that we can modify URLs.
412. Ignore any `index.html` files from the rule we are about
42 to specify.
433. Find any `.html` files within the website directory and
44 redirect it to exclude the file extension.
454. The final piece is adding the trailing slash (`/`) at the
46 end of the URL - you\'ll notice that I don\'t have an Apache rule
47 for that since Apache handles that automatically.
36This piece of code in the Apache `.conf` or `.htaccess` file will do the
37following:
38
391. Turn on the RewriteEngine so that we can modify URLs.
402. Ignore any `index.html` files from the rule we are about to specify.
413. Find any `.html` files within the website directory and redirect it to
42 exclude the file extension.
434. The final piece is adding the trailing slash (`/`) at the end of the URL -
44 you'll notice that I don't have an Apache rule for that since Apache
45 handles that automatically.
content/blog/2021-12-04-cisa.md +152 −167
@@ -8,208 +8,193 @@ draft = false
88# What is the CISA?
99
1010For 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
12Certified Information Systems Auditor. This certification and exam are
13part of ISACA\'s suite of certifications. As I often explain it to
14people like my family, it basically means you\'re employed to use your
15knowledge of information systems, regulations, common threats, risks,
16etc. in order to assess an organization\'s current control of their
17risk. If a risk isn\'t controlled (and the company doesn\'t want to
18accept the risk), an IS auditor will suggest implementing a control to
19address that risk.
20
21Now, the CISA certification itself is, in my opinion, the main
22certification for this career. While certifications such as the CPA or
23CISSP are beneficial, nothing matches the power of the CISA for an IS
24auditor when it comes to getting hired, getting a raise/bonus, or
25earning respect in the field.
26
27However, to be honest, I am a skeptic of most certifications. I
28understand the value they hold in terms of how much you need to commit
29to studying or learning on the job, as well as the market value for
30certifications such as the CISA. But I also have known some very
31~~incompetent~~ *less than stellar* auditors who have CPAs, CISAs, CIAs,
32etc.
33
34The same goes for most industries: if a person is good at studying, they
35can earn the certification. However, that knowledge means nothing unless
36you\'re actually able to use it in real life and perform as expected of
37a certification holder. The challenge comes when people are hired or
38connected strictly because of their certifications or resume; you need
39to see a person work before you can assume them having a CISA means
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.
11Auditing, [CISA](https://www.isaca.org/credentialing/cisa) stands for Certified
12Information Systems Auditor. This certification and exam are part of ISACA's
13suite of certifications. As I often explain it to people like my family, it
14basically means you're employed to use your knowledge of information systems,
15regulations, common threats, risks, etc. in order to assess an organization's
16current control of their risk. If a risk isn't controlled (and the company
17doesn't want to accept the risk), an IS auditor will suggest implementing a
18control to address that risk.
19
20Now, the CISA certification itself is, in my opinion, the main certification for
21this career. While certifications such as the CPA or CISSP are beneficial,
22nothing matches the power of the CISA for an IS auditor when it comes to getting
23hired, getting a raise/bonus, or earning respect in the field.
24
25However, to be honest, I am a skeptic of most certifications. I understand the
26value they hold in terms of how much you need to commit to studying or learning
27on the job, as well as the market value for certifications such as the CISA. But
28I also have known some very ~~incompetent~~ *less than stellar* auditors who
29have CPAs, CISAs, CIAs, etc.
30
31The same goes for most industries: if a person is good at studying, they can
32earn the certification. However, that knowledge means nothing unless you're
33actually able to use it in real life and perform as expected of a certification
34holder. The challenge comes when people are hired or connected strictly because
35of their certifications or resume; you need to see a person work before you can
36assume them having a CISA means they're better than someone without the CISA.
37
38Okay, rant over. Certifications are generally accepted as a measuring stick of
39commitment and quality of an employee, so I am accepting it too.
4540
4641# Exam Content
4742
48The CISA is broken down into five sections, each weighted with a
49percentage of test questions that may appear.
43The CISA is broken down into five sections, each weighted with a percentage of
44test questions that may appear.
5045
5146![CISA exam
5247sections](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-exam-sections.png)
5348
54Since the exam contains 150 questions, here\'s how those sections break
55down:
49Since the exam contains 150 questions, here's how those sections break down:
5650
57 Exam Section Percentage of Exam Questions
58 ----------------- -------------------- -----------
59 1 21% 32
60 2 17% 26
61 3 12% 18
62 4 23% 34
63 5 27% 40
64 **Grand Total** **100%** **150**
51| Exam Section | Percentage of Exam | Questions |
52|-----------------|--------------------|-----------|
53| 1 | 21% | 32 |
54| 2 | 17% | 26 |
55| 3 | 12% | 18 |
56| 4 | 23% | 34 |
57| 5 | 27% | 40 |
58| **Grand Total** | **100%** | **150** |
6559
6660# My Studying Habits
6761
68This part is a little hard for me to break down into specific detail due
69to the craziness of the last year. While I officially purchased my
70studying materials in December 2020 and opened them to \"start
71studying\" in January 2021, I really wasn\'t able to study much due to
72the demands of my job and personal life.
62This part is a little hard for me to break down into specific detail due to the
63craziness of the last year. While I officially purchased my studying materials
64in December 2020 and opened them to "start studying" in January 2021, I really
65wasn't able to study much due to the demands of my job and personal life.
7366
7467Let me approach this from a few different viewpoints.
7568
7669## Study Materials
7770
78Let\'s start by discussing the study materials I purchased. I\'ll be
79referring to #1 as the CRM and #2 as the QAE.
80
811. [CISA Review Manual, 27th Edition \|
82 Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK)
832. \[\[<https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK>\]\[CISA
84 Review Questions, Answers & Explanations Manual, 12th Edition \|
85 Print\]\]
86
87The CRM is an excellent source of information and could honestly be used
88as a reference for most IS auditors as a learning reference during their
89daily audit responsibilities. However, it is **full\*** of information
90and can be overloading if you\'re not good at filtering out useless
91information while studying.
92
93The QAE is the real star of the show here. This book contains 1000
94questions, separated by exam section, and a practice exam. My only
95complaint about the QAE is that each question is immediately followed
96with the correct answer and explanations below it, which means I had to
97use something to constantly cover the answers while I was studying.
98
99I didn\'t use the online database version of the QAE, but I\'ve heard
100that it\'s easier to use than the printed book. However, it is more
101expensive (\$299 database vs \$129 book) which might be important if
102you\'re paying for materials yourself.
103
104In terms of question difficulty, I felt that the QAE was a good
105representation of the actual exam. I\'ve seen a lot of people online say
106it wasn\'t accurate to the exam or that it was much easier/harder, but I
107disagree with all of those. The exam was fairly similar to the QAE, just
108focusing on whichever topics they chose for my version of the exam.
109
110If you understand the concepts, skim the CRM (and read in-depth on
111topics you struggle with), and use the QAE to continue practicing
112exam-like questions, you should be fine. I didn\'t use any online
113courses, videos, etc. - the ISACA materials are more than enough.
71Let's start by discussing the study materials I purchased. I'll be referring
72to #1 as the CRM and #2 as the QAE.
73
741. [CISA Review Manual, 27th Edition |
75Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK)
762. [CISA Review Questions, Answers & Explanations Manual, 12th Edition |
77Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK)
78
79The CRM is an excellent source of information and could honestly be used as a
80reference for most IS auditors as a learning reference during their daily audit
81responsibilities. However, it is **full** of information and can be
82overloading if you're not good at filtering out useless information while
83studying.
84
85The QAE is the real star of the show here. This book contains 1000 questions,
86separated by exam section, and a practice exam. My only complaint about the QAE
87is that each question is immediately followed with the correct answer and
88explanations below it, which means I had to use something to constantly cover
89the answers while I was studying.
90
91I didn't use the online database version of the QAE, but I've heard that it's
92easier to use than the printed book. However, it is more expensive ($299
93database vs $129 book) which might be important if you're paying for materials
94yourself.
95
96In terms of question difficulty, I felt that the QAE was a good representation
97of the actual exam. I've seen a lot of people online say it wasn't accurate to
98the exam or that it was much easier/harder, but I disagree with all of those.
99The exam was fairly similar to the QAE, just focusing on whichever topics they
100chose for my version of the exam.
101
102If you understand the concepts, skim the CRM (and read in-depth on topics you
103struggle with), and use the QAE to continue practicing exam-like questions, you
104should be fine. I didn't use any online courses, videos, etc. - the ISACA
105materials are more than enough.
114106
115107## Studying Process
116108
117While I was able to briefly read through sections 1 and 2 in early 2021,
118I had to stop and take a break from February/March to September. I
119switched jobs in September, which allowed me a lot more free time to
120study.
109While I was able to briefly read through sections 1 and 2 in early 2021, I had
110to stop and take a break from February/March to September. I switched jobs in
111September, which allowed me a lot more free time to study.
121112
122In September, I studied sections 3-5, took notes, and did a quick review
123of the section topics. Once I felt comfortable with my notes, I took a
124practice exam from the QAE manual and scored 70% (105/150).
113In September, I studied sections 3-5, took notes, and did a quick review of the
114section topics. Once I felt comfortable with my notes, I took a practice exam
115from the QAE manual and scored 70% (105/150).
125116
126Here\'s a breakdown of my initial practice exam:
117Here's a breakdown of my initial practice exam:
127118
128 Exam Section Incorrect Correct Grand Total Percent
129 ------------------- ----------- ----------- ------------- -----------
130 1 8 25 33 76%
131 2 5 20 25 80%
132 3 6 12 18 67%
133 4 10 23 33 70%
134 5 16 25 41 61%
135 **Grand Total\*** **45\*** **105\*** **150\*** **70%\***
119| Exam Section | Incorrect | Correct | Grand Total | Percent |
120|-----------------|-----------|---------|-------------|---------|
121| 1 | 8 | 25 | 33 | 76% |
122| 2 | 5 | 20 | 25 | 80% |
123| 3 | 6 | 12 | 18 | 67% |
124| 4 | 10 | 23 | 33 | 70% |
125| 5 | 16 | 25 | 41 | 61% |
126| **Grand Total** | **45** | **105** | **150** | **70%** |
136127
137128As I expected, my toughest sections were related to project management,
138129development, implementation, and security.
139130
140This just leaves October and November. For these months, I tried to
141practice every few days, doing 10 questions for each section, until the
142exam. This came out to 13 practice sessions, \~140 questions per
143section, and \~700 questions total.
144
145While some practice sessions were worse and some were better, the final
146results were similar to my practice exam results. As you can see below,
147my averages were slightly worse than my practice exam. However, I got in
148over 700 questions of practice and, most importantly, \*I read through
149the explanations every time I answered incorrectly and learned from my
150mistakes\*.
151
152 Exam Section Incorrect Correct Grand Total Percent
153 ------------------- ----------- ----------- ------------- -----------
154 1 33 108 141 77%
155 2 33 109 142 77%
156 3 55 89 144 62%
157 4 52 88 140 63%
158 5 55 85 140 61%
159 **Grand Total\*** **228\*** **479\*** **707\*** **68%\***
131This just leaves October and November. For these months, I tried to practice
132every few days, doing 10 questions for each section, until the exam. This came
133out to 13 practice sessions, ~140 questions per section, and ~700 questions
134total.
135
136While some practice sessions were worse and some were better, the final results
137were similar to my practice exam results. As you can see below, my averages were
138slightly worse than my practice exam. However, I got in over 700 questions of
139practice and, most importantly, *I read through the explanations every time I
140answered incorrectly and learned from my mistakes*.
141
142| Exam Section | Incorrect | Correct | Grand Total | Percent |
143|-----------------|-----------|---------|-------------|---------|
144| 1 | 33 | 108 | 141 | 77% |
145| 2 | 33 | 109 | 142 | 77% |
146| 3 | 55 | 89 | 144 | 62% |
147| 4 | 52 | 88 | 140 | 63% |
148| 5 | 55 | 85 | 140 | 61% |
149| **Grand Total** | **228** | **479** | **707** | **68%** |
160150
161151![CISA practice question
162152results](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-practice-questions-results.png)
163153
164154# Results
165155
166Now, how do the practice scores reflect my actual results? After all,
167it\'s hard to tell how good a practice regimen is unless you see how it
168turns out.
169
170 Exam Section Section Name Score
171 -------------- ------------------------------------------------------------------ ---------
172 1 Information Systems Auditing Process 678
173 2 Governance and Management of IT 590
174 3 Information Systems Acquisition, Development, and Implementation 721
175 4 Information Systems Operations and Business Resilience 643
176 5 Protection of Information Assets 511
177 **TOTAL** **616**
178
179Now, in order to pass the CISA, you need at least 450 on a sliding scale
180of 200-800. Personally, I really have no clue what an average CISA score
181is. After a *very* brief look online, I can see that the high end is
182usually in the low 700s. In addition, only about 50-60% of people pass
183the exam.
184
185Given this information, I feel great about my scores. 616 may not be
186phenomenal, and I wish I had done better on sections 2 & 5, but my
187practicing seems to have worked very well overall.
188
189However, the practice results do not conform to the actual results.
190Section 2 was one of my highest practice sections and was my
191second-lowest score in the exam. Conversely, section 3 was my
192second-lowest practice section and turned out to be my highest actual
193score!
194
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.
156Now, how do the practice scores reflect my actual results? After all, it's hard
157to tell how good a practice regimen is unless you see how it turns out.
158
159| Exam Section | Section Name | Score |
160|--------------|------------------------------------------------------------------|-------|
161| 1 | Information Systems Auditing Process | 678 |
162| 2 | Governance and Management of IT | 590 |
163| 3 | Information Systems Acquisition, Development, and Implementation | 721 |
164| 4 | Information Systems Operations and Business Resilience | 643 |
165| 5 | Protection of Information Assets | 511 |
166
167Now, in order to pass the CISA, you need at least 450 on a sliding scale of
168200-800. Personally, I really have no clue what an average CISA score is. After
169a *very* brief look online, I can see that the high end is usually in the low
170700s. In addition, only about 50-60% of people pass the exam.
171
172Given this information, I feel great about my scores. 616 may not be phenomenal,
173and I wish I had done better on sections 2 & 5, but my practicing seems to have
174worked very well overall.
175
176However, the practice results do not conform to the actual results. Section 2
177was one of my highest practice sections and was my second-lowest score in the
178exam. Conversely, section 3 was my second-lowest practice section and turned out
179to be my highest actual score!
180
181After reflecting, it is obvious that if you have any background on the CISA
182topics at all, the most important part of studying is doing practice questions.
183You really need to understand how to read the questions critically and pick the
184best answer.
199185
200186# Looking Forward
201187
202I am extremely happy that I was finally able to pass the CISA. Looking
203to the future, I\'m not sure what\'s next in terms of professional
204learning. My current company offers internal learning courses, so I will
205most likely focus on that if I need to gain more knowledge in certain
206areas.
207
208To be fair, even if you pass the CISA, it\'s hard to become an expert on
209any specific topic found within. My career may take me in a different
210direction, and I might need to focus more on security or networking
211certifications (or possibly building a better analysis/visualization
212portfolio if I want to go into data analysis/science).
188I am extremely happy that I was finally able to pass the CISA. Looking to the
189future, I'm not sure what's next in terms of professional learning. My current
190company offers internal learning courses, so I will most likely focus on that if
191I need to gain more knowledge in certain areas.
192
193To be fair, even if you pass the CISA, it's hard to become an expert on any
194specific topic found within. My career may take me in a different direction, and
195I might need to focus more on security or networking certifications (or possibly
196building a better analysis/visualization portfolio if I want to go into data
197analysis/science).
213198
214199All I know is that I am content at the moment and extremely proud of my
215200accomplishment.
content/blog/2022-02-10-leaving-the-office.md +141 −160
@@ -7,195 +7,180 @@ draft = false
77
88# The Working World is Changing
99
10There has been a trend for the past few years of companies slowly
11realizing that the pandemic is not just a temporary state that will go
12away eventually and let everything return to the way it was before. In
13terms of business and employment, this means that more and more jobs are
14being offered as permanently remote roles.
10There has been a trend for the past few years of companies slowly realizing that
11the pandemic is not just a temporary state that will go away eventually and let
12everything return to the way it was before. In terms of business and employment,
13this means that more and more jobs are being offered as permanently remote
14roles.
1515
1616I 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
18development field. However, I have found that almost all roles being
19sent to me via recruiters are permanently remote (although most are
20limited to US citizens or even region-locked for companies who only
21operate in select states).
17especially since I did not want to move over into the software development
18field. However, I have found that almost all roles being sent to me via
19recruiters are permanently remote (although most are limited to US citizens or
20even region-locked for companies who only operate in select states).
2221
23I decided to take a look back at my relatively short career so far and
24compare the positive and negative effects of the different work
25environments I\'ve been in.
22I decided to take a look back at my relatively short career so far and compare
23the positive and negative effects of the different work environments I've been
24in.
2625
2726# In-Person Offices
2827
2928## Retail Internship
3029
31I started my first job as a management intern at a busy retail pharmacy,
32working my 40-hour weeks on my feet. As these retail stores don\'t
33believe in resting or sitting down, you can guarantee that you will
34spend entire shifts standing, walking, or running around the store.
35Unfortunately, I worked at a time when our store didn\'t have enough
36managers, so I spent the majority of my tenure at the store running and
37breaking a sweat.
38
39Now, things aren\'t all bad in retail stores like this. It is definitely
40tiring and inefficient to force employees to work constantly, or pretend
41to work if there\'s nothing to do, and not allow anyone to sit down.
42However, if you are able to operate a retail store with a limited crew
43and provide enough comfort and support, I believe these jobs could be
44both comfortable and efficient.
30I started my first job as a management intern at a busy retail pharmacy, working
31my 40-hour weeks on my feet. As these retail stores don't believe in resting or
32sitting down, you can guarantee that you will spend entire shifts standing,
33walking, or running around the store. Unfortunately, I worked at a time when our
34store didn't have enough managers, so I spent the majority of my tenure at the
35store running and breaking a sweat.
36
37Now, things aren't all bad in retail stores like this. It is definitely tiring
38and inefficient to force employees to work constantly, or pretend to work if
39there's nothing to do, and not allow anyone to sit down. However, if you are
40able to operate a retail store with a limited crew and provide enough comfort
41and support, I believe these jobs could be both comfortable and efficient.
4542
4643## Semi-Private Cubicles
4744
4845![Semi-Private
4946Cubicles](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/private_cubicles.png)
5047
51After about a year, I was able to find another internship - this time,
52it was in my field of interest: internal auditing. This was for a life
53insurance company that was well over 100 years old. The age of the
54company shows if you work there, as most people in management are well
55into their 40s-60s with little to no youthful leadership in the company.
56Likewise, they owned a large headquarters in a nice area of town with
57plenty of space, parking, etc.
58
59One upside is that each person gets their own large L-shaped desk,
60formed into cubicles that house 4 desks/employees. These \"pods\" of
614-person cubicles are linked throughout each floor of the headquarters
62(except the sales people, who had that open-floor concept going on). The
63walls of the cubicle were tall and provided a lot of privacy and
64sound-proofing, except when I used the standing desk feature (I\'m over
656 feet tall, so probably not an issue for most people).
48After about a year, I was able to find another internship - this time, it was in
49my field of interest: internal auditing. This was for a life insurance company
50that was well over 100 years old. The age of the company shows if you work
51there, as most people in management are well into their 40s-60s with little to
52no youthful leadership in the company. Likewise, they owned a large headquarters
53in a nice area of town with plenty of space, parking, etc.
54
55One upside is that each person gets their own large L-shaped desk, formed into
56cubicles that house 4 desks/employees. These "pods" of 4-person cubicles are
57linked throughout each floor of the headquarters (except the sales people, who
58had that open-floor concept going on). The walls of the cubicle were tall and
59provided a lot of privacy and sound-proofing, except when I used the standing
60desk feature (I'm over 6 feet tall, so probably not an issue for most people).
6661
6762I 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
69chair and chat with my friends without leaving my chair. This is the
70closest I\'ve been to a home office environment (which is my personal
71favorite, as I\'ll get to later in this post).
63distractions, but also allowed easy access, so I could spin around in my chair
64and chat with my friends without leaving my chair. This is the closest I've
65been to a home office environment (which is my personal favorite, as I'll get
66to later in this post).
7267
7368## Semi-Open Floor Concept
7469
7570![Semi-Open Floor
7671Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/semi_open_office.png)
7772
78When I shifted to my first full-time internal audit job out of college,
79I was working at a company that was headquartered on a floor in a
80downtown high-rise building. The company was only about 20 years old
81when I worked there and were trying a lot of new things to attract young
82talent, one of which was a semi-open floor concept for the office. My
83department worked just around the hallway corner from the executive
84offices and used that \"modern\" layout young tech companies started
85using in the 2000s/2010s.
86
87Each desk was brief, and you could look most coworkers in the face
88without moving from your chair, I hated this so much. Directly to my
89left was the Chief Audit Executive (our department\'s leading boss), and
90his desk was pointed so that his face would stare straight at my desk
91all day. I spent more time thinking about who was looking at me or
92checking on me than actually working.
93
94The other annoying part of the open concept they used was that the
95kitchen area and pathways were too close to everyone\'s desks (since the
96desks were spread out, to provide space or something), so noise and
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.
73When I shifted to my first full-time internal audit job out of college, I was
74working at a company that was headquartered on a floor in a downtown high-rise
75building. The company was only about 20 years old when I worked there and were
76trying a lot of new things to attract young talent, one of which was a semi-open
77floor concept for the office. My department worked just around the hallway
78corner from the executive offices and used that "modern" layout young tech
79companies started using in the 2000s/2010s.
80
81Each desk was brief, and you could look most coworkers in the face without
82moving from your chair, I hated this so much. Directly to my left was the Chief
83Audit Executive (our department's leading boss), and his desk was pointed so
84that his face would stare straight at my desk all day. I spent more time
85thinking about who was looking at me or checking on me than actually working.
86
87The other annoying part of the open concept they used was that the kitchen area
88and pathways were too close to everyone's desks (since the desks were spread
89out, to provide space or something), so noise and conversation would be constant
90throughout the day while you try to work. For someone like me, who needs silence
91to get work done, that was a non-starter.
10092
10193## Hotel Office Concept
10294
10395![Hotel Office
10496Concept](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/hotel_desks.png)
10597
106I currently work for a company remotely (for now) and travel to the
107office every once in a while for events and to help coach the staff
108underneath me. The office I visit uses the hotel desk concept, where you
109need to check in at a touch screen when you enter the office and
110\"rent\" a desk for the day. The same goes for offices and meeting
111rooms.
112
113These desks are flat-top only and do not have any walls at all. In
114addition, they\'re stacked with one row of 4 desks facing another row of
1154 desks. These pairs of desk rows are repeated through the office.
116
117This means that when I go, I need to rent a random desk or try to
118remember the unique ID numbers on desks I like. Once I rent it, I have
119to make sure no one sat down in that desk without renting it. Then, I
120can sit down and work, but will probably need to adjust the monitors so
121that I\'m not staring in the face of the person across from me all day.
122Finally, I need to wear headphones as this environment does nothing to
123provide you with peace or quiet.
124
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.
98I currently work for a company remotely (for now) and travel to the office every
99once in a while for events and to help coach the staff underneath me. The office
100I visit uses the hotel desk concept, where you need to check in at a touch
101screen when you enter the office and "rent" a desk for the day. The same goes
102for offices and meeting rooms.
103
104These desks are flat-top only and do not have any walls at all. In addition,
105they're stacked with one row of 4 desks facing another row of 4 desks. These
106pairs of desk rows are repeated through the office.
107
108This means that when I go, I need to rent a random desk or try to remember the
109unique ID numbers on desks I like. Once I rent it, I have to make sure no one
110sat down in that desk without renting it. Then, I can sit down and work, but
111will probably need to adjust the monitors so that I'm not staring in the face
112of the person across from me all day. Finally, I need to wear headphones as this
113environment does nothing to provide you with peace or quiet.
114
115Luckily, you can rent offices with doors that offer quiet and privacy, which can
116be very nice if you have a lot of meetings or webinars on a certain day.
128117
129118# Home Office
130119
131120![Home
132121Office](https://img.cleberg.net/blog/20220210-leaving-office-based-work-in-the-past/home_office.png)
133122
134Okay, now let\'s finally get to the home office concept. I have worked
135from home for a little over two years at this point, across three
136different jobs/employers. Over this time, I have experimented with a
137plethora of different organizational ideas, desks, and room layouts to
138find what works best for me.
123Okay, now let's finally get to the home office concept. I have worked from home
124for a little over two years at this point, across three different
125jobs/employers. Over this time, I have experimented with a plethora of different
126organizational ideas, desks, and room layouts to find what works best for me.
139127
140These things might not apply to you, and that\'s fine. Everyone has a
141different situation, and I really don\'t think you\'ll know what works
142until you try.
128These things might not apply to you, and that's fine. Everyone has a different
129situation, and I really don't think you'll know what works until you try.
143130
144131## Tip #1
145132
146Let\'s start with my top rule for a home office:
133Let's start with my top rule for a home office:
147134
148135> If you live with others, working in a shared space is not effective.
149136
150It just does not work. If you have another person sleeping in your
151bedroom, it is difficult to manage your work schedule with their
152sleeping/work/school schedule. If they wake up after you need to start
153work, you might wake them up or have to suffer the agony of staring at
154bright screens in a dark room.
137It just does not work. If you have another person sleeping in your bedroom, it
138is difficult to manage your work schedule with their sleeping/work/school
139schedule. If they wake up after you need to start work, you might wake them up
140or have to suffer the agony of staring at bright screens in a dark room.
155141
156In a similar vein, working from a location such as the living room
157likely won\'t work either. Distractions will come far more frequently:
158televisions, cooking, cleaning, deliveries, etc. If you\'re like me,
159you\'ll end up playing a game instead of actually doing any work.
142In a similar vein, working from a location such as the living room likely won't
143work either. Distractions will come far more frequently: televisions, cooking,
144cleaning, deliveries, etc. If you're like me, you'll end up playing a game
145instead of actually doing any work.
160146
161147## Tip #2
162148
163Okay, the second thing I\'ve discovered that works for me:
149Okay, the second thing I've discovered that works for me:
164150
165> Use the pomodoro method (or something similar) to balance work tasks
166> with personal tasks.
151> Use the pomodoro method (or something similar) to balance work tasks with
152> personal tasks.
167153
168I use a very casual version of the pomodoro method where I will work for
1691-2 hours (usually set in strict intervals like 1, 1.5, 2 hours) and
170then will allow myself 30-60 minutes for personal tasks. This schedule
171works for me, since my work schedule really only comes to 3-6 hours of
172work per day.
154I use a very casual version of the pomodoro method where I will work for 1-2
155hours (usually set in strict intervals like 1, 1.5, 2 hours) and then will allow
156myself 30-60 minutes for personal tasks. This schedule works for me, since my
157work schedule really only comes to 3-6 hours of work per day.
173158
174In this case, I\'ll work through my list of tasks for an hour or two and
175then give myself personal time to get drinks and food, wash dishes, put
176clothes in the washer, get the mail, etc. If you\'re in a convenient
177location, this usually gives time for things like getting groceries (as
178long as you\'re not a slow shopper).
159In this case, I'll work through my list of tasks for an hour or two and then
160give myself personal time to get drinks and food, wash dishes, put clothes in
161the washer, get the mail, etc. If you're in a convenient location, this usually
162gives time for things like getting groceries (as long as you're not a slow
163shopper).
179164
180165## Tip #3
181166
182While I listed this one as number three, I don\'t think I\'d accomplish
183anything without it:
167While I listed this one as number three, I don't think I'd accomplish anything
168without it:
184169
185> Document everything: even things you didn\'t before - such as task
186> lists and notes from casual calls or meetings.
170> Document everything: even things you didn't before - such as task lists and
171> notes from casual calls or meetings.
187172
188I\'ve noticed that staying in an office gave me more constant reminders
189of outstanding tasks or facts I had learned in a conversation.
190Translating everything to a digital world has made me lose a bit of that
191focus (perhaps since I don\'t have visual reminders?).
173I've noticed that staying in an office gave me more constant reminders of
174outstanding tasks or facts I had learned in a conversation. Translating
175everything to a digital world has made me lose a bit of that focus (perhaps
176since I don't have visual reminders?).
192177
193Keeping a running task list of all things I have to do - even potential
194tasks! - has helped me keep up without missing anything small. Likewise,
195keeping notes for ALL meetings and calls, no matter how casual/quick,
196has improved my retention immensely. Beyond helping my mental
197recollection, it has saved me numerous times when I need to do a keyword
198search for some topic that was discussed 6+ months ago.
178Keeping a running task list of all things I have to do - even potential tasks! -
179has helped me keep up without missing anything small. Likewise, keeping notes
180for ALL meetings and calls, no matter how casual/quick, has improved my
181retention immensely. Beyond helping my mental recollection, it has saved me
182numerous times when I need to do a keyword search for some topic that was
183discussed 6+ months ago.
199184
200185## Tip #4
201186
@@ -203,39 +188,35 @@ Okay, last one for now.
203188
204189> Keep your work area clean.
205190
206This one is straightforward, but I know some people struggle with
207cleanliness or may not believe it makes a difference. Trust me, keeping
208your desk area clean and organized makes a huge difference, both
209mentally and emotionally.
191This one is straightforward, but I know some people struggle with cleanliness or
192may not believe it makes a difference. Trust me, keeping your desk area clean
193and organized makes a huge difference, both mentally and emotionally.
210194
211Just think about it, you walk into your home office and see a clean desk
212with a laptop, dock, monitors, keyboard, mouse, and a notepad with a pen
213on top.
195Just think about it, you walk into your home office and see a clean desk with a
196laptop, dock, monitors, keyboard, mouse, and a notepad with a pen on top.
214197
215Now imagine the opposite, there\'s an office with the same equipment,
216but there are clothes hanging on the chair, empty drink bottles, candy
217wrappers and dirty plates. This can take both a mental and emotional
218toll by bringing constant disarray and stress into your working
219environment.
198Now imagine the opposite, there's an office with the same equipment, but there
199are clothes hanging on the chair, empty drink bottles, candy wrappers and dirty
200plates. This can take both a mental and emotional toll by bringing constant
201disarray and stress into your working environment.
220202
221Just keep things clean each day, and you won\'t need to do any big
222cleaning days to recover.
203Just keep things clean each day, and you won't need to do any big cleaning days
204to recover.
223205
224206# My Preferences
225207
226I\'ve talked about the different environments I\'ve worked in and
227expressed some honest thoughts on pros or cons to each, but what do I
228prefer? Well, if you\'re reading along, you should be able to tell that
229I much prefer a home office above all else.
208I've talked about the different environments I've worked in and expressed some
209honest thoughts on pros or cons to each, but what do I prefer? Well, if you're
210reading along, you should be able to tell that I much prefer a home office above
211all else.
230212
231Being able to control my own day and allot my time as needed has brought
232a calmness to my life and has allowed me to maximize each day. I feel
233far more effective and efficient in a home office than any other office,
234especially open-office layouts.
213Being able to control my own day and allot my time as needed has brought a
214calmness to my life and has allowed me to maximize each day. I feel far more
215effective and efficient in a home office than any other office, especially
216open-office layouts.
235217
236If I do need to return to an office part-time in the future, I really
237hope the office will have privacy and quietness in order for me to get
238my work done.
218If I do need to return to an office part-time in the future, I really hope the
219office will have privacy and quietness in order for me to get my work done.
239220
240221Cubicles are good! I agree with Alice (from the comic Dilbert):
241222
content/blog/2022-02-10-njalla-dns-api.md +47 −56
@@ -5,48 +5,46 @@ description = ""
55draft = false
66+++
77
8# Njalla\'s API
8# Njalla's API
99
1010As noted in my recent post about [switching to Njalla from
11Cloudflare](file:///blog/ditching-cloudflare/), I was searching for a
12way to replace my very easy-to-use bash script to [update Cloudflare\'s
13DNS via their API](file:///blog/cloudflare-dns-api/).
11Cloudflare](file:///blog/ditching-cloudflare/), I was searching for a way to
12replace my very easy-to-use bash script to [update Cloudflare's DNS via their
13API](file:///blog/cloudflare-dns-api/).
1414
15To reiterate what I said in those posts, this is a common necessity for
16those of us who have non-static IP addresses that can change at any
17moment due to ISP policy.
15To reiterate what I said in those posts, this is a common necessity for those of
16us who have non-static IP addresses that can change at any moment due to ISP
17policy.
1818
19In order to keep a home server running smoothly, the server admin needs
20to have a process to constantly monitor their public IP address and
21update their domain\'s DNS records if it changes.
19In order to keep a home server running smoothly, the server admin needs to have
20a process to constantly monitor their public IP address and update their
21domain's DNS records if it changes.
2222
23This post explains how to use Python to update Njalla\'s DNS records
24whenever a machine\'s public IP address changes.
23This post explains how to use Python to update Njalla's DNS records whenever a
24machine's public IP address changes.
2525
2626## Creating a Token
2727
28To use Njalla\'s API, you will first need to create a token that will be
29used to authenticate you every time you call the API. Luckily, this is
30very easy to do if you have an account with Njalla.
28To use Njalla's API, you will first need to create a token that will be used to
29authenticate you every time you call the API. Luckily, this is very easy to do
30if you have an account with Njalla.
3131
32Simply go the [API Settings](https://njal.la/settings/api/) page and
33click the `Add Token` button. Next, enter a name for the
34token and click `Add`.
32Simply go the [API Settings](https://njal.la/settings/api/) page and click the
33`Add Token` button. Next, enter a name for the token and click `Add`.
3534
36Finally, click the `Manage` button next to your newly created
37token and copy the `API Token` field.
35Finally, click the `Manage` button next to your newly created token and copy the
36`API Token` field.
3837
3938## Finding the Correct API Request
4039
41Once you have a token, you\'re ready to call the Njalla API for any
42number of requests. For a full listing of available requests, see the
43[Njalla API Documentation](https://njal.la/api/).
40Once you have a token, you're ready to call the Njalla API for any number of
41requests. For a full listing of available requests, see the [Njalla API
42Documentation](https://njal.la/api/).
4443
45For this demo, we are using the `list-records` and
46`edit-record` requests.
44For this demo, we are using the `list-records` and `edit-record` requests.
4745
48The `list-records` request requires the following payload to
49be sent when calling the API:
46The `list-records` request requires the following payload to be sent when
47calling the API:
5048
5149``` txt
5250params: {
@@ -54,8 +52,8 @@ params: {
5452}
5553```
5654
57The `edit-record` request requires the following payload to
58be sent when calling the API:
55The `edit-record` request requires the following payload to be sent when calling
56the API:
5957
6058``` txt
6159params: {
@@ -67,14 +65,14 @@ params: {
6765
6866# Server Set-Up
6967
70To create this script, we will be using Python. By default, I use Python
713 on my servers, so please note that I did not test this in Python 2,
72and I do not know if Python 2 will work for this.
68To create this script, we will be using Python. By default, I use Python 3 on my
69servers, so please note that I did not test this in Python 2, and I do not know
70if Python 2 will work for this.
7371
7472## Creating the Script
7573
76First, find a suitable place to create your script. Personally, I just
77create a directory called `ddns` in my home directory:
74First, find a suitable place to create your script. Personally, I just create a
75directory called `ddns` in my home directory:
7876
7977```sh
8078mkdir ~/ddns
@@ -86,23 +84,17 @@ Next, create a Python script file:
8684nano ~/ddns/ddns.py
8785```
8886
89The following code snippet is quite long, so I won\'t go into depth on
90each part. However, I suggest you read through the entire script before
91running it; it is quite simple and contains comments to help explain
92each code block.
87The following code snippet is quite long, so I won't go into depth on each
88part. However, I suggest you read through the entire script before running it;
89it is quite simple and contains comments to help explain each code block.
9390
94:warning: **Note**: You will need to update the following variables for
95this to work:
91:warning: **Note**: You will need to update the following variables for this to
92work:
9693
97- `token`: This is the Njalla API token you created
98 earlier.
99- `user_domain`: This is the top-level domain you want to
100 modify.
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.
94- `token`: This is the Njalla API token you created earlier.
95- `user_domain`: This is the top-level domain you want to modify.
96- `include_subdomains`: Set this to `True` if you also want to modify subdomains found under the TLD.
97- `subdomains`: If `include_subdomains` = `True`, you can include your list of subdomains to be modified here.
10698
10799``` python
108100#!/usr/bin/python
@@ -187,8 +179,8 @@ for record in data['records']:
187179
188180## Running the Script
189181
190Once you\'ve created the script and are ready to test it, run the
191following command:
182Once you've created the script and are ready to test it, run the following
183command:
192184
193185```sh
194186python3 ~/ddns/ddns.py
@@ -196,16 +188,15 @@ python3 ~/ddns/ddns.py
196188
197189## Setting the Script to Run Automatically
198190
199To make sure the scripts run automatically, add it to the
200`cron` file so that it will run on a schedule. To do this,
201open the `cron` file:
191To make sure the scripts run automatically, add it to the `cron` file so that it
192will run on a schedule. To do this, open the `cron` file:
202193
203194```sh
204195crontab -e
205196```
206197
207In the cron file, paste the following at the bottom of the editor in
208order to check the IP every five minutes:
198In the cron file, paste the following at the bottom of the editor in order to
199check the IP every five minutes:
209200
210201```sh
211202*/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
1010![Debian +
1111neofetch](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/neofetch.png)
1212
13I\'ve used various Linux distributions throughout the years, but I\'ve
14never used anything except Ubuntu for my servers. Why? I really have no
15idea, mostly just comfort around the commands and software availability.
16
17However, I have always wanted to try Debian as a server OS after testing
18it out in a VM a few years ago (side-note: I\'d love to try Alpine too,
19but I always struggle with compatibility). So, I decided to launch a new
20VPS and use [Debian](https://www.debian.org) 11 as the OS. Spoiler
21alert: it feels identical to Ubuntu for my purposes.
22
23I did the normal things when first launching the VPS, such as adding a
24new user, locking down SSH, etc. If you want to see that level of
25detail, read my other post about [How to Set Up a VPS Web
13I've used various Linux distributions throughout the years, but I've never
14used anything except Ubuntu for my servers. Why? I really have no idea, mostly
15just comfort around the commands and software availability.
16
17However, I have always wanted to try Debian as a server OS after testing it out
18in a VM a few years ago (side-note: I'd love to try Alpine too, but I always
19struggle with compatibility). So, I decided to launch a new VPS and use
20[Debian](https://www.debian.org) 11 as the OS. Spoiler alert: it feels identical
21to Ubuntu for my purposes.
22
23I did the normal things when first launching the VPS, such as adding a new user,
24locking down SSH, etc. If you want to see that level of detail, read my other
25post about [How to Set Up a VPS Web
2626Server](https://cleberg.net/blog/how-to-set-up-a-vps-web-server/).
2727
28All of this has been similar, apart from small things such as the
29location of users\' home folders. No complaints at all from me - Debian
30seems great.
28All of this has been similar, apart from small things such as the location of
29users' home folders. No complaints at all from me - Debian seems great.
3130
3231# Web Server: Nginx
3332
3433![Nginx
3534status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/nginx.png)
3635
37Once I had the baseline server configuration set-up for Debian, I moved
38on to trying out [Nginx](https://nginx.org) as my web server software.
39This required me to install the `nginx` and `ufw`
40packages, as well as setting up the initial UFW config:
36Once I had the baseline server configuration set-up for Debian, I moved on to
37trying out [Nginx](https://nginx.org) as my web server software. This required
38me to install the `nginx` and `ufw` packages, as well as setting up the initial
39UFW config:
4140
4241```sh
4342sudo apt install nginx ufw
@@ -48,9 +47,9 @@ sudo ufw status
4847sudo systemctl status nginx
4948```
5049
51Once I had the firewall set, I moved on to creating the directories and
52files for my website. This is very easy and is basically the same as
53setting up an Apache server, so no struggles here.
50Once I had the firewall set, I moved on to creating the directories and files
51for my website. This is very easy and is basically the same as setting up an
52Apache server, so no struggles here.
5453
5554```sh
5655sudo mkdir -p /var/www/your_domain/html
@@ -59,10 +58,9 @@ sudo chmod -R 755 /var/www/your_domain
5958nano /var/www/your_domain/html/index.html
6059```
6160
62The next part, creating the Nginx configuration files, is quite a bit
63different from Apache. First, you need to create the files in the
64`sites-available` folder and symlink it the
65`sites-enabled` folder.
61The next part, creating the Nginx configuration files, is quite a bit different
62from Apache. First, you need to create the files in the `sites-available` folder
63and symlink it the `sites-enabled` folder.
6664
6765Creating the config file for your domain:
6866
@@ -95,11 +93,10 @@ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
9593```
9694
9795This will make your site available to the public (as long as you have
98`your_domain` DNS records pointed at the server\'s IP
99address)!
96`your_domain` DNS records pointed at the server's IP address)!
10097
101Next, I used [certbot](https://certbot.eff.org/) to issue an HTTPS
102certificate for my domains using the following commands:
98Next, I used [certbot](https://certbot.eff.org/) to issue an HTTPS certificate
99for my domains using the following commands:
103100
104101```sh
105102sudo apt install snapd; sudo snap install core; sudo snap refresh core
@@ -108,17 +105,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
108105sudo certbot --nginx
109106```
110107
111Now that certbot ran successfully and updated my Nginx config files to
112include a `443` server block of code, I went back in and
113edited the config file to include security HTTP headers. This part is
114optional, but is recommended for security purposes; you can even test a
115website\'s HTTP header security at [Security
108Now that certbot ran successfully and updated my Nginx config files to include a
109`443` server block of code, I went back in and edited the config file to include
110security HTTP headers. This part is optional, but is recommended for security
111purposes; you can even test a website's HTTP header security at [Security
116112Headers](https://securityheaders.com/).
117113
118The configuration below shows a set-up where you only want your website
119to serve content from its own domain, except for images and scripts,
120which may come from `nullitics.com`. All other content would
121be blocked from loading in a browser.
114The configuration below shows a set-up where you only want your website to serve
115content from its own domain, except for images and scripts, which may come from
116`nullitics.com`. All other content would be blocked from loading in a browser.
122117
123118```sh
124119sudo nano /etc/nginx/sites-available/your_domain
@@ -143,39 +138,36 @@ sudo systemctl restart nginx
143138
144139## Nginx vs. Apache
145140
146As I stated at the beginning, my historical hesitation with trying Nginx
147was that the differences in configuration formats scared me away from
148leaving Apache. However, I prefer Nginx to Apache for a few reasons:
149
1501. Nginx uses only one config file (`your_domain`) vs.
151 Apache\'s two-file approach for HTTP vs. HTTPS
152 (`your_domain.conf` and
153 `your_domain-le-ssl.conf`).
1542. Symlinking new configurations files and reloading Nginx are way
155 easier than Apache\'s process of having to enable headers with
156 `a2enmod mod_headers`, enable PHP with
157 `a2enmod php` (plus any other mods you need), and then
158 enabling sites with `a2ensite`, and THEN reloading
159 Apache.
1603. The contents of the Nginx config files seem more organized and
161 logical with the curly-bracket approach. This is a minor reason, but
162 everything just felt cleaner while I was installing my sites and
163 that had a big quality of life impact on the installation for me.
164
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.
141As I stated at the beginning, my historical hesitation with trying Nginx was
142that the differences in configuration formats scared me away from leaving
143Apache. However, I prefer Nginx to Apache for a few reasons:
144
1451. Nginx uses only one config file (`your_domain`) vs. Apache's two-file
146 approach for HTTP vs. HTTPS (`your_domain.conf` and
147 `your_domain-le-ssl.conf`).
1482. Symlinking new configurations files and reloading Nginx are way easier than
149 Apache's process of having to enable headers with `a2enmod mod_headers`,
150 enable PHP with `a2enmod php` (plus any other mods you need), and then
151 enabling sites with `a2ensite`, and THEN reloading Apache.
1523. The contents of the Nginx config files seem more organized and logical with
153 the curly-bracket approach. This is a minor reason, but everything just felt
154 cleaner while I was installing my sites and that had a big quality of life
155 impact on the installation for me.
156
157They're both great software packages, but Nginx just seems more organized and
158easier to use these days. I will certainly be exploring the Nginx docs to see
159what other fun things I can do with all of this.
168160
169161# Gemini Server: Agate
170162
171163![Agate
172164status](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/agate.png)
173165
174Finally, I set up the Agate software on this server again to host my
175Gemini server content, using Rust as I have before. You can read my
176other post for more information on installing Agate: [Hosting a Gemini
166Finally, I set up the Agate software on this server again to host my Gemini
167server content, using Rust as I have before. You can read my other post for more
168information on installing Agate: [Hosting a Gemini
177169Server](https://cleberg.net/blog/hosting-a-gemini-server/).
178170
179All in all, Debian + Nginx is very slick and I prefer it over my old
180combination of Ubuntu + Apache (although it\'s really just Nginx \>
181Apache for me, since Debian seems mostly the same as Ubuntu is so far).
171All in all, Debian + Nginx is very slick and I prefer it over my old combination
172of Ubuntu + Apache (although it's really just Nginx > Apache for me, since
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
77
88## Why Strip Metadata?
99
10Okay, so you want to strip metadata from your photos. Perhaps you take
11pictures of very rare birds, and the location metadata is a gold mine
12for poachers, or perhaps you\'re just privacy-oriented like me and
13prefer to strip metadata from publicly-available images.
10Okay, so you want to strip metadata from your photos. Perhaps you take pictures
11of very rare birds, and the location metadata is a gold mine for poachers, or
12perhaps you're just privacy-oriented like me and prefer to strip metadata from
13publicly-available images.
1414
15There are various components of image metadata that you may want to
16delete before releasing a photo to the public. Here\'s an incomplete
17list of things I could easily see just by inspecting a photo on my
18laptop:
15There are various components of image metadata that you may want to delete
16before releasing a photo to the public. Here's an incomplete list of things I
17could easily see just by inspecting a photo on my laptop:
1918
20- Location (Latitude & Longitude)
21- Dimensions
22- Device Make & Model
23- Color Space
24- Color Profile
25- Focal Length
26- Alpha Channel
27- Red Eye
28- Metering Mode
29- F Number
19- Location (Latitude & Longitude)
20- Dimensions
21- Device Make & Model
22- Color Space
23- Color Profile
24- Focal Length
25- Alpha Channel
26- Red Eye
27- Metering Mode
28- F Number
3029
31Regardless of your reasoning, I\'m going to explain how I used the
32`exiftool` package in Linux to automatically strip metadata
33from all images in a directory (+ subdirectories).
30Regardless of your reasoning, I'm going to explain how I used the `exiftool`
31package in Linux to automatically strip metadata from all images in a directory
32(+ subdirectories).
3433
3534## Installing `exiftool`
3635
37First things first: we need to install the tool. I\'m running Debian 11
38on my server (Ubuntu will work the same), so the command is as simple
39as:
36First things first: we need to install the tool. I'm running Debian 11 on my
37server (Ubuntu will work the same), so the command is as simple as:
4038
4139```sh
4240sudo apt install exiftool
@@ -47,22 +45,20 @@ distributions, but I really only care to test out this one package.
4745
4846## Recursively Strip Data
4947
50I actually use this tool extensively to strip any photos uploaded to the
51website that serves all the images for my blog
52(`img.cleberg.net`).
48I actually use this tool extensively to strip any photos uploaded to the website
49that serves all the images for my blog (`img.cleberg.net`).
5350
54The following command is incredibly useful and can be modified to
55include any image extensions that `exiftool` supports:
51The following command is incredibly useful and can be modified to include any
52image extensions that `exiftool` supports:
5653
5754```sh
5855exiftool -r -all= -ext jpg -ext png /path/to/directory/
5956```
6057
61See below for the results of my most recent usage of
62`exiftool` after I uploaded the image for this blog post. You
63can see that the command will let you know how many directories were
64scanned, how many images were updated, and how many images were
65unchanged.
58See below for the results of my most recent usage of `exiftool` after I uploaded
59the image for this blog post. You can see that the command will let you know how
60many directories were scanned, how many images were updated, and how many images
61were unchanged.
6662
6763![exiftool
6864results](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
77
88# Update Your Nginx Config to Cache Static Files
99
10If you run a website on Nginx that serves static content (i.e., content
11that is not dynamic and changing with interactions from the user), you
12would likely benefit from caching that content on the client-side. If
13you\'re used to Apache and looking for the Nginx equivalent, this post
14should help.
10If you run a website on Nginx that serves static content (i.e., content that is
11not dynamic and changing with interactions from the user), you would likely
12benefit from caching that content on the client-side. If you're used to Apache
13and looking for the Nginx equivalent, this post should help.
1514
16Luckily, setting up the cache is as easy as identifying the file types
17you want to cache and determining the expiration length. To include more
18file types, simply use the bar separator (`|`) and type the
19new file extension you want to include.
15Luckily, setting up the cache is as easy as identifying the file types you want
16to cache and determining the expiration length. To include more file types,
17simply use the bar separator (`|`) and type the new file extension you want to
18include.
2019
2120``` config
2221server {
@@ -30,44 +29,40 @@ server {
3029}
3130```
3231
33I have seen some people who prefer to set `expires` as
34`365d` or even `max`, but that is only for stable,
35infrequently changing websites. As my site often changes (i.e., I\'m
36never content with my website), I need to know that my readers are
37seeing the new content without waiting too long.
32I have seen some people who prefer to set `expires` as `365d` or even `max`, but
33that is only for stable, infrequently changing websites. As my site often
34changes (i.e., I'm never content with my website), I need to know that my
35readers are seeing the new content without waiting too long.
3836
39So, I went ahead and set the expiration date at `30d`, which
40is short enough to refresh for readers but long enough that
41clients/browsers won\'t be re-requesting the static files too often,
42hopefully resulting in faster loading times, as images should be the
43only thing slowing down my site.
37So, I went ahead and set the expiration date at `30d`, which is short enough to
38refresh for readers but long enough that clients/browsers won't be
39re-requesting the static files too often, hopefully resulting in faster loading
40times, as images should be the only thing slowing down my site.
4441
4542# Testing Results
4643
4744To test my changes to the Nginx configuration, I used the [HTTP Header
4845Live](https://addons.mozilla.org/en-US/firefox/addon/http-header-live/)
49extension on my Gecko browser and used the sidebar to inspect the
50headers of a recent image from my blog.
46extension on my Gecko browser and used the sidebar to inspect the headers of a
47recent image from my blog.
5148
52In the image below, you can see that the `Cache-Control`
53header is now present and set to 2592000, which is 30 days represented
54in seconds (30 days \_ 24 hours/day \_ 60 minutes/hour \*\* 60
55seconds/minute = 2,592,000 seconds).
49In the image below, you can see that the `Cache-Control` header is now present
50and set to 2592000, which is 30 days represented in seconds (30 days \_ 24
51hours/day \_ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds).
5652
57The `Expires` field is now showing 22 March 2022, which is 30
58days from the day of this post, 20 February 2022.
53The `Expires` field is now showing 22 March 2022, which is 30 days from the day
54of this post, 20 February 2022.
5955
6056![Image
6157Headers](https://img.cleberg.net/blog/20220220-caching-static-content-with-nginx/image_headers.png)
6258
6359# Caveats
6460
65Remember that this caching system is **client-side**, which means that
66content is only cached for as long as a client allows it. For example,
67my browser purges all caches, data, etc. upon exit, so this caching
68policy will only work as long as my browser remains open and running.
61Remember that this caching system is **client-side**, which means that content
62is only cached for as long as a client allows it. For example, my browser purges
63all caches, data, etc. upon exit, so this caching policy will only work as long
64as my browser remains open and running.
6965
70If you need to test updates to your site, you\'ll need to clear the
71cache to see updates for any file extension you configured. This can
72often be done with the `Shift + F5` or `Ctrl + F5`
73key combinations in most browsers.
66If you need to test updates to your site, you'll need to clear the cache to see
67updates for any file extension you configured. This can often be done with the
68`Shift + F5` or `Ctrl + F5` key combinations in most browsers.
content/blog/2022-02-22-tuesday.md +23 −30
@@ -7,36 +7,29 @@ draft = false
77
88# Tuesday, Twosday
99
10I\'m taking a break from my usual technology-related posts and writing
11about something a little more enjoyable today.
10I'm taking a break from my usual technology-related posts and writing about
11something a little more enjoyable today.
1212
13Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is
14Twosday.
13Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is Twosday.
1514
16Let\'s look at everything that fell in place today:
15Let's look at everything that fell in place today:
1716
181. Written in the `m-dd-yy` or `dd-m-yy` formats,
19 today is 2-22-22 or 22-2-22, which is a neat little palindrome in
20 either format. (The last ubiquitous six-digit palindrome was
21 1-11-11.)
222. Today is Tuesday, which is why everyone is using the nickname
23 Twosday to call out these similarities.
243. Falling on Tuesday means today is the 2nd day of the week (for most
25 cultures. For the US, it\'s the 3rd day of the week since we start
26 on Sunday).
274. The only culture I could find with a connection to a `2`
28 is that some Slavic languages derived their version of Tuesday from
29 the Old Church Slavonic word `въторъ`, meaning \"the
30 second.\"
315. Written in the classic monospaced, digital font (think of digital
32 clocks from the 80s/90s), there is nice symmetry to the numbers
33 ([view the image
34 here](https://img.cleberg.net/blog/20220222-tuesday/digital_font.png)!).
356. This one isn\'t naturally-occurring, but it seems people around the
36 world are celebrating the day. For example, a group is putting
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.
171. Written in the `m-dd-yy` or `dd-m-yy` formats, today is 2-22-22 or 22-2-22,
18 which is a neat little palindrome in either format. (The last ubiquitous
19 six-digit palindrome was 1-11-11.)
202. Today is Tuesday, which is why everyone is using the nickname Twosday to call
21 out these similarities.
223. Falling on Tuesday means today is the 2nd day of the week (for most cultures.
23 For the US, it's the 3rd day of the week since we start on Sunday).
244. The only culture I could find with a connection to a `2` is that some Slavic
25 languages derived their version of Tuesday from the Old Church Slavonic word
26 `въторъ`, meaning "the second."
275. Written in the classic monospaced, digital font (think of digital clocks from
28 the 80s/90s), there is nice symmetry to the numbers ([view the image
29 here](https://img.cleberg.net/blog/20220222-tuesday/digital_font.png)!).
306. This one isn't naturally-occurring, but it seems people around the world are
31 celebrating the day. For example, a group is putting together [a wedding of
32 222 couples at the California State Capitol in
33 Sacramento](https://www.eventbrite.com/e/2-22-22-a-collective-wedding-ceremony-at-the-state-capitol-tickets-211434605597),
34 concluding at exactly 2:22 PM. These couples will record their marriage dates
35 as 2-22-22 2:22 PM. Tickets were on sale for $222.22.
content/blog/2022-03-02-reliable-notes.md +72 −83
@@ -7,132 +7,121 @@ draft = false
77
88# Choosing Durable File Formats
99
10> TL;DR: Write in a format that can be easily rendered and read in
11> plain-text mode (e.g., `.txt`, `.md`, etc.).
10> TL;DR: Write in a format that can be easily rendered and read in plain-text
11> mode (e.g., `.txt`, `.md`, etc.).
1212
13As I\'ve written more and more over the years, I\'ve found that my love
14of note-taking is always growing. Everything I learn or need to remember
15can be written down in a note and saved digitally, with no cost to
16myself. Unlike paper copies that need physical storage space, digital
17files simply need space on your local disk or cloud storage, which is
18fairly abundant these days.
13As I've written more and more over the years, I've found that my love of
14note-taking is always growing. Everything I learn or need to remember can be
15written down in a note and saved digitally, with no cost to myself. Unlike paper
16copies that need physical storage space, digital files simply need space on your
17local disk or cloud storage, which is fairly abundant these days.
1918
20However, I had a historical struggle with migration of notes between
21different apps that require different formats and applied proprietary
22styling. This meant that I had to go through each note during migration
23and edit the file to look presentable again.
19However, I had a historical struggle with migration of notes between different
20apps that require different formats and applied proprietary styling. This meant
21that I had to go through each note during migration and edit the file to look
22presentable again.
2423
2524For the last year or two, I have written everything exclusively in
2625[Markdown](https://en.wikipedia.org/wiki/Markdown) format. Small notes,
27long-form writings, and even these blog posts are all written in
28Markdown.
29
30Why Markdown? While I do appreciate the simplicity of plain-text files
31without any formatting, I often need visual cues such as heading and
32code blocks to keep my thoughts straight. Markdown provides a minimal
33set of styling indicators for me to style my notes without adding any
34proprietary, embedded data into the files. If I want a top-level
35heading, I simply add a hash (`#`) before the line. An added
36bonus is that even if a system doesn\'t understand Markdown, it will
26long-form writings, and even these blog posts are all written in Markdown.
27
28Why Markdown? While I do appreciate the simplicity of plain-text files without
29any formatting, I often need visual cues such as heading and code blocks to keep
30my thoughts straight. Markdown provides a minimal set of styling indicators for
31me to style my notes without adding any proprietary, embedded data into the
32files. If I want a top-level heading, I simply add a hash (`#`) before the line.
33An added bonus is that even if a system doesn't understand Markdown, it will
3734render it as plain-text and I can read it just as easily.
3835
39For example, here\'s how TextEdit on macOS will open and display a
40Markdown file in plain-text, since it does contain any features to
41preview Markdown as HTML:
36For example, here's how TextEdit on macOS will open and display a Markdown file
37in plain-text, since it does contain any features to preview Markdown as HTML:
4238
4339![Plain Text
4440Markdown](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.png)
4541
4642## Saving & Syncing Files
4743
48In order to read and edit my notes across platforms, I use my personal
49cloud storage through Tresorit due to its native integration with macOS
50and iOS file managers. In addition, Tresorit works well on Debian-based
51Linux distros, which I used before macOS (and will likely switch back to
52in a few years).
44In order to read and edit my notes across platforms, I use my personal cloud
45storage through Tresorit due to its native integration with macOS and iOS file
46managers. In addition, Tresorit works well on Debian-based Linux distros, which
47I used before macOS (and will likely switch back to in a few years).
5348
54You can use whatever sync software you want - syncing plain-text or
55markdown files is incredibly easy and fast, since the files are
56generally tiny.
49You can use whatever sync software you want - syncing plain-text or markdown
50files is incredibly easy and fast, since the files are generally tiny.
5751
58Since the cloud storage syncs files automatically, there is no need for
59me to sync anything manually or kick-off a sync job to update my files.
60This means that I can edit on mobile, and it takes about 5-10 seconds to
61see the changes on desktop.
52Since the cloud storage syncs files automatically, there is no need for me to
53sync anything manually or kick-off a sync job to update my files. This means
54that I can edit on mobile, and it takes about 5-10 seconds to see the changes on
55desktop.
6256
6357### Version Control with Git
6458
65A different approach I\'ve contemplated is storing my notes and
66attachments is using a hosted Git repository to track changes to the
67files. However, I don\'t want to rely on an external service that could
68potentially see into my data, even if the repository is private.
59A different approach I've contemplated is storing my notes and attachments is
60using a hosted Git repository to track changes to the files. However, I don't
61want to rely on an external service that could potentially see into my data,
62even if the repository is private.
6963
70I might just do `git init` locally and then commit my changes
71each time I write or update a note, but that seems to be a lot of work
72just for tracking changes - which I don\'t necessarily care to know.
64I might just do `git init` locally and then commit my changes each time I write
65or update a note, but that seems to be a lot of work just for tracking changes -
66which I don't necessarily care to know.
7367
7468### Backups!
7569
76One small addition to the storage/sync conversation is the idea of
77backups. Personally, I manually create periodic backups of my entire
78cloud storage, compress it into an archive, and store it on my home
79server.
70One small addition to the storage/sync conversation is the idea of backups.
71Personally, I manually create periodic backups of my entire cloud storage,
72compress it into an archive, and store it on my home server.
8073
81To improve my workflow, I am going to be exploring options to
82automatically compress the mounted cloud directory and send it over to
83my server on a set schedule.
74To improve my workflow, I am going to be exploring options to automatically
75compress the mounted cloud directory and send it over to my server on a set
76schedule.
8477
8578## Writing on Desktop
8679
87> **Update (06.14.22)**: Since writing this post, I have reverted to
88> simply keeping my `notes` folder open and opening notes
89> individually in TextEdit for a more minimal and relaxing writing
90> experience on the desktop.
80> **Update (06.14.22)**: Since writing this post, I have reverted to simply
81> keeping my `notes` folder open and opening notes individually in TextEdit for
82> a more minimal and relaxing writing experience on the desktop.
9183
92The bulk of my writing occurs in a desktop environment, with a full
93keyboard layout and wide screen. I don\'t illustrate with a smart pen, I
94rarely use embedded images, and I love being able to see all of my
95notes/directories in a sidebar.
84The bulk of my writing occurs in a desktop environment, with a full keyboard
85layout and wide screen. I don't illustrate with a smart pen, I rarely use
86embedded images, and I love being able to see all of my notes/directories in a
87sidebar.
9688
97With this simple set of requirements, I chose
98[Obsidian](https://obsidian.md) as my desktop text editor. Obsidian has
99some in-depth tools like a graph view, command palette, mentions, etc.,
100but I\'ve found that using it as a simple Markdown editor is incredibly
101easy and straightforward.
89With this simple set of requirements, I chose [Obsidian](https://obsidian.md) as
90my desktop text editor. Obsidian has some in-depth tools like a graph view,
91command palette, mentions, etc., but I've found that using it as a simple
92Markdown editor is incredibly easy and straightforward.
10293
103Here\'s an example of how my Markdown notes look when opened in
104plain-text mode:
94Here's an example of how my Markdown notes look when opened in plain-text mode:
10595
10696![Obsidian Markdown Source
10797Mode](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.png)
10898
109Here\'s the \"live preview\" version, where the Markdown is rendered
110into its HTML format:
99Here's the "live preview" version, where the Markdown is rendered into its
100HTML format:
111101
112102![Obsidian Markdown Live
113103Preview](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.png)
114104
115105### Programming on Desktop
116106
117While I was writing this, I realized I should specify that I don\'t use
118the same editor for writing notes and for writing code. For programming
119purposes, I use [VSCodium](https://vscodium.com) as my development IDE.
107While I was writing this, I realized I should specify that I don't use the same
108editor for writing notes and for writing code. For programming purposes, I use
109[VSCodium](https://vscodium.com) as my development IDE.
120110
121111## Writing on Mobile
122112
123Personally, I write very little on mobile, except when needing to take
124important notes on-the-go. Any long-form writing, journals, etc. are
125done at home, where I always have my laptop available.
113Personally, I write very little on mobile, except when needing to take important
114notes on-the-go. Any long-form writing, journals, etc. are done at home, where I
115always have my laptop available.
126116
127I wanted a simple and foolproof editor for iOS, preferably open-source.
128After a long journey of testing the few (& terrible) open-source iOS
129note-taking apps, I finally found a phenomenal one:
130[Runestone](https://github.com/simonbs/runestone). This app is fantastic
131for note-taking, has plenty of optional features, and integrates
132natively with the iOS file manager.
117I wanted a simple and foolproof editor for iOS, preferably open-source. After a
118long journey of testing the few (& terrible) open-source iOS note-taking apps, I
119finally found a phenomenal one:
120[Runestone](https://github.com/simonbs/runestone). This app is fantastic for
121note-taking, has plenty of optional features, and integrates natively with the
122iOS file manager.
133123
134This app opens the iOS file manager and allows you to click any file you
135want, opens it up in an editor, and lets me save and close out of that
136note.
124This app opens the iOS file manager and allows you to click any file you want,
125opens it up in an editor, and lets me save and close out of that note.
137126
138127Quite simple but effective.
content/blog/2022-03-03-financial-database.md +157 −173
@@ -7,54 +7,50 @@ draft = false
77
88# Personal Financial Tracking
99
10For the last 6-ish years, I\'ve tracked my finances in a spreadsheet.
11This is common practice in the business world, but any good dev will
12cringe at the thought of storing long-term data in a spreadsheet. A
13spreadsheet is not for long-term storage or as a source of data to pull
14data/reports.
15
16As I wanted to expand the functionality of my financial data (e.g.,
17adding more reports), I decided to migrate the data into a database. To
18run reports, I would query the database and use a language like Python
19or Javascript to process the data, perform calculations, and visualize
20the data.
10For the last 6-ish years, I've tracked my finances in a spreadsheet. This is
11common practice in the business world, but any good dev will cringe at the
12thought of storing long-term data in a spreadsheet. A spreadsheet is not for
13long-term storage or as a source of data to pull data/reports.
14
15As I wanted to expand the functionality of my financial data (e.g., adding more
16reports), I decided to migrate the data into a database. To run reports, I would
17query the database and use a language like Python or Javascript to process the
18data, perform calculations, and visualize the data.
2119
2220# SQLite
2321
24When choosing the type of database I wanted to use for this project, I
25was split between three options:
22When choosing the type of database I wanted to use for this project, I was split
23between three options:
2624
271. MySQL: The database I have the most experience with and have used
28 for years.
292. PostgreSQL: A database I\'m new to, but want to learn.
303. SQLite: A database that I\'ve used for a couple projects and have
31 moderate experience.
251. MySQL: The database I have the most experience with and have used for years.
262. 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
28 experience.
3229
33I ended up choosing SQLite since it can be maintained within a single
34`.sqlite` file, which allows me more flexibility for storage
35and backup. I keep this file in my cloud storage and pull it up whenever
36needed.
30I ended up choosing SQLite since it can be maintained within a single `.sqlite`
31file, which allows me more flexibility for storage and backup. I keep this file
32in my cloud storage and pull it up whenever needed.
3733
3834## GUI Editing
3935
40Since I didn\'t want to try and import 1000--1500 records into my new
41database via the command line, I opted to use [DB Browser for SQLite
36Since I didn't want to try and import 1000--1500 records into my new database
37via the command line, I opted to use [DB Browser for SQLite
4238(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
44this database.
39excellent, and I don't see myself going back to the CLI when working in this
40database.
4541
4642DB4S 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,
481290 account statements, and 126 pay statements. Overall, I\'m guessing
49this took anywhere between 4--8 hours. In comparison, it probably took
50me 2-3 days to initially create the spreadsheet.
43straight into the SQL table. I used this process for all 36 accounts, 1290
44account statements, and 126 pay statements. Overall, I'm guessing this took
45anywhere between 4--8 hours. In comparison, it probably took me 2-3 days to
46initially create the spreadsheet.
5147
5248![DB4S](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/db4s.png)
5349
5450## Schema
5551
56The schema for this database is actually extremely simple and involves
57only three tables (for now):
52The schema for this database is actually extremely simple and involves only
53three tables (for now):
5854
59551. Accounts
60562. Statements
@@ -62,9 +58,9 @@ only three tables (for now):
6258
6359**Accounts**
6460
65The Accounts table contains summary information about an account, such
66as a car loan or a credit card. By viewing this table, you can find
67high-level data, such as interest rate, credit line, or owner.
61The Accounts table contains summary information about an account, such as a car
62loan or a credit card. By viewing this table, you can find high-level data, such
63as interest rate, credit line, or owner.
6864
6965``` sql
7066CREATE TABLE "Accounts" (
@@ -82,10 +78,10 @@ CREATE TABLE "Accounts" (
8278
8379**Statements**
8480
85The Statements table uses the same unique identifier as the Accounts
86table, meaning you can join the tables to find a monthly statement for
87any of the accounts listed in the Accounts table. Each statement has an
88account ID, statement date, and total balance.
81The Statements table uses the same unique identifier as the Accounts table,
82meaning you can join the tables to find a monthly statement for any of the
83accounts listed in the Accounts table. Each statement has an account ID,
84statement date, and total balance.
8985
9086``` sql
9187CREATE TABLE "Statements" (
@@ -100,10 +96,10 @@ CREATE TABLE "Statements" (
10096
10197**Payroll**
10298
103The Payroll table is a separate entity, unrelated to the Accounts or
104Statements tables. This table contains all information you would find on
105a pay statement from an employer. As you change employers or obtain new
106perks/benefits, just add new columns to adapt to the new data.
99The Payroll table is a separate entity, unrelated to the Accounts or Statements
100tables. This table contains all information you would find on a pay statement
101from an employer. As you change employers or obtain new perks/benefits, just add
102new columns to adapt to the new data.
107103
108104``` sql
109105CREATE TABLE "Payroll" (
@@ -139,134 +135,122 @@ CREATE TABLE "Payroll" (
139135
140136## Python Reporting
141137
142Once I created the database tables and imported all my data, the only
143step left was to create a process to report and visualize on various
144aspects of the data.
145
146In order to explore and create the reports I\'m interested in, I
147utilized a two-part process involving Jupyter Notebooks and Python
148scripts.
149
1501. Step 1: Jupyter Notebooks
151
152 When I need to explore data, try different things, and re-run my
153 code cell-by-cell, I use Jupyter Notebooks. For example, I explored
154 the `Accounts` table until I found the following useful
155 information:
156
157 ``` python
158 import sqlite3
159 import pandas as pd
160 import matplotlib
161
162 # Set up database filename and connect
163 db = "finances.sqlite"
164 connection = sqlite3.connect(db)
165 df = pd.read_sql_query("SELECT ** FROM Accounts", connection)
166
167 # Set global matplotlib variables
168 %matplotlib inline
169 matplotlib.rcParams['text.color'] = 'white'
170 matplotlib.rcParams['axes.labelcolor'] = 'white'
171 matplotlib.rcParams['xtick.color'] = 'white'
172 matplotlib.rcParams['ytick.color'] = 'white'
173 matplotlib.rcParams['legend.labelcolor'] = 'black'
174
175 # Display graph
176 df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%')
177 ```
178
1792. Step 2: Python Scripts
180
181 Once I explored enough through the notebooks and had a list of
182 reports I wanted, I moved on to create a Python project with the
183 following structure:
184
185 ``` txt
186 finance/
187 ├── notebooks/
188 │ │ ├── account_summary.ipynb
189 │ │ ├── account_details.ipynb
190 │ │ └── payroll.ipynb
191 ├── public/
192 │ │ ├── image-01.png
193 │ │ └── image-0X.png
194 ├── src/
195 │ └── finance.sqlite
196 ├── venv/
197 ├── _init.py
198 ├── database.py
199 ├── process.py
200 ├── requirements.txt
201 └── README.md
202 ```
203
204 This structure allows me to:
205
206 1. Compile all required python packages into
207 `requirements.txt` for easy installation if I move to
208 a new machine.
209 2. Activate a virtual environment in `venv/` so I don\'t
210 need to maintain a system-wide Python environment just for this
211 project.
212 3. Keep my `notebooks/` folder to continuously explore
213 the data as I see fit.
214 4. Maintain a local copy of the database in `src/` for
215 easy access.
216 5. Export reports, images, HTML files, etc. to
217 `public/`.
218
219 Now, onto the differences between the code in a Jupyter Notebook and
220 the actual Python files. To create the report in the Notebook
221 snippet above, I created the following function inside
222 `process.py`:
223
224 ``` python
225 # Create summary pie chart
226 def summary_data(accounts: pandas.DataFrame) -> None:
227 accounts_01 = accounts[accounts["Owner"] == "Person01"]
228 accounts_02 = accounts[accounts["Owner"] == "Person02"]
229 for x in range(1, 4):
230 if x == 1:
231 df = accounts
232 account_string = "All Accounts"
233 elif x == 2:
234 df = accounts_01
235 account_string = "Person01's Accounts"
236 elif x == 3:
237 df = accounts_02
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 )
138Once I created the database tables and imported all my data, the only step left
139was to create a process to report and visualize on various aspects of the data.
140
141In order to explore and create the reports I'm interested in, I utilized a
142two-part process involving Jupyter Notebooks and Python scripts.
143
144### Step 1: Jupyter Notebooks
145
146When I need to explore data, try different things, and re-run my code
147cell-by-cell, I use Jupyter Notebooks. For example, I explored the
148`Accounts` table until I found the following useful information:
149
150``` python
151import sqlite3
152import pandas as pd
153import matplotlib
154
155# Set up database filename and connect
156db = "finances.sqlite"
157connection = sqlite3.connect(db)
158df = pd.read_sql_query("SELECT ** FROM Accounts", connection)
159
160# Set global matplotlib variables
161%matplotlib inline
162matplotlib.rcParams['text.color'] = 'white'
163matplotlib.rcParams['axes.labelcolor'] = 'white'
164matplotlib.rcParams['xtick.color'] = 'white'
165matplotlib.rcParams['ytick.color'] = 'white'
166matplotlib.rcParams['legend.labelcolor'] = 'black'
167
168# Display graph
169df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%')
170```
171
172### Step 2: Python Scripts
173
174Once I explored enough through the notebooks and had a list of reports I
175wanted, I moved on to create a Python project with the following structure:
176
177``` txt
178finance/
179├── notebooks/
180│ │ ├── account_summary.ipynb
181│ │ ├── account_details.ipynb
182│ │ └── payroll.ipynb
183├── public/
184│ │ ├── image-01.png
185│ │ └── image-0X.png
186├── src/
187│ └── finance.sqlite
188├── venv/
189├── _init.py
190├── database.py
191├── process.py
192├── requirements.txt
193└── README.md
194```
195
196This structure allows me to:
197
1981. Compile all required python packages into `requirements.txt` for easy
199 installation if I move to a new machine.
2002. Activate a virtual environment in `venv/` so I don't need to maintain a
201 system-wide Python environment just for this project.
2023. Keep my `notebooks/` folder to continuously explore the data as I see
203 fit.
2044. Maintain a local copy of the database in `src/` for easy access.
2055. Export reports, images, HTML files, etc. to `public/`.
206
207Now, onto the differences between the code in a Jupyter Notebook and the
208actual Python files. To create the report in the Notebook snippet above, I
209created the following function inside `process.py`:
210
211``` python
212# Create summary pie chart
213def summary_data(accounts: pandas.DataFrame) -> None:
214 accounts_01 = accounts[accounts["Owner"] == "Person01"]
215 accounts_02 = accounts[accounts["Owner"] == "Person02"]
216 for x in range(1, 4):
217 if x == 1:
218 df = accounts
219 account_string = "All Accounts"
220 elif x == 2:
221 df = accounts_01
222 account_string = "Person01's Accounts"
223 elif x == 3:
224 df = accounts_02
225 account_string = "Person02's Accounts"
226 print(f"Generating pie chart summary image for {account_string}...")
227 summary_chart = (
228 df.groupby(["AccountType"])
229 .sum()
230 .plot.pie(
231 title=f"Credit Line by Type for {account_string}",
232 y="CreditLine",
233 autopct="%1.1f%%",
248234 )
249 summary_chart.figure.savefig(f"public/summary_chart_{x}.png", dpi=1200)
250 ```
251
252 The result? A high-quality pie chart that is read directly by the
253 `public/index.html` template I use.
254
255 ![Summary Pie
256 Chart](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/summary_chart.png)
257
258 Other charts generated by this project include:
259
260 - Charts of account balances over time.
261 - Line chart of effective tax rate (taxes divided by taxable
262 income).
263 - Salary projections and error limits using past income and
264 inflation rates.
265 - Multi-line chart of gross income, taxable income, and net
266 income.
267
268 The best thing about this project? I can improve it at any given
269 time, shaping it into whatever helps me the most for that time. I
270 imagine that I will be introducing an asset tracking table soon to
271 track the depreciating value of cars, houses, etc. Who knows what\'s
272 next?
235 )
236 summary_chart.figure.savefig(f"public/summary_chart_{x}.png", dpi=1200)
237```
238
239The result? A high-quality pie chart that is read directly by the
240`public/index.html` template I use.
241
242![Summary Pie
243Chart](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-database/summary_chart.png)
244
245Other charts generated by this project include:
246
247- Charts of account balances over time.
248- Line chart of effective tax rate (taxes divided by taxable income).
249- Salary projections and error limits using past income and inflation
250 rates.
251- Multi-line chart of gross income, taxable income, and net income.
252
253The best thing about this project? I can improve it at any given time,
254shaping it into whatever helps me the most for that time. I imagine that I
255will be introducing an asset tracking table soon to track the depreciating
256value of cars, houses, etc. Who knows what's next?
content/blog/2022-03-08-plex-migration.md +86 −102
@@ -7,15 +7,13 @@ draft = false
77
88# Migration Phases
99
10I recently decided to migrate my server from an old OptiPlex desktop
11machine to a custom-built tower with better hardware in every category.
12In order to do this, I would need to properly migrate a full Plex
13installation.
10I recently decided to migrate my server from an old OptiPlex desktop machine to
11a custom-built tower with better hardware in every category. In order to do
12this, I would need to properly migrate a full Plex installation.
1413
15The second part of this migration is that the new server uses an Nvidia
16GPU and does not have any integrated graphics, which requires extra work
17for installation, but provides much better hardware transcoding options
18for Plex.
14The second part of this migration is that the new server uses an Nvidia GPU and
15does not have any integrated graphics, which requires extra work for
16installation, but provides much better hardware transcoding options for Plex.
1917
2018Therefore, I have broken this migration down into three phases:
2119
@@ -28,42 +26,38 @@ Therefore, I have broken this migration down into three phases:
2826## Choosing an OS
2927
3028In 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
32that I have encountered numerous issues installing other Linux
33distributions properly with Nvidia graphics, I chose [Ubuntu
29appropriate operating system (OS) and install it on the machine. Given that I
30have encountered numerous issues installing other Linux distributions properly
31with Nvidia graphics, I chose [Ubuntu
3432Server](https://ubuntu.com/download/server).
3533
36The first step is to create a bootable USB with Ubuntu Server. This is
37easy with [Etcher](https://www.balena.io/etcher/), an app that runs on
38many different platforms. Just download the Ubuntu Server
39`.iso` image, launch Etcher, and install the
40`.iso` on the USB.
34The first step is to create a bootable USB with Ubuntu Server. This is easy with
35[Etcher](https://www.balena.io/etcher/), an app that runs on many different
36platforms. Just download the Ubuntu Server `.iso` image, launch Etcher, and
37install the `.iso` on the USB.
4138
42Once the USB is created, insert it into my server, reboot, and click
43`Esc` (or any of the `F1-12` keys) until the BIOS
44menu appears. Finally, launch the USB boot drive.
39Once the USB is created, insert it into my server, reboot, and click `Esc` (or
40any of the `F1-12` keys) until the BIOS menu appears. Finally, launch the USB
41boot drive.
4542
4643## Booting with Nvidia
4744
4845In order to install Ubuntu Server with an Nvidia Graphics card (and no
49integrated graphics on this device for some reason), you\'ll have to
50configure the boot menu to allow different graphics drivers to be
51loaded.
46integrated graphics on this device for some reason), you'll have to configure
47the boot menu to allow different graphics drivers to be loaded.
5248
53When booting from the USB, the machine will launch the initial
54installation menu. From this menu, type `e` to view the
55default command options that come with the device - it\'s a good idea to
56take a photo of this screen, so you can enter these commands on the next
57screen (along with adding support for Nvidia).
49When booting from the USB, the machine will launch the initial installation
50menu. From this menu, type `e` to view the default command options that come
51with the device - it's a good idea to take a photo of this screen, so you can
52enter these commands on the next screen (along with adding support for Nvidia).
5853
59Finally, type `Ctrl + C` to enter the command line. From this
60command line, enter the commands found on the `e` screen.
61\*Remember to add `nomodeset` to the `linux ...`
62line so that your Nvidia device will display the installation screens
63properly!\*
54Finally, type `Ctrl + C` to enter the command line. From this command line,
55enter the commands found on the `e` screen. *Remember to add `nomodeset` to the
56`linux ...` line so that your Nvidia device will display the installation
57screens properly!*
6458
65Here\'s an example of the commands I pulled from the `e`
66screen and entered on the command line.
59Here's an example of the commands I pulled from the `e` screen and entered on
60the command line.
6761
6862```sh
6963setparams 'Install Ubuntu Server'
@@ -79,12 +73,11 @@ boot
7973![Ubuntu Server Installation
807402](https://img.cleberg.net/blog/20220308-plex-media-server-migration/ubuntu_server_installation_02.png)
8175
82Once the machine is rebooted, enter the `e` screen again and
83add `nomodeset` to the `linux ...` line again and
84press `Ctrl + X` to save the boot options.
76Once the machine is rebooted, enter the `e` screen again and add `nomodeset` to
77the `linux ...` line again and press `Ctrl + X` to save the boot options.
8578
86The machine is now fully installed and can properly display on an
87external display using the Nvidia GPU.
79The machine is now fully installed and can properly display on an external
80display using the Nvidia GPU.
8881
8982Always remember to update and upgrade on a new installation:
9083
@@ -94,33 +87,30 @@ sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
9487
9588# Phase 2: Migrate Plex Data & Devices
9689
97This phase uses the great Plex article on migrations ([Move an
98Installation to Another
90This phase uses the great Plex article on migrations ([Move an Installation to
91Another
9992System](https://support.plex.tv/articles/201370363-move-an-install-to-another-system/))
10093and adds a bit more information to help with commands and context.
10194
10295## Terminology
10396
104**Source:\*** The original server that is being replaced.\
105**Destination:\*** The new server.\
106**Client:\*** Any application that can be used to modify settings for
107both source/destination.
97**Source:** The original server that is being replaced.\
98**Destination:** The new server.\
99**Client:** Any application that can be used to modify settings for both
100source/destination.
108101
109## Step 01: \[Client\] Update Settings
102## Step 01: [Client] Update Settings
110103
111Open up a Plex app and *disable* the `Account` \>
112`Library` \>
113`Empty trash automatically after every scan` preference for
114the source server.
104Open up a Plex app and *disable* the `Account` > `Library` > `Empty trash
105automatically after every scan` preference for the source server.
115106
116## Step 02: \[Destination\] Install Plex
107## Step 02: [Destination] Install Plex
117108
118109Open up the [Plex Media Server download
119page](https://www.plex.tv/media-server-downloads/) and copy the link for
120the appropriate platform.
110page](https://www.plex.tv/media-server-downloads/) and copy the link for the
111appropriate platform.
121112
122Execute the following commands on the destination server to install
123Plex:
113Execute the following commands on the destination server to install Plex:
124114
125115```sh
126116wget <url>
@@ -128,48 +118,45 @@ sudo dpkg -i <filename>
128118sudo systemctl stop plexmediaserver.service
129119```
130120
131## Step 03: \[Source\] Stop Plex & Migrate Data
121## Step 03: [Source] Stop Plex & Migrate Data
132122
133First, stop the Plex service so that no data is created or modified
134during the migration.
123First, stop the Plex service so that no data is created or modified during the
124migration.
135125
136126```sh
137127sudo systemctl stop plexmediaserver.service
138128```
139129
140Next, copy the data to the new server. To find where the Plex data
141directory is located, Plex has another excellent article available:
142[Where is the Plex Media Server data directory
130Next, copy the data to the new server. To find where the Plex data directory is
131located, Plex has another excellent article available: [Where is the Plex Media
132Server data directory
143133located?](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/).
144134
145There are many ways to copy the data to the new server and will largely
146depend on the size of the folder being copied. Personally, my data
147folder was \~23GB and I opted to simply use the `scp` command
148to copy the files over SSH.
135There are many ways to copy the data to the new server and will largely depend
136on the size of the folder being copied. Personally, my data folder was ~23GB
137and I opted to simply use the `scp` command to copy the files over SSH.
149138
150This process was throttled by the old server\'s slow HDD and ports and
151took approximately 90 minutes to complete. In comparison, moving the
152data from the new server\'s `home/user/` directory to the
153`/var/.../Plex Media Server` directory took 2-3 minutes.
139This process was throttled by the old server's slow HDD and ports and took
140approximately 90 minutes to complete. In comparison, moving the data from the
141new server's `home/user/` directory to the `/var/.../Plex Media Server`
142directory took 2-3 minutes.
154143
155144```sh
156145scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'"
157146```
158147
159## Step 04: \[Destination\] Update File Permissions
148## Step 04: [Destination] Update File Permissions
160149
161In case you move the data directory to a common area on the new server,
162it will have to be moved to the proper location before Plex can function
163properly:
150In case you move the data directory to a common area on the new server, it will
151have to be moved to the proper location before Plex can function properly:
164152
165153```sh
166154mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/
167155```
168156
169To ensure permissions were retained properly, the server will need to
170show that all files and folders in the data directory are owned by
171`plex:plex` (or whichever user is running the Plex
172application).
157To ensure permissions were retained properly, the server will need to show that
158all files and folders in the data directory are owned by `plex:plex` (or
159whichever user is running the Plex application).
173160
174161```sh
175162sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"
@@ -182,43 +169,40 @@ sudo systemctl start plexmediaserver.service
182169sudo systemctl status plexmediaserver.service
183170```
184171
185## Step 05: \[Client\] Update Libraries & Metadata
172## Step 05: [Client] Update Libraries & Metadata
186173
187The first step - now that the new server is up and running - is to sign
188out of the client and sign back in. Once this is done, update any
189library locations, if necessary. This was unnecessary in my case since I
190simply moved my storage drives from the source server to the destination
191server.
174The first step - now that the new server is up and running - is to sign out of
175the client and sign back in. Once this is done, update any library locations, if
176necessary. This was unnecessary in my case since I simply moved my storage
177drives from the source server to the destination server.
192178
193179Next, perform the following actions in the client:
194180
1951. On the left sidebar, click `More` \> Three-Dot Menu \>
196 `Scan Library Files`
1972. *Enable* the `Account` \> `Library` \>
198 `Empty trash automatically after every scan` preference
199 for the source server.
2003. On the left sidebar, click `More` \> Three-Dot Menu \>
201 `Manage Server` \> `Empty Trash`
2024. On the left sidebar, click `More` \> Three-Dot Menu \>
203 `Manage Server` \> `Clean Bundles`
2045. On the left sidebar, click `More` \> Three-Dot Menu \>
205 `Manage Server` \> `Optimize Database`
1811. On the left sidebar, click `More` > Three-Dot Menu > `Scan Library Files`
1822. *Enable* the `Account` > `Library` > `Empty trash automatically after every
183 scan` preference for the source server.
1843. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
185 `Empty Trash`
1864. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
187 `Clean Bundles`
1885. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
189 `Optimize Database`
206190
207Finally, double-check the Remote Access settings to make sure no changes
208have caused issues with accessing the server from outside the network.
191Finally, double-check the Remote Access settings to make sure no changes have
192caused issues with accessing the server from outside the network.
209193
210In my case, I use a single port forwarding rule in my router and needed
211to update the Local LAN IP Address to the new server IP address.
194In my case, I use a single port forwarding rule in my router and needed to
195update the Local LAN IP Address to the new server IP address.
212196
213197![Router port
214198forwarding](https://img.cleberg.net/blog/20220308-plex-media-server-migration/port_forwarding.png)
215199
216200# Phase 3: Configure GPU Transcoding
217201
218The final piece to the migration is enabling hardware transcoding so
219that Plex can fully utilize the new Nvidia GPU available in the server.
220The first step is to install Nvidia graphics drivers. This process may
221take a few minutes, but the commands are pretty simple:
202The final piece to the migration is enabling hardware transcoding so that Plex
203can fully utilize the new Nvidia GPU available in the server. The first step is
204to install Nvidia graphics drivers. This process may take a few minutes, but the
205commands are pretty simple:
222206
223207```sh
224208sudo add-apt-repository ppa:graphics-drivers/ppa
content/blog/2022-03-23-cloudflare-dns-api.md +18 −23
@@ -7,15 +7,14 @@ draft = false
77
88# DDNS: Dynamic DNS
99
10If you\'re hosting a service from a location with dynamic DNS (where
11your IP may change at any time), you must have a solution to update the
12DNS so that you can access your service even when the IP of the server
13changes.
10If you're hosting a service from a location with dynamic DNS (where your IP may
11change at any time), you must have a solution to update the DNS so that you can
12access your service even when the IP of the server changes.
1413
15The process below uses the [Cloudflare API](https://api.cloudflare.com/)
16to update DNS `A` and `AAAA` records with the
17server\'s current IP. If you use another DNS provider, you will have to
18find a way to update your DNS (or find a way to get a static IP).
14The process below uses the [Cloudflare API](https://api.cloudflare.com/) to
15update DNS `A` and `AAAA` records with the server's current IP. If you use
16another DNS provider, you will have to find a way to update your DNS (or find a
17way to get a static IP).
1918
2019First, install `jq` since we will use it in the next script:
2120
@@ -23,18 +22,16 @@ First, install `jq` since we will use it in the next script:
2322sudo apt install jq
2423```
2524
26Next, create a location for your DDNS update scripts and open the first
27script:
25Next, create a location for your DDNS update scripts and open the first script:
2826
2927```sh
3028mkdir ~/ddns
3129nano ~/ddns/update.sh
3230```
3331
34The following `update.sh` script will take all of your
35domains and subdomains and check Cloudflare to see if the current
36`A` and `AAAA` records match your server\'s IP
37address. If not, it will update the records.
32The following `update.sh` script will take all of your domains and subdomains
33and check Cloudflare to see if the current `A` and `AAAA` records match your
34server's IP address. If not, it will update the records.
3835
3936```sh
4037# file: update.sh
@@ -60,17 +57,16 @@ do
6057done
6158```
6259
63Next, open up the `ddns.sh` script. Paste the following into
64the script and update the `api_token` and `email`
65variables.
60Next, open up the `ddns.sh` script. Paste the following into the script and
61update the `api_token` and `email` variables.
6662
6763```sh
6864nano ~/ddns/ddns.sh
6965```
7066
71**Note**: If you want your DNS records to be proxied through Cloudflare,
72find and update the following snippet: `"proxied":false}"` to
73say `true` instead of `false`.
67**Note**: If you want your DNS records to be proxied through Cloudflare, find
68and update the following snippet: `"proxied":false}"` to say `true` instead of
69`false`.
7470
7571```sh
7672# file: ddns.sh
@@ -180,9 +176,8 @@ You can test the script by running it manually:
180176./update.sh
181177```
182178
183To make sure the scripts run automatically, add it to the
184`cron` file so that it will run on a schedule. To do this,
185open the cron file:
179To make sure the scripts run automatically, add it to the `cron` file so that it
180will run on a schedule. To do this, open the cron file:
186181
187182```sh
188183crontab -e
content/blog/2022-03-23-nextcloud-on-ubuntu.md +27 −35
@@ -7,8 +7,8 @@ draft = false
77
88# What is Nextcloud?
99
10[Nextcloud](https://nextcloud.com/) is a self-hosted solution for
11storage, communications, editing, calendar, contacts, and more.
10[Nextcloud](https://nextcloud.com/) is a self-hosted solution for storage,
11communications, editing, calendar, contacts, and more.
1212
1313This tutorial assumes that you have an Ubuntu server and a domain name
1414configured 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
2525
2626# Set Up MySQL
2727
28Next, you will need to log in to MySQL as the `root` user of
29the machine.
28Next, you will need to log in to MySQL as the `root` user of the machine.
3029
3130```sh
3231sudo mysql -uroot -p
3332```
3433
35Once you\'ve logged in, you must create a new user so that Nextcloud can
36manage the database. You will also create a `nextcloud`
37database and assign privileges:
34Once you've logged in, you must create a new user so that Nextcloud can manage
35the database. You will also create a `nextcloud` database and assign privileges:
3836
3937``` sql
4038CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
@@ -47,14 +45,12 @@ quit;
4745# Download & Install Nextcloud
4846
4947To download Nextcloud, go the [Nextcloud downloads
50page](https://nextcloud.com/install/#instructions-server), click on
51`Archive File` and right-click the big blue button to copy
52the link.
48page](https://nextcloud.com/install/#instructions-server), click on `Archive
49File` and right-click the big blue button to copy the link.
5350
54Then, go to your server and enter the following commands to download,
55unzip, and move the files to your destination directory. This example
56uses `example.com` as the destination, but you can put it
57wherever you want to server your files from.
51Then, go to your server and enter the following commands to download, unzip, and
52move the files to your destination directory. This example uses `example.com` as
53the destination, but you can put it wherever you want to server your files from.
5854
5955```sh
6056wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip
@@ -65,9 +61,9 @@ sudo cp -r nextcloud /var/www/example.com
6561
6662# Configure the Apache Web Server
6763
68Now that the database is set up and Nextcloud is installed, you need to
69set up the Apache configuration files to tell the server how to handle
70requests for `example.com/nextcloud`.
64Now that the database is set up and Nextcloud is installed, you need to set up
65the Apache configuration files to tell the server how to handle requests for
66`example.com/nextcloud`.
7167
7268First, open the following file in the editor:
7369
@@ -75,8 +71,8 @@ First, open the following file in the editor:
7571sudo nano /etc/apache2/sites-available/nextcloud.conf
7672```
7773
78Once the editor is open, paste the following information in. Then, save
79and close the file.
74Once the editor is open, paste the following information in. Then, save and
75close the file.
8076
8177``` config
8278<VirtualHost *:80>
@@ -111,16 +107,15 @@ Next, enable the Apache mods required by Nextcloud:
111107sudo a2enmod rewrite headers env dir mime
112108```
113109
114Finally, restart Apache. If any errors arise, you must solve those
115before continuing.
110Finally, restart Apache. If any errors arise, you must solve those before
111continuing.
116112
117113```sh
118114sudo systemctl restart apache2
119115```
120116
121117For the app to work, you must have the correct file permissions on your
122`nextcloud` directory. Set the owner to be
123`www-data`:
118`nextcloud` directory. Set the owner to be `www-data`:
124119
125120```sh
126121sudo 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/
129124# DNS
130125
131126If 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
133changes.
127settings (at your DNS provider) whenever your dynamic IP address changes.
134128
135For an example on how I do that with Cloudflare, see my other post:
136[Updating Dynamic DNS with Cloudflare
137API](../updating-dynamic-dns-with-cloudflare-api/)
129For an example on how I do that with Cloudflare, see my other post: [Updating
130Dynamic DNS with Cloudflare API](../updating-dynamic-dns-with-cloudflare-api/)
138131
139132# Certbot
140133
141If you want to serve Nextcloud from HTTPS rather than plain HTTP, use
142the following commands to issue Let\'s Encrypt SSL certificates:
134If you want to serve Nextcloud from HTTPS rather than plain HTTP, use the
135following commands to issue Let's Encrypt SSL certificates:
143136
144137```sh
145138sudo apt install snapd
@@ -152,12 +145,11 @@ sudo certbot --apache
152145
153146# Results
154147
155Voilà! You\'re all done and should be able to access Nextcloud from your
156domain or IP address.
148Voilà! You're all done and should be able to access Nextcloud from your domain
149or IP address.
157150
158See the screenshots below for the dashboard and a settings page on my
159instance of Nextcloud, using the `Breeze Dark` theme I
160installed from the Apps page.
151See the screenshots below for the dashboard and a settings page on my instance
152of Nextcloud, using the `Breeze Dark` theme I installed from the Apps page.
161153
162154![Nextcloud
163155Dashboard](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
77
88# Post Updates
99
10> After reviewing this post today (2022-10-04), I noticed quite a few
11> gaps in my write-up and wanted to add a few things, even though this
12> blog is really just a retrospective and knowledge dump for myself. I
13> left things intact and simply crossed them out (~~like this~~) for
14> posterity.
10> After reviewing this post today (2022-10-04), I noticed quite a few gaps in my
11> write-up and wanted to add a few things, even though this blog is really just
12> a retrospective and knowledge dump for myself. I left things intact and simply
13> crossed them out (~~like this~~) for posterity.
1514
1615# Planning Data Flows & Security
1716
@@ -31,104 +30,97 @@ draft = false
3130
3231## Thought Process
3332
34To serve content from your home server and harden your security posture,
35you have to think about the transport of data from `server`
36to `client`.
37
38Let\'s start with the actual server itself. Think about the following:
39
40- Do I have a firewall enabled? Do I need to update this to allow new
41 ports or IPs?
42- Do I have an IPS/IDS that may prevent outside traffic?
43- Do I have any other security software installed?
44- Are the services hosted inside Docker containers, behind a reverse
45 proxy, or virtualized? If so, are they configured to allow outside
46 traffic?
47
48Once the data leaves the server, where does it go? In my case, it goes
49to a managed switch. In this case, I asked the following:
50
51- What configurations is the switch using?
52- Am I using VLANs?
53 - Yes, I am using 802.1Q VLANs.
54- Are the VLANs configured properly?
55 - Yes, as shown in the Switch section below, I have a separate
56 VLAN to allow outside traffic to and from the server alone. No
57 other devices, except for a service port, and in that VLAN.
58
59At this point, the data has been processed through the switch. Where
60does it go next? In my case, it\'s pretty simple: it goes to the
61router/modem device.
62
63- Does my ISP block any ports that I need?
64 - This is an important step that a lot of people run into when
65 self-hosting at home. Use an online port-checker tool for your
66 IP or call your ISP if you think ports are blocked.
67- Is there a router firewall?
68 - Yes, I checked that it\'s configured to allow the ports I need
69 to run my services publicly. Common web servers and reverse
70 proxies require ports 80 and 443, but other services like media
71 servers or games can require unique ports, so be sure to check
72 the documentation for your service(s).
73- Are there any other settings affecting inbound/outbound traffic?
74 - Schedules or access blocks
75 - Static Routing
76 - QoS
77 - Port Forwarding
78 - DMZ Hosting
79 - Remote Management (this can sometimes mess with services that
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.
33To serve content from your home server and harden your security posture, you
34have to think about the transport of data from `server` to `client`.
35
36Let's start with the actual server itself. Think about the following:
37
38- Do I have a firewall enabled? Do I need to update this to allow new ports or
39 IPs?
40- Do I have an IPS/IDS that may prevent outside traffic?
41- Do I have any other security software installed?
42- Are the services hosted inside Docker containers, behind a reverse proxy, or
43 virtualized? If so, are they configured to allow outside traffic?
44
45Once the data leaves the server, where does it go? In my case, it goes to a
46managed switch. In this case, I asked the following:
47
48- What configurations is the switch using?
49- Am I using VLANs?
50 - Yes, I am using 802.1Q VLANs.
51- Are the VLANs configured properly?
52 - Yes, as shown in the Switch section below, I have a separate VLAN to allow
53 outside traffic to and from the server alone. No other devices, except for
54 a service port, and in that VLAN.
55
56At this point, the data has been processed through the switch. Where does it go
57next? In my case, it's pretty simple: it goes to the router/modem device.
58
59- Does my ISP block any ports that I need?
60 - This is an important step that a lot of people run into when self-hosting
61 at home. Use an online port-checker tool for your IP or call your ISP if
62 you think ports are blocked.
63- Is there a router firewall?
64 - Yes, I checked that it's configured to allow the ports I need to run my
65 services publicly. Common web servers and reverse proxies require ports 80
66 and 443, but other services like media servers or games can require unique
67 ports, so be sure to check the documentation for your service(s).
68- Are there any other settings affecting inbound/outbound traffic?
69 - Schedules or access blocks
70 - Static Routing
71 - QoS
72 - Port Forwarding
73 - DMZ Hosting
74 - Remote Management (this can sometimes mess with services that also require
75 the use of ports 80 and 443)
76
77Once the data leaves my router, it goes to the upstream ISP and can be accessed
78publicly.
8479
8580### Server
8681
87+The services I run on my server are installed straight into the OS,
88without any use of Docker or VMs, so I don\'t need any extra application
89configuration to make them accessible to the outside world.+
90
91As of 2022-10-04, the paragraph above is no longer true as I now run a
92reverse proxy with Nginx and host many services inside Docker. However,
93it doesn\'t change anything regarding this post as I still just need to
94open ports 80 & 443 and create the necessary website configuration
95files.
96
97When creating new services - either installed directly on bare metal or
98within something like Docker - I ensure that I read through the
99documentation thoroughly to understand a few key things: - What network
100activities should this app perform (if any)? Using which ports and
101protocols? - Does this app require any commands/services to be run as
102`root`? - Does this app log errors, authentication
103failures/successes, or anything else that would be useful for an
82+The services I run on my server are installed straight into the OS, without any
83use of Docker or VMs, so I don't need any extra application configuration to
84make them accessible to the outside world.+
85
86As of 2022-10-04, the paragraph above is no longer true as I now run a reverse
87proxy with Nginx and host many services inside Docker. However, it doesn't
88change anything regarding this post as I still just need to open ports 80 & 443
89and create the necessary website configuration files.
90
91When creating new services - either installed directly on bare metal or within
92something like Docker - I ensure that I read through the documentation
93thoroughly to understand a few key things: - What network activities should this
94app perform (if any)? Using which ports and protocols? - Does this app require
95any commands/services to be run as `root`? - Does this app log errors,
96authentication failures/successes, or anything else that would be useful for an
10497investigation?
10598
106For extra security, I use limit all incoming connections to SSH
107connections through my server firewall (`ufw`) and disable
108common SSH settings. After all of that, I use `fail2ban` as a
109preventative measure against brute-force login attempts.
99For extra security, I use limit all incoming connections to SSH connections
100through my server firewall (`ufw`) and disable common SSH settings. After all of
101that, I use `fail2ban` as a preventative measure against brute-force login
102attempts.
110103
111As another piece of security, you can randomize your SSH port to ensure
112that random scanners or attackers can\'t easily try to force their way
113into your network. For example, you can edit the port rules in your
114server to block all connection requests to port `22` but
115forward all remote connections from port `12345` to your
116server\'s port `22`. Then you just need to SSH to your
117network via your randomized port.
104As another piece of security, you can randomize your SSH port to ensure that
105random scanners or attackers can't easily try to force their way into your
106network. For example, you can edit the port rules in your server to block all
107connection requests to port `22` but forward all remote connections from port
108`12345` to your server's port `22`. Then you just need to SSH to your network
109via your randomized port.
118110
119111## `ufw`
120112
121To see how to configure `ufw`, see my other post: [Secure
122Your Network with the Uncomplicated
113To see how to configure `ufw`, see my other post: [Secure Your Network with the
114Uncomplicated
123115Firewall](../secure-your-network-with-the-uncomplicated-firewall/).
124116
125The general notion with an on-device firewall is that you want to deny
126all incoming connections by default and then selectively open certain
127ports for services or users that you know need access.
117The general notion with an on-device firewall is that you want to deny all
118incoming connections by default and then selectively open certain ports for
119services or users that you know need access.
128120
129If you know that you will only be logging into this server from a
130certain set or list of IPs, you can always set the firewall to only
131allow connections to port 22 from those IPs.
121If you know that you will only be logging into this server from a certain set or
122list of IPs, you can always set the firewall to only allow connections to port
12322 from those IPs.
132124
133125For a quick start to only allow SSH connections to the server, use this:
134126
@@ -145,31 +137,30 @@ sudo ufw enable
145137
1461381. Using SSH Keys
147139
148 First, make sure you have an SSH keypair generated on the device(s)
149 that you\'ll be using to log in to the server. If you don\'t have an
150 SSH key, run this command:
140 First, make sure you have an SSH keypair generated on the device(s) that
141 you'll be using to log in to the server. If you don't have an SSH key, run
142 this command:
151143
152144 ```sh
153145 ssh-keygen
154146 ```
155147
156 Now that we have an SSH key, copy it to the server with the
157 following command, which will ask for the user\'s password before
158 accepting the key:
148 Now that we have an SSH key, copy it to the server with the following
149 command, which will ask for the user's password before accepting the key:
159150
160151 ```sh
161152 ssh-copy-id my_user@my_server
162153 ```
163154
164 If you have multiple keys, you\'ll need to specify which to use.
165 After it\'s complete, `ssh` back into the server as that
166 user and make sure it doesn\'t ask for a password.
155 If you have multiple keys, you'll need to specify which to use. After it's
156 complete, `ssh` back into the server as that user and make sure it doesn't
157 ask for a password.
167158
1681592. Disable Password & Root Authentication
169160
170 Now that we can access the server without a password, we will
171 disable password authentication and disable anyone from using
172 `ssh` to login as `root`.
161 Now that we can access the server without a password, we will disable
162 password authentication and disable anyone from using `ssh` to login as
163 `root`.
173164
174165 To do this, open the `sshd_config` file:
175166
@@ -177,9 +168,9 @@ sudo ufw enable
177168 sudo nano /etc/ssh/sshd_config
178169 ```
179170
180 You\'ll need to update the parameters to the values below. If one of
181 these rules is commented-out or doesn\'t exist, create the rule at
182 the bottom of the file.
171 You'll need to update the parameters to the values below. If one of these
172 rules is commented-out or doesn't exist, create the rule at the bottom of
173 the file.
183174
184175 ``` config
185176 PermitRootLogin no
@@ -193,36 +184,33 @@ sudo ufw enable
193184 sudo systemctl restart sshd.service
194185 ```
195186
196 To test that everything\'s working so far, open ANOTHER terminal and
197 try logging in as `root` over SSH. It is very important
198 that you keep your current SSH session open and test with an
199 additional session, or you will lock yourself out at some point and
200 will need to use a recovery method (e.g., hooking monitor up to home
201 server) to get yourself back in.
187 To test that everything's working so far, open ANOTHER terminal and try
188 logging in as `root` over SSH. It is very important that you keep your
189 current SSH session open and test with an additional session, or you will
190 lock yourself out at some point and will need to use a recovery method
191 (e.g., hooking monitor up to home server) to get yourself back in.
202192
2031933. Enable MFA for `ssh`
204194
205 This part is optional, but I highly recommend it. So far, we\'ve
206 ensured that no one can log into our user on the server without
207 using our secret key, and we\'ve ensured that no one can log in
208 remotely as `root`. Next, you can enable MFA
209 authentication for `ssh` connections.
195 This part is optional, but I highly recommend it. So far, we've ensured
196 that no one can log into our user on the server without using our secret
197 key, and we've ensured that no one can log in remotely as `root`. Next, you
198 can enable MFA authentication for `ssh` connections.
210199
211 This process involves editing a couple files and installing an MFA
212 package, so I will not include all the details in this post. To see
213 how to configure MFA for `ssh`, see my other post:
214 [Enabling MFA for SSH](../enable-totp-mfa-for-ssh/).
200 This process involves editing a couple files and installing an MFA package,
201 so I will not include all the details in this post. To see how to configure
202 MFA for `ssh`, see my other post: [Enabling MFA for
203 SSH](../enable-totp-mfa-for-ssh/).
215204
216205 ![SSH
217206 MFA](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/ssh_mfa.png)
218207
219208## `fail2ban`
220209
221I haven\'t written a post on how I use `fail2ban`, but it\'s
222quite simple. I use the default `sshd` jail, but you can
223always create new jails for respective applications or ports. For
224example, if you use Nginx as your web server, you can use the
225`nginx-http-auth` jail.
210I haven't written a post on how I use `fail2ban`, but it's quite simple. I use
211the default `sshd` jail, but you can always create new jails for respective
212applications or ports. For example, if you use Nginx as your web server, you can
213use the `nginx-http-auth` jail.
226214
227215In order to get it up and running, use the following commands:
228216
@@ -232,122 +220,132 @@ sudo fail2ban-client start sshd
232220sudo fail2ban-client status sshd
233221```
234222
235This should be used as a last-resort defense and shouldn\'t be a
236replacement for the security measures mentioned above.
223This should be used as a last-resort defense and shouldn't be a replacement for
224the security measures mentioned above.
237225
238226![fail2ban](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/fail2ban.png)
239227
240228# Switch
241229
242Between the router and any local devices is my managed switch, which is
243used to create VLANs. The example below shows how I would isolate the
244VLANs if I were starting to host a single service at home.
230Between the router and any local devices is my managed switch, which is used to
231create VLANs. The example below shows how I would isolate the VLANs if I were
232starting to host a single service at home.
245233
246234## 802.1Q VLAN Configuration
247235
248In this configuration, port 8 is the public server that needs to be
249accessed from the outside. Port 23 is my \'dedicated service port\' for
250this server. In order to SSH to this server, I need to plug my laptop
251into port 23 or else I cannot SSH. Otherwise, I\'d need to hook up a
252monitor and keyboard directly to the server to manage it.
236In this configuration, port 8 is the public server that needs to be accessed
237from the outside. Port 23 is my 'dedicated service port' for this server. In
238order to SSH to this server, I need to plug my laptop into port 23 or else I
239cannot SSH. Otherwise, I'd need to hook up a monitor and keyboard directly to
240the server to manage it.
253241
254 VLAN ID VLAN Name Member Ports Tagged Ports Untagged Ports
255 --------- ----------- -------------- -------------- ----------------
256 1 Default 1-24 1-24
257 2 Server 1,8,23 1,8,23
242|
243
244| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports |
245|---------|-----------|--------------|--------------|----------------|
246| 1 | Default | 1-24 | 1-24 | |
247| 2 | Server | 1,8,23 | 1,8,23 | |
258248
259249## 802.1Q VLAN PVID Setting
260250
261Once the VLAN is created, I simply add the `VLAN ID` of
262`2` as the `PVID` for any related ports (in this
263case, see that ports `8` and `23` have a PVID of
251Once the VLAN is created, I simply add the `VLAN ID` of `2` as the `PVID` for
252any related ports (in this case, see that ports `8` and `23` have a PVID of
264253`2`).
265254
266 Port PVID
267 ------ ------
268 1 1
269 2 1
270 3 1
271 4 1
272 5 1
273 6 1
274 7 1
275 8 2
276 9 1
277 10 1
278 11 1
279 12 1
280 13 1
281 14 1
282 15 1
283 16 1
284 17 1
285 18 1
286 19 1
287 20 1
288 21 1
289 22 1
290 23 2
291 24 1
255| Port | PVID |
256|------|------|
257| 1 | 1 |
258| 2 | 1 |
259| 3 | 1 |
260| 4 | 1 |
261| 5 | 1 |
262| 6 | 1 |
263| 7 | 1 |
264| 8 | 2 |
265| 9 | 1 |
266| 10 | 1 |
267| 11 | 1 |
268| 12 | 1 |
269| 13 | 1 |
270| 14 | 1 |
271| 15 | 1 |
272| 16 | 1 |
273| 17 | 1 |
274| 18 | 1 |
275| 19 | 1 |
276| 20 | 1 |
277| 21 | 1 |
278| 22 | 1 |
279| 23 | 2 |
280| 24 | 1 |
292281
293282# Router
294283
295On my router, the configuration was as easy as opening the firewall
296settings and unblocking the ports I needed for my services (e.g.,
297HTTP/S, Plex, SSH, MySQL, etc.).
284On my router, the configuration was as easy as opening the firewall settings and
285unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL,
286etc.).
298287
299+Since I\'m relying on an ISP-provided modem/router combo for now (not
300by choice), I do not use any other advanced settings on my router that
301would inhibit any valid traffic to these services.+
288*Since I'm relying on an ISP-provided modem/router combo for now (not by
289choice), I do not use any other advanced settings on my router that would
290inhibit any valid traffic to these services.*
302291
303The paragraph above regarding the ISP-owned router is no longer accurate
304as I now use the Ubiquiti Unifi Dream Machine Pro as my router. Within
305this router, I enabled port forwarding/firewall rules, segregate the
306network based on the device, and enable traffic restrictions (e.g.,
307silently drop traffic from certain countries and threat categories).
292The paragraph above regarding the ISP-owned router is no longer accurate as I
293now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I
294enabled port forwarding/firewall rules, segregate the network based on the
295device, and enable traffic restrictions (e.g., silently drop traffic from
296certain countries and threat categories).
308297
309If you have the option with your ISP, I recommend using a personal
310router with software that you are familiar with so that you can explore
311all the options available to you.
298If you have the option with your ISP, I recommend using a personal router with
299software that you are familiar with so that you can explore all the options
300available to you.
312301
313302# Physical Security
314303
315One large piece of self-hosting that people generally don\'t discuss
316online is physical security. However, physical security is very
317important for everyone who hosts a server like this. Exactly *how*
318important it is depends on the server use/purpose.
304One large piece of self-hosting that people generally don't discuss online is
305physical security. However, physical security is very important for everyone who
306hosts a server like this. Exactly *how* important it is depends on the server
307use/purpose.
319308
320If you self-host customer applications that hold protected data (HIPAA,
321GDPR, COPPA, etc.), then physical security is extremely important and
322cannot be ignored. If you simply host a blog and some hobby sites, then
323it\'s a relatively minor consideration, but one you still need to think
324about.
309If you self-host customer applications that hold protected data (HIPAA, GDPR,
310COPPA, etc.), then physical security is extremely important and cannot be
311ignored. If you simply host a blog and some hobby sites, then it's a relatively
312minor consideration, but one you still need to think about.
325313
326314## Location
327315
328The first consideration is quite simple: location. - Is the server
329within a property you own or housed on someone else\'s property? - Is it
330nearby (in your house, in your work office, in your neighbor\'s garage,
331in a storage unit, etc.)? - Do you have 24/7 access to the server? - Are
332there climate considerations, such as humidity, fires, tornadoes,
333monsoons? - Do you have emergency equipment nearby in case of emergency?
316The first consideration is quite simple: location.
317
318- Is the server within a property you own or housed on someone else's property?
319- Is it nearby (in your house, in your work office, in your neighbor's garage,
320 in a storage unit, etc.)?
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?
334325
335326## Hardware Ownership
336327
337Secondly, consider the hardware itself: - Do you own the server in its
338entirety? - Are any other users able to access the server, even if your
339data/space is segregated? - If you\'re utilizing a third party, do they
340have any documentation to show responsibility? This could be a SOC 1/2/3
341report, ISO compliance report, internal security/safety documentation.
328Secondly, consider the hardware itself:
329
330- Do you own the server in its entirety?
331- Are any other users able to access the server, even if your data/space is
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.
342336
343337## Physical Controls
344338
345Regardless of who owns the hardware, ensure that there are adequate
346safeguards in place, if necessary. These usually don\'t apply to small
347home servers and are usually covered already if you\'re utilizing a
348third party.
339Regardless of who owns the hardware, ensure that there are adequate safeguards
340in place, if necessary. These usually don't apply to small home servers and are
341usually covered already if you're utilizing a third party.
342
343These can include:
349344
350These can include: - Server bezel locks - Server room locks - physical,
351digital, or biometric authentication - Security cameras - Raised
352floors/lowered ceilings with proper guards/gates in-place within the
353floors or ceilings - Security personnel - Log sheets and/or guest badges
345- Server bezel locks
346- Server room locks - physical, digital, or biometric authentication
347- Security cameras
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 @@
11+++
22date = 2022-03-26
3title = "Enablt TOTP MFA for SSH"
3title = "Enable TOTP MFA for SSH"
44description = ""
55draft = false
66+++
77
88# Why Do I Need MFA for SSH?
99
10If you are a sysadmin of a server anywhere (that includes at home!), you
11may want an added layer of protection against intruders. This is not a
12replacement for other security measures, such as:
10If you are a sysadmin of a server anywhere (that includes at home!), you may
11want an added layer of protection against intruders. This is not a replacement
12for other security measures, such as:
1313
14- Disable root SSH
15- Disable SSH password authentication
16- Allow only certain users to login via SSH
17- Allow SSH only from certain IPs
14- Disable root SSH
15- Disable SSH password authentication
16- Allow only certain users to login via SSH
17- Allow SSH only from certain IPs
1818
19However, MFA can be added as an additional security measure to ensure
20that your server is protected. This is especially important if you need
21to allow password authentication for SSH.
19However, MFA can be added as an additional security measure to ensure that your
20server is protected. This is especially important if you need to allow password
21authentication for SSH.
2222
23For more guidance on server security measures, see my other post:
24[Hardening a Public-Facing Home
25Server](../hardening-a-public-facing-home-server/).
23For more guidance on server security measures, see my other post: [Hardening a
24Public-Facing Home Server](../hardening-a-public-facing-home-server/).
2625
2726# Install MFA PAM Module
2827
29PAM, which stands for Pluggable Authentication Module, is an
30authentication infrastructure used on Linux systems to authenticate a
31user. In order to use this technology, let\'s install the
32`libpam-google-authenticator` package:
28PAM, which stands for Pluggable Authentication Module, is an authentication
29infrastructure used on Linux systems to authenticate a user. In order to use
30this technology, let's install the `libpam-google-authenticator` package:
3331
3432```sh
3533sudo apt-get update
@@ -43,16 +41,16 @@ sudo apt-get install libpam-google-authenticator
4341
4442## Interactive Method
4543
46Once the package is installed, initialize it and following the
47interactive prompts to generate your OTP or TOTP:
44Once the package is installed, initialize it and following the interactive
45prompts to generate your OTP or TOTP:
4846
4947```sh
5048google-authenticator
5149```
5250
53If you are not sure how to answer, read the prompts carefully and think
54about having to how each situation would affect your normal login
55attempts. If you are still not sure, use my default responses below.
51If you are not sure how to answer, read the prompts carefully and think about
52having to how each situation would affect your normal login attempts. If you are
53still not sure, use my default responses below.
5654
5755``` txt
5856OUTPUT
@@ -60,9 +58,9 @@ OUTPUT
6058Do you want authentication tokens to be time-based (y/n) y
6159```
6260
63At this point, use an authenticator app somewhere one of your devices to
64scan the QR code. Any future login attempts after our upcoming
65configuration changes will require that TOTP.
61At this point, use an authenticator app somewhere one of your devices to scan
62the QR code. Any future login attempts after our upcoming configuration changes
63will require that TOTP.
6664
6765``` txt
6866OUTPUT
@@ -104,9 +102,9 @@ Do you want to enable rate-limiting? (y/n) y
104102
105103## Non-Interactive Method
106104
107If you need to do this quickly, know your responses to the prompts, or
108are setting this up for numerous users, the non-interactive method can
109be much faster:
105If you need to do this quickly, know your responses to the prompts, or are
106setting this up for numerous users, the non-interactive method can be much
107faster:
110108
111109```sh
112110google-authenticator -t -d -f -r 3 -R 30 -w 3
@@ -136,23 +134,23 @@ google-authenticator [<options>]
136134 -e, --emergency-codes=N Number of emergency codes to generate
137135```
138136
139This fully configures the authenticator, saves it to a file, and then
140outputs the secret key, QR code, and recovery codes. (If you add the
141flag `-q`, then there won\'t be any output). If you use this
142command in an automated fashion, make sure your script captures the
143secret key and/or recovery codes and makes them available to the user.
137This fully configures the authenticator, saves it to a file, and then outputs
138the secret key, QR code, and recovery codes. (If you add the flag `-q`, then
139there won't be any output). If you use this command in an automated fashion,
140make sure your script captures the secret key and/or recovery codes and makes
141them available to the user.
144142
145143# PAM Configuration Settings
146144
147Once you\'ve enabled the T/OTP and have it saved to an MFA app on your
148phone or other device, open the PAM `sshd` file:
145Once you've enabled the T/OTP and have it saved to an MFA app on your phone or
146other device, open the PAM `sshd` file:
149147
150148```sh
151149sudo nano /etc/pam.d/sshd
152150```
153151
154You need to do two things in this file. First, add the following lines
155to the bottom of the file:
152You need to do two things in this file. First, add the following lines to the
153bottom of the file:
156154
157155``` config
158156auth required pam_google_authenticator.so nullok
@@ -161,8 +159,8 @@ auth required pam_permit.so
161159
162160Second, comment-out the following line near the top of the file.
163161
164If you leave this line uncommented, every SSH login attempt will ask for
165the following three authentication factors:
162If you leave this line uncommented, every SSH login attempt will ask for the
163following three authentication factors:
166164
1671651. Publickey
1681662. Password
@@ -180,9 +178,8 @@ Finally, edit the `sshd_config` file again:
180178sudo nano /etc/ssh/sshd_config
181179```
182180
183You\'ll need to change `ChallengeResponseAuthentication` to
184yes and add the `AuthenticationMethods` line to the bottom of
185the file.
181You'll need to change `ChallengeResponseAuthentication` to yes and add the
182`AuthenticationMethods` line to the bottom of the file.
186183
187184``` config
188185ChallengeResponseAuthentication yes
content/blog/2022-04-02-nginx-reverse-proxy.md +83 −92
@@ -7,36 +7,34 @@ draft = false
77
88# What is a Reverse Proxy?
99
10A reverse proxy is a server that is placed between local servers or
11services and clients/users (e.g., the internet). The reverse proxy
12intercepts all requests from clients at the network edge and uses its
13configuration files to determine where each request should be sent.
10A reverse proxy is a server that is placed between local servers or services and
11clients/users (e.g., the internet). The reverse proxy intercepts all requests
12from clients at the network edge and uses its configuration files to determine
13where each request should be sent.
1414
1515## A Brief Example
1616
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:
1818
19- Server~01~ (`example.com`)
20- Server~02~ (`service01.example.com`)
21- Server~03~ (`service02.example.com`)
19- Server01 (`example.com`)
20- Server02 (`service01.example.com`)
21- Server03 (`service02.example.com`)
2222
23I also run a reverse proxy in my home that intercepts all public
24traffic:
23I also run a reverse proxy in my home that intercepts all public traffic:
2524
26- Reverse Proxy
25- Reverse Proxy
2726
28Assume that I have a domain name (`example.com`) that allows
29clients to request websites or services from my home servers.
27Assume that I have a domain name (`example.com`) that allows clients to request
28websites or services from my home servers.
3029
31In this case, the reverse proxy will intercept all traffic from
32`example.com` that enters my network and determine if the
33client is requesting valid data, based on my configuration.
30In this case, the reverse proxy will intercept all traffic from `example.com`
31that enters my network and determine if the client is requesting valid data,
32based on my configuration.
3433
35If the user is requesting `example.com` and my configuration
36files say that Server~01~ holds that data, Nginx will send the user to
37Server~01~. If I were to change the configuration so that
38`example.com` is routed to Server~02~, that same user would
39be sent to Server~02~ instead.
34If the user is requesting `example.com` and my configuration files say that
35Server~01~ holds that data, Nginx will send the user to Server~01~. If I were to
36change the configuration so that `example.com` is routed to Server~02~, that
37same user would be sent to Server~02~ instead.
4038
4139``` txt
4240┌──────┐ ┌───────────┐
@@ -52,62 +50,61 @@ be sent to Server~02~ instead.
5250
5351# Reverse Proxy Options
5452
55There are a lot of options when it comes to reverse proxy servers, so
56I\'m just going to list a few of the options I\'ve heard recommended
57over the last few years:
53There are a lot of options when it comes to reverse proxy servers, so I'm just
54going to list a few of the options I've heard recommended over the last few
55years:
5856
59- [Nginx](https://nginx.com)
60- [Caddy](https://caddyserver.com)
61- [Traefik](https://traefik.io/)
62- [HAProxy](https://www.haproxy.org/)
63- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid)
57- [Nginx](https://nginx.com)
58- [Caddy](https://caddyserver.com)
59- [Traefik](https://traefik.io/)
60- [HAProxy](https://www.haproxy.org/)
61- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid)
6462
65In this post, we will be using Nginx as our reverse proxy, running on
66Ubuntu Server 20.04.4 LTS.
63In this post, we will be using Nginx as our reverse proxy, running on Ubuntu
64Server 20.04.4 LTS.
6765
6866# Nginx Reverse Proxy Example
6967
7068## Local Applications
7169
72You may be like me and have a lot of applications running on your local
73network that you\'d like to expose publicly with a domain.
70You may be like me and have a lot of applications running on your local network
71that you'd like to expose publicly with a domain.
7472
75In my case, I have services running in multiple Docker containers within
76a single server and want a way to visit those services from anywhere
77with a URL. For example, on my local network, [Dashy](https://dashy.to)
78runs through port 4000 (`localhost:4000`) and [Uptime
73In my case, I have services running in multiple Docker containers within a
74single server and want a way to visit those services from anywhere with a URL.
75For example, on my local network, [Dashy](https://dashy.to) runs through port
764000 (`localhost:4000`) and [Uptime
7977Kuma](https://github.com/louislam/uptime-kuma) runs through port 3001
8078(`localhost:3001`).
8179
8280In order to expose these services to the public, I will need to do the
8381following:
8482
851. Set up DNS records for a domain or subdomain (one per service) to
86 point toward the IP address of the server.
872. Open up the server network\'s HTTP and HTTPS ports (80 & 443) so
88 that the reverse proxy can accept traffic and determine where to
89 send it.
903. Install the reverse proxy software.
914. Configure the reverse proxy to recognize which service should get
92 traffic from any of the domains or subdomains.
831. Set up DNS records for a domain or subdomain (one per service) to point
84 toward the IP address of the server.
852. Open up the server network's HTTP and HTTPS ports (80 & 443) so that the
86 reverse proxy can accept traffic and determine where to send it.
873. Install the reverse proxy software.
884. Configure the reverse proxy to recognize which service should get traffic
89 from any of the domains or subdomains.
9390
9491## Step 1: DNS Configuration
9592
96To start, update your DNS configuration so that you have an
97`A` record for each domain or subdomain.
93To start, update your DNS configuration so that you have an `A` record for each
94domain or subdomain.
9895
99The `A` records should point toward the public IP address of
100the server. If you don\'t know the public IP address, log in to the
101server and run the following command:
96The `A` records should point toward the public IP address of the server. If you
97don't know the public IP address, log in to the server and run the following
98command:
10299
103100```sh
104101curl ifconfig.co
105102```
106103
107In the DNS example below, `xxx.xxx.xxx.xxx` is the public IP
108address of the server.
104In the DNS example below, `xxx.xxx.xxx.xxx` is the public IP address of the
105server.
109106
110``` config
107```conf
111108example.com A xxx.xxx.xxx.xxx
112109uptime.example.com A xxx.xxx.xxx.xxx
113110dashy.example.com A xxx.xxx.xxx.xxx
@@ -115,33 +112,30 @@ www CNAME example.com
115112```
116113
117114Finally, ensure the DNS has propagated correctly with [DNS
118Checker](https://dnschecker.org) by entering your domains or subdomains
119in the search box and ensuring the results are showing the correct IP
120address.
115Checker](https://dnschecker.org) by entering your domains or subdomains in the
116search box and ensuring the results are showing the correct IP address.
121117
122118## Step 2: Open Network Ports
123119
124This step will be different depending on which router you have in your
125home. If you\'re not sure, try to visit
126[192.168.1.1](http://192.168.1.1) in your browser. Login credentials are
127usually written on a sticker somewhere on your modem/router.
120This step will be different depending on which router you have in your home. If
121you're not sure, try to visit [192.168.1.1](http://192.168.1.1) in your
122browser. Login credentials are usually written on a sticker somewhere on your
123modem/router.
128124
129Once you\'re able to log in to your router, find the Port Forwarding
130settings. You will need to forward ports `80` and
131`443` to whichever machine is running the reverse proxy.
125Once you're able to log in to your router, find the Port Forwarding settings.
126You will need to forward ports `80` and `443` to whichever machine is running
127the reverse proxy.
132128
133In my case, the table below shows the port-forwarding rules I\'ve
134created. In this table, `xxx.xxx.xxx.xxx` is the local device
135IP of the reverse proxy server, it will probably be an IP between
136`192.168.1.1` and `192.168.1.255`.
129In my case, the table below shows the port-forwarding rules I've created. In
130this table, `xxx.xxx.xxx.xxx` is the local device IP of the reverse proxy
131server, it will probably be an IP between `192.168.1.1` and `192.168.1.255`.
137132
138 NAME FROM PORT DEST PORT/IP ENABLED
139 ------- ------ ------ ----------------- ---------
140 HTTP ​\*\* 80 xxx.xxx.xxx.xxx TRUE
141 HTTPS ​\*\* 443 xxx.xxx.xxx.xxx TRUE
133| NAME | FROM PORT | DEST PORT/IP | ENABLED |
134|-------|-----------|-----------------|---------|
135| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE |
136| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE |
142137
143Once configured, these rules will direct all web traffic to your reverse
144proxy.
138Once configured, these rules will direct all web traffic to your reverse proxy.
145139
146140## Step 3: Nginx Installation
147141
@@ -151,12 +145,11 @@ To install Nginx, simply run the following command:
151145sudo apt install nginx
152146```
153147
154If you have a firewall enabled, open up ports `80` and
155`443` on your server so that Nginx can accept web traffic
156from the router.
148If you have a firewall enabled, open up ports `80` and `443` on your server so
149that Nginx can accept web traffic from the router.
157150
158For example, if you want to use `ufw` for web traffic and
159SSH, run the following commands:
151For example, if you want to use `ufw` for web traffic and SSH, run the following
152commands:
160153
161154```sh
162155sudo ufw allow 'Nginx Full'
@@ -166,14 +159,12 @@ sudo ufw enable
166159
167160## Step 4: Nginx Configuration
168161
169Now that we have domains pointing toward the server, the only step left
170is to configure the reverse proxy to direct traffic from domains to
171local services.
162Now that we have domains pointing toward the server, the only step left is to
163configure the reverse proxy to direct traffic from domains to local services.
172164
173To start, you\'ll need to create a configuration file for each domain in
174`/etc/nginx/sites-available/`. They will look identical
175except for the `server_name` variable and the
176`proxy_pass` port.
165To start, you'll need to create a configuration file for each domain in
166`/etc/nginx/sites-available/`. They will look identical except for the
167`server_name` variable and the `proxy_pass` port.
177168
178169Dashy:
179170
@@ -209,8 +200,8 @@ server {
209200}
210201```
211202
212Once the configuration files are created, you will need to enable them
213with the `symlink` command:
203Once the configuration files are created, you will need to enable them with the
204`symlink` command:
214205
215206```sh
216207sudo 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.
220211
221212# HTTPS with Certbot
222213
223If you\'ve followed along, you\'ll notice that your services are only
224available via HTTP (not HTTPS).
214If you've followed along, you'll notice that your services are only available
215via HTTP (not HTTPS).
225216
226If you want to enable HTTPS for your new domains, you will need to
227generate SSL/TLS certificates for them. The easiest way to generate
228certificates on Nginx is [Certbot](https://certbot.eff.org):
217If you want to enable HTTPS for your new domains, you will need to generate
218SSL/TLS certificates for them. The easiest way to generate certificates on Nginx
219is [Certbot](https://certbot.eff.org):
229220
230221```sh
231222sudo 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
99
1010## Overview
1111
12The [PineTime](https://www.pine64.org/pinetime/) is an open-source
13smartwatch, created by [PINE64](https://www.pine64.org). Originally
14announced in September 2019, this ARM-based watch is a fantastic option
15for users who want the benefits of a modern smartwatch with the backing
16of open-source components and software.
12The [PineTime](https://www.pine64.org/pinetime/) is an open-source smartwatch,
13created by [PINE64](https://www.pine64.org). Originally announced in September
142019, this ARM-based watch is a fantastic option for users who want the benefits
15of a modern smartwatch with the backing of open-source components and software.
1716
1817## Product Specifications
1918
20I 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
22prices for each watch and the primary functions:
19I won't dive into too many details that you can find on [the product
20page](https://www.pine64.org/pinetime/), but I wanted to point out the prices
21for each watch and the primary functions:
2322
24231. Price:
2524
26 - \$26.99 (Sealed)
27 - \$24.99 (Dev Kit)
28 - \$51.98 (One Sealed + One Dev Kit)
25 - $26.99 (Sealed)
26 - $24.99 (Dev Kit)
27 - $51.98 (One Sealed + One Dev Kit)
2928
30292. Primary Functionality:
3130
32 - Clock (+ Smartphone Sync)
33 - Pedometer
34 - Heart Rate Monitor
35 - Sleep Monitor
36 - Calories burned
37 - Messaging
38 - Smartphone Notifications
39 - Media Controls
31 - Clock (+ Smartphone Sync)
32 - Pedometer
33 - Heart Rate Monitor
34 - Sleep Monitor
35 - Calories burned
36 - Messaging
37 - Smartphone Notifications
38 - Media Controls
4039
4140# Unboxing
4241
43Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and
44was delivered on 2022-03-23. With the current delays on shipping times
45around the world (and the semiconductor shortage), a month for delivery
46from China seems reasonable to me.
42Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and was
43delivered on 2022-03-23. With the current delays on shipping times around the
44world (and the semiconductor shortage), a month for delivery from China seems
45reasonable to me.
4746
48The packaging is simple, and the watch comes with instructions,
49technical information, the watch, and a charger (it does not include a
50USB wall adapter).
47The packaging is simple, and the watch comes with instructions, technical
48information, the watch, and a charger (it does not include a USB wall adapter).
5149
52The watch itself was able to turn on immediately when I pulled it out of
53the box, but the battery was depleted and required charging right away.
50The watch itself was able to turn on immediately when I pulled it out of the
51box, but the battery was depleted and required charging right away.
5452
5553![PineTime Box
5654Contents](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
5957
6058## Watch OS: InfiniTime
6159
62While turning on the watch for the first time, some of the main design
63choices you can see in the watch OS,
60While turning on the watch for the first time, some of the main design choices
61you can see in the watch OS,
6462[InfiniTime](https://wiki.pine64.org/wiki/InfiniTime), are:
6563
66- A square bezel, not too thin against the sides of the watch.
67- A simple, rubber band.
68- Basic font and screen pixel design.
69- Swipe gestures to access other screens.
64- A square bezel, not too thin against the sides of the watch.
65- A simple, rubber band.
66- Basic font and screen pixel design.
67- Swipe gestures to access other screens.
7068
7169![PineTime
7270Screens](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime.png)
7371
74The OS itself is fantastic in terms of functionality for me. It does
75exactly what a smartwatch should do - track time, steps, heart rates,
76and connect to another smart device, without being overly burdensome to
77the user.
72The OS itself is fantastic in terms of functionality for me. It does exactly
73what a smartwatch should do - track time, steps, heart rates, and connect to
74another smart device, without being overly burdensome to the user.
7875
79My only gripe so far is that it\'s *really* difficult to swipe to
80different screens, such as pulling down the notification tray. I\'m not
81sure if this is an OS or hardware issue, but it makes it quite hard to
82quickly move around the screens.
76My only gripe so far is that it's *really* difficult to swipe to different
77screens, such as pulling down the notification tray. I'm not sure if this is an
78OS or hardware issue, but it makes it quite hard to quickly move around the
79screens.
8380
84However, my absolute favorite design choice is that the button the side
85turns the screen on and off and tilting/waving my wrist doesn\'t
86accidentally turn on the screen. With other watches, I absolutely hated
87not being able to turn off the raise-to-wake or wave features (i.e.,
88blinding myself while wearing a watch at night because I moved my arm).
81However, my absolute favorite design choice is that the button the side turns
82the screen on and off and tilting/waving my wrist doesn't accidentally turn on
83the screen. With other watches, I absolutely hated not being able to turn off
84the raise-to-wake or wave features (i.e., blinding myself while wearing a watch
85at night because I moved my arm).
8986
9087## iOS App: InfiniLink
9188
9289Since 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
94watch.
90[InfiniLink](https://github.com/xan-m/InfiniLink) app to connect my watch.
9591
9692This app provides the following for PineTime owners:
9793
98- Firmware updates
99- Steps
100- Charts
101- Notifications
94- Firmware updates
95- Steps
96- Charts
97- Notifications
10298
103I mashed up a few screenshots to show off the home page, menu, firmware
104update, and notification test screens:
99I mashed up a few screenshots to show off the home page, menu, firmware update,
100and notification test screens:
105101
106102![InfiniLink
107103Home](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_home.png)
108104
109Another big feature of InfiniLink is the ability to track pedometer
110steps in a collection of beautiful graphs, with the option to change
111your step goal and add in manual steps.
105Another big feature of InfiniLink is the ability to track pedometer steps in a
106collection of beautiful graphs, with the option to change your step goal and add
107in manual steps.
112108
113109![InfiniLink
114110Steps](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/infinilink_steps.png)
115111
116Finally, there are charts to display the battery percentage and heart
117rates over time. This area also comes with an option to clear data.
112Finally, there are charts to display the battery percentage and heart rates over
113time. This area also comes with an option to clear data.
118114
119115![InfiniLink
120116Charts](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
123119
124120## Pros
125121
126After wearing my watch for a few weeks, I have mostly positive thoughts
127about the watch so far. In the past, I have owned smartwatches by
128FitBit, Fossil, Apple, etc. - **but I prefer the PineTime over all of
129those watches**.
122After wearing my watch for a few weeks, I have mostly positive thoughts about
123the watch so far. In the past, I have owned smartwatches by FitBit, Fossil,
124Apple, etc. - **but I prefer the PineTime over all of those watches**.
130125
131The PineTime strips out all the unnecessary features and performs the
132functions that it provides effectively and efficiently.
126The PineTime strips out all the unnecessary features and performs the functions
127that it provides effectively and efficiently.
133128
134The battery life is amazing on this device. By default, the watch seems
135to last anywhere from a few days to a week before dying.
129The battery life is amazing on this device. By default, the watch seems to last
130anywhere from a few days to a week before dying.
136131
137And of course, it\'s open source and backed by some of the most
138dedicated enthusiasts and developers I\'ve seen. Watching the Matrix
139channel, forums, and website have been exciting to see.
132And of course, it's open source and backed by some of the most dedicated
133enthusiasts and developers I've seen. Watching the Matrix channel, forums, and
134website have been exciting to see.
140135
141136## Cons
142137
143If I had to complain about anything, it would simply be the small bugs
144in some features that can be contributed to the companion apps more than
145the watch itself.
138If I had to complain about anything, it would simply be the small bugs in some
139features that can be contributed to the companion apps more than the watch
140itself.
146141
147A regular user would want native notification support out-of-the-box,
148which is the biggest item not working for me at the moment.
142A regular user would want native notification support out-of-the-box, which is
143the biggest item not working for me at the moment.
149144
150My only other complaint is that the battery indicator on the watch
151doesn\'t seem accurate when it\'s nearing depletion - it seems that
152there\'s a bit of battery life left and then my watch is dead very
153suddenly after. This could just be me misinterpreting the battery level
154icons, but it has fooled me a few times into thinking I had more battery
155left than I actually did.
145My only other complaint is that the battery indicator on the watch doesn't seem
146accurate when it's nearing depletion - it seems that there's a bit of battery
147life left and then my watch is dead very suddenly after. This could just be me
148misinterpreting the battery level icons, but it has fooled me a few times into
149thinking I had more battery left than I actually did.
156150
157Other than those small items, I really do love this watch and am glad I
158replaced my Apple Watch with the PineTime.
151Other than those small items, I really do love this watch and am glad I replaced
152my Apple Watch with the PineTime.
content/blog/2022-06-01-ditching-cloudflare.md +52 −58
@@ -7,89 +7,83 @@ draft = false
77
88# Registrar
99
10After spending a year or so using Cloudflare for DNS only - no proxying
11or applications - I spent the last few months using Cloudflare Tunnels
12and Cloudflare Access to protect my self-hosted websites and
13applications via their proxy traffic model.
10After spending a year or so using Cloudflare for DNS only - no proxying or
11applications - I spent the last few months using Cloudflare Tunnels and
12Cloudflare Access to protect my self-hosted websites and applications via their
13proxy traffic model.
1414
15However, I have never liked using Cloudflare due to their increasingly
16large share of control over web traffic, as well as their business model
17of being a MITM for all of your traffic.
15However, I have never liked using Cloudflare due to their increasingly large
16share of control over web traffic, as well as their business model of being a
17MITM for all of your traffic.
1818
1919So, as of today, I have switched over to [Njalla](https://njal.la) as my
2020registrar and DNS manager. I was able to easily transfer my domains over
21rapidly, with only one domain taking more than 15-30 minutes to
22propagate.
21rapidly, with only one domain taking more than 15-30 minutes to propagate.
2322
24+I do still have two domains sitting at Cloudflare for the moment while
25I decide if they\'re worth the higher rates (one domain is 30€ and the
26other is 45€).+
23+I do still have two domains sitting at Cloudflare for the moment while I decide
24if they're worth the higher rates (one domain is 30€ and the other is 45€).+
2725
28> **Update (2022.06.03)**: I ended up transferring my final two domains
29> over to Njalla, clearing my Cloudflare account of personal data, and
30> deleting the Cloudflare account entirely. *I actually feel relieved to
31> have moved on to a provider I trust.*
26> **Update (2022.06.03)**: I ended up transferring my final two domains over to
27> Njalla, clearing my Cloudflare account of personal data, and deleting the
28> Cloudflare account entirely. *I actually feel relieved to have moved on to a
29> provider I trust.*
3230
3331# DNS
3432
35As noted above, I\'m using Njalla exclusively for DNS configurations on
36my domains.
33As noted above, I'm using Njalla exclusively for DNS configurations on my
34domains.
3735
38However, the transfer process was not ideal. As soon as the domains
39transferred over, I switched the nameservers from Cloudflare to Njalla
40and lost most of the associated DNS records. So, the majority of the
41time spent during the migration was simply re-typing all the DNS records
42back in one-by-one.
36However, the transfer process was not ideal. As soon as the domains transferred
37over, I switched the nameservers from Cloudflare to Njalla and lost most of the
38associated DNS records. So, the majority of the time spent during the migration
39was simply re-typing all the DNS records back in one-by-one.
4340
44This would be much simpler if I were able to edit the plain-text format
45of the DNS configuration. I was able to do that at a past registrar
46(perhaps it was [Gandi.net](https://gandi.net/)?) and it made life a lot
47easier.
41This would be much simpler if I were able to edit the plain-text format of the
42DNS configuration. I was able to do that at a past registrar (perhaps it was
43[Gandi.net](https://gandi.net/)?) and it made life a lot easier.
4844
4945## Dynamic DNS Updates
5046
51I have built an easy Python script to run (or set-up in
52`cron` to run automatically) that will check my server\'s
53IPv4 and IPv6, compare it to Njalla, and update the DNS records if they
54don\'t match. You can see the full script and process in my other post:
55[Updating Dynamic DNS with Njalla API](../njalla-dns-api/).
47I have built an easy Python script to run (or set-up in `cron` to run
48automatically) that will check my server's IPv4 and IPv6, compare it to Njalla,
49and update the DNS records if they don't match. You can see the full script and
50process in my other post: [Updating Dynamic DNS with Njalla
51API](../njalla-dns-api/).
5652
57I haven\'t used this other method, but I do know that you can create
58`Dynamic` DNS records with Njalla that [work for updating
59dynamic subdomains](https://njal.la/docs/ddns/).
53I haven't used this other method, but I do know that you can create `Dynamic`
54DNS records with Njalla that [work for updating dynamic
55subdomains](https://njal.la/docs/ddns/).
6056
61## Njalla\'s DNS Tool
57## Njalla's DNS Tool
6258
6359One neat upside to Njalla is that they have a [DNS lookup
64tool](https://check.njal.la/dns/) that provides a lot of great
65information for those of you (AKA: me) who hate using the
66`dig` command.
60tool](https://check.njal.la/dns/) that provides a lot of great information for
61those of you (AKA: me) who hate using the `dig` command.
6762
68This was very useful for monitoring a couple of my transferred domains
69to see when the changes in nameservers, records, and DNSSEC went into
70effect.
63This was very useful for monitoring a couple of my transferred domains to see
64when the changes in nameservers, records, and DNSSEC went into effect.
7165
7266# Tunnel
7367
7468Cloudflare 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
76the server hosting my various websites and apps.
69Cloudflare's servers) and allowed me to mask the private IP address of the
70server hosting my various websites and apps.
7771
78However, as I was moving away from Cloudflare, I was not able to find a
79suitable replacement that was both inexpensive and simple. So, I simply
80went back to hosting [my own reverse proxy with
81Nginx](file:///blog/set-up-nginx-reverse-proxy/). With the recent
82additions of Unifi hardware in my server/network rack, I am much more
83protected against spam and malicious attacks at the network edge than I
84was before I switched to Cloudflare.
72However, as I was moving away from Cloudflare, I was not able to find a suitable
73replacement that was both inexpensive and simple. So, I simply went back to
74hosting [my own reverse proxy with
75Nginx](file:///blog/set-up-nginx-reverse-proxy/). With the recent additions of
76Unifi hardware in my server/network rack, I am much more protected against spam
77and malicious attacks at the network edge than I was before I switched to
78Cloudflare.
8579
8680# Access
8781
88Cloudflare Access, another app I used in combination with Cloudflare
89Tunnel, provided an authentication screen that required you to enter
90valid credentials before Cloudflare would forward you to the actual
91website or app (if the website/app has their own authentication, you\'d
92then have to authenticate a second time).
82Cloudflare Access, another app I used in combination with Cloudflare Tunnel,
83provided an authentication screen that required you to enter valid credentials
84before Cloudflare would forward you to the actual website or app (if the
85website/app has their own authentication, you'd then have to authenticate a
86second time).
9387
94I did not replace this service with anything since I only host a handful
95of non-sensitive apps that don\'t require duplicate authentication.
88I did not replace this service with anything since I only host a handful of
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
77
88# Why RSS?
99
10After noticing that I have collected 50+ blogs as bookmarks, I decided
11to migrate back to using RSS feeds to stay up-to-date with my favorite
12websites. Using RSS allows me to read all of these posts in a single app
13(on both mobile & desktop) and allows me to be notified when new posts
14are available.
10After noticing that I have collected 50+ blogs as bookmarks, I decided to
11migrate back to using RSS feeds to stay up-to-date with my favorite websites.
12Using RSS allows me to read all of these posts in a single app (on both mobile &
13desktop) and allows me to be notified when new posts are available.
1514
16However, I ran into one issue: syncing subscriptions and read/unread
17posts across devices. Since I want to be able to easily read on both
18mobile and desktop, I decided to look for a self-hosted RSS solution.
15However, I ran into one issue: syncing subscriptions and read/unread posts
16across devices. Since I want to be able to easily read on both mobile and
17desktop, I decided to look for a self-hosted RSS solution.
1918
20Thus, I found [FreshRSS](https://www.freshrss.org/) and was able to
21successfully install it on my server in about 30 minutes.
19Thus, I found [FreshRSS](https://www.freshrss.org/) and was able to successfully
20install it on my server in about 30 minutes.
2221
2322# Documentation
2423
25While it\'s certainly not robust, the [FreshRSS
26documentation](https://freshrss.github.io/FreshRSS/) is helpful for
27figuring out basic information about the service.
24While it's certainly not robust, the [FreshRSS
25documentation](https://freshrss.github.io/FreshRSS/) is helpful for figuring out
26basic information about the service.
2827
29However, I wanted to install this service as a Docker container and
30stumbled across the [Docker
31README](https://github.com/FreshRSS/FreshRSS/tree/edge/Docker) within
32the GitHub repository.
28However, I wanted to install this service as a Docker container and stumbled
29across the [Docker
30README](https://github.com/FreshRSS/FreshRSS/tree/edge/Docker) within the GitHub
31repository.
3332
34This README was the documentation I actually needed. However, as you\'ll
35see below, I still had to manually edit one file
36(`config.php`) to access the API externally via my RSS apps.
33This README was the documentation I actually needed. However, as you'll see
34below, I still had to manually edit one file (`config.php`) to access the API
35externally via my RSS apps.
3736
3837# Installation
3938
4039## DNS
4140
42The first step, as required by any external web service, was assigning a
43domain name to use. I chose to use a subdomain, like
44`rss.example.com`.
41The first step, as required by any external web service, was assigning a domain
42name to use. I chose to use a subdomain, like `rss.example.com`.
4543
46To assign this, I created an `A` record in my DNS settings
47with the IPv4 address of the server and an `AAAA` record with
48the IPv6 address of the server. Note: assigning an IPv6
49(`AAAA`) record is optional, but I like to enable IPV6 for my
44To assign this, I created an `A` record in my DNS settings with the IPv4 address
45of the server and an `AAAA` record with the IPv6 address of the server. Note:
46assigning an IPv6 (`AAAA`) record is optional, but I like to enable IPV6 for my
5047services.
5148
5249``` config
@@ -56,15 +53,13 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx
5653
5754## Docker
5855
59I initially tried to set up a `docker-compose.yml` file with
60a `.env` file because I prefer to have a file I can look back
61at later to see how I initially started the container, but it simply
62wouldn\'t work for me. I\'m not sure why, but I assume I wasn\'t telling
63`docker-compose` where the `.env` file was.
56I initially tried to set up a `docker-compose.yml` file with a `.env` file
57because I prefer to have a file I can look back at later to see how I initially
58started the container, but it simply wouldn't work for me. I'm not sure why,
59but I assume I wasn't telling `docker-compose` where the `.env` file was.
6460
65Regardless, I chose to simply run the service with
66`docker run`. See the following command for my
67`docker run` configuration:
61Regardless, I chose to simply run the service with `docker run`. See the
62following command for my `docker run` configuration:
6863
6964```sh
7065sudo 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 \
7772 freshrss/freshrss
7873```
7974
80This started the container successfully and allowed me to visit the
81FreshRSS instance at `localhost:8080`.
75This started the container successfully and allowed me to visit the FreshRSS
76instance at `localhost:8080`.
8277
8378## Fresh RSS Set-Up
8479
85I **HIGHLY\*** suggest that you set up your user account prior to
86exposing this service to the public. It\'s unlikely that someone is
87trying to access the exact domain or IP/port you\'re assigning here, but
88as soon as you expose this service, the first person to open the URL
89will be able to create the admin user.
80I **HIGHLY** suggest that you set up your user account prior to exposing this
81service to the public. It's unlikely that someone is trying to access the exact
82domain or IP/port you're assigning here, but as soon as you expose this
83service, the first person to open the URL will be able to create the admin user.
9084
91In order to set up your FreshRSS service, open the
92`localhost:8080` URL in your browser (you may need to use a
93local IP instead of `localhost` if you\'re accessing the page
94from a different machine on the network - e.g.,
85In order to set up your FreshRSS service, open the `localhost:8080` URL in your
86browser (you may need to use a local IP instead of `localhost` if you're
87accessing the page from a different machine on the network - e.g.,
9588`192.168.1.20:8080`).
9689
9790Once the page loads, set up your default user with a strong username and
98password. You may also choose to configure other settings prior to
99exposing this service.
91password. You may also choose to configure other settings prior to exposing this
92service.
10093
10194## Nginx Reverse-Proxy
10295
10396In order to access this service outside my home, I needed to set up a
104reverse-proxy to connect `localhost:8080` to
105`rss.example.com`.
97reverse-proxy to connect `localhost:8080` to `rss.example.com`.
10698
10799First, I created a new Nginx configuration file:
108100
@@ -143,8 +135,7 @@ server {
143135}
144136```
145137
146Finally, restart Nginx and you will be able to access your service via
147HTTP:
138Finally, restart Nginx and you will be able to access your service via HTTP:
148139
149140```sh
150141sudo systemctl restart nginx.service
@@ -152,51 +143,46 @@ sudo systemctl restart nginx.service
152143
153144## HTTPS
154145
155However, I don\'t want to access my RSS feeds via HTTP. I want it
156available only via HTTPS. In order to do this, I ran the
157[certbot](https://certbot.eff.org/) program to generate SSL certificates
158for me:
146However, I don't want to access my RSS feeds via HTTP. I want it available only
147via HTTPS. In order to do this, I ran the [certbot](https://certbot.eff.org/)
148program to generate SSL certificates for me:
159149
160150```sh
161151sudo certbot --nginx
162152```
163153
164This process will automatically generate an SSL certificate for you and
165modify the Nginx configuration file to include a redirect from HTTP to
166HTTPS.
154This process will automatically generate an SSL certificate for you and modify
155the Nginx configuration file to include a redirect from HTTP to HTTPS.
167156
168157# Post-Installation Fixes
169158
170At this point, we have a functional FreshRSS website, available from
171anywhere and secured with HTTPS. However, attempting to connect this
172service to an RSS app resulted in many errors regarding unavailable URLs
173and incorrect credentials.
159At this point, we have a functional FreshRSS website, available from anywhere
160and secured with HTTPS. However, attempting to connect this service to an RSS
161app resulted in many errors regarding unavailable URLs and incorrect
162credentials.
174163
175164## API Set-Up
176165
177First, you need to open your user profile in FreshRSS
178(`Settings` \> `Profile`) and set an API password
179in the field at the bottom. This is the password you will need to
180provide to your RSS apps.
166First, you need to open your user profile in FreshRSS (`Settings` > `Profile`)
167and set an API password in the field at the bottom. This is the password you
168will need to provide to your RSS apps.
181169
182Once that is set and saved, click the link below the API password field
183to open the API check tool. It should look something like
184`https://localhost:8080/api/` or
185`https://rss.example.com/api/`.
170Once that is set and saved, click the link below the API password field to open
171the API check tool. It should look something like `https://localhost:8080/api/`
172or `https://rss.example.com/api/`.
186173
187Within this page, you *should* see your correct external URL and
188\"PASS\" at the bottom of each API type. This would mean everything is
189set up correctly, and you can now move on and login to any RSS apps that
190support self-hosted options.
174Within this page, you *should* see your correct external URL and "PASS" at the
175bottom of each API type. This would mean everything is set up correctly, and you
176can now move on and login to any RSS apps that support self-hosted options.
191177
192178In 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
194case, see the next section for a fix.
179`base_url` variable may be misconfigured. If this is the case, see the next
180section for a fix.
195181
196182## Base URL Fix
197183
198In order to fix the `base_url` for the API, I opened up my
199docker container with the following command:
184In order to fix the `base_url` for the API, I opened up my docker container with
185the following command:
200186
201187```sh
202188sudo docker exec -it freshrss bash
@@ -209,17 +195,15 @@ apt-get update
209195apt-get install nano
210196```
211197
212Finally, open up `config.php` in the `data`
213directory:
198Finally, open up `config.php` in the `data` directory:
214199
215200```sh
216201nano data/config.php
217202```
218203
219Within `config.php`, you will need to update the
220`base_url` variable and update it to match your external URL.
221In my case, I simply commented-out the incorrect URL with
222`//` and added the correct one on a new line:
204Within `config.php`, you will need to update the `base_url` variable and update
205it to match your external URL. In my case, I simply commented-out the incorrect
206URL with `//` and added the correct one on a new line:
223207
224208``` php
225209<?php
@@ -232,9 +216,8 @@ In my case, I simply commented-out the incorrect URL with
232216>
233217```
234218
235You can now exit the file with `Ctrl + x`, press
236`y` to save the file, and then click `Enter` to
237keep the same file name.
219You can now exit the file with `Ctrl + x`, press `y` to save the file, and then
220click `Enter` to keep the same file name.
238221
239222Finally, just exit out of the docker container:
240223
@@ -248,8 +231,8 @@ Next, just restart the container:
248231sudo docker restart freshrss
249232```
250233
251Voilà! Your API check should now \"PASS\" and you should be able to use
252one of the API URLs in your RSS apps.
234Voilà! Your API check should now "PASS" and you should be able to use one of
235the API URLs in your RSS apps.
253236
254In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop
255and phone.
237In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop and
238phone.
content/blog/2022-06-16-terminal-lifestyle.md +113 −126
@@ -7,165 +7,155 @@ draft = false
77
88# Text-Based Simplicity
99
10I\'ve detailed my views on web-based minimalism and related topics in
11other posts throughout the years; e.g., JavaScript/CSS bloat slowing
12down websites that are essentially a text document. However, I have
13never really expanded beyond talking about the web and describing how I
14focus on minimizing distractions in other digital environments.
15
16This post is going to set the baseline for how I *try* to live my
17digital life. It does not necessarily get into my physical life, which
18is often harder to control and contain all the noise in our modern
19world.
20
21While there are new things to do every day in our digital world, I find
22that keeping a core set of values and interests can ground you and keep
23you mindful of *why* you are participating in the digital world. For
24example, if - at your core - you have no interest in what strangers
25think about random topics, it would be unwise to start participating in
26social media. However, I am someone who has been dragged in by effective
27advertising to participate in communities that I realize I do not care
28for.
29
30I won\'t dive much further into explaining the philosophy of all this,
31but I will link a few helpful articles that may pique your interest if
32you\'re in search of more meaningful experiences:
33
34- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness)
35- [Minimalism](https://en.wikipedia.org/wiki/Minimalism)
36- [Stoicism](https://en.wikipedia.org/wiki/Stoicism)
10I've detailed my views on web-based minimalism and related topics in other
11posts throughout the years; e.g., JavaScript/CSS bloat slowing down websites
12that are essentially a text document. However, I have never really expanded
13beyond talking about the web and describing how I focus on minimizing
14distractions in other digital environments.
15
16This post is going to set the baseline for how I *try* to live my digital life.
17It does not necessarily get into my physical life, which is often harder to
18control and contain all the noise in our modern world.
19
20While there are new things to do every day in our digital world, I find that
21keeping a core set of values and interests can ground you and keep you mindful
22of *why* you are participating in the digital world. For example, if - at your
23core - you have no interest in what strangers think about random topics, it
24would be unwise to start participating in social media. However, I am someone
25who has been dragged in by effective advertising to participate in communities
26that I realize I do not care for.
27
28I won't dive much further into explaining the philosophy of all this, but I
29will link a few helpful articles that may pique your interest if you're in
30search of more meaningful experiences:
31
32- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness)
33- [Minimalism](https://en.wikipedia.org/wiki/Minimalism)
34- [Stoicism](https://en.wikipedia.org/wiki/Stoicism)
3735
3836# Living Life in the Terminal
3937
40My personal approach to reducing digital distractions and increasing my
41focus on the task at hand is to use a terminal for as much as I possibly
42can.
38My personal approach to reducing digital distractions and increasing my focus on
39the task at hand is to use a terminal for as much as I possibly can.
4340
44Most days, this means that I have a few tabs open constantly in my
45terminal:
41Most days, this means that I have a few tabs open constantly in my terminal:
4642
471. A web browser
482. A chat client
493. An email client
504. An RSS feed reader
515. A local shell for navigating my computer\'s files
526. A remote shell for managing servers and other machines
431. A web browser
442. A chat client
453. An email client
464. An RSS feed reader
475. A local shell for navigating my computer's files
486. A remote shell for managing servers and other machines
5349
54Beyond this, I rarely open other tabs or GUI applications, unless
55absolutely necessary. If you look, you may be surprised what can be
56accomplished in the terminal.
50Beyond this, I rarely open other tabs or GUI applications, unless absolutely
51necessary. If you look, you may be surprised what can be accomplished in the
52terminal.
5753
58For example, I have moved my music and entertainment downloads to the
59terminal, along with my device VPN connections. I am exploring options
60for moving my RSS subscriptions to something like
61[Newsboat](https://newsboat.org/), so that I can read my daily articles
62without all the fuss.
54For example, I have moved my music and entertainment downloads to the terminal,
55along with my device VPN connections. I am exploring options for moving my RSS
56subscriptions to something like [Newsboat](https://newsboat.org/), so that I can
57read my daily articles without all the fuss.
6358
64Now that we have some examples out of the way, let\'s dive into the
65specifics.
59Now that we have some examples out of the way, let's dive into the specifics.
6660
6761## Browsing the Web
6862
69I\'m going to start off with a hard topic for those who prefer to live
70in the terminal: web browsing. This task is made hard mostly by websites
71and web apps that require JavaScript to run. The other difficult part is
72that if you\'re using a text-based browser, that means images won\'t
73load (hopefully that\'s obvious).
63I'm going to start off with a hard topic for those who prefer to live in the
64terminal: web browsing. This task is made hard mostly by websites and web apps
65that require JavaScript to run. The other difficult part is that if you're
66using a text-based browser, that means images won't load (hopefully that's
67obvious).
7468
75I am using [Lynx](https://lynx.invisible-island.net), a text-based
76browser that runs quickly and easily in the terminal. Lynx allows me to
77browser most websites by simply typing `g` and then typing in
78the URL I want.
69I am using [Lynx](https://lynx.invisible-island.net), a text-based browser that
70runs quickly and easily in the terminal. Lynx allows me to browser most websites
71by simply typing `g` and then typing in the URL I want.
7972
8073![Lynx](https://img.cleberg.net/blog/20220616-terminal-lifestyle/lynx.png)
8174
8275If you need a search engine while in Lynx, I recommend [DuckDuckGo
83(Lite)](https://lite.duckduckgo.com/lite/), which allows you to search
84the web using their text-only interface.
76(Lite)](https://lite.duckduckgo.com/lite/), which allows you to search the web
77using their text-only interface.
8578
8679![DuckDuckGo
8780!Lite](https://img.cleberg.net/blog/20220616-terminal-lifestyle/ddg.png)
8881
89Eventually, you will run into websites that don\'t work (or are just too
90ugly and messy) in a text-only mode, and you\'ll be forced to switch
91over to a GUI browser to look at that site. Personally, I don\'t mind
92this as it doesn\'t happen as often as I thought it would.
82Eventually, you will run into websites that don't work (or are just too ugly
83and messy) in a text-only mode, and you'll be forced to switch over to a GUI
84browser to look at that site. Personally, I don't mind this as it doesn't
85happen as often as I thought it would.
9386
94The only time I need to do this is when I want to browse an
95image/video-focused webpage or if I need to log in to a site, and it
96doesn\'t support a text-only login page. For example, I am able to
97easily log in to [Sourcehut](https://sr.ht) in lynx.
87The only time I need to do this is when I want to browse an image/video-focused
88webpage or if I need to log in to a site, and it doesn't support a text-only
89login page. For example, I am able to easily log in to
90[Sourcehut](https://sr.ht) in lynx.
9891
9992## Chatting with Friends
10093
101After web browsing activities, my main form of terminal communication is
102Matrix. I use the [gomuks](https://docs.mau.fi/gomuks/) client
103currently.
94After web browsing activities, my main form of terminal communication is Matrix.
95I use the [gomuks](https://docs.mau.fi/gomuks/) client currently.
10496
105This was incredibly easy to install on macOS (but I will need to see if
106it\'ll be just as easy on Linux when my new laptop arrives):
97This was incredibly easy to install on macOS (but I will need to see if it'll
98be just as easy on Linux when my new laptop arrives):
10799
108100```sh
109101brew install gomuks
110102```
111103
112Once you launch gomuks, it will sync and require your username and
113password to login. After doing so, the only problem I ran into was
114verifying my gomuks client so that I could participate in rooms with
115E2EE.
104Once you launch gomuks, it will sync and require your username and password to
105login. After doing so, the only problem I ran into was verifying my gomuks
106client so that I could participate in rooms with E2EE.
116107
117Finally, I was able to verify the session by opening the Element desktop
118app (I assume you can do this in the browser and mobile app too, but
119I\'m not sure) and manually verifying myself with this process:
108Finally, I was able to verify the session by opening the Element desktop app (I
109assume you can do this in the browser and mobile app too, but I'm not sure) and
110manually verifying myself with this process:
120111
1211. Open the Element desktop app
1222. Open a room I was a member of
1233. Open the `Room Info` pane
1244. Open the `People` menu and search for myself
1255. Click on my profile name
1266. Click on the session link under the `Security` section
127 and follow the prompts to manually verify the session
1121. Open the Element desktop app
1132. Open a room I was a member of
1143. Open the `Room Info` pane
1154. Open the `People` menu and search for myself
1165. Click on my profile name
1176. Click on the session link under the `Security` section and follow the prompts
118 to manually verify the session
128119
129Overall, I like gomuks and am able to enjoy all the features I was using
130in Element. The only hiccup I have occurred is manually downloading
131images to view them, which can be annoying.
120Overall, I like gomuks and am able to enjoy all the features I was using in
121Element. The only hiccup I have occurred is manually downloading images to view
122them, which can be annoying.
132123
133124![gomuks](https://img.cleberg.net/blog/20220616-terminal-lifestyle/gomuks.png)
134125
135126## Email
136127
137Moving email to the terminal has been the hardest of the tasks for me.
138Unlike web browsing, where I can simply decide to not look at a website
139that does not work in the terminal, I cannot simply ignore emails sent
140to me.
128Moving email to the terminal has been the hardest of the tasks for me. Unlike
129web browsing, where I can simply decide to not look at a website that does not
130work in the terminal, I cannot simply ignore emails sent to me.
141131
142132Personally, I am experimenting with [neomutt](https://neomutt.org/) as a
143133potential email client.
144134
145However, this requires a **TON\*** of configuration and tweaking to get
146right. Even when I was able to set up neomutt, configure my email
147account, and customize a few personal preferences, a lot of emails still
148do not display correctly (mostly due to HTML and images).
135However, this requires a **TON** of configuration and tweaking to get right.
136Even when I was able to set up neomutt, configure my email account, and
137customize a few personal preferences, a lot of emails still do not display
138correctly (mostly due to HTML and images).
149139
150I won\'t get into the details of configuring `neomutt`; I
151mostly followed this blog post: [Email in the Terminal: Configuring
140I won't get into the details of configuring `neomutt`; I mostly followed this
141blog post: [Email in the Terminal: Configuring
152142Neomutt](https://gideonwolfe.com/posts/workflow/neomutt/intro/).
153143
154Finally, I have yet to figure out how to connect my GPG keys to
155`neomutt`, but that\'s a problem for another day.
144Finally, I have yet to figure out how to connect my GPG keys to `neomutt`, but
145that's a problem for another day.
156146
157147## RSS Feed Reader
158148
159I have just started using [Newsboat](https://newsboat.org/) to read
160articles in my terminal and have found quick success with it.
149I have just started using [Newsboat](https://newsboat.org/) to read articles in
150my terminal and have found quick success with it.
161151
162I\'ll show you a quick screenshot first:
152I'll show you a quick screenshot first:
163153
164154![Newsboat](https://img.cleberg.net/blog/20220616-terminal-lifestyle/newsboat.png)
165155
166The configuration was super easy for this app; I simply installed the
167app, created a file for URLs, and imported my OPML subscriptions that I
168had exported out of my old feed reader:
156The configuration was super easy for this app; I simply installed the app,
157created a file for URLs, and imported my OPML subscriptions that I had exported
158out of my old feed reader:
169159
170160```sh
171161brew install newsboat
@@ -181,13 +171,12 @@ newsboat -i=my_subscriptions.opml
181171
182172## Writing & Programming
183173
184Unfortunately, the weak link in my terminal-based environment right now
185is my grasp of the possibilities of editing files within a shell.
174Unfortunately, the weak link in my terminal-based environment right now is my
175grasp of the possibilities of editing files within a shell.
186176
187I am used to the easy extensions found in VSCodium and Kate, so I am
188slowly learning how to mold the default editing tools to my needs.
189Currently, this means I am using `nano` with the following
190configuration:
177I am used to the easy extensions found in VSCodium and Kate, so I am slowly
178learning how to mold the default editing tools to my needs. Currently, this
179means I am using `nano` with the following configuration:
191180
192181``` config
193182set breaklonglines
@@ -199,18 +188,16 @@ set fill 80
199188```
200189
201190This configuration allows nano to automatically hard-wrap lines at 80
202characters, autoindent the wrapped lines (if the previous line was
203indented), use 2 spaces per tab, and display line numbers within each
204file I open.
205
206I am currently looking to see if `vim` or `emacs`
207would be more useful for my current needs, but I\'m not in any rush, so
208I don\'t expect to find an answer anytime soon.
209
210With my current life demands, I am not programming at the moment and
211have not explored the best terminal set-up for programming. However, I
212have seen many peers find success configuring `vim` and
213`emacs`, so that\'s where I will start when I pick my
214projects back up.
191characters, autoindent the wrapped lines (if the previous line was indented),
192use 2 spaces per tab, and display line numbers within each file I open.
193
194I am currently looking to see if `vim` or `emacs` would be more useful for my
195current needs, but I'm not in any rush, so I don't expect to find an answer
196anytime soon.
197
198With my current life demands, I am not programming at the moment and have not
199explored the best terminal set-up for programming. However, I have seen many
200peers find success configuring `vim` and `emacs`, so that's where I will start
201when I pick my projects back up.
215202
216203![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
77
88# Source Code
99
10I don\'t want to bury the lede here, so if you\'d like to see the full
11source code I use to email myself plaintext poems daily, visit the
12repository:
10I don't want to bury the lede here, so if you'd like to see the full source
11code I use to email myself plaintext poems daily, visit the repository:
1312[daily-poem.git](https://git.cleberg.net/?p=daily-poem.git;a=summary).
1413
1514# My Daily Dose of Poetry
@@ -17,36 +16,35 @@ repository:
1716Most of my programming projects are small, random projects that are made
1817strictly to fix some small problem I have or enhance my quality of life.
1918
20In this case, I was looking for a simply and easy way to get a daily
21dose of literature or poetry to read in the mornings.
19In this case, I was looking for a simply and easy way to get a daily dose of
20literature or poetry to read in the mornings.
2221
23However, I don\'t want to sign up for a random mailing list on just any
24website. I also don\'t want to have to work to find the reading content
25each morning, as I know I would simply give up and stop reading daily.
22However, I don't want to sign up for a random mailing list on just any website.
23I also don't want to have to work to find the reading content each morning, as
24I know I would simply give up and stop reading daily.
2625
27Thus, I found a way to deliver poetry to myself in plain-text format, on
28a daily basis, and scheduled to deliver automatically.
26Thus, I found a way to deliver poetry to myself in plain-text format, on a daily
27basis, and scheduled to deliver automatically.
2928
3029# Prerequisites
3130
32This solution uses Python and email, so the following process requires
33the following to be installed:
31This solution uses Python and email, so the following process requires the
32following to be installed:
3433
351. An SMTP server, which can be as easy as installing
36 `mailutils` if you\'re on a Debian-based distro.
372. Python (& pip!)
383. The following Python packages: `email`,
39 `smtplib`, `json`, and `requests`
341. An SMTP server, which can be as easy as installing `mailutils` if you're on
35 a Debian-based distro.
362. Python (& pip!)
373. The following Python packages: `email`, `smtplib`, `json`, and `requests`
4038
4139# Breaking Down the Logic
4240
43I want to break down the logic for this program, as it\'s quite simple
44and informational.
41I want to break down the logic for this program, as it's quite simple and
42informational.
4543
4644## Required Packages
4745
48This program starts with a simple import of the required packages, so I
49wanted to explain why each package is used:
46This program starts with a simple import of the required packages, so I wanted
47to explain why each package is used:
5048
5149``` python
5250from email.mime.text import MIMEText # Required for translating MIMEText
@@ -57,9 +55,9 @@ import requests # Required to send out a request to the API
5755
5856## Sending the API Request
5957
60Next, we need to actually send the API request. In my case, I\'m calling
61a random poem from the entire API. If you want, you can call specific
62poems or authors from this API.
58Next, we need to actually send the API request. In my case, I'm calling a
59random poem from the entire API. If you want, you can call specific poems or
60authors from this API.
6361
6462``` python
6563json_data = requests.get('https://poetrydb.org/random').json()
@@ -97,24 +95,22 @@ This gives us the following result in JSON:
9795
9896## Parsing the API Results
9997
100In order to parse this into a readable format, we need to use the
101`json` package and extract the fields we want. In the example
102below, I am grabbing every field presented by the API.
98In order to parse this into a readable format, we need to use the `json` package
99and extract the fields we want. In the example below, I am grabbing every field
100presented by the API.
103101
104For the actual poem content, we need to loop over each line in the
105`lines` variable since each line is a separate string by
106default.
102For the actual poem content, we need to loop over each line in the `lines`
103variable since each line is a separate string by default.
107104
108> You *could* also extract the title or author and make another call out
109> to the API to avoid having to build the plaintext poem with a loop,
110> but it just doesn\'t make sense to me to send multiple requests when
111> we can create a simple loop on our local machine to work with the data
112> we already have.
105> You *could* also extract the title or author and make another call out to the
106> API to avoid having to build the plaintext poem with a loop, but it just
107> doesn't make sense to me to send multiple requests when we can create a
108> simple loop on our local machine to work with the data we already have.
113109>
114110> For
115111> [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
117> returned in plaintext.
112> look at the raw data response of this link to see the poem's lines returned
113> in plaintext.
118114
119115``` python
120116title = json_data[0]['title']
@@ -127,21 +123,20 @@ for line in json_data[0]['lines']:
127123
128124## Composing the Email
129125
130Now that I have all the data I need, I just need to compose it into a
131message and prepare the message metadata.
126Now that I have all the data I need, I just need to compose it into a message
127and prepare the message metadata.
132128
133For my daily email, I want to see the title of the poem first, followed
134by the author, then a blank line, and finally the full poem. This code
135snippet combines that data and packages it into a MIMEText container,
136ready to be emailed.
129For my daily email, I want to see the title of the poem first, followed by the
130author, then a blank line, and finally the full poem. This code snippet combines
131that data and packages it into a MIMEText container, ready to be emailed.
137132
138133``` python
139134msg_body = title + "\n" + author + "\n\n" + lines
140135msg = MIMEText(msg_body)
141136```
142137
143Before we send the email, we need to prepare the metadata (subject,
144from, to, etc.):
138Before we send the email, we need to prepare the metadata (subject, from, to,
139etc.):
145140
146141``` python
147142sender_email = 'example@server.local'
@@ -153,10 +148,9 @@ msg['To'] = recipient_email
153148
154149## Sending the Email
155150
156Now that I have everything ready to be emailed, the last step is to
157simply connect to an SMTP server and send the email out to the
158recipients. In my case, I installed `mailutils` on Ubuntu and
159let my SMTP server be `localhost`.
151Now that I have everything ready to be emailed, the last step is to simply
152connect to an SMTP server and send the email out to the recipients. In my case,
153I installed `mailutils` on Ubuntu and let my SMTP server be `localhost`.
160154
161155``` python
162156smtp_server = 'localhost'
@@ -167,9 +161,8 @@ s.quit()
167161
168162# The Result!
169163
170Instead of including a screenshot, I\'ve copied the contents of the
171email that was delivered to my inbox below since I set this process up
172in plaintext format.
164Instead of including a screenshot, I've copied the contents of the email that
165was delivered to my inbox below since I set this process up in plaintext format.
173166
174167``` txt
175168Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
@@ -201,18 +194,17 @@ Some, wise in show, more fools indeed than they.
201194
202195# Scheduling the Daily Email
203196
204Last, but not least, is scheduling this Python script with
205`crontab`. To schedule a script to run daily, you can add it
206to the `crontab` file. To do this, open `crontab`
207in editing mode:
197Last, but not least, is scheduling this Python script with `crontab`. To
198schedule a script to run daily, you can add it to the `crontab` file. To do
199this, open `crontab` in editing mode:
208200
209201```sh
210202crontab -e
211203```
212204
213In the file, simply paste the following snippet at the bottom of the
214file and ensure that the file path is correctly pointing to wherever you
215saved your Python script:
205In the file, simply paste the following snippet at the bottom of the file and
206ensure that the file path is correctly pointing to wherever you saved your
207Python script:
216208
217209``` config
2182100 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.
1515My decision to leave macOS really came down to just a few important
1616things:
1717
18- Apple Security (Gatekeeper) restricting me from running any software
19 I want. Even if you disable Gatekeeper and allow software to bypass
20 the rest of the device installation security, you still have to
21 repeat that process every time the allowed software is updated.
22- macOS sends out nearly constant connections, pings, telemetry, etc.
23 to a myriad of mysterious Apple services. I\'m not even going to
24 dive into how many macOS apps have constant telemetry on, as well.
25- Lastly, I just *really* missed the customization and freedom that
26 comes with Linux. Being able to switch to entirely new kernel, OS,
27 or desktop within minutes is a freedom I took for granted when I
28 switched to macOS.
29
30Now that I\'ve covered macOS, I\'m going to move on to more exciting
31topics: my personal choice of OS, DE, and various customizations I\'m
18- Apple Security (Gatekeeper) restricting me from running any software I want.
19 Even if you disable Gatekeeper and allow software to bypass the rest of the
20 device installation security, you still have to repeat that process every time
21 the allowed software is updated.
22- macOS sends out nearly constant connections, pings, telemetry, etc. to a
23 myriad of mysterious Apple services. I'm not even going to dive into how many
24 macOS apps have constant telemetry on, as well.
25- Lastly, I just *really* missed the customization and freedom that comes with
26 Linux. Being able to switch to entirely new kernel, OS, or desktop within
27 minutes is a freedom I took for granted when I switched to macOS.
28
29Now 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
3231using.
3332
3433# Fedora
@@ -37,8 +36,8 @@ After trying a ton of distros (I think I booted and tested around 20-25
3736distros), I finally landed on [Fedora Linux](https://getfedora.org/). I
3837have quite a bit of experience with Fedora and enjoy the
3938`dnf` package manager. Fedora allows me to keep up-to-date
40with recent software (I\'m looking at you, Debian), but still provides a
41level of stability you don\'t find in every distro.
39with recent software (I'm looking at you, Debian), but still provides a
40level of stability you don't find in every distro.
4241
4342In a very close second place was Arch Linux, as well as its spin-off:
4443Garuda 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
4746packaging systems.
4847
4948Basically, everything else I tested was unacceptable in at least one way
50or another. Void (`glibc`) was great, but doesn\'t support
51all the software I need. Slackware worked well as a tui, but I wasn\'t
49or another. Void (`glibc`) was great, but doesn't support
50all the software I need. Slackware worked well as a tui, but I wasn't
5251skilled enough to get a tiling window manager (WM) working on it.
5352
5453## i3
@@ -57,7 +56,7 @@ One of the reasons I settled on Fedora is that it comes with an official
5756i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of
5857the biggest things I wanted to do as soon as I adopted Linux again.
5958
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
6160any of my configurations, but nothing big has been configured thus far.
6261
6362The two main things I have updated in i3wm are natural scrolling and
@@ -123,37 +122,37 @@ binding my brightness keys to the `brightnessctl` program.
123122
124123 My config for this menu bar is basically just the default settings
125124 with modified colors and an added battery block to quickly show me
126 the machine\'s battery info.
125 the machine's battery info.
127126
1281274. `alacritty`
129128
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,
131130 but I installed `alacritty` as my default terminal, and I
132131 am using `zsh` and the shell.
133132
134133# Software Choices
135134
136Again, 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
135Again, I'm not going to say much that I haven't said yet in other blog
136posts, so I'll just do a quick rundown of the apps I installed
138137immediately after I set up the environment.
139138
140139Flatpak Apps:
141140
142- Cryptomator
143- pCloud
144- Signal
141- Cryptomator
142- pCloud
143- Signal
145144
146145Fedora Packages:
147146
148- gomuks
149- neomutt
150- neofetch
151- Firefox
152 - uBlock Origin
153 - Bitwarden
154 - Stylus
155 - Privacy Redirect
147- gomuks
148- neomutt
149- neofetch
150- Firefox
151 - uBlock Origin
152 - Bitwarden
153 - Stylus
154 - Privacy Redirect
156155
157156Other:
158157
159- exiftool
158- exiftool
content/blog/2022-07-01-git-server.md +151 −182
@@ -7,60 +7,54 @@ draft = false
77
88# My Approach to Self-Hosting Git
99
10I have often tried to self-host my Git repositories, but have always
11fallen short when I tried to find a suitable web interface to show on
12the front-end.
13
14After a few years, I have finally found a combination of methods that
15allow me to easily self-host my projects, view them on the web, and
16access them from anywhere.
17
18Before I dive into the details, I want to state a high-level summary of
19my self-hosted Git approach:
20
21- This method uses the `ssh://` (read & write) and
22 `git://` (read-only) protocols for push and pull access.
23 - For the `git://` protocol, I create a
24 `git-daemon-export-ok` file in any repository that I
25 want to be cloneable by anyone.
26 - The web interface I am using (`cgit`) allows simple
27 HTTP cloning by default. I do not disable this setting as I want
28 beginners to be able to clone one of my repositories even if
29 they don\'t know the proper method.
30- I am not enabling Smart HTTPS for any repositories. Updates to
31 repositories must be pushed via SSH.
32- Beyond the actual repository management, I am using
33 `cgit` for the front-end web interface.
34 - If you use the `scan-path=<path>` configuration in
35 the `cgitrc` configuration file to automatically find
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.
10I have often tried to self-host my Git repositories, but have always fallen
11short when I tried to find a suitable web interface to show on the front-end.
12
13After a few years, I have finally found a combination of methods that allow me
14to easily self-host my projects, view them on the web, and access them from
15anywhere.
16
17Before I dive into the details, I want to state a high-level summary of my
18self-hosted Git approach:
19
20- This method uses the `ssh://` (read & write) and `git://` (read-only)
21 protocols for push and pull access.
22 - For the `git://` protocol, I create a `git-daemon-export-ok` file in any
23 repository that I want to be cloneable by anyone.
24 - The web interface I am using (`cgit`) allows simple HTTP cloning by default.
25 I do not disable this setting as I want beginners to be able to clone one of
26 my repositories even if they don't know the proper method.
27- I am not enabling Smart HTTPS for any repositories. Updates to repositories
28 must be pushed via SSH.
29- Beyond the actual repository management, I am using `cgit` for the front-end
30 web interface.
31 - If you use the `scan-path=<path>` configuration in the `cgitrc`
32 configuration file to automatically find repositories, you can't exclude a
33 repository from `cgit` if it's stored within the path that `cgit` reads. To
34 host private repositories, you'd need to set up another directory that
35 `cgit` can't read.
4136
4237# Assumptions
4338
4439For the purposes of this walkthrough, I am assuming you have a URL
45(`git.example.com`) or IP address
46(`207.84.26.991`) addressed to the server that you will be
47using to host your git repositories.
40(`git.example.com`) or IP address (`207.84.26.991`) addressed to the server that
41you will be using to host your git repositories.
4842
4943# Adding a Git User
5044
51In order to use the SSH method associated with git, we will need to add
52a user named `git`. If you have used the SSH method for other
53git hosting sites, you are probably used to the following syntax:
45In order to use the SSH method associated with git, we will need to add a user
46named `git`. If you have used the SSH method for other git hosting sites, you
47are probably used to the following syntax:
5448
5549```sh
5650git clone [user@]server:project.git
5751```
5852
59The syntax above is an `scp`-like syntax for using SSH on the
60`git` user on the server to access your repository.
53The syntax above is an `scp`-like syntax for using SSH on the `git` user on the
54server to access your repository.
6155
62Let\'s delete any remnants of an old `git` user, if any, and
63create the new user account:
56Let's delete any remnants of an old `git` user, if any, and create the new user
57account:
6458
6559```sh
6660sudo deluser --remove-home git
@@ -69,21 +63,19 @@ sudo adduser git
6963
7064## Import Your SSH Keys to the Git User
7165
72Once the `git` user is created, you will need to copy your
73public SSH key on your local development machine to the `git`
74user on the server.
66Once the `git` user is created, you will need to copy your public SSH key on
67your local development machine to the `git` user on the server.
7568
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:
7770
7871```sh
7972ssh-keygen
8073```
8174
82Once you create the key pair, the public should be saved to
83`~/.ssh/id_rsa.pub`.
75Once you create the key pair, the public should be saved to `~/.ssh/id_rsa.pub`.
8476
85If your server still has password-based authentication available, you
86can copy it over to your user\'s home directory like this:
77If your server still has password-based authentication available, you can copy
78it over to your user's home directory like this:
8779
8880```sh
8981ssh-copy-id git@server
@@ -95,8 +87,8 @@ Otherwise, copy it over to any user that you can access.
9587scp ~/.ssh/id_rsa.pub your_user@your_server:
9688```
9789
98Once on the server, you will need to copy the contents into the
99`git` user\'s `authorized_keys` file:
90Once on the server, you will need to copy the contents into the `git` user's
91`authorized_keys` file:
10092
10193```sh
10294cat id_rsa.pub > /home/git/.ssh/authorized_keys
@@ -104,16 +96,15 @@ cat id_rsa.pub > /home/git/.ssh/authorized_keys
10496
10597## (Optional) Disable Password-Based SSH
10698
107If you want to lock down your server and ensure that no one can
108authenticate in via SSH with a password, you will need to edit your SSH
109configuration.
99If you want to lock down your server and ensure that no one can authenticate in
100via SSH with a password, you will need to edit your SSH configuration.
110101
111102```sh
112103sudo nano /etc/ssh/sshd_config
113104```
114105
115Within this file, find the following settings and set them to the values
116I am showing below:
106Within this file, find the following settings and set them to the values I am
107showing below:
117108
118109``` conf
119110PermitRootLogin no
@@ -121,19 +112,17 @@ PasswordAuthentication no
121112AuthenticationMethods publickey
122113```
123114
124You may have other Authentication Methods required in your personal
125set-up, so the key here is just to ensure that
126`AuthenticationMethods` does not allow passwords.
115You may have other Authentication Methods required in your personal set-up, so
116the key here is just to ensure that `AuthenticationMethods` does not allow
117passwords.
127118
128119### Setting up the Base Directory
129120
130Now that we have set up a `git` user to handle all transport
131methods, we need to set up the directory that we will be using as our
132base of all repositories.
121Now that we have set up a `git` user to handle all transport methods, we need to
122set up the directory that we will be using as our base of all repositories.
133123
134In my case, I am using `/git` as my source folder. To create
135this folder and assign it to the user we created, execute the following
136commands:
124In my case, I am using `/git` as my source folder. To create this folder and
125assign it to the user we created, execute the following commands:
137126
138127```sh
139128sudo mkdir /git
@@ -142,15 +131,15 @@ sudo chown -R git:git /git
142131
143132### Creating a Test Repository
144133
145On your server, switch over to the `git` user in order to
146start managing git files.
134On your server, switch over to the `git` user in order to start managing git
135files.
147136
148137```sh
149138su git
150139```
151140
152Once logged-in as the `git` user, go to your base directory
153and create a test repository.
141Once logged-in as the `git` user, go to your base directory and create a test
142repository.
154143
155144```sh
156145cd /git
@@ -158,9 +147,9 @@ mkdir test.git && cd test.git
158147git init --bare
159148```
160149
161If you want to make this repo viewable/cloneable to the public via the
162`git://` protocol, you need to create a
163`git-daemon-export-ok` file inside the repository.
150If you want to make this repo viewable/cloneable to the public via the `git://`
151protocol, you need to create a `git-daemon-export-ok` file inside the
152repository.
164153
165154```sh
166155touch git-daemon-export-ok
@@ -168,34 +157,33 @@ touch git-daemon-export-ok
168157
169158# Change the Login Shell for `git`
170159
171To make sure that the `git` user is only used for git
172operations and nothing else, you need to change the user\'s login shell.
173To do this, simply use the `chsh` command:
160To make sure that the `git` user is only used for git operations and nothing
161else, you need to change the user's login shell. To do this, simply use the
162`chsh` command:
174163
175164```sh
176165sudo chsh git
177166```
178167
179The interactive prompt will ask which shell you want the
180`git` user to use. You must use the following value:
168The interactive prompt will ask which shell you want the `git` user to use. You
169must use the following value:
181170
182171```sh
183172/usr/bin/git-shell
184173```
185174
186Once done, no one will be able to SSH to the `git` user or
187execute commands other than the standard git commands.
175Once done, no one will be able to SSH to the `git` user or execute commands
176other than the standard git commands.
188177
189178# Opening the Firewall
190179
191Don\'t forget to open up ports on the device firewall and network
192firewall if you want to access these repositories publicly. If you\'re
193using default ports, forward ports `22` (ssh) and
194`9418` (git) from your router to your server\'s IP address.
180Don't forget to open up ports on the device firewall and network firewall if
181you want to access these repositories publicly. If you're using default ports,
182forward ports `22` (ssh) and `9418` (git) from your router to your server's IP
183address.
195184
196If your server also has a firewall, ensure that the firewall allows the
197same ports that are forwarded from the router. For example, if you use
198`ufw`:
185If your server also has a firewall, ensure that the firewall allows the same
186ports that are forwarded from the router. For example, if you use `ufw`:
199187
200188```sh
201189sudo ufw allow 22
@@ -204,12 +192,12 @@ sudo ufw allow 9418
204192
205193## Non-Standard SSH Ports
206194
207If you use a non-standard port for SSH, such as `9876`, you
208will need to create an SSH configuration file on your local development
209machine in order to connect to your server\'s git repositories.
195If you use a non-standard port for SSH, such as `9876`, you will need to create
196an SSH configuration file on your local development machine in order to connect
197to your server's git repositories.
210198
211To do this, you\'ll need to define your custom port on your client
212machine in your `~/.ssh/config` file:
199To do this, you'll need to define your custom port on your client machine in
200your `~/.ssh/config` file:
213201
214202```sh
215203nano ~/.ssh/config
@@ -227,11 +215,11 @@ Host git.example.com
227215
228216There are two main syntaxes you can use to manage git over SSH:
229217
230- `git clone [user@]server:project.git`
231- `git clone ssh://[user@]server/project.git`
218- `git clone [user@]server:project.git`
219- `git clone ssh://[user@]server/project.git`
232220
233I prefer the first, which is an `scp`-like syntax. To test
234it, try to clone the test repository you set up on the server:
221I prefer the first, which is an `scp`-like syntax. To test it, try to clone the
222test repository you set up on the server:
235223
236224```sh
237225git clone git@git.example.com:/git/test.git
@@ -239,9 +227,8 @@ git clone git@git.example.com:/git/test.git
239227
240228# Enabling Read-Only Access
241229
242If you want people to be able to clone any repository where you\'ve
243placed a `git-daemon-export-ok` file, you will need to start
244the git daemon.
230If you want people to be able to clone any repository where you've placed a
231`git-daemon-export-ok` file, you will need to start the git daemon.
245232
246233To do this on a system with `systemd`, create a service file:
247234
@@ -279,8 +266,7 @@ sudo systemctl enable git-daemon.service
279266sudo systemctl start git-daemon.service
280267```
281268
282To clone read-only via the `git://` protocol, you can use the
283following syntax:
269To clone read-only via the `git://` protocol, you can use the following syntax:
284270
285271```sh
286272git clone git://git.example.com/test.git
@@ -291,9 +277,9 @@ git clone git://git.example.com/test.git
291277At this point, we have a working git server that works with both SSH and
292278read-only access.
293279
294For each of the repositories I had hosted a different provider, I
295executed the following commands in order to place a copy on my server as
296my new source of truth:
280For each of the repositories I had hosted a different provider, I executed the
281following commands in order to place a copy on my server as my new source of
282truth:
297283
298284Server:
299285
@@ -316,23 +302,20 @@ git push
316302
317303# Optional Web View: `cgit`
318304
319If you want a web viewer for your repositories, you can use various
320tools, such as `gitweb`, `cgit`, or
321`klaus`. I chose `cgit` due to its simple
322interface and fairly easy set-up (compared to others). Not to mention
323that the [Linux kernel uses `cgit`](https://git.kernel.org/).
305If you want a web viewer for your repositories, you can use various tools, such
306as `gitweb`, `cgit`, or `klaus`. I chose `cgit` due to its simple interface and
307fairly easy set-up (compared to others). Not to mention that the [Linux kernel
308uses `cgit`](https://git.kernel.org/).
324309
325310## Docker Compose
326311
327Instead of using my previous method of using a `docker run`
328command, I\'ve updated this section to use `docker-compose`
329instead for an easier installation and simpler management and
330configuration.
312Instead of using my previous method of using a `docker run` command, I've
313updated this section to use `docker-compose` instead for an easier installation
314and simpler management and configuration.
331315
332In order to use Docker Compose, you will set up a
333`docker-compose.yml` file to automatically connect resources
334like the repositories, `cgitrc`, and various files or folders
335to the `cgit` container you\'re creating:
316In order to use Docker Compose, you will set up a `docker-compose.yml` file to
317automatically connect resources like the repositories, `cgitrc`, and various
318files or folders to the `cgit` container you're creating:
336319
337320```sh
338321mkdir ~/cgit && cd ~/cgit
@@ -363,17 +346,16 @@ Then, just start the container:
363346sudo docker-compose up -d
364347```
365348
366Once it\'s finished installing, you can access the site at
367`<SERVER_IP>:8763` or use a reverse-proxy service to forward
368`cgit` to a URL, such as `git.example.com`. See
369the next section for more details on reverse proxying a URL to a local
370port.
349Once it's finished installing, you can access the site at `<SERVER_IP>:8763` or
350use a reverse-proxy service to forward `cgit` to a URL, such as
351`git.example.com`. See the next section for more details on reverse proxying a
352URL to a local port.
371353
372354## Nginx Reverse Proxy
373355
374I am using Nginx as my reverse proxy so that the `cgit`
375Docker container can use `git.example.com` as its URL. To do
376so, I simply created the following configuration file:
356I am using Nginx as my reverse proxy so that the `cgit` Docker container can use
357`git.example.com` as its URL. To do so, I simply created the following
358configuration file:
377359
378360```sh
379361sudo 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/
422404sudo systemctl restart nginx.service
423405```
424406
425As we can see below, my site at `git.example.com` is
426available and running:
407As we can see below, my site at `git.example.com` is available and running:
427408
428409## Settings Up Git Details
429410
430Once you have `cgit` running, you can add some small details,
431such as repository owners and descriptions by editing the following
432files within each repository.
411Once you have `cgit` running, you can add some small details, such as repository
412owners and descriptions by editing the following files within each repository.
433413
434Alternatively, you can use the `cgitrc` file to edit these
435details if you only care to edit them for the purpose of seeing them on
436your website.
414Alternatively, you can use the `cgitrc` file to edit these details if you only
415care to edit them for the purpose of seeing them on your website.
437416
438The `description` file within the repository on your server
439will display the description online.
417The `description` file within the repository on your server will display the
418description online.
440419
441420```sh
442421cd /git/example.git
443422nano description
444423```
445424
446You can add a `[gitweb]` block to the `config`
447file in order to display the owner of the repository.
425You can add a `[gitweb]` block to the `config` file in order to display the
426owner of the repository.
448427
449428```sh
450429cd /git/example.git
@@ -456,21 +435,20 @@ nano config
456435 owner = "YourName"
457436```
458437
459Note that you can ignore the configuration within each repository and
460simply set up this information in the `cgitrc` file, if you
461want to do it that way.
438Note that you can ignore the configuration within each repository and simply set
439up this information in the `cgitrc` file, if you want to do it that way.
462440
463441## Editing `cgit`
464442
465In order to edit certain items within `cgit`, you need to
466edit the `cgitrc` file.
443In order to edit certain items within `cgit`, you need to edit the `cgitrc`
444file.
467445
468446```sh
469447nano ~/cgit/cgitrc
470448```
471449
472Below is an example configuration for `cgitrc`. You can find
473all the configuration options within the \[configuration manual\]
450Below is an example configuration for `cgitrc`. You can find all the
451configuration options within the [configuration manual]
474452(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>).
475453
476454``` conf
@@ -549,17 +527,14 @@ repo.desc=An example repository!
549527
550528## Final Fixes: Syntax Highlighting & README Rendering
551529
552After completing my initial install and playing around with it for a few
553days, I noticed two issues:
530After completing my initial install and playing around with it for a few days, I
531noticed two issues:
554532
5551. Syntax highlighting did not work when viewing the source code within
556 a file.
5572. The `about` tab within a repository was not rendered to
558 HTML.
5331. Syntax highlighting did not work when viewing the source code within a file.
5342. The `about` tab within a repository was not rendered to HTML.
559535
560The following process fixes these issues. To start, let\'s go to the
561`cgit` directory where we were editing our configuration file
562earlier.
536The following process fixes these issues. To start, let's go to the `cgit`
537directory where we were editing our configuration file earlier.
563538
564539```sh
565540cd ~/cgit
@@ -589,15 +564,13 @@ curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html
589564chmod 755 md2html
590565```
591566
592If you need other filters or html-converters found within [the cgit
593project files](https://git.zx2c4.com/cgit/tree/filters), repeat the
594`curl` and `chmod` process above for whichever
595files you need.
567If you need other filters or html-converters found within [the cgit project
568files](https://git.zx2c4.com/cgit/tree/filters), repeat the `curl` and `chmod`
569process above for whichever files you need.
596570
597However, formatting will not work quite yet since the Docker cgit
598container we\'re using doesn\'t have the formatting package installed.
599You can install this easily by install Python 3+ and the
600`pygments` package:
571However, formatting will not work quite yet since the Docker cgit container
572we're using doesn't have the formatting package installed. You can install
573this easily by install Python 3+ and the `pygments` package:
601574
602575```sh
603576# Enter the container's command line
@@ -613,13 +586,11 @@ pip3 install markdown pygments && \
613586exit
614587```
615588
616**You will need to enter the cgit docker container and re-run these
617`yum` commands every time you kill and restart the
618container!**
589**You will need to enter the cgit docker container and re-run these `yum`
590commands every time you kill and restart the container!**
619591
620If not done already, we need to add the following variables to our
621`cgitrc` file in order for `cgit` to know where
622our filtering files are:
592If not done already, we need to add the following variables to our `cgitrc` file
593in order for `cgit` to know where our filtering files are:
623594
624595``` conf
625596# Highlight source code with python pygments-based highlighter
@@ -630,26 +601,24 @@ source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
630601about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
631602```
632603
633Now you should see that syntax highlighting and README rendering to the
634`about` tab is fixed.
604Now you should see that syntax highlighting and README rendering to the `about`
605tab is fixed.
635606
636607## Theming
637608
638I won\'t go into much detail in this section, but you can fully theme
639your installation of `cgit` since you have access to the
640`cgit.css` file in your web root. This is another file you
641can add as a volume to the `docker-compose.yml` file if you
642want to edit this without entering the container\'s command line.
609I won't go into much detail in this section, but you can fully theme your
610installation of `cgit` since you have access to the `cgit.css` file in your web
611root. This is another file you can add as a volume to the `docker-compose.yml`
612file if you want to edit this without entering the container's command line.
643613
644614### :warning: Remember to Back Up Your Data!
645615
646The last thing to note is that running services on your own equipment
647means that you\'re assuming a level of risk that exists regarding data
648loss, catastrophes, etc. In order to reduce the impact of any such
649occurrence, I suggest backing up your data regularly.
616The last thing to note is that running services on your own equipment means that
617you're assuming a level of risk that exists regarding data loss, catastrophes,
618etc. In order to reduce the impact of any such occurrence, I suggest backing up
619your data regularly.
650620
651Backups can be automated via `cron`, by hooking your base
652directory up to a cloud provider, or even setting up hooks to push all
653repository info to git mirrors on other git hosts. Whatever the method,
654make sure that your data doesn\'t vanish in the event that your drives
655or servers fail.
621Backups can be automated via `cron`, by hooking your base directory up to a
622cloud provider, or even setting up hooks to push all repository info to git
623mirrors on other git hosts. Whatever the method, make sure that your data
624doesn't vanish in the event that your drives or servers fail.
content/blog/2022-07-14-gnupg.md +126 −140
@@ -7,33 +7,31 @@ draft = false
77
88# The History of GPG
99
10[GNU Privacy Guard](https://gnupg.org/), also known as GnuPG and GPG, is
11a free (\"free\" as in both speech and beer) software that fully
12implements the OpenPGP Message Format documented in [RFC
134880](https://www.rfc-editor.org/rfc/rfc4880).
10[GNU Privacy Guard](https://gnupg.org/), also known as GnuPG and GPG, is a free
11("free" as in both speech and beer) software that fully implements the OpenPGP
12Message Format documented in [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880).
1413
15I won\'t go in-depth on the full history of the software in this post,
16but it is important to understand that GPG is not the same as PGP
17(Pretty Good Privacy), which is a different implementation of RFC 4880.
18However, GPG was designed to interoperate with PGP.
14I won't go in-depth on the full history of the software in this post, but it is
15important to understand that GPG is not the same as PGP (Pretty Good Privacy),
16which is a different implementation of RFC 4880. However, GPG was designed to
17interoperate with PGP.
1918
2019GPG was originally developed in the late 1990s by [Werner
21Koch](https://en.wikipedia.org/wiki/Werner_Koch) and has historically
22been funded generously by the German government.
20Koch](https://en.wikipedia.org/wiki/Werner_Koch) and has historically been
21funded generously by the German government.
2322
24Now that we have all the high-level info out of the way, let\'s dive
25into the different aspects of GPG and its uses.
23Now that we have all the high-level info out of the way, let's dive into the
24different aspects of GPG and its uses.
2625
2726# Encryption Algorithms
2827
2928GPG supports a wide range of different encryption algorithms, including
30public-key, cipher, hash, and compression algorithms. The support for
31these algorithms has grown since the adoption of the Libgcrypt library
32in the 2.x versions of GPG.
29public-key, cipher, hash, and compression algorithms. The support for these
30algorithms has grown since the adoption of the Libgcrypt library in the 2.x
31versions of GPG.
3332
34As you will be able to see below in an example of a full key generation
35with the GPG command line tool, GPG recommends the following algorithms
36to new users:
33As you will be able to see below in an example of a full key generation with the
34GPG command line tool, GPG recommends the following algorithms to new users:
3735
3836```sh
3937Please select what kind of key you want:
@@ -45,77 +43,71 @@ Please select what kind of key you want:
4543 (10) ECC (sign only)
4644```
4745
48I am not doing an in-depth explanation here in order to keep the focus
49on GPG and not encryption algorithms. If you want a deep dive into
50cryptography or encryption algorithms, please read my other posts:
46I am not doing an in-depth explanation here in order to keep the focus on GPG
47and not encryption algorithms. If you want a deep dive into cryptography or
48encryption algorithms, please read my other posts:
5149
52- [AES Encryption](../aes-encryption/) (2018)
53- [Cryptography Basics](../cryptography-basics/) (2020)
50- [AES Encryption](../aes-encryption/) (2018)
51- [Cryptography Basics](../cryptography-basics/) (2020)
5452
5553## Vulnerabilities
5654
57As of 2022-07-14, there are a few different vulnerabilities associated
58with GPG or the libraries it uses:
59
60- 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
62 released, one can recover the signer\'s private key in less than a
63 second on a PC.\"
64 ([Source](https://www.di.ens.fr/~pnguyen/pub_Ng04.htm))
65- GPG versions prior to 1.4.2.1 contain a false positive signature
66 verification bug.
67 ([Source](https://lists.gnupg.%20org/pipermail/gnupg-announce/2006q1/000211.html))
68- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned
69 data. (
70 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html))
71- Libgcrypt, a library used by GPG, contained a bug which enabled full
72 key recovery for RSA-1024 and some RSA-2048 keys. This was resolved
73 in a GPG update in 2017.
74 ([Source](https://lwn.net/Articles/727179/))
75- The [ROCA
76 Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability)
77 affects RSA keys generated by YubiKey 4 tokens.
78 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf))
79- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows
80 an attacker to spoof digital signatures.
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/))
55As of 2022-07-14, there are a few different vulnerabilities associated with GPG
56or the libraries it uses:
57
58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one
59 (GPG-generated) ElGamal signature of an arbitrary message is released, one can
60 recover the signer's private key in less than a second on a PC."
61 ([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
63 bug.
64 ([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. (
66 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html))
67- Libgcrypt, a library used by GPG, contained a bug which enabled full key
68 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG
69 update in 2017. ([Source](https://lwn.net/Articles/727179/))
70- The [ROCA Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability)
71 affects RSA keys generated by YubiKey 4 tokens.
72 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf))
73- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows an
74 attacker to spoof digital signatures.
75 ([Source](https://arstechnica.%20com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/))
76- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow,
77 fixed in Libgcrypt 1.9.1
78 ([Source](https://web.archive.%20org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/))
8579
8680### Platforms
8781
88Originally developed as a command-line program for \*nix systems, GPG
89now has a wealth of front-end applications and libraries available for
90end-users. However, the most recommended programs remain the same:
82Originally developed as a command-line program for *nix systems, GPG now has a
83wealth of front-end applications and libraries available for end-users. However,
84the most recommended programs remain the same:
9185
92- [GnuPG](https://gnupg.org) for Linux (depending on distro)
93- [Gpg4win](https://gpg4win.org) for Windows
94- [GPGTools](https://gpgtools.org) for macOS
86- [GnuPG](https://gnupg.org) for Linux (depending on distro)
87- [Gpg4win](https://gpg4win.org) for Windows
88- [GPGTools](https://gpgtools.org) for macOS
9589
9690# Creating a Key Pair
9791
98In order to create a GPG key pair, a user would first need to install
99GPG on their system. If we\'re assuming that the user is on Fedora
100Linux, they would execute the following:
92In order to create a GPG key pair, a user would first need to install GPG on
93their system. If we're assuming that the user is on Fedora Linux, they would
94execute the following:
10195
10296```sh
10397sudo dnf install gpg
10498```
10599
106Once installed, a user can create a new key pair with the following
107command(s):
100Once installed, a user can create a new key pair with the following command(s):
108101
109102```sh
110103gpg --full-generate-key
111104```
112105
113GPG will walk the user through an interactive setup that asks for an
114algorithm preference, expiration date, name, and email to associate with
115this key.
106GPG will walk the user through an interactive setup that asks for an algorithm
107preference, expiration date, name, and email to associate with this key.
116108
117See the following example key set-up for a default key generation using
118the GnuPG command-line interface:
109See the following example key set-up for a default key generation using the
110GnuPG command-line interface:
119111
120112```sh
121113gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc.
@@ -178,66 +170,63 @@ interface.
178170
179171As noted in RFC 4880, the general functions of OpenPGP are as follows:
180172
181- digital signatures
182- encryption
183- compression
184- Radix-64 conversion
185- key management and certificate services
173- digital signatures
174- encryption
175- compression
176- Radix-64 conversion
177- key management and certificate services
186178
187From this, you can probably gather that the main use of GPG is for
188encrypting data and/or signing the data with a key. The purpose of
189encrypting data with GPG is to ensure that no one except the intended
190recipient(s) can access the data.
179From this, you can probably gather that the main use of GPG is for encrypting
180data and/or signing the data with a key. The purpose of encrypting data with GPG
181is to ensure that no one except the intended recipient(s) can access the data.
191182
192Let\'s explore some specific GPG use-cases.
183Let's explore some specific GPG use-cases.
193184
194185## Email
195186
196One of the more popular uses of GPG is to sign and/or encrypt emails.
197With the use of a GPG keypair, you can encrypt a message, its subject,
198and even the attachments within.
199
200The first process, regarding the signing of a message without any
201encryption, is generally used to provide assurance that an email is
202truly coming from the sender that the message claims. When I send an
203email, and it\'s signed with my public key, the recipient(s) of the
204message can verify that the message was signed with my personal key.
205
206The second process, regarding the actual encryption of the message and
207its contents, works by using a combination of the sender\'s keys and the
208recipient\'s keys. This process may vary slightly by implementation, but
209it most commonly uses asymmetric cryptography, also known as public-key
210cryptography. In this version of encryption, the sender\'s private key
211to sign the message and a combination of the sender\'s keys and the
212recipient\'s public key to encrypt the message.
213
214If two people each have their own private keys and exchange their public
215keys, they can send encrypted messages back and forth with GPG. This is
216also possible with symmetric cryptography, but the process differs since
217there are no key pairs.
218
219Implementation of email encryption varies greatly between email clients,
220so you will need to reference your email client\'s documentation to
221ensure you are setting it up correctly for that specific client.
187One of the more popular uses of GPG is to sign and/or encrypt emails. With the
188use of a GPG keypair, you can encrypt a message, its subject, and even the
189attachments within.
190
191The first process, regarding the signing of a message without any encryption, is
192generally used to provide assurance that an email is truly coming from the
193sender that the message claims. When I send an email, and it's signed with my
194public key, the recipient(s) of the message can verify that the message was
195signed with my personal key.
196
197The second process, regarding the actual encryption of the message and its
198contents, works by using a combination of the sender's keys and the
199recipient's keys. This process may vary slightly by implementation, but it most
200commonly uses asymmetric cryptography, also known as public-key cryptography. In
201this version of encryption, the sender's private key to sign the message and a
202combination of the sender's keys and the recipient's public key to encrypt the
203message.
204
205If two people each have their own private keys and exchange their public keys,
206they can send encrypted messages back and forth with GPG. This is also possible
207with symmetric cryptography, but the process differs since there are no key
208pairs.
209
210Implementation of email encryption varies greatly between email clients, so you
211will need to reference your email client's documentation to ensure you are
212setting it up correctly for that specific client.
222213
223214## File Encryption
224215
225As noted in the section above regarding emails, GPG enables users to be
226able to send a message to each other if they are both set-up with GPG
227keys. In this example, I am going to show how a user could send a file
228called `example_file.txt` to another user via the
229recipient\'s email.
216As noted in the section above regarding emails, GPG enables users to be able to
217send a message to each other if they are both set-up with GPG keys. In this
218example, I am going to show how a user could send a file called
219`example_file.txt` to another user via the recipient's email.
230220
231The sender would find the file they want to send and execute the
232following command:
221The sender would find the file they want to send and execute the following
222command:
233223
234224```sh
235225gpg --encrypt --output example_file.txt.gpg --recipient \
236226recipient@example.com example_file.txt
237227```
238228
239Once received, the recipient can decrypt the file with the following
240command:
229Once received, the recipient can decrypt the file with the following command:
241230
242231```sh
243232gpg --decrypt --output example_file.txt example_file.txt.gpg
@@ -245,29 +234,28 @@ gpg --decrypt --output example_file.txt example_file.txt.gpg
245234
246235## Ownership Signatures
247236
248One important aspect of GPG, especially for developers, is the ability
249to sign data without encrypting it. For example, developers often sign
250code changes when they commit the changes back to a central repository,
251in order to display ownership of who made the changes. This allows other
252users to look at a code change and determine that the change was valid.
237One important aspect of GPG, especially for developers, is the ability to sign
238data without encrypting it. For example, developers often sign code changes when
239they commit the changes back to a central repository, in order to display
240ownership of who made the changes. This allows other users to look at a code
241change and determine that the change was valid.
253242
254In order to do this using [Git](https://git-scm.com), the developer
255simply needs to alter the `git commit` command to include the
256`-S` flag. Here\'s an example:
243In order to do this using [Git](https://git-scm.com), the developer simply needs
244to alter the `git commit` command to include the `-S` flag. Here's an example:
257245
258246```sh
259247git commit -S -m "my commit message"
260248```
261249
262As an expansion of the example above, Git users can configure their
263environment with a default key to use by adding their GPG signature:
250As an expansion of the example above, Git users can configure their environment
251with a default key to use by adding their GPG signature:
264252
265253```sh
266254git config --global user.signingkey XXXXXXXXXXXXXXXX
267255```
268256
269If you\'re not sure what your signature is, you can find it titled
270`sig` in the output of this command:
257If you're not sure what your signature is, you can find it titled `sig` in the
258output of this command:
271259
272260```sh
273261gpg --list-signatures
@@ -275,12 +263,11 @@ gpg --list-signatures
275263
276264## File Integrity
277265
278When a person generates a signature for data, they are allowing users
279the ability to verify the signature on that data in the future to ensure
280the data has not been corrupted. This is most common with software
281applications hosted on the internet - developers provide signatures so
282that users can verify a website was not hijacked and download links
283replaced with dangerous software.
266When a person generates a signature for data, they are allowing users the
267ability to verify the signature on that data in the future to ensure the data
268has not been corrupted. This is most common with software applications hosted on
269the internet - developers provide signatures so that users can verify a website
270was not hijacked and download links replaced with dangerous software.
284271
285272In order to verify signed data, a user needs to have:
286273
@@ -288,9 +275,8 @@ In order to verify signed data, a user needs to have:
2882752. A signature file
2892763. The public GPG key of the signer
290277
291Once the signer\'s public key is imported on the user\'s system, and
292they have the data and signature, they can verify the data with the
293following commands:
278Once the signer's public key is imported on the user's system, and they have
279the data and signature, they can verify the data with the following commands:
294280
295281```sh
296282# If the signature is attached to the data
@@ -302,13 +288,13 @@ gpg --verify [signature-file] [original-file]
302288
303289### Finding Public Keys
304290
305In order to use GPG with others, a user needs to know the other user(s)
306keys. This is easy to do if the user knows the other user(s) in person,
307but may be hard if the relationship is strictly digital. Luckily, there
308are a few options. The first option is to look at a user\'s web page or
309social pages if they have them.
291In order to use GPG with others, a user needs to know the other user(s) keys.
292This is easy to do if the user knows the other user(s) in person, but may be
293hard if the relationship is strictly digital. Luckily, there are a few options.
294The first option is to look at a user's web page or social pages if they have
295them.
310296
311297Otherwise, the best option is to use a keyserver, such as:
312298
313- [pgp.mit.edu](https://pgp.mit.edu)
314- [keys.openpgp.org](https://keys.openpgp.org)
299- [pgp.mit.edu](https://pgp.mit.edu)
300- [keys.openpgp.org](https://keys.openpgp.org)
content/blog/2022-07-25-curseradio.md +36 −42
@@ -8,62 +8,56 @@ draft = false
88# Overview
99
1010While exploring some interesting Linux applications, I stumbled across
11[curseradio](https://github.com/chronitis/curseradio), a command-line
12radio player based on Python.
11[curseradio](https://github.com/chronitis/curseradio), a command-line radio
12player based on Python.
1313
14This application is fantastic and incredibly easy to install, so I
15wanted to dedicate a post today to this app. Let\'s look at the features
16within the app and then walk through the installation process I took to
17get `curseradio` working.
14This application is fantastic and incredibly easy to install, so I wanted to
15dedicate a post today to this app. Let's look at the features within the app
16and then walk through the installation process I took to get `curseradio`
17working.
1818
1919# Features
2020
2121![curseradio](https://img.cleberg.net/blog/20220725-curseradio/curseradio.png)
2222
23The radio player itself is quite minimal. As you can see in the
24screenshot above, it contains a simple plaintext list of all available
25categories, which can be broken down further and further. In addition,
26radio shows are available for listening, alongside regular radio
27stations.
23The radio player itself is quite minimal. As you can see in the screenshot
24above, it contains a simple plaintext list of all available categories, which
25can be broken down further and further. In addition, radio shows are available
26for listening, alongside regular radio stations.
2827
29For example, the `Sports` \> `Pro Basketball` \>
30`Shows` category contains a number of specific shows related
31to Professional Basketball.
28For example, the `Sports` > `Pro Basketball` > `Shows` category contains a
29number of specific shows related to Professional Basketball.
3230
33Aside from being able to play any of the listed stations/shows, you can
34make a channel your favorite by pressing `f`. It will now
35show up at the top of the radio player in the `Favourites`
36category.
31Aside from being able to play any of the listed stations/shows, you can make a
32channel your favorite by pressing `f`. It will now show up at the top of the
33radio player in the `Favourites` category.
3734
3835## Commands/Shortcuts
3936
40 Key(s) Command
41 ------------ ---------------------------------
42 ↑, ↓ navigate
43 PgUp, PgDn navigate quickly
44 Home, End to top/bottom
45 Enter open/close folders, play stream
46 k stop playing stream
47 q quit
48 f toggle favourite
37| Key(s) | Command |
38|------------|---------------------------------|
39| ↑, ↓ | navigate |
40| PgUp, PgDn | navigate quickly |
41| Home, End | to top/bottom |
42| Enter | open/close folders, play stream |
43| k | stop playing stream |
44| q | quit |
45| f | toggle favourite |
4946
5047# Installation
5148
5249## Dependencies
5350
54Before installing `curseradio`, a handful of system and
55Python packages are required. To get started, install
56`python3`, `pip3`, and `mpv` on your
57system. In this example, I\'m using Fedora Linux, which uses the
58`dnf` package manager. You may need to adjust this if you\'re
59using a different system.
51Before installing `curseradio`, a handful of system and Python packages are
52required. To get started, install `python3`, `pip3`, and `mpv` on your system.
53In this example, I'm using Fedora Linux, which uses the `dnf` package manager.
54You may need to adjust this if you're using a different system.
6055
6156```sh
6257sudo dnf install python3 pip3 mpv
6358```
6459
65Next, use `pip3` to install `requests`,
66`xdg`, and `lxml`:
60Next, use `pip3` to install `requests`, `xdg`, and `lxml`:
6761
6862```sh
6963pip3 install requests xdg lxml
@@ -71,23 +65,23 @@ pip3 install requests xdg lxml
7165
7266## Repository Source Installation
7367
74Once all the dependencies are installed, we can clone the source code
75and enter that directory:
68Once all the dependencies are installed, we can clone the source code and enter
69that directory:
7670
7771```sh
7872git clone https://github.com/chronitis/curseradio && cd curseradio
7973```
8074
81Once you\'re within the `curseradio` directory, you can
82install the application with the provided `setup.py` script.
75Once you're within the `curseradio` directory, you can install the application
76with the provided `setup.py` script.
8377
8478```sh
8579sudo python3 setup.py install
8680```
8781
88In my case, I ran into a few errors and needed to create the folders
89that curseradio wanted to use for its installation. If you don\'t get
90any errors, you can skip this and run the app.
82In my case, I ran into a few errors and needed to create the folders that
83curseradio wanted to use for its installation. If you don't get any errors, you
84can skip this and run the app.
9185
9286```sh
9387sudo 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
1111effectively archive all the music I own in the [FLAC file
1212format](https://en.wikipedia.org/wiki/FLAC), a lossless audio codec.
1313
14However, streaming FLAC files outside the home can be difficult due to
15the size of the files, especially if you\'re using a weak connection.
14However, streaming FLAC files outside the home can be difficult due to the size
15of the files, especially if you're using a weak connection.
1616
17So, in order to archive the music in a lossless format and still be able
18to stream it easily, I opted to create a copy of my FLAC files in the
19[Opus audio codec](https://en.wikipedia.org/wiki/Opus_(audio_format)).
20This allows me to archive a quality, lossless version of the music and
21then point my streaming service to the smaller, stream-ready version.
17So, in order to archive the music in a lossless format and still be able to
18stream it easily, I opted to create a copy of my FLAC files in the [Opus audio
19codec](https://en.wikipedia.org/wiki/Opus_(audio_format)). This allows me to
20archive a quality, lossless version of the music and then point my streaming
21service to the smaller, stream-ready version.
2222
2323## Dependencies
2424
25The process I follow utilizes the `opus-tools` package in
26Ubuntu. Before proceeding, install the package:
25The process I follow utilizes the `opus-tools` package in Ubuntu. Before
26proceeding, install the package:
2727
2828```sh
2929sudo apt install opus-tools
3030```
3131
32If you want to use a different conversion method, such as
33`ffmpeg` or `avconv`, simply install that package
34instead.
32If you want to use a different conversion method, such as `ffmpeg` or `avconv`,
33simply install that package instead.
3534
3635## Conversion Process
3736
38The script I\'m using is stored in my home directory, but feel free to
39create it wherever you want. It does not need to be in the same
40directory as your music files.
37The script I'm using is stored in my home directory, but feel free to create it
38wherever you want. It does not need to be in the same directory as your music
39files.
4140
4241```sh
4342cd ~ && nano transform.sh
4443```
4544
46Once you have your new bash script opened in an editor, go ahead and
47paste the following logic into the script.
45Once you have your new bash script opened in an editor, go ahead and paste the
46following logic into the script.
4847
4948You **MUST** edit the following variables in order for it to work:
5049
51- `source`: The source directory where your FLAC files are
52 stored.
53- `dest`: The destination directory where you want the
54 resulting Opus files to be stored.
50- `source`: The source directory where your FLAC files are stored.
51- `dest`: The destination directory where you want the resulting Opus files to
52 be stored.
5553
5654You **MAY** want to edit the following variables to suit your needs:
5755
58- `filename`: If you are converting to a file format other
59 than Opus, you\'ll need to edit this so that your resulting files
60 have the correct filename extension.
61- `reldir`: This variable can be edited to strip out more
62 leading directories in the file path. As you\'ll see later, I ignore
63 this for now and simply clean it up afterward.
64- `opusenc`: This is the actual conversion process. You may
65 want to edit the bitrate to suit your needs. I set mine at 128 but
66 some prefer 160 or higher.
56- `filename`: If you are converting to a file format other than Opus, you'll
57 need to edit this so that your resulting files have the correct filename
58 extension.
59- `reldir`: This variable can be edited to strip out more leading directories in
60 the file path. As you'll see later, I ignore this for now and simply clean it
61 up afterward.
62- `opusenc`: This is the actual conversion process. You may want to edit the
63 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher.
6764
6865```sh
6966#!/bin/bash
@@ -129,8 +126,8 @@ opusenc --vbr --bitrate 128 --date "$DATE" \
129126done
130127```
131128
132Once you\'re done, simply save the file and exit your editor. Don\'t
133forget to enable execution of the script:
129Once you're done, simply save the file and exit your editor. Don't forget to
130enable execution of the script:
134131
135132```sh
136133chmod +x transform.sh
@@ -142,17 +139,16 @@ Finally, you may now run the script:
142139./transform.sh
143140```
144141
145If you used `opusenc`, you\'ll see the conversions happen
146within the terminal as it progresses. You will also see variables
147printed if you uncommented any of the bash script\'s comments.
142If you used `opusenc`, you'll see the conversions happen within the terminal as
143it progresses. You will also see variables printed if you uncommented any of the
144bash script's comments.
148145
149146## Cleanup
150147
151As I noted above, I didn\'t customize my `reldir` variable in
152the script, which caused my output directory to be
153`/mnt/music/library/archives` instead of
154`/mnt/music/library`. So, I moved the output up one level and
155deleted the accidental directory.
148As I noted above, I didn't customize my `reldir` variable in the script, which
149caused my output directory to be `/mnt/music/library/archives` instead of
150`/mnt/music/library`. So, I moved the output up one level and deleted the
151accidental directory.
156152
157153```sh
158154cd /mnt/music/library
@@ -162,8 +158,8 @@ rm -rf archives
162158
163159## Check the Resulting Size
164160
165If you want to see what kind of file size savings you\'ve gained, you
166can always use the `du` command to check:
161If you want to see what kind of file size savings you've gained, you can always
162use the `du` command to check:
167163
168164```sh
169165cd /mnt/music
content/blog/2022-07-31-bash-it.md +66 −72
@@ -8,30 +8,30 @@ draft = false
88# Bash
99
1010For those who are not familiar,
11[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is a Unix shell
12that is used as the default login shell for most Linux distributions.
13This shell and command processor should be familiar if you\'ve used
14Linux (or older version of macOS) before.
11[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is a Unix shell that is
12used as the default login shell for most Linux distributions. This shell and
13command processor should be familiar if you've used Linux (or older version of
14macOS) before.
1515
16However, bash is not the only option. There are numerous other shells
17that exist. Here are some popular examples:
16However, bash is not the only option. There are numerous other shells that
17exist. Here are some popular examples:
1818
19- [zsh](https://en.wikipedia.org/wiki/Z_shell)
20- [fish](https://en.wikipedia.org/wiki/Fish_(Unix_shell))
21- [oksh](https://github.com/ibara/oksh)
22- [mksh](https://wiki.gentoo.org/wiki/Mksh)
23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell)
19- [zsh](https://en.wikipedia.org/wiki/Z_shell)
20- [fish](https://en.wikipedia.org/wiki/Fish_(Unix_shell))
21- [oksh](https://github.com/ibara/oksh)
22- [mksh](https://wiki.gentoo.org/wiki/Mksh)
23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell)
2424
25While each shell has its differences, bash is POSIX compliant and the
26default for many Linux users. Because of this, I am going to explore a
27program called `bash-it` below that helps bash users increase
28the utility of their shell without installing a completely new shell.
25While each shell has its differences, bash is POSIX compliant and the default
26for many Linux users. Because of this, I am going to explore a program called
27`bash-it` below that helps bash users increase the utility of their shell
28without installing a completely new shell.
2929
3030## Installation
3131
32First, if bash is not already installed on your system, you can
33[download bash from GNU](https://www.gnu.org/software/bash/) or use your
34package manager to install it.
32First, if bash is not already installed on your system, you can [download bash
33from GNU](https://www.gnu.org/software/bash/) or use your package manager to
34install it.
3535
3636For example, this is how you can install bash on Fedora Linux:
3737
@@ -39,29 +39,29 @@ For example, this is how you can install bash on Fedora Linux:
3939sudo dnf install bash
4040```
4141
42If you are not using bash as your default shell, use the
43`chsh` command to change your shell:
42If you are not using bash as your default shell, use the `chsh` command to
43change your shell:
4444
4545```sh
4646chsh
4747```
4848
49You should see a prompt like the one below. If the brackets
50(`[]`) contain `bash` already, you\'re done, and
51you can simply continue by hitting the Enter key.
49You should see a prompt like the one below. If the brackets (`[]`) contain
50`bash` already, you're done, and you can simply continue by hitting the Enter
51key.
5252
53If the brackets contain another shell path (e.g.
54`/usr/bin/zsh`), enter the path to the bash program on your
55system (it\'s most likely located at `/usr/bin/bash`).
53If the brackets contain another shell path (e.g. `/usr/bin/zsh`), enter the path
54to the bash program on your system (it's most likely located at
55`/usr/bin/bash`).
5656
5757```sh
5858Changing shell for <user>.
5959New shell [/usr/bin/bash]:
6060```
6161
62You must log out or restart the machine in order for the login shell to
63be refreshed. You can do it now or wait until you\'re finished
64customizing the shell.
62You must log out or restart the machine in order for the login shell to be
63refreshed. You can do it now or wait until you're finished customizing the
64shell.
6565
6666```sh
6767sudo reboot now
@@ -69,30 +69,28 @@ sudo reboot now
6969
7070# Bash-it
7171
72As noted on the [Bash-it](https://github.com/Bash-it/bash-it)
73repository:
72As noted on the [Bash-it](https://github.com/Bash-it/bash-it) repository:
7473
75> Bash-it is a collection of community Bash commands and scripts for
76> Bash 3.2+. (And a shameless ripoff of oh-my-zsh 😃)
74> Bash-it is a collection of community Bash commands and scripts for Bash 3.2+.
75> (And a shameless ripoff of oh-my-zsh 😃)
7776
78Bash-it makes it easy to install plugins, set up aliases for common
79commands, and easily change the visual theme of your shell.
77Bash-it makes it easy to install plugins, set up aliases for common commands,
78and easily change the visual theme of your shell.
8079
8180## Installation
8281
8382To install the framework, simply copy the repository files and use the
84`install.sh` script provided. If you want, you can (and
85should!) inspect the contents of the installation script before you run
86it.
83`install.sh` script provided. If you want, you can (and should!) inspect the
84contents of the installation script before you run it.
8785
8886```sh
8987git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it
9088~/.bash_it/install.sh
9189```
9290
93If you didn\'t restart your session after making bash the default, and
94are currently working within another shell, be sure to enter a bash
95session before using `bash-it`:
91If you didn't restart your session after making bash the default, and are
92currently working within another shell, be sure to enter a bash session before
93using `bash-it`:
9694
9795```sh
9896bash
@@ -101,16 +99,16 @@ bash
10199## Aliases
102100
103101Bash-it contains a number of aliases for common commands to help improve
104efficiency in the terminal. To list all available options, use the
105following command:
102efficiency in the terminal. To list all available options, use the following
103command:
106104
107105```sh
108106bash-it show aliases
109107```
110108
111This will provide you a list that looks like the following text block.
112Within this screen, you will be able to see all available options and
113which ones are currently enabled.
109This will provide you a list that looks like the following text block. Within
110this screen, you will be able to see all available options and which ones are
111currently enabled.
114112
115113``` txt
116114Alias Enabled? Description
@@ -141,9 +139,8 @@ bash-it disable alias <alias name> [alias name]... -or- $ bash-it disable alias
141139
142140## Plugins
143141
144Similar to aliases, plugins are available with bash-it. You can find a
145complete list of plugins in the same way as aliases. Simply execute the
146following:
142Similar to aliases, plugins are available with bash-it. You can find a complete
143list of plugins in the same way as aliases. Simply execute the following:
147144
148145```sh
149146bash-it show plugins
@@ -188,9 +185,8 @@ To list all themes:
188185ls ~/.bash_it/themes/
189186```
190187
191To use a new theme, you\'ll need to edit `.bashrc` and alter
192the `BASH_IT_THEME` variable to your desired theme. For
193example, I am using the `zork` theme.
188To use a new theme, you'll need to edit `.bashrc` and alter the `BASH_IT_THEME`
189variable to your desired theme. For example, I am using the `zork` theme.
194190
195191```sh
196192nano ~/.bashrc
@@ -200,23 +196,22 @@ nano ~/.bashrc
200196export BASH_IT_THEME='zork'
201197```
202198
203Once you save your changes, you just need to exit your terminal and
204create a new one in order to see your changes to the
205`.bashrc` file. You can also `source` the file to
206see changes, but I recommend starting a completely new shell instead.
199Once you save your changes, you just need to exit your terminal and create a new
200one in order to see your changes to the `.bashrc` file. You can also `source`
201the file to see changes, but I recommend starting a completely new shell
202instead.
207203
208204### ble.sh
209205
210One big feature I was missing in Bash that both `zsh` and
211`fish` have is an autosuggestion feature. To explain: as you
212type, an autosuggestion feature in the shell will offer suggestions in a
213lighter font color beyond the characters already typed. Once you see the
214command you want, you can click the right arrow and have the shell
215auto-complete that line for you.
206One big feature I was missing in Bash that both `zsh` and `fish` have is an
207autosuggestion feature. To explain: as you type, an autosuggestion feature in
208the shell will offer suggestions in a lighter font color beyond the characters
209already typed. Once you see the command you want, you can click the right arrow
210and have the shell auto-complete that line for you.
216211
217Luckily, the [Bash Line Editor](https://github.com/akinomyoga/ble.sh)
218(ble.sh) exists! This program provides a wonderful autosuggestions
219feature perfectly, among other features that I haven\'t tested yet.
212Luckily, the [Bash Line Editor](https://github.com/akinomyoga/ble.sh) (ble.sh)
213exists! This program provides a wonderful autosuggestions feature perfectly,
214among other features that I haven't tested yet.
220215
221216In order to install ble.sh, execute the following:
222217
@@ -226,17 +221,16 @@ make -C ble.sh install PREFIX=~/.local
226221echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
227222```
228223
229Again, exit the terminal and open a new one in order to see the
230newly-configured shell.
224Again, exit the terminal and open a new one in order to see the newly-configured
225shell.
231226
232227# Restart the Session
233228
234Finally, as mentioned above, you\'ll need to restart the session to
235ensure that your user is using bash by default.
229Finally, as mentioned above, you'll need to restart the session to ensure that
230your user is using bash by default.
236231
237You will also need to exit and re-open a shell (e.g., terminal or
238terminal tab) any time you make changes to the `.bashrc`
239file.
232You will also need to exit and re-open a shell (e.g., terminal or terminal tab)
233any time you make changes to the `.bashrc` file.
240234
241235```sh
242236sudo reboot now
content/blog/2022-08-31-privacy-com-changes.md +54 −61
@@ -7,93 +7,86 @@ draft = false
77
88# Privacy.com Changes Their Terms
99
10Recently, Privacy.com reached out to their customers regarding a change
11in their terms of use. Further, all customers are required to agree to
12the changes in order to continue using their accounts.
10Recently, Privacy.com reached out to their customers regarding a change in their
11terms of use. Further, all customers are required to agree to the changes in
12order to continue using their accounts.
1313
1414[You can view the new cardholder agreement
1515here](https://privacy.com/commercial-cardholder-agreement).
1616
17When you log in, you\'ll be greeted with a pop-up window asking you to
18review and agree to the new terms of use. You will also not be able to
19open any new cards until the terms are agreed to.
17When you log in, you'll be greeted with a pop-up window asking you to review
18and agree to the new terms of use. You will also not be able to open any new
19cards until the terms are agreed to.
2020
21## Changing from a \"Prepaid Debit\" Model to a \"Charge Card\" Model
21## Changing from a "Prepaid Debit" Model to a "Charge Card" Model
2222
23The actual content of the changes is interesting. While the historical
24model of using Privacy.com was akin to prepaid debit cards, the new
25model is very similar to a credit card (they use the term \"charge
26card\").
23The actual content of the changes is interesting. While the historical model of
24using Privacy.com was akin to prepaid debit cards, the new model is very similar
25to a credit card (they use the term "charge card").
2726
28I have used Privacy.com for 1-2 years, and the process was always that
29you would create a single-use or merchant-locked card. This card could
30be used for any dollar limit you set and would immediately draw the
31funds from whatever funding source you connected, e.g. PayPal account or
32a bank account.
27I have used Privacy.com for 1-2 years, and the process was always that you would
28create a single-use or merchant-locked card. This card could be used for any
29dollar limit you set and would immediately draw the funds from whatever funding
30source you connected, e.g. PayPal account or a bank account.
3331
34The benefit this service provides with a premium account is masking the
35merchant names from your funding source. If you have a concern that your
36bank account uses merchant data from your account, you could direct all
37charges through Privacy.com and set the merchant as one of their pre-set
38options, such as \"Smiley\'s Corner Store\" or \"NSA Gift Shop.\"
32The benefit this service provides with a premium account is masking the merchant
33names from your funding source. If you have a concern that your bank account
34uses merchant data from your account, you could direct all charges through
35Privacy.com and set the merchant as one of their pre-set options, such as
36"Smiley's Corner Store" or "NSA Gift Shop."
3937
40The new model still works with a bank account as a funding source, but
41the model is changed so that you get a \"line of credit\" set according
42to a 14-day billing cycle. It seems that Privacy.com will now allow
43charges to be incurred without being immediately paid.
38The new model still works with a bank account as a funding source, but the model
39is changed so that you get a "line of credit" set according to a 14-day
40billing cycle. It seems that Privacy.com will now allow charges to be incurred
41without being immediately paid.
4442
4543## Daily Payments and Available Credit
4644
47Instead of paying as charges are incurred, you must make a \"Daily
48Payment\" and your \"Available Credit\" will be locked until you make
49that payment. There are also \"End of Billing Cycle Payments\" that are
50assigned a due date.
45Instead of paying as charges are incurred, you must make a "Daily Payment" and
46your "Available Credit" will be locked until you make that payment. There are
47also "End of Billing Cycle Payments" that are assigned a due date.
5148
52Further, Privacy.com will decline charges that would cause you to exceed
53your Available Credit or Credit Limit.
49Further, Privacy.com will decline charges that would cause you to exceed your
50Available Credit or Credit Limit.
5451
5552One particular interesting section states the following:
5653
57> YOUR OBLIGATION TO PAY US BACK FOR ALL CARD TRANSACTIONS AND OTHER
58> OBLIGATIONS YOU INCUR IS SECURED BY THE SECURED ACCOUNT. IF YOU DO NOT
59> PAY US BACK FOR ANY AMOUNT YOU OWE US WHEN YOUR PAYMENTS ARE DUE, WE
60> WILL EXERCISE OUR INTEREST AND DEBIT THE SECURED ACCOUNT, AND YOU WILL
61> LOSE THE MONEY IN THE SECURED ACCOUNT. SEE SECTION 8: SECURITY
62> AGREEMENT FOR MORE INFORMATION.
54> YOUR OBLIGATION TO PAY US BACK FOR ALL CARD TRANSACTIONS AND OTHER OBLIGATIONS
55> YOU INCUR IS SECURED BY THE SECURED ACCOUNT. IF YOU DO NOT PAY US BACK FOR ANY
56> AMOUNT YOU OWE US WHEN YOUR PAYMENTS ARE DUE, WE WILL EXERCISE OUR INTEREST
57> AND DEBIT THE SECURED ACCOUNT, AND YOU WILL LOSE THE MONEY IN THE SECURED
58> ACCOUNT. SEE SECTION 8: SECURITY AGREEMENT FOR MORE INFORMATION.
6359
6460## Personal Information
6561
66Now that Privacy.com is more of a financial institution, they are
67obligated to comply with the [know your
68customer](https://en.wikipedia.org/wiki/Know_your_customer)
69guidelines/laws.
62Now that Privacy.com is more of a financial institution, they are obligated to
63comply with the [know your
64customer](https://en.wikipedia.org/wiki/Know_your_customer) guidelines/laws.
7065
71I did not proceed with the change to my Privacy.com account, but I have
72heard from some peers that the changes require more personal information
73to be submitted, such as SSN. I am not aware of all new personal
74information required or if the funding source is now required to only be
75a bank account.
66I did not proceed with the change to my Privacy.com account, but I have heard
67from some peers that the changes require more personal information to be
68submitted, such as SSN. I am not aware of all new personal information required
69or if the funding source is now required to only be a bank account.
7670
7771## Fees
7872
79Luckily, the fees section did not change much. The subscription fees for
80a premium account are still the only fees.
73Luckily, the fees section did not change much. The subscription fees for a
74premium account are still the only fees.
8175
8276# My Thoughts
8377
84Personally, I wiped my personal information from my account and then
85permanently deleted it when I heard about these changes. I have no
86interest in yet another method of credit lending offered by private
87companies. While I accepted that they would have access to my bank
88account information for the purposes of paying off my prepaid debit
89payments, I have no interest in incurring charges that will need to be
90paid back at a later date. I also have no interest in submitting
78Personally, I wiped my personal information from my account and then permanently
79deleted it when I heard about these changes. I have no interest in yet another
80method of credit lending offered by private companies. While I accepted that
81they would have access to my bank account information for the purposes of paying
82off my prepaid debit payments, I have no interest in incurring charges that will
83need to be paid back at a later date. I also have no interest in submitting
9184personal information to Privacy.com.
9285
93This type of change toward a \"buy it now, pay us later\" model is
94concerning, and I will be watching Privacy.com to see if they further
95their interests in the credit model as time goes on.
86This type of change toward a "buy it now, pay us later" model is concerning,
87and I will be watching Privacy.com to see if they further their interests in the
88credit model as time goes on.
9689
97Could we see them start charging interest, fees, etc.? I\'m not sure,
98but this change does not inspire confidence in their mission as a
99privacy-focused company.
90Could we see them start charging interest, fees, etc.? I'm not sure, but this
91change does not inspire confidence in their mission as a privacy-focused
92company.
content/blog/2022-09-17-serenity-os.md +41 −47
@@ -7,39 +7,37 @@ draft = false
77
88# Overview
99
10[SerenityOS](https://serenityos.org) is a unique operating system (OS)
11that I have seen pop up in my news feed a few times over the last few
12years, but I have never had time to test it out until now.
10[SerenityOS](https://serenityos.org) is a unique operating system (OS) that I
11have seen pop up in my news feed a few times over the last few years, but I have
12never had time to test it out until now.
1313
1414Testing out this system brought back fond memories of yellowed,
15modem-screeching, 100-pound computers that brought so many fond memories
16to my youth.
15modem-screeching, 100-pound computers that brought so many fond memories to my
16youth.
1717
1818Per their website:
1919
2020> A graphical Unix-like operating system for desktop computers!
2121>
22> SerenityOS is a love letter to \'90s user interfaces with a custom
23> Unix-like core. It flatters with sincerity by stealing beautiful ideas
24> from various other systems.
22> SerenityOS is a love letter to '90s user interfaces with a custom Unix-like
23> core. It flatters with sincerity by stealing beautiful ideas from various
24> other systems.
2525>
26> Roughly speaking, the goal is a marriage between the aesthetic of
27> late-1990s productivity software and the power-user accessibility of
28> late-2000s \*nix.
26> Roughly speaking, the goal is a marriage between the aesthetic of late-1990s
27> productivity software and the power-user accessibility of late-2000s *nix.
2928>
3029> This is a system by us, for us, based on the things we like.
3130
3231# Building
3332
34Your first question may be \"Where\'s the iso?\" and the answer is...
35there are none. SerenityOS does not provide pre-built images for
36testing. You must build the images yourself. This seems intentionally to
37limit participation to only those who are truly interested enough to
38learn how to build the OS.
33Your first question may be "Where's the iso?" and the answer is... there are
34none. SerenityOS does not provide pre-built images for testing. You must build
35the images yourself. This seems intentionally to limit participation to only
36those who are truly interested enough to learn how to build the OS.
3937
4038## Clone
4139
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:
4341
4442```sh
4543git clone https://github.com/SerenityOS/serenity && cd serenity
@@ -50,23 +48,21 @@ git clone https://github.com/SerenityOS/serenity && cd serenity
5048Note that I followed the [Build
5149Instructions](https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md)
5250in the SerenityOS repository as of commit
53`660d2b53b1206e868d5470eee80b5e62d7e30da7`. Things may have
54changed since my installation, and you should double-check the
55instructions first.
51`660d2b53b1206e868d5470eee80b5e62d7e30da7`. Things may have changed since my
52installation, and you should double-check the instructions first.
5653
57Regardless, I want to repeat my steps here to illustrate any errors or
58differing commands I needed to run in order to build and run SerenityOS.
54Regardless, I want to repeat my steps here to illustrate any errors or differing
55commands I needed to run in order to build and run SerenityOS.
5956
60Since I am running Fedora, I needed to install these packages in order
61to build the OS images:
57Since I am running Fedora, I needed to install these packages in order to build
58the OS images:
6259
6360```sh
6461sudo 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
6562```
6663
67Next, make sure you\'re inside the `serenity` directory
68created earlier during the git cloning process and process to build the
69toolchain:
64Next, make sure you're inside the `serenity` directory created earlier during
65the git cloning process and process to build the toolchain:
7066
7167```sh
7268Meta/serenity.sh rebuild-toolchain
@@ -78,45 +74,43 @@ Once the toolchain is built, you can Build and run the OS!
7874Meta/serenity.sh run
7975```
8076
81After this process is completed, the image should run automatically and
82launch.
77After this process is completed, the image should run automatically and launch.
8378
8479# Issues
8580
86I played around in SerenityOS for an hour or two in order to see what I
87could do and had a lot of fun with it. The only issue I ran into was a
88lack of working internet. I didn\'t try very hard, but I could tell that
89the main network link wasn\'t connecting to my Fedora host properly.
81I played around in SerenityOS for an hour or two in order to see what I could do
82and had a lot of fun with it. The only issue I ran into was a lack of working
83internet. I didn't try very hard, but I could tell that the main network link
84wasn't connecting to my Fedora host properly.
9085
9186# Screenshots
9287
93The initial launch of the image displays the SerenityOS desktop, with a
94simple terminal already launched:
88The initial launch of the image displays the SerenityOS desktop, with a simple
89terminal already launched:
9590
9691![SerenityOS
9792Terminal](https://img.cleberg.net/blog/20220917-serenityos/initial_launch.png)
9893
99Here you can see the Fire application (literally just shows fire
100burning), a browser with the local Serenity Browser page loaded, and a
101text editor.
94Here you can see the Fire application (literally just shows fire burning), a
95browser with the local Serenity Browser page loaded, and a text editor.
10296
10397![SerenityOS
10498Fire](https://img.cleberg.net/blog/20220917-serenityos/basic_apps.png)
10599
106I also poked around the system utilities and found most tools you\'d
107expect to find within a standard desktop.
100I also poked around the system utilities and found most tools you'd expect to
101find within a standard desktop.
108102
109103![SerenityOS System
110104Monitor](https://img.cleberg.net/blog/20220917-serenityos/system_monitor.png)
111105
112Lastly, I noted that the default desktop contains numerous pre-defined
113themes to choose from. This is a small piece, but it\'s actually
114wonderful to see desktop developers consider theming directly out of the
115box rather than using an addon-based mentality.
106Lastly, I noted that the default desktop contains numerous pre-defined themes to
107choose from. This is a small piece, but it's actually wonderful to see desktop
108developers consider theming directly out of the box rather than using an
109addon-based mentality.
116110
117111![SerenityOS
118112Themes](https://img.cleberg.net/blog/20220917-serenityos/themes.png)
119113
120I didn\'t take a screenshot of the other pre-installed games, but I did
121spend nearly 30 minutes playing Solitaire before remembering that I was
122supposed to be writing a post about the OS.
114I didn't take a screenshot of the other pre-installed games, but I did spend
115nearly 30 minutes playing Solitaire before remembering that I was supposed to be
116writing a post about the OS.
content/blog/2022-09-21-graphene-os.md +53 −62
@@ -7,27 +7,24 @@ draft = false
77
88# Introduction
99
10After using iOS for a couple of years, I finally took the plunge and
11purchased a Pixel 6 Pro in order to test and use \[GrapheneOS\]
12(<https://grapheneos.org>).
10After using iOS for a couple of years, I finally took the plunge and purchased a
11Pixel 6 Pro in order to test and use [GrapheneOS] (<https://grapheneos.org>).
1312
14The installation process was rather quick once you have the tools and
15files you need. Overall, it can be done in just a few minutes.
13The installation process was rather quick once you have the tools and files you
14need. Overall, it can be done in just a few minutes.
1615
1716# Gathering Tools & Files
1817
1918## Android Tools
2019
21First, in order to interact with the device, we will need the [Android
22platform
23tools](https://developer.android.com/studio/releases/platform-tools.html).
24Find the Linux download and save the ZIP folder to your preferred
25location.
20First, in order to interact with the device, we will need the [Android platform
21tools](https://developer.android.com/studio/releases/platform-tools.html). Find
22the Linux download and save the ZIP folder to your preferred location.
2623
27Once we\'ve downloaded the files, we will need to unzip them, enter the
28directory, and move the necessary executables to a central location,
29such as `/usr/bin/`. For this installation, we only need the
30`fastboot` and `adb` executables.
24Once we've downloaded the files, we will need to unzip them, enter the
25directory, and move the necessary executables to a central location, such as
26`/usr/bin/`. For this installation, we only need the `fastboot` and `adb`
27executables.
3128
3229```sh
3330cd ~/Downloads
@@ -42,11 +39,11 @@ sudo mv adb /usr/bin
4239
4340## GrapheneOS Files
4441
45Next, we need the [GrapheneOS files](https://grapheneos.org/releases)
46for our device and model. For example, the Pixel 6 Pro is codenamed
47`raven` on the release page.
42Next, we need the [GrapheneOS files](https://grapheneos.org/releases) for our
43device and model. For example, the Pixel 6 Pro is codenamed `raven` on the
44release page.
4845
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:
5047
5148```sh
5249curl -O https://releases.grapheneos.org/factory.pub
@@ -56,9 +53,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
5653
57541. Validate Integrity
5855
59 In order to validate the integrity of the downloaded files, we will
60 need the `signify` package and Graphene\'s
61 `factory.pub` file.
56 In order to validate the integrity of the downloaded files, we will need the
57 `signify` package and Graphene's `factory.pub` file.
6258
6359 ```sh
6460 sudo dnf install signify
@@ -68,8 +64,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
6864 curl -O https://releases.grapheneos.org/factory.pub
6965 ```
7066
71 Then we can validate the files and ensure that no data was corrupted
72 or modified before it was saved to our device.
67 Then we can validate the files and ensure that no data was corrupted or
68 modified before it was saved to our device.
7369
7470 ```sh
7571 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
7773
78742. Unzip Files
7975
80 Once the files are verified, we can unzip the Graphene image and
81 enter the directory:
76 Once the files are verified, we can unzip the Graphene image and enter the
77 directory:
8278
8379 ```sh
8480 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400
@@ -88,35 +84,34 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
8884
8985## Enable Developer Debugging & OEM Unlock
9086
91Before we can actually flash anything to the phone, we will need to
92enable OEM Unlocking, as well as either USB Debugging or Wireless
93Debugging, depending on which method we will be using.
87Before we can actually flash anything to the phone, we will need to enable OEM
88Unlocking, as well as either USB Debugging or Wireless Debugging, depending on
89which method we will be using.
9490
95To start, enable developer mode by going to `Settings` \>
96`About` and tapping `Build Number` seven (7)
97times. You may need to enter your PIN to enable this mode.
91To start, enable developer mode by going to `Settings` > `About` and tapping
92`Build Number` seven (7) times. You may need to enter your PIN to enable this
93mode.
9894
99Once developer mode is enabled, go to `Settings` \>
100`System` \> `Devloper Options` and enable OEM
101Unlocking, as well as USB or Wireless Debugging. In my case, I chose USB
102Debugging and performed all actions via USB cable.
95Once developer mode is enabled, go to `Settings` > `System` > `Devloper
96Options` and enable OEM Unlocking, as well as USB or Wireless Debugging. In my
97case, I chose USB Debugging and performed all actions via USB cable.
10398
104Once these options are enabled, plug the phone into the computer and
105execute the following command:
99Once these options are enabled, plug the phone into the computer and execute the
100following command:
106101
107102```sh
108103adb devices
109104```
110105
111If an unauthorized error occurs, make sure the USB mode on the phone is
112changed from charging to something like \"File Transfer\" or \"PTP.\"
113You can find the USB mode in the notification tray.
106If an unauthorized error occurs, make sure the USB mode on the phone is changed
107from charging to something like "File Transfer" or "PTP." You can find the
108USB mode in the notification tray.
114109
115110## Reboot Device
116111
117Once we have found the device via `adb`, we can either boot
118into the bootloader interface by holding the volume down button while
119the phone reboots or by executing the following command:
112Once we have found the device via `adb`, we can either boot into the bootloader
113interface by holding the volume down button while the phone reboots or by
114executing the following command:
120115
121116```sh
122117adb reboot bootloader
@@ -124,17 +119,14 @@ adb reboot bootloader
124119
125120## Unlock the Bootloader
126121
127The phone will reboot and load the bootloader screen upon startup. At
128this point, we are ready to start the actual flashing of GrapheneOS onto
129the device.
122The phone will reboot and load the bootloader screen upon startup. At this
123point, we are ready to start the actual flashing of GrapheneOS onto the device.
130124
131**NOTE**: In my situation, I needed to use `sudo` with every
132`fastboot` command, but not with `adb` commands. I
133am not sure if this is standard or a Fedora quirk, but I\'m documenting
134my commands verbatim in this post.
125**NOTE**: In my situation, I needed to use `sudo` with every `fastboot` command,
126but not with `adb` commands. I am not sure if this is standard or a Fedora
127quirk, but I'm documenting my commands verbatim in this post.
135128
136First, we start by unlocking the bootloader so that we can load other
137ROMs:
129First, we start by unlocking the bootloader so that we can load other ROMs:
138130
139131```sh
140132sudo fastboot flashing unlock
@@ -142,24 +134,23 @@ sudo fastboot flashing unlock
142134
143135## Flashing Factory Images
144136
145Once the phone is unlocked, we can flash it with the
146`flash-all.sh` script found inside the
147`raven-factory-2022091400` folder we entered earlier:
137Once the phone is unlocked, we can flash it with the `flash-all.sh` script found
138inside the `raven-factory-2022091400` folder we entered earlier:
148139
149140```sh
150141sudo ./flash-all.sh
151142```
152143
153This process should take a few minutes and will print informational
154messages as things progress. Avoid doing anything on the phone while
155this process is operating.
144This process should take a few minutes and will print informational messages as
145things progress. Avoid doing anything on the phone while this process is
146operating.
156147
157148## Lock the Bootloader
158149
159If everything was successful, the phone should reboot a few times and
160finally land back on the bootloader screen. At this point, we can
161re-lock the bootloader to enable full verified boot and protect the
162device from unwanted flashing or erasure of data.
150If everything was successful, the phone should reboot a few times and finally
151land back on the bootloader screen. At this point, we can re-lock the bootloader
152to enable full verified boot and protect the device from unwanted flashing or
153erasure of data.
163154
164155```sh
165156sudo fastboot flashing lock
content/blog/2022-10-04-mtp-linux.md +23 −26
@@ -5,31 +5,30 @@ description = ""
55draft = false
66+++
77
8I recently ran into trouble attempting to mount my GrapheneOS phone to
9my laptop running Fedora Linux via the [Media Transfer
10Protocol](https://en.wikipedia.org/wiki/Media_transfer_protocol) (MTP)
11and discovered a simple and effective solution.
8I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop
9running Fedora Linux via the [Media Transfer
10Protocol](https://en.wikipedia.org/wiki/Media_transfer_protocol) (MTP) and
11discovered a simple and effective solution.
1212
1313# Use a USB 3.0 Port
1414
15First, ensure that the device was plugged in to the laptop through a USB
163.0 port, if possible. From a brief glance online, it seems that USB 2.0
17ports may cause issues with dropped connections over MTP. This is purely
18anecdotal since I don\'t have any evidence to link showing that USB 2.0
19causes issues, but I can confirm that switching to a USB 3.0 port seemed
20to cut out most of my issues.
15First, ensure that the device was plugged in to the laptop through a USB 3.0
16port, if possible. From a brief glance online, it seems that USB 2.0 ports may
17cause issues with dropped connections over MTP. This is purely anecdotal since I
18don't have any evidence to link showing that USB 2.0 causes issues, but I can
19confirm that switching to a USB 3.0 port seemed to cut out most of my issues.
2120
2221# Switch USB Preferences to MTP
2322
24Secondly, you need to ensure that the phone\'s USB preferences/mode is
25changed to MTP or File Transfer once the phone is plugged in. Other
26modes will not allow you to access the phone\'s file system.
23Secondly, you need to ensure that the phone's USB preferences/mode is changed
24to MTP or File Transfer once the phone is plugged in. Other modes will not allow
25you to access the phone's file system.
2726
2827# Install `jmtpfs`
2928
30Next, I used the `jmtpfs` package to mount my phone to my
31laptop. There are other packages that exist, but this one worked
32perfectly for me. On Fedora Linux, you can install it like this:
29Next, I used the `jmtpfs` package to mount my phone to my laptop. There are
30other packages that exist, but this one worked perfectly for me. On Fedora
31Linux, you can install it like this:
3332
3433```sh
3534sudo dnf install jmtpfs -y
@@ -37,19 +36,18 @@ sudo dnf install jmtpfs -y
3736
3837# Create a Mount Point
3938
40Once you have the package installed, you just need to create a folder
41for the device to use as a mount point. In my case, I used
42`/mnt/pixel`:
39Once you have the package installed, you just need to create a folder for the
40device to use as a mount point. In my case, I used `/mnt/pixel`:
4341
4442```sh
4543sudo mkdir /mnt/pixel
4644sudo chown -R $USER:$USER /mnt/pixel
4745```
4846
49# Mount & Access the Phone\'s File System
47# Mount & Access the Phone's File System
5048
51Finally, plug-in and mount the device, and you should be able to see all
52storage (internal and external) inside your new folder!
49Finally, plug-in and mount the device, and you should be able to see all storage
50(internal and external) inside your new folder!
5351
5452```sh
5553jmtpfs /mnt/pixel
@@ -62,16 +60,15 @@ Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
6260Android device detected, assigning default bug flags
6361```
6462
65Now you are mounted and can do anything you\'d like with the device\'s
66files:
63Now you are mounted and can do anything you'd like with the device's files:
6764
6865```sh
6966cd /mnt/pixel
7067ls -lha
7168```
7269
73From here, you will be able to see any internal or external storage
74available on the device:
70From here, you will be able to see any internal or external storage available on
71the device:
7572
7673```sh
7774total 0
content/blog/2022-10-04-syncthing.md +93 −103
@@ -7,26 +7,25 @@ draft = false
77
88# An Overview of Syncthing
99
10If you\'ve been looking around the self-hosted cloud storage space for a
11while, you\'ve undoubtedly run into someone suggesting
12[Syncthing](https://syncthing.net) as an option. However, it is an
13unusual alternative for those users out there who are used to having a
14centralized cloud server that serves as the \"controller\" of the data
15and interacts with clients on devices to fetch files.
10If you've been looking around the self-hosted cloud storage space for a while,
11you've undoubtedly run into someone suggesting
12[Syncthing](https://syncthing.net) as an option. However, it is an unusual
13alternative for those users out there who are used to having a centralized cloud
14server that serves as the "controller" of the data and interacts with clients
15on devices to fetch files.
1616
17This post is a walkthrough of the Syncthing software, how I set up my
18personal storage, and some pros and cons of using the software.
17This post is a walkthrough of the Syncthing software, how I set up my personal
18storage, and some pros and cons of using the software.
1919
2020# Installing Syncthing
2121
22To install Syncthing, visit the
23[Downloads](https://syncthing.net/downloads/) page or install via your
24device\'s package manager.
22To install Syncthing, visit the [Downloads](https://syncthing.net/downloads/)
23page or install via your device's package manager.
2524
2625## Server & Desktop
2726
28You can install Syncthing on servers and desktops via the Downloads page
29linked above or via the command-line.
27You can install Syncthing on servers and desktops via the Downloads page linked
28above or via the command-line.
3029
3130For Debian-based distros:
3231
@@ -43,37 +42,36 @@ sudo dnf install syncthing
4342## Mobile
4443
4544Syncthing for Android is available on
46[F-Droid](https://f-droid.org/packages/com.nutomic.syncthingandroid/)
47and [Google
45[F-Droid](https://f-droid.org/packages/com.nutomic.syncthingandroid/) and
46[Google
4847Play](https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid).
49Syncthing does not have an official iOS client, but there is a
50third-party client called [Möbius
48Syncthing does not have an official iOS client, but there is a third-party
49client called [Möbius
5150Sync](https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216).
5251
5352# How Does Syncthing Work?
5453
55To start, I wanted to include the main marketing blurb from their
56website:
54To start, I wanted to include the main marketing blurb from their website:
5755
58> Syncthing is a continuous file synchronization program. It
59> synchronizes files between two or more computers in real time, safely
60> protected from prying eyes. Your data is your data alone, and you
61> deserve to choose where it is stored, whether it is shared with some
62> third party, and how it\'s transmitted over the internet.
56> Syncthing is a continuous file synchronization program. It synchronizes files
57> between two or more computers in real time, safely protected from prying eyes.
58> Your data is your data alone, and you deserve to choose where it is stored,
59> whether it is shared with some third party, and how it's transmitted over the
60> internet.
6361
64Let\'s break this apart and add in some other details to help explain
65what exactly Syncthing does in order to sync files between devices.
62Let's break this apart and add in some other details to help explain what
63exactly Syncthing does in order to sync files between devices.
6664
6765## Local Syncthing Server(s)
6866
69Syncthing syncs files between multiple devices by creating a local
70server on each device. These local servers handle a few different
71things, such as watching files and directories for changes, hosting an
72administrative GUI website, and authenticating with connected devices.
67Syncthing syncs files between multiple devices by creating a local server on
68each device. These local servers handle a few different things, such as watching
69files and directories for changes, hosting an administrative GUI website, and
70authenticating with connected devices.
7371
74You can also start, stop, and restart the Syncthing server via the
75command-line or web dashboard. If you\'re running Syncthing on a device
76with `systemd`, you can use the following commands:
72You can also start, stop, and restart the Syncthing server via the command-line
73or web dashboard. If you're running Syncthing on a device with `systemd`, you
74can use the following commands:
7775
7876```sh
7977sudo systemctl start syncthing@username.service
@@ -83,97 +81,89 @@ sudo systemctl stop syncthing@username.service
8381
8482## Syncthing Dashboard
8583
86This biggest part of Syncthing is the admin GUI website that runs on
87each device (note that mobile devices will use the Syncthing app rather
88than the web GUI). The admin GUI is available through the web browser on
89the local device that is running Syncthing - simply go to
90`http://localhost:8384` or
91`http://127.0.0.1:8384`. This web page is the place where you
92will change settings, add/modify synced files, and add/modify connected
93devices.
84This biggest part of Syncthing is the admin GUI website that runs on each device
85(note that mobile devices will use the Syncthing app rather than the web GUI).
86The admin GUI is available through the web browser on the local device that is
87running Syncthing - simply go to `http://localhost:8384` or
88`http://127.0.0.1:8384`. This web page is the place where you will change
89settings, add/modify synced files, and add/modify connected devices.
9490
95Here\'s an example web GUI dashboard:
91Here's an example web GUI dashboard:
9692
9793![Syncthing
9894Dashboard](https://img.cleberg.net/blog/20221020-syncthing/syncthing_gui.png)
9995
10096## Remote Devices
10197
102A cloud storage solution wouldn\'t be very useful if you aren\'t able to
103share data among various devices. Syncthing does this by sharing Device
104IDs to connect servers, and then by manually sharing Folders with
105devices that have been connected.
98A cloud storage solution wouldn't be very useful if you aren't able to share
99data among various devices. Syncthing does this by sharing Device IDs to connect
100servers, and then by manually sharing Folders with devices that have been
101connected.
106102
107For instance, if you have a laptop running Syncthing and then install
108the Syncthing mobile app on a phone, you could scan the laptop\'s QR
109code for Device ID and then accept the authentication on the laptop\'s
110dashboard. Next, you can use either device to select a folder for
111sharing and dictating which device should send, receive, or both.
103For instance, if you have a laptop running Syncthing and then install the
104Syncthing mobile app on a phone, you could scan the laptop's QR code for Device
105ID and then accept the authentication on the laptop's dashboard. Next, you can
106use either device to select a folder for sharing and dictating which device
107should send, receive, or both.
112108
113When you connect devices, you can set one device as an \"Introducer,\"
114which can add devices from the introducer to the device list, for
115mutually shared folders. You can also configure Auto Accept,
116compression, rate limits, and more settings per device.
109When you connect devices, you can set one device as an "Introducer," which can
110add devices from the introducer to the device list, for mutually shared folders.
111You can also configure Auto Accept, compression, rate limits, and more settings
112per device.
117113
118114# My Personal Cloud Storage Set-up
119115
120Personally, I use a model similar to a traditional cloud storage
121service. I have a \"centralized\" server running 24/7 that acts as an
122Introducer for my Syncthing network. I think of this as my main storage
123and all other devices as tertiary client devices. I will likely add
124additional servers as backups as time goes on so that I don\'t have to
125rely on my laptop or phone as the only backups.
116Personally, I use a model similar to a traditional cloud storage service. I have
117a "centralized" server running 24/7 that acts as an Introducer for my
118Syncthing network. I think of this as my main storage and all other devices as
119tertiary client devices. I will likely add additional servers as backups as time
120goes on so that I don't have to rely on my laptop or phone as the only backups.
126121
127Currently, I have one desktop and one mobile device connected to the
128network, both running intermittently as they are not powered-on 24/7.
122Currently, I have one desktop and one mobile device connected to the network,
123both running intermittently as they are not powered-on 24/7.
129124
130The initial set-up of the software was easy enough, but data transfer
131rates were incredibly slow for me due to the Wi-Fi. Instead, I plugged
132my laptop into the ethernet network that my server is on and manually
133copied my folders over to the server with `scp`. Once
134complete, Syncthing validated that all files were there and not missing,
135and it did not need to transfer any data through the WAN.
125The initial set-up of the software was easy enough, but data transfer rates were
126incredibly slow for me due to the Wi-Fi. Instead, I plugged my laptop into the
127ethernet network that my server is on and manually copied my folders over to the
128server with `scp`. Once complete, Syncthing validated that all files were there
129and not missing, and it did not need to transfer any data through the WAN.
136130
137As slow as the transfer was going, this probably saved me a few days of
138waiting for my \~100GB sync.
131As slow as the transfer was going, this probably saved me a few days of waiting
132for my ~100GB sync.
139133
140134# Pros & Cons
141135
142I\'ve put together a short list of pros and cons for Syncthing. I
143thought about my experiences with Nextcloud, WebDAV, proprietary
144services (Google Drive, iCloud, etc.), and privacy-focused cloud
145solutions (pCloud, Tresorit, etc.).
136I've put together a short list of pros and cons for Syncthing. I thought about
137my experiences with Nextcloud, WebDAV, proprietary services (Google Drive,
138iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.).
146139
147140**Pros:**
148141
149- I\'ve faced no data loss at all through my two-month trial run.
150- No third-parties store your data on their servers.
151- You have full control over your data and can take your data and
152 leave at any time.
153- It\'s possible to encrypt client-side easily with software like
154 Cryptomator.
155- No proprietary clients or mounted volumes, just plain files and
156 folders.
142- I've faced no data loss at all through my two-month trial run.
143- No third-parties store your data on their servers.
144- You have full control over your data and can take your data and leave at any
145 time.
146- It's possible to encrypt client-side easily with software like Cryptomator.
147- No proprietary clients or mounted volumes, just plain files and folders.
157148
158149**Cons:**
159150
160- The learning curve is steeper than traditional cloud services and is
161 focused on a technical audience.
162- If a device needs to modify files in a Folder, the devices will need
163 to sync ALL files from the folder, which may be large. To avoid size
164 restraints, split large folders into smaller folders for syncing.
165- Syncing can be slow due to the clients/servers initially connecting
166 or re-connecting after sleeping.
167- Multiple personal devices are required and require the user to own
168 or rent them as no third-party servers are involved in the storage
169 of data.
170
171Overall, I\'ve had a great experience with Syncthing so far. I\'ve had
172no data loss, syncing has been quick and easy when changes are made to
173files, device connections are reliable, and I love the freedom of
174controlling the clients and servers as I choose.
175
176Not to mention that I appreciate that I - or someone else - could pull
177the Syncthing [source code](https://github.com/syncthing) and continue
178development/support if the Syncthing Foundation decides to stop
179developing the software or sells the business.
151- The learning curve is steeper than traditional cloud services and is focused
152 on a technical audience.
153- If a device needs to modify files in a Folder, the devices will need to sync
154 ALL files from the folder, which may be large. To avoid size restraints, split
155 large folders into smaller folders for syncing.
156- Syncing can be slow due to the clients/servers initially connecting or
157 re-connecting after sleeping.
158- Multiple personal devices are required and require the user to own or rent
159 them as no third-party servers are involved in the storage of data.
160
161Overall, I've had a great experience with Syncthing so far. I've had no data
162loss, syncing has been quick and easy when changes are made to files, device
163connections are reliable, and I love the freedom of controlling the clients and
164servers as I choose.
165
166Not to mention that I appreciate that I - or someone else - could pull the
167Syncthing [source code](https://github.com/syncthing) and continue
168development/support if the Syncthing Foundation decides to stop developing the
169software or sells the business.
content/blog/2022-10-22-alpine-linux.md +96 −110
@@ -7,80 +7,73 @@ draft = false
77
88# Alpine Linux
99
10[Alpine Linux](https://alpinelinux.org) is a very small distro, built on
11musl libc and busybox. It uses ash as the default shell, OpenRC as the
12init system, and apk as the package manager. According to their website,
13an Alpine container \"requires no more than 8 MB and a minimal
14installation to disk requires around 130 MB of storage.\" An actual bare
15metal machine is recommended to have 100 MB of RAM and 0-700 MB of
16storage space.
17
18Historically, I\'ve used Ubuntu\'s minimal installation image as my
19server OS for the last five years. Ubuntu worked well and helped as my
20original server contained an nVidia GPU and no onboard graphics, so
21quite a few distros won\'t boot or install without a lot of tinkering.
22
23Alpine has given me a huge increase in performance across my Docker apps
24and Nginx websites. CPU load for the new server I\'m using to test
25Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100
26CPU @ 3.70GHz.
27
28The only services I haven\'t moved over to Alpine are Plex Media Server
29and Syncthing, which may increase CPU load quite a bit depending on how
30many streams are running.
10[Alpine Linux](https://alpinelinux.org) is a very small distro, built on musl
11libc and busybox. It uses ash as the default shell, OpenRC as the init system,
12and apk as the package manager. According to their website, an Alpine container
13"requires no more than 8 MB and a minimal installation to disk requires around
14130 MB of storage." An actual bare metal machine is recommended to have 100 MB
15of RAM and 0-700 MB of storage space.
16
17Historically, I've used Ubuntu's minimal installation image as my server OS
18for the last five years. Ubuntu worked well and helped as my original server
19contained an nVidia GPU and no onboard graphics, so quite a few distros won't
20boot or install without a lot of tinkering.
21
22Alpine has given me a huge increase in performance across my Docker apps and
23Nginx websites. CPU load for the new server I'm using to test Alpine hovers
24around 0-5% on average with an Intel(R) Core(TM) i3-6100 CPU @ 3.70GHz.
25
26The only services I haven't moved over to Alpine are Plex Media Server and
27Syncthing, which may increase CPU load quite a bit depending on how many streams
28are running.
3129
3230## Installation
3331
3432In terms of installation, Alpine has an incredibly useful
35[wiki](https://wiki.alpinelinux.org/wiki/Installation) that will guide a
36user throughout the installation and post-installation processes, as
37well as various other articles and guides.
33[wiki](https://wiki.alpinelinux.org/wiki/Installation) that will guide a user
34throughout the installation and post-installation processes, as well as various
35other articles and guides.
3836
3937To install Alpine, find an appropriate [image to
40download](https://alpinelinux.org/downloads/) and flash it to a USB
41using software such as Rufus or Etcher. I opted to use the Standard
42image for my x86~64~ architecture.
38download](https://alpinelinux.org/downloads/) and flash it to a USB using
39software such as Rufus or Etcher. I opted to use the Standard image for my
40x86~64~ architecture.
4341
44Once the USB is ready, plug it into the machine and reboot. Note that
45you may have to use a key such as `Esc` or `F1-12`
46to access the boot menu. The Alpine Linux terminal will load quickly and
47for a login.
42Once the USB is ready, plug it into the machine and reboot. Note that you may
43have to use a key such as `Esc` or `F1-12` to access the boot menu. The Alpine
44Linux terminal will load quickly and for a login.
4845
49To log in to the installation image, use the `root` account;
50there is no password. Once logged-in, execute the setup command:
46To log in to the installation image, use the `root` account; there is no
47password. Once logged-in, execute the setup command:
5148
5249```sh
5350setup-alpine
5451```
5552
56The setup script will ask a series of questions to configure the system.
57Be sure to answer carefully or else you may have to re-configure the
58system after boot.
59
60- Keyboard Layout (Local keyboard language and usage mode, e.g., us
61 and variant of us-nodeadkeys.)
62- Hostname (The name for the computer.)
63- Network (For example, automatic IP address discovery with the
64 \"DHCP\" protocol.)
65- DNS Servers (Domain Name Servers to query. For privacy reasons, it
66 is NOT recommended to route every local request to servers like
67 Google\'s 8.8.8.8 .)
68- Timezone
69- Proxy (Proxy server to use for accessing the web. Use \"none\" for
70 direct connections to the internet.)
71- Mirror (From where to download packages. Choose the organization you
72 trust giving your usage patterns to.)
73- SSH (Secure SHell remote access server. \"Openssh\" is part of the
74 default install image. Use \"none\" to disable remote login, e.g. on
75 laptops.)
76- NTP (Network Time Protocol client used for keeping the system clock
77 in sync with a time-server. Package \"chrony\" is part of the
78 default install image.)
79- Disk Mode (Select between diskless (disk=\"none\"), \"data\" or
80 \"sys\", as described above.)
81
82Once the setup script is finished, be sure to reboot the machine and
83remove the USB device.
53The setup script will ask a series of questions to configure the system. Be sure
54to answer carefully or else you may have to re-configure the system after boot.
55
56- Keyboard Layout (Local keyboard language and usage mode, e.g., us and variant
57 of us-nodeadkeys.)
58- Hostname (The name for the computer.)
59- Network (For example, automatic IP address discovery with the "DHCP"
60 protocol.)
61- DNS Servers (Domain Name Servers to query. For privacy reasons, it is NOT
62 recommended to route every local request to servers like Google's 8.8.8.8.)
63- Timezone
64- Proxy (Proxy server to use for accessing the web. Use "none" for direct
65 connections to the internet.)
66- Mirror (From where to download packages. Choose the organization you trust
67 giving your usage patterns to.)
68- SSH (Secure SHell remote access server. "Openssh" is part of the default
69 install image. Use "none" to disable remote login, e.g. on laptops.)
70- NTP (Network Time Protocol client used for keeping the system clock in sync
71 with a time-server. Package "chrony" is part of the default install image.)
72- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as
73 described above.)
74
75Once the setup script is finished, be sure to reboot the machine and remove the
76USB device.
8477
8578```sh
8679reboot
@@ -89,14 +82,12 @@ reboot
8982## Post-Installation
9083
9184There 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.
93I\'m going to walk through my personal post-installation setup for my
94web server.
85running, and it largely depends on what you'll use the machine for. I'm going
86to walk through my personal post-installation setup for my web server.
9587
96881. Upgrade the System
9789
98 First, login as `root` in order to update and upgrade the
99 system:
90 First, login as `root` in order to update and upgrade the system:
10091
10192 ```sh
10293 apk -U upgrade
@@ -104,9 +95,9 @@ web server.
10495
105962. Adding a User
10697
107 I needed to add a user so that I don\'t need to log in as root. Note
108 that if you\'re used to using the `sudo` command, you
109 will now need to use the `doas` command on Alpine Linux.
98 I needed to add a user so that I don't need to log in as root. Note that if
99 you're used to using the `sudo` command, you will now need to use the
100 `doas` command on Alpine Linux.
110101
111102 ```sh
112103 apk add doas
@@ -122,15 +113,14 @@ web server.
122113
1231143. Enable Community Packages
124115
125 In order to install more common packages that aren\'t found in the
126 `main` repository, you will need to enable the
127 `community` repository:
116 In order to install more common packages that aren't found in the `main`
117 repository, you will need to enable the `community` repository:
128118
129119 ```sh
130120 doas nano /etc/apk/repositories
131121 ```
132122
133 Uncomment the community line for whichever version of Alpine you\'re
123 Uncomment the community line for whichever version of Alpine you're
134124 running:
135125
136126 ```sh
@@ -144,9 +134,9 @@ web server.
144134
1451354. Install Required Packages
146136
147 Now that the community packages are available, you can install any
148 packages you need. In my case, I installed the web server packages I
149 need for my services:
137 Now that the community packages are available, you can install any packages
138 you need. In my case, I installed the web server packages I need for my
139 services:
150140
151141 ```sh
152142 doas apk add nano nginx docker docker-compose ufw
@@ -154,15 +144,15 @@ web server.
154144
1551455. SSH
156146
157 If you didn\'t install OpenSSH as part of the installation, you can
158 do so now:
147 If you didn't install OpenSSH as part of the installation, you can do so
148 now:
159149
160150 ```sh
161151 doas apk add openssh
162152 ```
163153
164 Next, either create a new key or copy your SSH key to the server
165 from your current machines:
154 Next, either create a new key or copy your SSH key to the server from your
155 current machines:
166156
167157 ```sh
168158 # Create a new key
@@ -178,9 +168,9 @@ web server.
178168
1791696. Firewall
180170
181 Lastly, I installed `ufw` above as my firewall. To set
182 up, default to deny incoming and allow outgoing connections. Then
183 selectively allow other ports or apps as needed.
171 Lastly, I installed `ufw` above as my firewall. To set up, default to deny
172 incoming and allow outgoing connections. Then selectively allow other ports
173 or apps as needed.
184174
185175 ```sh
186176 doas ufw default deny incoming
@@ -192,8 +182,8 @@ web server.
192182
1931837. Change Hostname
194184
195 If you don\'t like the hostname set during installation, you just
196 need to edit two files. First, edit the simple hostname file:
185 If you don't like the hostname set during installation, you just need to
186 edit two files. First, edit the simple hostname file:
197187
198188 ```sh
199189 doas nano /etc/hostname
@@ -216,8 +206,8 @@ web server.
216206
217207# Nginx Web Server
218208
219To set up my web server, I simply created the `www` user and
220created the necessary files.
209To set up my web server, I simply created the `www` user and created the
210necessary files.
221211
222212```sh
223213doas adduser -D -g 'www' www
@@ -227,17 +217,17 @@ doas chown -R www:www /var/lib/nginx/
227217doas chown -R www:www /www
228218```
229219
230If you\'re running a simple webroot, you can alter the main
231`nginx.conf` file. Otherwise, you can drop configuration
232files in the following directory. You don\'t need to enable or symlink
233the configuration file like you do in other systems.
220If you're running a simple webroot, you can alter the main `nginx.conf` file.
221Otherwise, you can drop configuration files in the following directory. You
222don't need to enable or symlink the configuration file like you do in other
223systems.
234224
235225```sh
236226doas nano /etc/nginx/http.d/example_website.conf
237227```
238228
239Once the configuration is set and pointed at the `/www`
240directory to serve files, enable the Nginx service:
229Once the configuration is set and pointed at the `/www` directory to serve
230files, enable the Nginx service:
241231
242232```sh
243233# Note that 'default' must be included or Nginx will not start on boot
@@ -246,19 +236,16 @@ doas rc-update add nginx default
246236
247237# Docker Containers
248238
249Docker works exactly the same as other systems. Either execute a
250`docker run` command or create a
251`docker-compose.yml` file and do
252`docker-compose up -d`.
239Docker works exactly the same as other systems. Either execute a `docker run`
240command or create a `docker-compose.yml` file and do `docker-compose up -d`.
253241
254242# Git Server
255243
256I went in-depth on how to self-host a git server in another post:
257[Self-Hosting a Personal Git Server](../git-server/).
244I went in-depth on how to self-host a git server in another post: [Self-Hosting
245a Personal Git Server](../git-server/).
258246
259However, there are a few differences with Alpine. First note that in
260order to change the `git` user\'s shell, you must do a few
261things a little different:
247However, there are a few differences with Alpine. First note that in order to
248change the `git` user's shell, you must do a few things a little different:
262249
263250```sh
264251doas apk add libuser
@@ -270,12 +257,11 @@ doas lchsh git
270257
271258# Thoughts on Alpine
272259
273So far, I love Alpine Linux. I have no complaints about anything at this
274point, but I\'m not completely finished with the migration yet. Once
275I\'m able to upgrade my hardware to a rack-mounted server, I will
276migrate Plex and Syncthing over to Alpine as well - possibly putting
277Plex into a container or VM.
260So far, I love Alpine Linux. I have no complaints about anything at this point,
261but I'm not completely finished with the migration yet. Once I'm able to
262upgrade my hardware to a rack-mounted server, I will migrate Plex and Syncthing
263over to Alpine as well - possibly putting Plex into a container or VM.
278264
279The performance is stellar, the `apk` package manager is
280seamless, and system administration tasks are effortless. My only regret
281is that I didn\'t install Alpine sooner.
265The performance is stellar, the `apk` package manager is seamless, and system
266administration tasks are effortless. My only regret is that I didn't install
267Alpine sooner.
content/blog/2022-10-30-linux-display-manager.md +20 −25
@@ -8,18 +8,16 @@ draft = false
88# Display Manager Services
99
1010In order to change the [display
11manager](https://en.wikipedia.org/wiki/Display_manager) on Void Linux -
12or any other Linux distro - you need to identify the currently enabled
13display manager.
11manager](https://en.wikipedia.org/wiki/Display_manager) on Void Linux - or any
12other Linux distro - you need to identify the currently enabled display manager.
1413
1514## Disabling the Current Display Manager
1615
17Void Linux only has one ISO available for download with a pre-built
18display manager at the time of this post: the XFCE ISO. If you\'ve
19installed this version, the pre-assigned display manager is
20`lxdm`. If you installed another display manager, replace
21`lxdm` in the following command with the display manager you
22have installed.
16Void Linux only has one ISO available for download with a pre-built display
17manager at the time of this post: the XFCE ISO. If you've installed this
18version, the pre-assigned display manager is `lxdm`. If you installed another
19display manager, replace `lxdm` in the following command with the display
20manager you have installed.
2321
2422To disable `lxdm`, simply remove the service symlink:
2523
@@ -29,9 +27,8 @@ sudo rm /var/service/lxdm
2927
3028## Enabling a New Display Manager
3129
32If you want to enable a new display manager, you can do so after
33`lxdm` is disabled. Make sure to replace
34`<new_display_manager>` with your new DM, such as
30If you want to enable a new display manager, you can do so after `lxdm` is
31disabled. Make sure to replace `<new_display_manager>` with your new DM, such as
3532`gdm`, `xdm`, etc.
3633
3734```sh
@@ -41,8 +38,8 @@ sudo ln -s /etc/sv/<new_display_manager> /var/service
4138# Set Up `.xinitrc`
4239
4340Depending 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
45launch the i3wm as my desktop.
41`~/.xinitrc`. For my personal set-up, I created this file to launch the i3wm as
42my desktop.
4643
4744```sh
4845nano ~/.xinitrc
@@ -54,21 +51,20 @@ nano ~/.xinitrc
5451exec i3
5552```
5653
57If you run a desktop other than i3, simply replace `i3` with
58the shell command that launches that desktop.
54If you run a desktop other than i3, simply replace `i3` with the shell command
55that launches that desktop.
5956
6057# Set Up Your Shell Profile
6158
62Finally, in order to automatically launch an X session upon login, you
63will need to edit the `.bash_profile` (bash) or
64`.zprofile` (zsh) files for your shell:
59Finally, in order to automatically launch an X session upon login, you will need
60to edit the `.bash_profile` (bash) or `.zprofile` (zsh) files for your shell:
6561
6662```sh
6763nano ~/.zprofile
6864```
6965
70Add the following snippet to the end of the shell profile file. This
71will execute the `startx` command upon login.
66Add the following snippet to the end of the shell profile file. This will
67execute the `startx` command upon login.
7268
7369```sh
7470if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
@@ -76,7 +72,6 @@ if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
7672fi
7773```
7874
79Alternatively, you can ignore this step and simply choose to manually
80execute `startx` upon login. This can be useful if you have
81issues with your desktop or like to manually launch different desktops
82by choice.
75Alternatively, you can ignore this step and simply choose to manually execute
76`startx` upon login. This can be useful if you have issues with your desktop or
77like to manually launch different desktops by choice.
content/blog/2022-11-07-self-hosting-matrix.md +43 −52
@@ -7,21 +7,21 @@ draft = false
77
88# Synpase
99
10If you\'re reading this, you likely know that
10If you're reading this, you likely know that
1111[Synapse](https://github.com/matrix-org/synapse/) is a popular
12[Matrix](https://matrix.org/) home server software that allows users to
13run their own Matrix home server.
12[Matrix](https://matrix.org/) home server software that allows users to run
13their own Matrix home server.
1414
15This post is a short guide describing how I was able to get Synapse
16working in a minimally-usable state on Alpine Linux.
15This post is a short guide describing how I was able to get Synapse working in a
16minimally-usable state on Alpine Linux.
1717
1818# Installation Process
1919
2020## Dependencies
2121
22First, since there is no Alpine-specific package for Synapse, we need to
23ensure that Alpine has the required dependencies for the Python-based
24installation method.
22First, since there is no Alpine-specific package for Synapse, we need to ensure
23that Alpine has the required dependencies for the Python-based installation
24method.
2525
2626```sh
2727doas apk -U update
@@ -41,10 +41,9 @@ pip install matrix-synapse
4141
4242## Running Synapse
4343
44Once installed, running Synapse is easy. Simply execute the following
45command, replacing `example.com` with the domain name that
46will be used with this home server. This will generate the configuration
47files needed to run the server.
44Once installed, running Synapse is easy. Simply execute the following command,
45replacing `example.com` with the domain name that will be used with this home
46server. This will generate the configuration files needed to run the server.
4847
4948```sh
5049python -m synapse.app.homeserver \
@@ -62,16 +61,14 @@ synctl start
6261
6362## Configuring Synapse
6463
65To make any change to Synapse, we need to edit the `YAML`
66configuration file:
64To make any change to Synapse, we need to edit the `YAML` configuration file:
6765
6866```sh
6967nano ~/synapse/homeserver.yaml
7068```
7169
72For now, we just need to ensure the `server_name` is
73accurate. However, there are a lot of other configuration options found
74in the [Configuring
70For now, we just need to ensure the `server_name` is accurate. However, there
71are a lot of other configuration options found in the [Configuring
7572Synapse](https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html)
7673documentation that can be enabled/disabled at any point.
7774
@@ -87,9 +84,9 @@ synctl restart
8784
8885## Nginx Reverse-Proxy
8986
90To ensure that Synapse is reachable from the public, we need to connect
91our domain to the Synapse server. In my case, I use a Nginx
92reverse-proxy for this purpose.
87To ensure that Synapse is reachable from the public, we need to connect our
88domain to the Synapse server. In my case, I use a Nginx reverse-proxy for this
89purpose.
9390
9491To use Nginx, we need to create a reverse-proxy configuration file:
9592
@@ -97,9 +94,8 @@ To use Nginx, we need to create a reverse-proxy configuration file:
9794doas nano /etc/nginx/http.d/example.com.conf
9895```
9996
100If you already have TLS certificates for this domain
101(`example.com`), you can simply use the SSL configuration and
102point toward your TLS certificates.
97If you already have TLS certificates for this domain (`example.com`), you can
98simply use the SSL configuration and point toward your TLS certificates.
10399
104100``` conf
105101server {
@@ -143,10 +139,9 @@ server {
143139```
144140
145141If you need to generate TLS certificates (I recommend
146[Certbot](https://certbot.eff.org/)), you\'ll need a more minimal Nginx
147conf file before you can use the TLS-enabled example above. Instead, use
148this configuration file during the Certbot certificate generation
149process:
142[Certbot](https://certbot.eff.org/)), you'll need a more minimal Nginx conf
143file before you can use the TLS-enabled example above. Instead, use this
144configuration file during the Certbot certificate generation process:
150145
151146``` conf
152147server {
@@ -158,20 +153,19 @@ server {
158153}
159154```
160155
161Once you\'re done editing the Nginx conf file, restart Nginx:
156Once you're done editing the Nginx conf file, restart Nginx:
162157
163158```sh
164159doas rc-service nginx restart
165160```
166161
167If you still need to generate TLS certificates, run `certbot`
168now and obtain the certificates. Certbot will ask if you want to use a
169webroot or spin up a temporary web server. I **highly\*** recommend
170using the temporary web server due to the many issues with using a
171webroot.
162If you still need to generate TLS certificates, run `certbot` now and obtain the
163certificates. Certbot will ask if you want to use a webroot or spin up a
164temporary web server. I **highly** recommend using the temporary web server due
165to the many issues with using a webroot.
172166
173You will need to stop Nginx in order to user the temporary web server
174option with Certbot:
167You will need to stop Nginx in order to user the temporary web server option
168with Certbot:
175169
176170```sh
177171# Stop Nginx so certbot can spin up a temp webserver for cert generation
@@ -182,13 +176,13 @@ doas rc-service nginx start
182176
183177## Open Firewall & Router Ports
184178
185If you use a firewall on the server, open the `8448` port for
186discovery and federation, as well as the normal web server ports if
187you\'re using a reverse proxy. If you want additional services, such as
188voice calls, you will need to read the Synapse documentation to see
189which ports need to be opened for those features.
179If you use a firewall on the server, open the `8448` port for discovery and
180federation, as well as the normal web server ports if you're using a reverse
181proxy. If you want additional services, such as voice calls, you will need to
182read the Synapse documentation to see which ports need to be opened for those
183features.
190184
191Here\'s an example of the Universal Firewall (UFW) software:
185Here's an example of the Universal Firewall (UFW) software:
192186
193187```sh
194188# Matrix port
@@ -197,15 +191,13 @@ doas ufw allow 8448
197191doas ufw allow "Nginx Full"
198192```
199193
200Remember to forward any Synapse ports, such as `8448`,
201`80`, and `443`, in your Router from the internet
202to your server\'s IP address.
194Remember to forward any Synapse ports, such as `8448`, `80`, and `443`, in your
195Router from the internet to your server's IP address.
203196
204197## Adding Matrix Users
205198
206Finally, if you didn\'t enable public registration in the
207`homeserver.yaml` file, you can manually create users via the
208command-line:
199Finally, if you didn't enable public registration in the `homeserver.yaml`
200file, you can manually create users via the command-line:
209201
210202```sh
211203cd ~/synapse
@@ -213,9 +205,8 @@ register_new_matrix_user -c homeserver.yaml
213205```
214206
215207Remember that the format for federated Matrix usernames is
216`@username:example.com` when logging in to client
217applications.
208`@username:example.com` when logging in to client applications.
218209
219Once Synapse is running, and you have a username, you are ready to log
220in to a Matrix client and start sending messages, joining rooms, and
221utilizing your very own Matrix server.
210Once Synapse is running, and you have a username, you are ready to log in to a
211Matrix client and start sending messages, joining rooms, and utilizing your very
212own Matrix server.
content/blog/2022-11-11-nginx-tmp-errors.md +17 −20
@@ -5,15 +5,14 @@ description = ""
55draft = false
66+++
77
8*This is a brief post so that I personally remember the solution as it
9has occurred multiple times for me.*
8*This is a brief post so that I personally remember the solution as it has
9occurred multiple times for me.*
1010
1111# The Problem
1212
13After migrating to a new server OS, I started receiving quite a few
14permission errors like the one below. These popped up for various
15different websites I\'m serving via Nginx on this server, but did not
16prevent the website from loading.
13After migrating to a new server OS, I started receiving quite a few permission
14errors like the one below. These popped up for various different websites I'm
15serving via Nginx on this server, but did not prevent the website from loading.
1716
1817I found the errors in the standard log file:
1918
@@ -25,20 +24,18 @@ cat /var/log/nginx/error.log
25242022/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/"
2625```
2726
28You can see that the error is `13: Permission denied` and it
29occurs in the `/var/lib/nginx/tmp/` directory. In my case, I
30had thousands of errors where Nginx was denied permission to read/write
31files in this directory.
27You can see that the error is `13: Permission denied` and it occurs in the
28`/var/lib/nginx/tmp/` directory. In my case, I had thousands of errors where
29Nginx was denied permission to read/write files in this directory.
3230
3331So how do I fix it?
3432
3533# The Solution
3634
37In order to resolve the issue, I had to ensure the
38`/var/lib/nginx` directory is owned by Nginx. Mine was owned
39by the `www` user and Nginx was not able to read or write
40files within that directory. This prevented Nginx from caching temporary
41files.
35In order to resolve the issue, I had to ensure the `/var/lib/nginx` directory is
36owned by Nginx. Mine was owned by the `www` user and Nginx was not able to read
37or write files within that directory. This prevented Nginx from caching
38temporary files.
4239
4340```sh
4441# Alpine Linux
@@ -48,9 +45,9 @@ doas chown -R nginx:nginx /var/lib/nginx
4845sudo chown -R nginx:nginx /var/lib/nginx
4946```
5047
51You *may* also be able to change the `proxy_temp_path` in
52your Nginx config, but I did not try this. Here\'s a suggestion I found
53online that may work if the above solution does not:
48You *may* also be able to change the `proxy_temp_path` in your Nginx config, but
49I did not try this. Here's a suggestion I found online that may work if the
50above solution does not:
5451
5552```sh
5653nano /etc/nginx/http.d/example.com.conf
@@ -68,8 +65,8 @@ server {
6865}
6966```
7067
71Finally, restart Nginx and your server should be able to cache temporary
72files again.
68Finally, restart Nginx and your server should be able to cache temporary files
69again.
7370
7471```sh
7572# Alpine Linux (OpenRC)
content/blog/2022-11-27-server-build.md +85 −90
@@ -7,142 +7,137 @@ draft = false
77
88# The Dilemma
99
10For years, I have been using desktops and a Raspberry Pi as the backbone
11of my homelab. I have always wanted to move toward a single dedicated
12server that could handle all of my tasks, but was often put off by the
13complexity of the choices (and financial roadblocks at some times).
10For years, I have been using desktops and a Raspberry Pi as the backbone of my
11homelab. I have always wanted to move toward a single dedicated server that
12could handle all of my tasks, but was often put off by the complexity of the
13choices (and financial roadblocks at some times).
1414
15However, after purchasing a small server rack this past year, I have
16been researching to see what kind of rack-mounted server I could buy. I
17initially bought a Dell R720XD loaded up with everything I could ever
18want in a server - but I did not care for it. It was far too loud, and
19the age of the CPU/RAM was something I wanted to improve upon.
15However, after purchasing a small server rack this past year, I have been
16researching to see what kind of rack-mounted server I could buy. I initially
17bought a Dell R720XD loaded up with everything I could ever want in a server -
18but I did not care for it. It was far too loud, and the age of the CPU/RAM was
19something I wanted to improve upon.
2020
21After returning the R720XD, I decided that I wanted to build my own
22server with modern, consumer-grade PC components. This time, I am very
23happy with the results of my server.
21After returning the R720XD, I decided that I wanted to build my own server with
22modern, consumer-grade PC components. This time, I am very happy with the
23results of my server.
2424
2525# Components
2626
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:
2828
29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount
29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount
3030 Case](https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825)
31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550)
32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics
33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that
34 support onboard graphics.
35- **RAM**: 64GB RAM (2x32GB) *Max of 128GB RAM on this motherboard*
36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD
37- **HDD Bay**:
38 - 10TB 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
41 build, so I grabbed two of these)*
42- **PSU**: Corsair RM850 PSU
43- **Extras**:
44 - Corsair TM3Q Thermal Paste
45 - Noctua 120mm fan *(replacement for front case fan)*
46 - 2 x Noctua 80mm fans *(replacement for rear case fans)*
47 - CableMatters 6Gbps SATA Cables
31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550)
32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics
33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that support
34 onboard graphics.
35- **RAM**: 64GB RAM (2x32GB) *Max of 128GB RAM on this motherboard*
36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD
37- **HDD Bay**:
38 - 10TB 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 build,
41 so I grabbed two of these)*
42- **PSU**: Corsair RM850 PSU
43- **Extras**:
44 - Corsair TM3Q Thermal Paste
45 - Noctua 120mm fan *(replacement for front case fan)*
46 - 2 x Noctua 80mm fans *(replacement for rear case fans)*
47 - CableMatters 6Gbps SATA Cables
4848
4949# Building the Server
5050
51This took quite a while for me to build (in my opinion of time),
52totaling around 3 hours from start to finish. The case has some peculiar
53construction, so you have to completely remove the ODD & HDD cages to
54install the motherboard and other components first.
51This took quite a while for me to build (in my opinion of time), totaling around
523 hours from start to finish. The case has some peculiar construction, so you
53have to completely remove the ODD & HDD cages to install the motherboard and
54other components first.
5555
56Now, I\'ve never built a computer of any kind before, so I was quite
57nervous. Personally, the only challenging part was getting the CPU
58cooler to screw into the motherboard without sliding the thermal paste
59around too much underneath. I\'m still not entirely sure if I did a
60great job of it, but nothing\'s broken yet.
56Now, I've never built a computer of any kind before, so I was quite nervous.
57Personally, the only challenging part was getting the CPU cooler to screw into
58the motherboard without sliding the thermal paste around too much underneath.
59I'm still not entirely sure if I did a great job of it, but nothing's broken
60yet.
6161
62The main components were all fine and simple. However, installing the
63hard drives is slightly tedious as I need to power off the server and
64completely unscrew the HDD cage to install or remove any drives.
65Additionally, the drives are screwed directly into the metal cage with
66small screws, which are quite a bit different from the HDD trays I\'m
67used to in other machines.
62The main components were all fine and simple. However, installing the hard
63drives is slightly tedious as I need to power off the server and completely
64unscrew the HDD cage to install or remove any drives. Additionally, the drives
65are screwed directly into the metal cage with small screws, which are quite a
66bit different from the HDD trays I'm used to in other machines.
6867
69Seeing that the cases with hot-swap bays were 3-4x the price, I\'m okay
70dealing with the tedium of removing the cage to install new drives.
68Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay dealing
69with the tedium of removing the cage to install new drives.
7170
7271# Software
7372
74I\'m not going to dive into the software as I have done so in other
75recent posts. However, I wanted to note that I am using Alpine Linux on
76this server and hosting most services inside Docker. No virtual machines
77(VMs) and very few bare-metal services.
73I'm not going to dive into the software as I have done so in other recent
74posts. However, I wanted to note that I am using Alpine Linux on this server and
75hosting most services inside Docker. No virtual machines (VMs) and very few
76bare-metal services.
7877
7978# The Results
8079
81How did my build turn out? Well, after migrating my other servers and
82their services over, I found that my server is blazing fast. The
83heaviest of my applications, Plex, is handled with ease. Even 4k
84streaming seems to be effortless.
80How did my build turn out? Well, after migrating my other servers and their
81services over, I found that my server is blazing fast. The heaviest of my
82applications, Plex, is handled with ease. Even 4k streaming seems to be
83effortless.
8584
86I am very happy with the results and will likely continue to improve on
87this server as the years go by rather than buying another used server
88online.
85I am very happy with the results and will likely continue to improve on this
86server as the years go by rather than buying another used server online.
8987
9088## Mistakes I Made
9189
92This post wouldn\'t be complete unless I wrote about the mistakes I made
93while building. The only real mistake I made beyond a \"whoops I dropped
94a screw\" related to airflow and fan direction.
90This post wouldn't be complete unless I wrote about the mistakes I made while
91building. The only real mistake I made beyond a "whoops I dropped a screw"
92related to airflow and fan direction.
9593
96While installing the two new hard drives that showed up on 2022-11-30
97and getting ready to install the case in my rack, I noticed that the
98hard drive temperatures were quite high.
94While installing the two new hard drives that showed up on 2022-11-30 and
95getting ready to install the case in my rack, I noticed that the hard drive
96temperatures were quite high.
9997
100I used the `smartctl` command for each of my drives
101(`/dev/sda` through `/dev/sdd`):
98I used the `smartctl` command for each of my drives (`/dev/sda` through
99`/dev/sdd`):
102100
103101```sh
104102doas smartctl -a /dev/sda | grep Temperature_Celsius
105103```
106104
107The results were unusual - all four drives were idling at \~44-46
108degrees Celsius. The only drive that was cooler was my 10TB drive, which
109was at 38 degrees Celsius. I noted that this 10TB drive was also closest
110to the case fan.
105The results were unusual - all four drives were idling at ~44-46 degrees
106Celsius. The only drive that was cooler was my 10TB drive, which was at 38
107degrees Celsius. I noted that this 10TB drive was also closest to the case fan.
111108
112109```sh
113110ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
114111# /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)
116113# /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)
118115# /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)
120117# /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)
122119```
123120
124After looking to see if I could fit more fans into the case, I noticed
125that the 120mm fan used for intake from the front of the case was
126actually pushing air out of the case by mistake. This fan sits right in
127front of the hard drive bay.
121After looking to see if I could fit more fans into the case, I noticed that the
122120mm fan used for intake from the front of the case was actually pushing air
123out of the case by mistake. This fan sits right in front of the hard drive bay.
128124
129Once I flipped the fan around to act as an intake fan, the temperatures
130dropped immediately! They are now idling at \~31-33 degrees Celsius. A
131single fan spinning the wrong way caused my drives to idle 10-15 degrees
132higher than they should have.
125Once I flipped the fan around to act as an intake fan, the temperatures dropped
126immediately! They are now idling at ~31-33 degrees Celsius. A single fan
127spinning the wrong way caused my drives to idle 10-15 degrees higher than they
128should have.
133129
134130```sh
135131ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
136132# /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)
138134# /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)
140136# /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)
142138# /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)
144140```
145141
146This was a silly error to make, but I\'m glad I found it today before I
147screwed the case into the rack and made things a lot more tedious to
148fix.
142This was a silly error to make, but I'm glad I found it today before I screwed
143the case into the rack and made things a lot more tedious to fix.
content/blog/2022-11-29-nginx-referrer-ban-list.md +25 −26
@@ -7,9 +7,9 @@ draft = false
77
88# Creating the Ban List
99
10In order to ban list referral domains or websites with Nginx, you need
11to create a ban list file. The file below will accept regexes for
12different domains or websites you wish to block.
10In order to ban list referral domains or websites with Nginx, you need to create
11a ban list file. The file below will accept regexes for different domains or
12websites you wish to block.
1313
1414First, create the file in your nginx directory:
1515
@@ -17,8 +17,8 @@ First, create the file in your nginx directory:
1717doas nano /etc/nginx/banlist.conf
1818```
1919
20Next, paste the following contents in and fill out the regexes with
21whichever domains you\'re blocking.
20Next, paste the following contents in and fill out the regexes with whichever
21domains you're blocking.
2222
2323``` conf
2424# /etc/nginx/banlist.conf
@@ -35,15 +35,15 @@ map $http_referer $bad_referer {
3535
3636# Configuring Nginx
3737
38In order for the ban list to work, Nginx needs to know it exists and how
39to handle it. For this, edit the `nginx.conf` file.
38In order for the ban list to work, Nginx needs to know it exists and how to
39handle it. For this, edit the `nginx.conf` file.
4040
4141```sh
4242doas nano /etc/nginx/nginx.conf
4343```
4444
45Within this file, find the `http` block and add your ban list
46file location to the end of the block.
45Within this file, find the `http` block and add your ban list file location to
46the end of the block.
4747
4848``` conf
4949# /etc/nginx/nginx.conf
@@ -58,24 +58,23 @@ http {
5858
5959# Enabling the Ban List
6060
61Finally, we need to take action when a bad referral site is found. To do
62so, edit the configuration file for your website. For example, I have
63all website configuration files in the `http.d` directory.
64You may have them in the `sites-available` directory on some
65distributions.
61Finally, we need to take action when a bad referral site is found. To do so,
62edit the configuration file for your website. For example, I have all website
63configuration files in the `http.d` directory. You may have them in the
64`sites-available` directory on some distributions.
6665
6766```sh
6867doas nano /etc/nginx/http.d/example.com.conf
6968```
7069
71Within each website\'s configuration file, edit the `server`
72blocks that are listening to ports 80 and 443 and create a check for the
73`$bad_referrer` variable we created in the ban list file.
70Within each website's configuration file, edit the `server` blocks that are
71listening to ports 80 and 443 and create a check for the `$bad_referrer`
72variable we created in the ban list file.
7473
7574If a matching site is found, you can return any [HTTP Status
76Code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) you want.
77Code 403 (Forbidden) is logical in this case since you are preventing a
78client connection due to a banned domain.
75Code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) you want. Code
76403 (Forbidden) is logical in this case since you are preventing a client
77connection due to a banned domain.
7978
8079``` conf
8180server {
@@ -100,8 +99,8 @@ doas rc-service nginx restart
10099
101100# Testing Results
102101
103In order to test the results, let\'s curl the contents of our site. To
104start, I\'ll curl the site normally:
102In order to test the results, let's curl the contents of our site. To start,
103I'll curl the site normally:
105104
106105```sh
107106curl https://cleberg.net
@@ -113,15 +112,15 @@ The HTML contents of the page come back successfully:
113112<!doctype html>...</html>
114113```
115114
116Next, let\'s include a banned referrer:
115Next, let's include a banned referrer:
117116
118117```sh
119118curl --referer https://news.ycombinator.com https://cleberg.net
120119```
121120
122This time, I\'m met with a 403 Forbidden response page. That means we
123are successful and any clients being referred from a banned domain will
124be met with this same response code.
121This time, I'm met with a 403 Forbidden response page. That means we are
122successful and any clients being referred from a banned domain will be met with
123this same response code.
125124
126125``` html
127126<html>
content/blog/2022-12-01-nginx-compression.md +33 −37
@@ -7,24 +7,23 @@ draft = false
77
88# Text Compression
99
10Text compression allows a web server to serve text-based resources
11faster than uncompressed data. This can speed up things like First
12Contentful Paint, Tie to Interactive, and Speed Index.
10Text compression allows a web server to serve text-based resources faster than
11uncompressed data. This can speed up things like First Contentful Paint, Tie to
12Interactive, and Speed Index.
1313
1414# Enable Nginx Compression with gzip
1515
16In order to enable text compression on Nginx, we need to enable it
17within the configuration file:
16In order to enable text compression on Nginx, we need to enable it within the
17configuration file:
1818
1919```sh
2020nano /etc/nginx/nginx.conf
2121```
2222
23Within the `http` block, find the section that shows
24something like the block below. This is the default gzip configuration I
25found in my `nginx.conf` file on Alpine Linux 3.17. Yours may
26look slightly different, just make sure that you\'re not creating any
27duplicate gzip options.
23Within the `http` block, find the section that shows something like the block
24below. This is the default gzip configuration I found in my `nginx.conf` file on
25Alpine Linux 3.17. Yours may look slightly different, just make sure that
26you're not creating any duplicate gzip options.
2827
2928``` conf
3029# Enable gzipping of responses.
@@ -48,33 +47,30 @@ gzip_disable "MSIE [1-6]";
4847
4948# Explanations of ngx~httpgzipmodule~ Options
5049
51Each of the lines above enables a different aspect of the gzip response
52for Nginx. Here are the full explanations:
50Each of the lines above enables a different aspect of the gzip response for
51Nginx. Here are the full explanations:
5352
54- `gzip` -- Enables or disables gzipping of responses.
55- `gzip_vary` -- Enables or disables inserting the \"Vary:
56 Accept-Encoding\" response header field if the directives gzip,
57 gzip~static~, or gunzip are active.
58- `gzip_min_length` -- Sets the minimum length of a
59 response that will be gzipped. The length is determined only from
60 the \"Content-Length\" response header field.
61- `gzip_proxied` -- Enables or disables gzipping of
62 responses for proxied requests depending on the request and
63 response. The fact that the request is proxied is determined by the
64 presence of the \"Via\" request header field.
65- `gzip_types` -- Enables gzipping of responses for the
66 specified MIME types in addition to \"text/html\". The special value
67 "\*" matches any MIME type (0.8.29). Responses with the
68 \"text/html\" type are always compressed.
69- `gzip_disable` -- Disables gzipping of responses for
70 requests with \"User-Agent\" header fields matching any of the
71 specified regular expressions.
72 - The special mask \"msie6\" (0.7.12) corresponds to the regular
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.
53- `gzip` -- Enables or disables gzipping of responses.
54- `gzip_vary` -- Enables or disables inserting the "Vary: Accept-Encoding"
55 response header field if the directives gzip, gzip~static~, or gunzip are
56 active.
57- `gzip_min_length` -- Sets the minimum length of a response that will be
58 gzipped. The length is determined only from the "Content-Length" response
59 header field.
60- `gzip_proxied` -- Enables or disables gzipping of responses for proxied
61 requests depending on the request and response. The fact that the request is
62 proxied is determined by the presence of the "Via" request header field.
63- `gzip_types` -- Enables gzipping of responses for the specified MIME types in
64 addition to "text/html". The special value "*" matches any MIME type
65 (0.8.29). Responses with the "text/html" type are always compressed.
66- `gzip_disable` -- Disables gzipping of responses for requests with
67 "User-Agent" header fields matching any of the specified regular
68 expressions.
69 - The special mask "msie6" (0.7.12) corresponds to the regular expression
70 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE
71 6.0; ... SV1" is excluded from this mask.
7672
77More information on these directives and their options can be found on
78the [Module
73More information on these directives and their options can be found on the
74[Module
7975ngx~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
77
88# Problem
99
10I recently migrated domains and replaced the old webpage with a simple
11info page with instructions to users on how to edit their bookmarks and
12URLs to get to the page they were seeking.
10I recently migrated domains and replaced the old webpage with a simple info page
11with instructions to users on how to edit their bookmarks and URLs to get to the
12page they were seeking.
1313
14This was not ideal as it left the work up to the user and may have
15caused friction for users who accessed my RSS feed.
14This was not ideal as it left the work up to the user and may have caused
15friction for users who accessed my RSS feed.
1616
1717# Solution
1818
19Instead, I finally found a solution that allows me to redirect both
20subdomains AND trailing content. For example, both of these URLs now
21redirect properly using the logic I\'ll explain below:
19Instead, I finally found a solution that allows me to redirect both subdomains
20AND trailing content. For example, both of these URLs now redirect properly
21using the logic I'll explain below:
2222
2323``` txt
2424# Example 1 - Simple base domain redirect with trailing content
@@ -34,15 +34,15 @@ Go ahead, try the URLs if you want to test them.
3434
3535## Nginx Config
3636
37To make this possible. I needed to configure a proper redirect scheme in
38my Nginx configuration.
37To make this possible. I needed to configure a proper redirect scheme in my
38Nginx configuration.
3939
4040```sh
4141doas nano /etc/nginx/http.d/domain1.conf
4242```
4343
44Within this file, I had one block configured to redirect HTTP requests
45to HTTPS for the base domain and all subdomains.
44Within this file, I had one block configured to redirect HTTP requests to HTTPS
45for the base domain and all subdomains.
4646
4747``` conf
4848server {
@@ -62,10 +62,9 @@ server {
6262}
6363```
6464
65For the base domain, I have another `server` block dedicated
66to redirecting all base domain requests. You can see that the
67`rewrite` line is instructing Nginx to gather all trailing
68content and append it to the new `domain2.com` URL.
65For the base domain, I have another `server` block dedicated to redirecting all
66base domain requests. You can see that the `rewrite` line is instructing Nginx
67to gather all trailing content and append it to the new `domain2.com` URL.
6968
7069``` conf
7170server {
@@ -81,19 +80,16 @@ server {
8180}
8281```
8382
84Finally, the tricky part is figuring out how to tell Nginx to redirect
85while keeping both a subdomain and trailing content intact. I found that
86the easiest way to do this is to give it a `server` block of
87its own.
83Finally, the tricky part is figuring out how to tell Nginx to redirect while
84keeping both a subdomain and trailing content intact. I found that the easiest
85way to do this is to give it a `server` block of its own.
8886
89Within this block, we need to do some regex on the
90`server_name` line before we can rewrite anything. This
91creates a variable called `subdomain`.
87Within this block, we need to do some regex on the `server_name` line before we
88can rewrite anything. This creates a variable called `subdomain`.
9289
93Once the server gets to the `rewrite` line, it pulls the
94`subdomain` variable from above and uses it on the new
95`domain2.com` domain before appending the trailing content
96(`$request_uri`).
90Once the server gets to the `rewrite` line, it pulls the `subdomain` variable
91from above and uses it on the new `domain2.com` domain before appending the
92trailing content (`$request_uri`).
9793
9894``` conf
9995server {
@@ -109,15 +105,15 @@ server {
109105}
110106```
111107
112That\'s all there is to it. With this, I simply restarted Nginx and
113watched the redirections work in-action.
108That's all there is to it. With this, I simply restarted Nginx and watched the
109redirections work in-action.
114110
115111```sh
116112doas rc-service nginx restart
117113```
118114
119Looking back on it, I wish I had done this sooner. Who knows how many
120people went looking for my sites or bookmarks and gave up when they saw
121the redirect instructions page.
115Looking back on it, I wish I had done this sooner. Who knows how many people
116went looking for my sites or bookmarks and gave up when they saw the redirect
117instructions page.
122118
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
77
88# st
99
10[st](https://st.suckless.org) standards for Simple Terminal, a simple
11terminal implementation for X made by the
12[suckless](https://suckless.org) team.
10[st](https://st.suckless.org) standards for Simple Terminal, a simple terminal
11implementation for X made by the [suckless](https://suckless.org) team.
1312
14This post walks through the dependencies needed and process to build and
15install `st` on Fedora Workstation.
13This post walks through the dependencies needed and process to build and install
14`st` on Fedora Workstation.
1615
1716## Obtain Files
1817
19To start, obtain the source files for `st` via
20`git clone`.
18To start, obtain the source files for `st` via `git clone`.
2119
2220```sh
2321mkdir ~/suckless && cd ~/suckless
@@ -26,8 +24,8 @@ git clone https://git.suckless.org/st && cd st
2624
2725## Dependencies
2826
29Once you have the files and are in the `st` directory, ensure
30the following packages are installed.
27Once you have the files and are in the `st` directory, ensure the following
28packages are installed.
3129
3230```sh
3331sudo dnf update && sudo dnf upgrade
@@ -42,13 +40,12 @@ Before building, ensure that you read the README file.
4240cat README
4341```
4442
45Once you\'ve read the instructions, open the `config.mk` file
46and ensure it matches your setup. If you\'re not sure, leave the default
47options within the file.
43Once you've read the instructions, open the `config.mk` file and ensure it
44matches your setup. If you're not sure, leave the default options within the
45file.
4846
49Finally, you can build `st` with the following command.
50Ensure you run as root (e.g., `sudo`) or else you may not end
51up with a usable application file.
47Finally, you can build `st` with the following command. Ensure you run as root
48(e.g., `sudo`) or else you may not end up with a usable application file.
5249
5350```sh
5451sudo make clean install
@@ -56,39 +53,38 @@ sudo make clean install
5653
5754## Customization (Patches)
5855
59Note that customizing `st` requires you to modify the source
60files or to download one of the [available
61patches](https://st.suckless.org/patches/) for suckless.org.
56Note that customizing `st` requires you to modify the source files or to
57download one of the [available patches](https://st.suckless.org/patches/) for
58suckless.org.
6259
63If you\'ve already installed `st` and want to customize or
64install a patch, start by uninstalling the current program.
60If you've already installed `st` and want to customize or install a patch,
61start by uninstalling the current program.
6562
6663```sh
6764cd ~/suckless/st
6865sudo make uninstall
6966```
7067
71Next, grab the `<path>.diff` file from the page of the patch
72you chose. For example, I will be using the
73[defaultfontsize](https://st.suckless.org/patches/defaultfontsize/)
74patch in the below example.
68Next, grab the `<path>.diff` file from the page of the patch you chose. For
69example, I will be using the
70[defaultfontsize](https://st.suckless.org/patches/defaultfontsize/) patch in the
71below example.
7572
7673```sh
7774wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff
7875```
7976
80Once the file is downloaded inside the `st` folder, apply the
81patch and re-install the program. You may need to install the
82`patch` command if you don\'t have it installed already (you
83should have installed it above).
77Once the file is downloaded inside the `st` folder, apply the patch and
78re-install the program. You may need to install the `patch` command if you
79don't have it installed already (you should have installed it above).
8480
8581```sh
8682patch -i st-defaultfontsize-20210225-4ef0cbd.diff
8783sudo make clean install
8884```
8985
90Once installed, you can use the default font size patch to launch
91`st` with any font size you wish:
86Once installed, you can use the default font size patch to launch `st` with any
87font size you wish:
9288
9389```sh
9490st -z 16
content/blog/2022-12-23-alpine-desktop.md +45 −52
@@ -5,33 +5,31 @@ description = ""
55draft = false
66+++
77
8# Isn't Alpine Linux for Servers?
89
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.
1012
11This is a question I see a lot when people are presented with an example
12of Alpine Linux running as a desktop OS.
13While Alpine is small, fast, and minimal, that doesn't stop it from functioning
14at a productive level for desktop users.
1315
14While Alpine is small, fast, and minimal, that doesn\'t stop it from
15functioning at a productive level for desktop users.
16
17This post is documentation of how I installed and modified Alpine Linux
18to become my daily desktop OS.
16This post is documentation of how I installed and modified Alpine Linux to
17become my daily desktop OS.
1918
2019# Installation
2120
22Note that I cover the installation of Alpine Linux in my other post, so
23I won\'t repeat it here: [Alpine Linux: My New Server
24OS](../alpine-linux/).
21Note that I cover the installation of Alpine Linux in my other post, so I won't
22repeat it here: [Alpine Linux: My New Server OS](../alpine-linux/).
2523
26Basically, get a bootable USB or whatever you prefer with Alpine on it,
27boot the ISO, and run the setup script.
24Basically, get a bootable USB or whatever you prefer with Alpine on it, boot the
25ISO, and run the setup script.
2826
2927```sh
3028setup-alpine
3129```
3230
33Once you have gone through all the options and installer finishes
34without errors, reboot.
31Once you have gone through all the options and installer finishes without
32errors, reboot.
3533
3634```sh
3735reboot
@@ -40,9 +38,9 @@ reboot
4038# Initial Setup
4139
4240Once 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
44here, you should start by updating and upgrading the system in case the
45ISO was not fully up-to-date.
41initially or `su` to root once you log in as your user. From here, you should
42start by updating and upgrading the system in case the ISO was not fully
43up-to-date.
4644
4745```sh
4846# Update and upgrade system
@@ -52,8 +50,8 @@ apk -U update && apk -U upgrade
5250apk add nano
5351```
5452
55You need to uncomment the `community` repository for your
56version of Alpine Linux.
53You need to uncomment the `community` repository for your version of Alpine
54Linux.
5755
5856For v3.17, the `repositories` file should look like this:
5957
@@ -80,11 +78,11 @@ adduser $USER wheel
8078
8179# Window Manager (Desktop)
8280
83The [Sway installation guide](https://wiki.alpinelinux.org/wiki/Sway)
84has everything you need to get Sway working on Alpine.
81The [Sway installation guide](https://wiki.alpinelinux.org/wiki/Sway) has
82everything you need to get Sway working on Alpine.
8583
86However, I\'ll include a brief list of the commands I ran and their
87purpose for posterity here.
84However, I'll include a brief list of the commands I ran and their purpose for
85posterity here.
8886
8987```sh
9088# Add eudev and set it up
@@ -126,11 +124,10 @@ apk add \ # Install optional dependencies:
126124```
127125
128126Once you have the packages installed and set-up, you need to export the
129`XDG_RUNTIME_DIR` upon login. To do this, edit your
130`.profile` file.
127`XDG_RUNTIME_DIR` upon login. To do this, edit your `.profile` file.
131128
132If you use another shell, such as `zsh`, you need to edit
133that shell\'s profile (e.g., `~/.zprofile`)!
129If you use another shell, such as `zsh`, you need to edit that shell's profile
130(e.g., `~/.zprofile`)!
134131
135132```sh
136133nano ~/.profile
@@ -148,7 +145,7 @@ if test -z "${XDG_RUNTIME_DIR}"; then
148145fi
149146```
150147
151Once that\'s complete, you can launch Sway manually.
148Once that's complete, you can launch Sway manually.
152149
153150```sh
154151dbus-run-session -- sway
@@ -156,8 +153,7 @@ dbus-run-session -- sway
156153
157154## Personal Touches
158155
159I also added the following packages, per my personal preferences and
160situation.
156I also added the following packages, per my personal preferences and situation.
161157
162158```sh
163159doas apk add brightnessctl \ # Brightness controller
@@ -171,16 +167,16 @@ doas apk add brightnessctl \ # Brightness controller
171167 gnupg # GPG key manager
172168```
173169
174From here, I use my Syncthing storage to pull all the configuration
175files I stored from prior desktops, such as [my
170From here, I use my Syncthing storage to pull all the configuration files I
171stored from prior desktops, such as [my
176172dotfiles](https://git.sr.ht/~cmc/dotfiles).
177173
178174# Resolving Issues
179175
180176## WiFi Issues
181177
182I initially tried to set up my Wi-Fi the standard way with
183`iwd`, but it didn\'t work.
178I initially tried to set up my Wi-Fi the standard way with `iwd`, but it didn't
179work.
184180
185181Here is what I initially tried (I did all of this as `root`):
186182
@@ -191,8 +187,7 @@ iwctl station wlan0 connect <SSID> # This will prompt for the password
191187rc-update add iwd boot && rc-update add dbus boot
192188```
193189
194Then, I added the Wi-Fi entry to the bottom of the networking interface
195file:
190Then, I added the Wi-Fi entry to the bottom of the networking interface file:
196191
197192```sh
198193nano /etc/network/interfaces
@@ -209,13 +204,11 @@ Finally, restart the networking service:
209204rc-service networking restart
210205```
211206
212My Wi-Fi interface would receive an IP address from the router, but it
213could not ping anything in the network. To solve the Wi-Fi issues, I
214originally upgraded to Alpine\'s `edge` repositories, which
215was unnecessary.
207My Wi-Fi interface would receive an IP address from the router, but it could not
208ping anything in the network. To solve the Wi-Fi issues, I originally upgraded
209to Alpine's `edge` repositories, which was unnecessary.
216210
217Really, the solution was to enable the
218`NameResolvingService=resolvconf` in
211Really, the solution was to enable the `NameResolvingService=resolvconf` in
219212`/etc/iwd/main.conf`.
220213
221214```sh
@@ -232,8 +225,8 @@ Once I finished this process, my Wi-Fi is working flawlessly.
232225
233226## Sound Issues
234227
235Same as with the Wi-Fi, I had no sound and could not control the
236mute/unmute or volume buttons on my laptop.
228Same as with the Wi-Fi, I had no sound and could not control the mute/unmute or
229volume buttons on my laptop.
237230
238231To resolve this, I installed
239232[pipewire](https://wiki.alpinelinux.org/wiki/PipeWire).
@@ -247,9 +240,9 @@ addgroup $USER video
247240apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa
248241```
249242
250Finally, I needed to add `/usr/libexec/pipewire-launcher` to
251my `.config/sway/config` file so that Pipewire would run
252every time I launched sway.
243Finally, I needed to add `/usr/libexec/pipewire-launcher` to my
244`.config/sway/config` file so that Pipewire would run every time I launched
245sway.
253246
254247```sh
255248nano ~/.config/sway/config
@@ -266,8 +259,8 @@ bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ to
266259bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle
267260```
268261
269Note that I do not use bluetooth or screen sharing, so I won\'t cover
270those options in this post.
262Note that I do not use bluetooth or screen sharing, so I won't cover those
263options in this post.
271264
272Other than these issues, I have a working Alpine desktop. No other
273complaints thus far!
265Other than these issues, I have a working Alpine desktop. No other complaints
266thus far!
content/blog/2023-01-03-recent-website-changes.md +47 −51
@@ -7,80 +7,76 @@ draft = false
77
88# The State of This Website
99
10Over the years, this website has changed URLs, styles, content focus,
11and much more. However, it seems that I am never done, as I am yet again
12changing this page to fit my current needs and wants.
10Over the years, this website has changed URLs, styles, content focus, and much
11more. However, it seems that I am never done, as I am yet again changing this
12page to fit my current needs and wants.
1313
14While this site was already minimal (\~12kb), it contained a lot of
15disorganized content and some poorly chosen color schemes.
14While this site was already minimal (~12kb), it contained a lot of disorganized
15content and some poorly chosen color schemes.
1616
17The recent updates attempt to fix these items while focusing on what I
18truly care about here: the content within each page.
17The recent updates attempt to fix these items while focusing on what I truly
18care about here: the content within each page.
1919
2020# Recent Changes
2121
22I\'ve made quite a few changes to the style of this website today, both
23in the CSS and in the HTML.
22I've made quite a few changes to the style of this website today, both in the
23CSS and in the HTML.
2424
25Here are some of the key takeaways from today\'s changes:
25Here are some of the key takeaways from today's changes:
2626
271. Reduce the width of the website from `60em` to
28 `40em`.
292. Remove breadcrumb navigation and replaced with a simple \"Return
30 Home\" link when visiting anything other than the homepage.
313. Remove syntax highlighting from code blocks. CSS now loads from a
32 single file.
334. Move blog posts on the homepage to the top, pushing tertiary content
34 down.
355. Update font-family from `monospace` to
36 `sans-serif` for readability.
271. Reduce the width of the website from `60em` to `40em`.
282. Remove breadcrumb navigation and replaced with a simple "Return Home" link
29 when visiting anything other than the homepage.
303. Remove syntax highlighting from code blocks. CSS now loads from a single
31 file.
324. Move blog posts on the homepage to the top, pushing tertiary content down.
335. Update font-family from `monospace` to `sans-serif` for readability.
3734
3835# Future Focus
3936
4037## Accessibility
4138
42My main focus amidst all the changes this past year was accessibility. I
43tried to improve the accessibility of all pages on this site as well as
44I know how. For example, I added aria labels to identify different
45navigation menus in November.
39My main focus amidst all the changes this past year was accessibility. I tried
40to improve the accessibility of all pages on this site as well as I know how.
41For example, I added aria labels to identify different navigation menus in
42November.
4643
47I want to continue this in 2023 and learn more about the accessibility
48features I can utilize to help those who may need them.
44I want to continue this in 2023 and learn more about the accessibility features
45I can utilize to help those who may need them.
4946
5047## Content First
5148
52Beyond accessibility, I am making a concerted effort to bring the
53content of this site to the forefront and push the tertiary information
54(e.g., About Me, Services, etc.) down below the content.
49Beyond accessibility, I am making a concerted effort to bring the content of
50this site to the forefront and push the tertiary information (e.g., About Me,
51Services, etc.) down below the content.
5552
56Further, I want to review and edit previous blog posts for grammar,
57accuracy, dead links, and more. Where necessary, I may even add a blurb
58at the top of old posts that are no longer accurate or helpful.
53Further, I want to review and edit previous blog posts for grammar, accuracy,
54dead links, and more. Where necessary, I may even add a blurb at the top of old
55posts that are no longer accurate or helpful.
5956
6057## Style
6158
62As always, I will be searching for ways to reduce distractions and bring
63a minimalistic approach to this site. While there are certainly more
64drastic measures I could take, such as making this a [Shinobi
65Website](https://shinobi.bt.ht) or a [No CSS
66Website](https://nocss.club), I prefer to keep some modern features
67here.
59As always, I will be searching for ways to reduce distractions and bring a
60minimalistic approach to this site. While there are certainly more drastic
61measures I could take, such as making this a [Shinobi
62Website](https://shinobi.bt.ht) or a [No CSS Website](https://nocss.club), I
63prefer to keep some modern features here.
6864
69Two ideas have been floating around in my head, but I am not sure how I
70feel about these approaches yet:
65Two ideas have been floating around in my head, but I am not sure how I feel
66about these approaches yet:
7167
721. Going all-in with Emacs org-mode and creating a script to
73 auto-publish all my blog posts from org-mode to plain HTML files and
74 then letting my CSS style it after the fact.
752. Focus on publishing for Gemini or Gopher and then utilize a
76 conversion program to translate the pages to HTML.
681. Going all-in with Emacs org-mode and creating a script to auto-publish all my
69 blog posts from org-mode to plain HTML files and then letting my CSS style it
70 after the fact.
712. Focus on publishing for Gemini or Gopher and then utilize a conversion
72 program to translate the pages to HTML.
7773
7874# Looking Back
7975
80As I sit here and finalize the changes, as well as this post, I am happy
81with the current state of this website. It\'s certainly a long way from
82my first attempts (parallax background images, anyone?) and it\'s good
83to see the progress.
76As I sit here and finalize the changes, as well as this post, I am happy with
77the current state of this website. It's certainly a long way from my first
78attempts (parallax background images, anyone?) and it's good to see the
79progress.
8480
85I can only hope and work hard to ensure that I make more meaningful
86progress by this time next year.
81I can only hope and work hard to ensure that I make more meaningful progress by
82this time next year.
content/blog/2023-01-05-mass-unlike-tumblr-posts.md +32 −39
@@ -7,27 +7,24 @@ draft = false
77
88# The Dilemma
99
10The dilemma I had was pretty simple: I wanted to unlike all the posts I
11have liked on Tumblr so that I could follow a new focus on blogs and
12start fresh. Otherwise, Tumblr will keep recommending content based on
13your previous likes.
10The dilemma I had was pretty simple: I wanted to unlike all the posts I have
11liked on Tumblr so that I could follow a new focus on blogs and start fresh.
12Otherwise, Tumblr will keep recommending content based on your previous likes.
1413
1514# The Solution
1615
17I searched the web for a while and noted that most solutions referenced
18Tumblr setting and dashboard pages that no longer exist. Additionally, I
19did not want to install a third party extension to do this, as some
20suggested.
16I searched the web for a while and noted that most solutions referenced Tumblr
17setting and dashboard pages that no longer exist. Additionally, I did not want
18to install a third party extension to do this, as some suggested.
2119
22Luckily, I used Javascript for a while a few years ago and figured it
23would be easy enough to script a solution, as long as Tumblr had a
24system for the unlike buttons.
20Luckily, I used Javascript for a while a few years ago and figured it would be
21easy enough to script a solution, as long as Tumblr had a system for the unlike
22buttons.
2523
2624## Identifying Unlike Buttons
2725
28Tumblr\'s unlike buttons are structured as you can see in the following
29code block. All unlike buttons have an `aria-label` with a
30value of `Unlike`.
26Tumblr's unlike buttons are structured as you can see in the following code
27block. All unlike buttons have an `aria-label` with a value of `Unlike`.
3128
3229``` html
3330<button class="TRX6J" aria-label="Unlike">
@@ -43,28 +40,26 @@ value of `Unlike`.
4340## Running a Script to Unlike All Likes
4441
4542To run this script, you will need to load the [Likes \|
46Tumblr](https://www.tumblr.com/likes) page while logged in to your
47account.
43Tumblr](https://www.tumblr.com/likes) page while logged in to your account.
4844
49Further, be sure to scroll down to the bottom and force Tumblr to load
50more posts so that this script unlikes more posts at a time.
45Further, be sure to scroll down to the bottom and force Tumblr to load more
46posts so that this script unlikes more posts at a time.
5147
52Once you are logged in and the page is loaded, open the Developer Tools
53and be sure you\'re on the \"Console\" tab. It should look something
54like this (this is in Firefox, Chromium should be similar):
48Once you are logged in and the page is loaded, open the Developer Tools and be
49sure you're on the "Console" tab. It should look something like this (this is
50in Firefox, Chromium should be similar):
5551
5652![Firefox Dev
5753!Tools](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/dev_console.png)
5854
59All you need to do is paste the following snippet into the dev console.
60This code will collect all unlike buttons (`elements`) and
61then click each button to unlike it.
55All you need to do is paste the following snippet into the dev console. This
56code will collect all unlike buttons (`elements`) and then click each button to
57unlike it.
6258
63Optionally, you can comment-out the line
64`elements[i].click();` and uncomment the
65`console.log()` lines to simply print out information without
66performing any actions. This can be useful to debug issues or confirm
67that the code below isn\'t doing anything you don\'t want it to.
59Optionally, you can comment-out the line `elements[i].click();` and uncomment
60the `console.log()` lines to simply print out information without performing any
61actions. This can be useful to debug issues or confirm that the code below
62isn't doing anything you don't want it to.
6863
6964``` javascript
7065const elements = document.querySelectorAll('[aria-label="Unlike"]');
@@ -78,18 +73,16 @@ for (let i=0; i < elements.length; i++) {
7873
7974# Results
8075
81The results were quick for my situation, as it unliked \~200 posts
82within 2-3 seconds. I am not sure how this will perform on larger sets
83of likes (or if Tumblr has a limit to unliking posts).
76The results were quick for my situation, as it unliked ~200 posts within 2-3
77seconds. I am not sure how this will perform on larger sets of likes (or if
78Tumblr has a limit to unliking posts).
8479
85You can see the below screenshot showing that I pasted the snippet into
86the console, pressed Enter, and then the posts are automatically
87unliked.
80You can see the below screenshot showing that I pasted the snippet into the
81console, pressed Enter, and then the posts are automatically unliked.
8882
8983![Script
9084!Results](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/script_results.png)
9185
92Thinking about this further, I would bet that this would be fairly
93simple to package into a browser add-on so that users could install the
94add-on, go to their Likes page, and click a button to run the script.
95Food for thought.
86Thinking about this further, I would bet that this would be fairly simple to
87package into a browser add-on so that users could install the add-on, go to
88their Likes page, and click a button to run the script. Food for thought.
content/blog/2023-01-08-fedora-login-manager.md +12 −12
@@ -5,15 +5,15 @@ description = ""
55draft = false
66+++
77
8# Fedora i3\'s Login Manager
8# Fedora i3's Login Manager
99
10Since I use the i3 spin of Fedora Workstation, I don\'t like to have a
11login manager installed by default. As of the current version of Fedora
12i3, the default login manager is LightDM.
10Since I use the i3 spin of Fedora Workstation, I don't like to have a login
11manager installed by default. As of the current version of Fedora i3, the
12default login manager is LightDM.
1313
14If this is no longer the case, you can search for currently-installed
15packages with the following command and see if you can identify a
16different login manager.
14If this is no longer the case, you can search for currently-installed packages
15with the following command and see if you can identify a different login
16manager.
1717
1818```sh
1919sudo dnf list installed
@@ -29,16 +29,16 @@ sudo dnf remove lightdm
2929
3030# Launching i3 Manually
3131
32In order to launch i3 manually, you need to set up your X session
33properly. To start, create or edit the `~/.xinitrc` file to
34include the following at the bottom.
32In order to launch i3 manually, you need to set up your X session properly. To
33start, create or edit the `~/.xinitrc` file to include the following at the
34bottom.
3535
3636``` config
3737exec i3
3838```
3939
40Now, whenever you log in to the TTY, you can launch your desktop with
41the following command.
40Now, whenever you log in to the TTY, you can launch your desktop with the
41following command.
4242
4343```sh
4444startx
content/blog/2023-01-21-flatpak-symlinks.md +16 −20
@@ -7,45 +7,41 @@ draft = false
77
88# Running Flatpak Apps Should Be Faster
99
10If you\'re like me and use Flatpak for those pesky apps that cannot run
11on your system for one reason or another, you likely get annoyed with
12opening a terminal and manually running the Flatpak app with the lengthy
13`flatpak run ...` command.
10If you're like me and use Flatpak for those pesky apps that cannot run on your
11system for one reason or another, you likely get annoyed with opening a terminal
12and manually running the Flatpak app with the lengthy `flatpak run ...` command.
1413
15In the past, I manually created aliases in my `.zshrc` file
16for certain apps. For example, an alias would look like the example
17below.
14In the past, I manually created aliases in my `.zshrc` file for certain apps.
15For example, an alias would look like the example below.
1816
1917This 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.
2119
2220```sh
2321# ~/.zshrc
2422alias librewolf = "flatpak run io.gitlab.librewolf-community"
2523```
2624
27However, I now use a much faster and better method that integrates with
28the tiling WMs I use and their application launchers -
29`dmenu` and `bemenu`.
25However, I now use a much faster and better method that integrates with the
26tiling WMs I use and their application launchers - `dmenu` and `bemenu`.
3027
3128# Creating Symlinks for Flatpak Apps
3229
33Let\'s use the example of Librewolf below. I can install the application
34like so:
30Let's use the example of Librewolf below. I can install the application like
31so:
3532
3633```sh
3734flatpak install flathub io.gitlab.librewolf-community
3835```
3936
40Once installed, I can create a symlink to link the flatpak app to my new
41symlink in a location commonly included in your PATH. In this case, I
42chose `/usr/bin`. You may need to choose a different location
43if `/usr/bin` isn\'t in your PATH.
37Once installed, I can create a symlink to link the flatpak app to my new symlink
38in a location commonly included in your PATH. In this case, I chose `/usr/bin`.
39You may need to choose a different location if `/usr/bin` isn't in your PATH.
4440
4541```sh
4642ln -s /var/lib/flatpak/exports/bin/io.gitlab.librewolf-community /usr/bin/librewolf
4743```
4844
49Once complete, you should be able to launch the app using the command
50name you chose above in the symlink (`librewolf`) from a
51terminal or from your application launcher!
45Once complete, you should be able to launch the app using the command name you
46chose above in the symlink (`librewolf`) from a terminal or from your
47application launcher!
content/blog/2023-01-23-random-wireguard.md +26 −28
@@ -7,18 +7,18 @@ draft = false
77
88# Mullvad Wireguard
99
10If you\'re using an OS that does not support one of Mullvad\'s apps,
11you\'re likely using the Wireguard configuration files instead.
10If you're using an OS that does not support one of Mullvad's apps, you're
11likely using the Wireguard configuration files instead.
1212
13If not, the first step is to visit Mullvad\'s [Wireguard configuration
14files](https://mullvad.net/en/account/#/wireguard-config) page and
15download a ZIP of the configuration files you want to use.
13If not, the first step is to visit Mullvad's [Wireguard configuration
14files](https://mullvad.net/en/account/#/wireguard-config) page and download a
15ZIP of the configuration files you want to use.
1616
17Personally, I downloaded all configuration files across the world and
18chose my connections using the script below.
17Personally, I downloaded all configuration files across the world and chose my
18connections using the script below.
1919
20Once the files are downloaded, unzip them and move them to your
21preferred location:
20Once the files are downloaded, unzip them and move them to your preferred
21location:
2222
2323```sh
2424cd Downloads
@@ -28,8 +28,8 @@ mkdir ~/mullvad && mv ~/Downloads/*.conf ~/mullvad/
2828
2929### Creating a Script to Connect to a Random Host
3030
31Once you have a folder of Wireguard configuration files from Mullvad,
32you can create a script to randomly connect to any one of the locations.
31Once you have a folder of Wireguard configuration files from Mullvad, you can
32create a script to randomly connect to any one of the locations.
3333
3434Start by creating a shell script - mine is called `vpn.sh`.
3535
@@ -37,10 +37,9 @@ Start by creating a shell script - mine is called `vpn.sh`.
3737nano ~/vpn.sh
3838```
3939
40Within this script, you can paste the following info. Note that I
41specify `us-*` in my script, which means that it will only
42consider US-based VPN locations. You can alter this or simply change it
43`*` to consider all locations.
40Within this script, you can paste the following info. Note that I specify `us-*`
41in my script, which means that it will only consider US-based VPN locations. You
42can alter this or simply change it `*` to consider all locations.
4443
4544```sh
4645#!/bin/sh
@@ -55,8 +54,8 @@ ls /home/$USER/mullvad/us-** |sort -R |tail -n 1 |while read file; do
5554done
5655```
5756
58Once you\'ve modified the script to your liking, add executable
59permissions and run the script:
57Once you've modified the script to your liking, add executable permissions and
58run the script:
6059
6160```sh
6261chmod +x ~/vpn.sh
@@ -76,21 +75,20 @@ Printing new IP info:
7675You are connected to Mullvad (server country-city-wg-num). Your IP address is 12.345.678.99
7776```
7877
79That\'s all there is to it. You can see your new location and IP via the
80`printf` and `curl` commands included in the
81script.
78That's all there is to it. You can see your new location and IP via the
79`printf` and `curl` commands included in the script.
8280
8381You can also go to the [Connection Check ​\|
84Mullvad](https://mullvad.net/en/check/) page to see if you are fully
85connected to Mullvad and if any leaks exist.
82Mullvad](https://mullvad.net/en/check/) page to see if you are fully connected
83to Mullvad and if any leaks exist.
8684
8785![Mullvad Connection
8886Check](https://img.cleberg.net/blog/20230123-random-mullvad-wireguard/mullvad_check.png)
8987
9088# Disconnecting from the Wireguard Connection
9189
92If you forget which connection you\'re using, you can execute the
93following command to see where Wireguard is currently connected:
90If you forget which connection you're using, you can execute the following
91command to see where Wireguard is currently connected:
9492
9593```sh
9694wg show
@@ -99,15 +97,15 @@ wg show
9997This command will show you the Wireguard interfaces and should output a
10098connection like so: `interface: us-lax-wg-104`.
10199
102Once you have this, just disconnect using that files\' full path:
100Once you have this, just disconnect using that files' full path:
103101
104102```sh
105103wg-quick down /home/user/mullvad/us-lax-wg-104.conf
106104```
107105
108I have a TODO item on figuring out how to easily export an environment
109variable that contains the configuration file\'s full name, so that I
110can just execute the following:
106I have a TODO item on figuring out how to easily export an environment variable
107that contains the configuration file's full name, so that I can just execute
108the following:
111109
112110```sh
113111# 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
77
88# Wger: The Self-Hosted Workout Manager
99
10[Wger Workout Manager](https://wger.de) is a fitness tracking tool for
11those who enjoy self-hosting their data. You can also register an
12account on their main website if you\'d prefer to try without
13self-hosting.
10[Wger Workout Manager](https://wger.de) is a fitness tracking tool for those who
11enjoy self-hosting their data. You can also register an account on their main
12website if you'd prefer to try without self-hosting.
1413
1514## Features
1615
17I didn\'t see a full listing of features anywhere, so I compiled this
18list of my own after installing wger:
16I didn't see a full listing of features anywhere, so I compiled this list of my
17own after installing wger:
1918
20191. Dashboard
2120
22 - Dashboard view of Workout Schedule, Nutrition Plan, Weight
23 Graph, & last 5 Weight Logs
21 - Dashboard view of Workout Schedule, Nutrition Plan, Weight Graph, & last
22 5 Weight Logs
2423
25242. Training
2625
27 - Workout Log
28 - Workout Schedule
29 - Calendar (shows weight logs and Bad/Neutral/Good days)
30 - Gallery (shows images you upload)
31 - Workout templates
32 - Public templates
33 - Exercises
26 - Workout Log
27 - Workout Schedule
28 - Calendar (shows weight logs and Bad/Neutral/Good days)
29 - Gallery (shows images you upload)
30 - Workout templates
31 - Public templates
32 - Exercises
3433
35343. Nutrition
3635
37 - Nutrition plans
38 - BMI calculator
39 - Daily calories calculator
40 - Ingredient overview
36 - Nutrition plans
37 - BMI calculator
38 - Daily calories calculator
39 - Ingredient overview
4140
42414. Body Weight
4342
44 - Weight overview
43 - Weight overview
4544
4645## Documentation
4746
4847In order to self-host wger, I opted to use the Docker version of the
4948application. You can read the README within the
50[wger-project/docker](https://github.com/wger-project/docker) project on
51GitHub for information and installation instructions.
49[wger-project/docker](https://github.com/wger-project/docker) project on GitHub
50for information and installation instructions.
5251
5352## Installation
5453
55To start the installation, I created a folder for wger and started
56creating the three necessary files:
54To start the installation, I created a folder for wger and started creating the
55three necessary files:
5756
5857```sh
5958mkdir ~/wger && mkdir ~/wger/config
@@ -62,23 +61,20 @@ touch ~/wger/config/prod.env && \
6261touch ~/wger/config/nginx.conf
6362```
6463
65Once you have the folders and files created, you will need to copy the
66contents of the `docker-compose.yml`, `prod.env`,
67and `nginx.conf` from the GitHub link above.
64Once you have the folders and files created, you will need to copy the contents
65of the `docker-compose.yml`, `prod.env`, and `nginx.conf` from the GitHub link
66above.
6867
6968A few notes to explain the changes I made to the default files:
7069
71- I updated the `ALLOW_REGISTRAION` variable in
72 `prod.env` to `False` after I created an
73 account via my LAN connection, **before\*** I connected this app to
74 a publicly-available domain.
75- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be
76 equal to the public version of this app:
77 `https://wger.example.com`.
78- I updated the port within `docker-compose.yml`, within
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).
70- I updated the `ALLOW_REGISTRAION` variable in `prod.env` to `False` after I
71 created an account via my LAN connection, **before** I connected this app to a
72 publicly-available domain.
73- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be equal to the public
74 version of this app: `https://wger.example.com`.
75- I updated the port within `docker-compose.yml`, within the `nginx` block. The
76 port I updated this to will be reflected in my nginx configuration file on the
77 server (NOT the wger nginx.conf file).
8278
8379## Deploy
8480
@@ -89,17 +85,16 @@ container.
8985docker-compose up -d
9086```
9187
92You can now visit the website on your LAN by going to
93`localhost:YOUR_PORT` or by the server\'s IP, if you\'re not
94on the same machine that is running the container.
88You can now visit the website on your LAN by going to `localhost:YOUR_PORT` or
89by the server's IP, if you're not on the same machine that is running the
90container.
9591
96If you wish to connect this app to a public domain name, you\'ll need to
97point an `A` DNS record from the domain to your server\'s
98public IP. You\'ll then need to create a configuration file for
99whichever web server or reverse proxy you\'re using.
92If you wish to connect this app to a public domain name, you'll need to point
93an `A` DNS record from the domain to your server's public IP. You'll then need
94to create a configuration file for whichever web server or reverse proxy you're
95using.
10096
101Wger\'s README suggests the following reverse proxy configuration for
102Nginx:
97Wger's README suggests the following reverse proxy configuration for Nginx:
10398
10499``` conf
105100upstream wger {
@@ -132,20 +127,19 @@ server {
132127
133128# Thoughts on Wger
134129
135I\'m still playing around with the app itself, but it seems to be a
136solid all-around workout manager, weight log, and food log.
130I'm still playing around with the app itself, but it seems to be a solid
131all-around workout manager, weight log, and food log.
137132
138I like that the weight log graph is fluid and updates quickly. You can
139also import or export data in CSV format if you\'d like to move your
140data elsewhere.
133I like that the weight log graph is fluid and updates quickly. You can also
134import or export data in CSV format if you'd like to move your data elsewhere.
141135
142The workout manager is slightly odd, as it requires you to enter sets
143and reps for each exercise when you enter it into the plan. Then, when
144you add a log entry for performing a workout, you then add what you
145actually performed, in terms of reps and weight.
136The workout manager is slightly odd, as it requires you to enter sets and reps
137for each exercise when you enter it into the plan. Then, when you add a log
138entry for performing a workout, you then add what you actually performed, in
139terms of reps and weight.
146140
147I haven\'t tried the food log yet and I likely will not, at least for a
148while. I have no need for a food log or calorie tracker at the moment.
141I haven't tried the food log yet and I likely will not, at least for a while. I
142have no need for a food log or calorie tracker at the moment.
149143
150144## Screenshot Example
151145
content/blog/2023-02-02-exploring-hare.md +65 −76
@@ -7,87 +7,80 @@ draft = false
77
88# A Quick Note
99
10By no means am I a professional developer, so this post will be rather
11short. I won\'t be going into depth on the specification or anything
12that technical.
10By no means am I a professional developer, so this post will be rather short. I
11won't be going into depth on the specification or anything that technical.
1312
14Instead, I will simply be talking about how I (a relatively basic
15hobbyist programmer) have been playing with Hare and what intrigues me
16about the language.
13Instead, I will simply be talking about how I (a relatively basic hobbyist
14programmer) have been playing with Hare and what intrigues me about the
15language.
1716
1817# Hare
1918
20The [Hare](https://harelang.org) programming language is a
21straightforward language that should look familiar if you\'ve ever
22programmed with C, Rust, or other languages that aim to build software
23at the system-level.
19The [Hare](https://harelang.org) programming language is a straightforward
20language that should look familiar if you've ever programmed with C, Rust, or
21other languages that aim to build software at the system-level.
2422
2523The Hare homepage states the following:
2624
27> Hare is a systems programming language designed to be simple, stable,
28> and robust. Hare uses a static type system, manual memory management,
29> and minimal runtime. It is well-suited to writing operating systems,
30> system tools, compilers, networking software, and other low-level,
31> high performance tasks.
25> Hare is a systems programming language designed to be simple, stable, and
26> robust. Hare uses a static type system, manual memory management, and minimal
27> runtime. It is well-suited to writing operating systems, system tools,
28> compilers, networking software, and other low-level, high performance tasks.
3229
33I have found this all to be true while playing with it for the first
34time today. In the next few sections, I\'m going to walk through my
35installation and first program.
30I have found this all to be true while playing with it for the first time today.
31In the next few sections, I'm going to walk through my installation and first
32program.
3633
3734## Installation
3835
39I\'m currently running Alpine Linux on my Thinkpad, so the installation
40was quite easy as there is a package for Hare in the `apk`
41repositories.
36I'm currently running Alpine Linux on my Thinkpad, so the installation was
37quite easy as there is a package for Hare in the `apk` repositories.
4238
4339```sh
4440doas apk add hare hare-doc
4541```
4642
47However, I was able to install Hare from scratch on Fedora Linux a short
48while ago, which was also very easy to do. If you need further
49instructions and Hare doesn\'t have a package on your system, take a
50look at the [Hare Installation](https://harelang.org/installation/)
51page.
43However, I was able to install Hare from scratch on Fedora Linux a short while
44ago, which was also very easy to do. If you need further instructions and Hare
45doesn't have a package on your system, take a look at the [Hare
46Installation](https://harelang.org/installation/) page.
5247
5348## Creating a Test Project
5449
5550In order to play with the language, I created
56[hare-test](https://git.sr.ht/~cmc/hare-projects) and will be putting
57any of my Hare-related adventures in here.
51[hare-test](https://git.sr.ht/~cmc/hare-projects) and will be putting any of my
52Hare-related adventures in here.
5853
59> **Update:\*** I also created a simple Hare program for creating a file
60> from user input:
54> **Update:** I also created a simple Hare program for creating a file from user
55> input:
6156> [files.ha](https://git.sr.ht/~cmc/hare-projects/tree/main/item/files/files.ha)
6257
63Luckily, Hare doesn\'t require any complex set-up tools or build
64environment. Once you have Hare installed, you simply need to create a
65file ending with `.ha` and you can run a Hare program.
58Luckily, Hare doesn't require any complex set-up tools or build environment.
59Once you have Hare installed, you simply need to create a file ending with `.ha`
60and you can run a Hare program.
6661
67I created a file called `rgb.ha` in order to test out the
68random number generation and passing parameters between functions.
62I created a file called `rgb.ha` in order to test out the random number
63generation and passing parameters between functions.
6964
7065```sh
7166nano rgb.ha
7267```
7368
74Within this file, I was able to easily import a few of the [standard
75library modules](https://harelang.org/tutorials/stdlib/):
76`fmt`, `math::random`, and `datetime`.
69Within this file, I was able to easily import a few of the [standard library
70modules](https://harelang.org/tutorials/stdlib/): `fmt`, `math::random`, and
71`datetime`.
7772
7873With these modules, I created two functions:
7974
801. `main`: This function calls the `generate_rgb`
81 function and then prints out the returned values.
822. `generate_rgb`: This function uses the current Unix epoch
83 time to generate a pseudo-random value and uses this value to create
84 three more random values between 0 and 255. These three numbers
85 represent a color in RGB format.
751. `main`: This function calls the `generate_rgb` function and then prints out
76 the returned values.
772. `generate_rgb`: This function uses the current Unix epoch time to generate a
78 pseudo-random value and uses this value to create three more random values
79 between 0 and 255. These three numbers represent a color in RGB format.
8680
87> **Note**: Some syntax coloring may look odd, as Zola currently
88> doesn\'t have a syntax highlighting theme for Hare. Instead, I\'m
89> using the C theme, which may not be exactly accurate when coloring the
90> code below.
81> **Note**: Some syntax coloring may look odd, as Zola currently doesn't have a
82> syntax highlighting theme for Hare. Instead, I'm using the C theme, which may
83> not be exactly accurate when coloring the code below.
9184
9285```c
9386use datetime;
@@ -120,8 +113,7 @@ fn generate_rgb() []u64 = {
120113
121114## Running a Program
122115
123Once you have a Hare file written and ready to run, you simply need to
124run it:
116Once you have a Hare file written and ready to run, you simply need to run it:
125117
126118```sh
127119hare run file.ha
@@ -136,37 +128,34 @@ hare build -o example file.ha
136128
137129## Initial Thoughts
138130
1391. Documentation Improvements Would Help
1311. Documentation Improvements Would Help
140132
141 While I was able to piece everything together eventually, the
142 biggest downfall right now in Hare\'s documentation. For such a new
143 project, the documentation is in a great spot. However, bare
144 specifications don\'t help as much as a brief examples section
145 would.
133 While I was able to piece everything together eventually, the biggest
134 downfall right now in Hare's documentation. For such a new project, the
135 documentation is in a great spot. However, bare specifications don't help
136 as much as a brief examples section would.
146137
147 For example, it took me a while to figure out what the
148 `u64n` function was looking for. I could tell that it
149 took two parameters and the second was my max value (255), but
150 couldn\'t figure out what the first value should be. Eventually, I
151 inspected the `random.ha` file in the [Hare source
138 For example, it took me a while to figure out what the `u64n` function was
139 looking for. I could tell that it took two parameters and the second was my
140 max value (255), but couldn't figure out what the first value should be.
141 Eventually, I inspected the `random.ha` file in the [Hare source
152142 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
154 `init()` value in the form of `&var`.
143 and found the test suite that helped me discover that it needed an `init()`
144 value in the form of `&var`.
155145
1562. More Basic Modules
1462. More Basic Modules
157147
158 This is another point that comes from Hare being new and awaiting
159 more contributions, but there are some basic functions that I would
160 personally enjoy seeing in Hare, such as one to convert decimal
161 (base 10) values to hexadecimal (base 16).
148 This is another point that comes from Hare being new and awaiting more
149 contributions, but there are some basic functions that I would personally
150 enjoy seeing in Hare, such as one to convert decimal (base 10) values to
151 hexadecimal (base 16).
162152
163 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
165 code.
153 If I'm feeling comfortable with my math, I may work on the list of
154 functions I want and see if any can make it into the Hare source code.
166155
1673. Overall Thoughts
1563. Overall Thoughts
168157
169 Overall, I actually really enjoy Hare. It\'s not as tedious to get a
170 project up and running as Rust, but it\'s also simpler and more
171 user-friendly than learning C. I am going to continue playing with
172 it and see if I can make anything of particular value.
158 Overall, I actually really enjoy Hare. It's not as tedious to get a project
159 up and running as Rust, but it's also simpler and more user-friendly than
160 learning C. I am going to continue playing with it and see if I can make
161 anything of particular value.
content/blog/2023-05-22-burnout.md +25 −25
@@ -7,39 +7,39 @@ draft = false
77
88# RE: Burnout {#re-burnout-1}
99
10I recently read [Drew DeVault\'s post on
11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html)
12around the same time I was pulling out of a burnout rut myself earlier
13this month. Finally, seeing the light at the end of my burnout tunnel
14made me want to write my first post back on this topic.
10I recently read [Drew DeVault's post on
11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html) around the
12same time I was pulling out of a burnout rut myself earlier this month. Finally,
13seeing the light at the end of my burnout tunnel made me want to write my first
14post back on this topic.
1515
1616# Busy Seasons on Busy Seasons
1717
18My career deals with busy seasons, generally driven by client demand.
19This last year, I dealt with a harsh busy season from Aug to Oct 2022 to
20issue a few SOC reports for the period ending 2022-09-30. Immediately
21following that, I had to pivot and found another busy season from Oct to
22Jan for financial statement audits ending on 2022-12-31. Then again,
23supporting other clients from Jan to Mar 2023, followed by my current
24client workload aiming for SOC reports due on 2023-06-30.
18My career deals with busy seasons, generally driven by client demand. This last
19year, I dealt with a harsh busy season from Aug to Oct 2022 to issue a few SOC
20reports for the period ending 2022-09-30. Immediately following that, I had to
21pivot and found another busy season from Oct to Jan for financial statement
22audits ending on 2022-12-31. Then again, supporting other clients from Jan to
23Mar 2023, followed by my current client workload aiming for SOC reports due on
242023-06-30.
2525
26The result? A busy season that has lasted from August 2022 through
27today. I will likely be rushing throughout the next month or two before
28I have a brief break and need to focus on the 2023-09-30 SOC reports
29again. While auditing and consulting always involve a busy season, this
30is the first time I\'ve had one last 9+ months without a break.
26The result? A busy season that has lasted from August 2022 through today. I will
27likely be rushing throughout the next month or two before I have a brief break
28and need to focus on the 2023-09-30 SOC reports again. While auditing and
29consulting always involve a busy season, this is the first time I've had one
30last 9+ months without a break.
3131
32While it\'s been tough, I have a handful of breaks pre-planned
33throughout this next cycle and should be able to moderate the level of
34commitment required for each client.
32While it's been tough, I have a handful of breaks pre-planned throughout this
33next cycle and should be able to moderate the level of commitment required for
34each client.
3535
3636# Refocusing
3737
38Outside of work, I finally have time to work on hobbies such as this
39website, programming, athletics, games, etc.
38Outside of work, I finally have time to work on hobbies such as this website,
39programming, athletics, games, etc.
4040
41You may have noticed my absence if you\'re in the same channels, forums,
42and rooms that I am, but I should finally be active again.
41You may have noticed my absence if you're in the same channels, forums, and
42rooms that I am, but I should finally be active again.
4343
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
4545building 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
77
88# Overview
99
10[GoAccess](https://goaccess.io/) is an open source real-time web log
11analyzer and interactive viewer that runs in a terminal in \*nix systems
12or through your browser.
10[GoAccess](https://goaccess.io/) is an open source real-time web log analyzer
11and interactive viewer that runs in a terminal in *nix systems or through your
12browser.
1313
1414# Installation
1515
16To start, you\'ll need to install GoAccess for your OS. Here\'s an
17example for Debian-based distros:
16To start, you'll need to install GoAccess for your OS. Here's an example for
17Debian-based distros:
1818
1919```sh
2020sudo apt install goaccess
2121```
2222
23Next, find any number of the MaxMind GeoIP database files on GitHub or
24another file hosting website. We\'re going to use P3TERX\'s version in
25this example:
23Next, find any number of the MaxMind GeoIP database files on GitHub or another
24file hosting website. We're going to use P3TERX's version in this example:
2625
2726```sh
2827wget 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!
3231
3332# Usage
3433
35In order to utilize the full capabilities of GoAccess and MMDB, start
36with the command template below and customize as necessary. This will
37export an HTML view of the GoAccess dashboard, showing all relevant
38information related to that site\'s access log. You can also omit the
39`-o output.html` parameter if you prefer to view the data
40within the CLI instead of creating an HTML file.
34In order to utilize the full capabilities of GoAccess and MMDB, start with the
35command template below and customize as necessary. This will export an HTML view
36of the GoAccess dashboard, showing all relevant information related to that
37site's access log. You can also omit the `-o output.html` parameter if you
38prefer to view the data within the CLI instead of creating an HTML file.
4139
42With the addition of the GeoIP Database parameter, section
43`16 - Geo Location` will be added with the various countries
44that are associated with the collected IP addresses.
40With the addition of the GeoIP Database parameter, section `16 - Geo Location`
41will be added with the various countries that are associated with the collected
42IP addresses.
4543
4644```sh
4745zcat /var/log/nginx/example.access.log.*.gz | goaccess \
@@ -60,11 +58,11 @@ See below for an example of the HTML output:
6058![GoAccess
6159HTML](https://img.cleberg.net/blog/20230608-goaccess/goaccess-dashboard.png)
6260
63You can also see the GeoIP card created by the integration of the
64MaxMind database information.
61You can also see the GeoIP card created by the integration of the MaxMind
62database information.
6563
6664![GoAccess
6765GeoIP](https://img.cleberg.net/blog/20230608-goaccess/goaccess-geoip.png)
6866
69That\'s all there is to it! Informational data is provided in an
70organized fashion with minimal effort.
67That's all there is to it! Informational data is provided in an organized
68fashion with minimal effort.
content/blog/2023-06-08-self-hosting-baikal.md +47 −51
@@ -7,27 +7,26 @@ draft = false
77
88# What is Baikal?
99
10[Baikal](https://sabre.io/baikal/) is a lightweight CalDAV + CardDAV
11server that you can self-host on your own machine. While I have tried (&
12failed) to get this CalDAV + CardDAV server running before, it was quite
13easy this time. Not really sure what I did differently this time, but
14I\'m documenting my process here to ensure I don\'t forget.
10[Baikal](https://sabre.io/baikal/) is a lightweight CalDAV + CardDAV server that
11you can self-host on your own machine. While I have tried (& failed) to get this
12CalDAV + CardDAV server running before, it was quite easy this time. Not really
13sure what I did differently this time, but I'm documenting my process here to
14ensure I don't forget.
1515
1616# Installation
1717
18First, create a folder on your server and open a
19`docker-compose.yml` file for editing:
18First, create a folder on your server and open a `docker-compose.yml` file for
19editing:
2020
2121```sh
2222mkdir baikal && cd baikal
2323nano docker-compose.yml
2424```
2525
26Within this file, you\'ll need to paste the information below. You can
27customize the `ports` section to use any port on your server
28to pass through to port 80 in the container. You can also edit the
29`volumes` section to use docker volumes instead of local
30folders.
26Within this file, you'll need to paste the information below. You can customize
27the `ports` section to use any port on your server to pass through to port 80 in
28the container. You can also edit the `volumes` section to use docker volumes
29instead of local folders.
3130
3231``` conf
3332version: "2"
@@ -42,8 +41,8 @@ services:
4241 - ./data:/var/www/baikal/Specific
4342```
4443
45Once finished with editing, save and close the file. Then, launch the
46docker container:
44Once finished with editing, save and close the file. Then, launch the docker
45container:
4746
4847```sh
4948sudo docker-compose up -d
@@ -51,42 +50,40 @@ sudo docker-compose up -d
5150
5251# Intial Setup
5352
54As long as no issues came up when starting the container, you should be
55able to visit the server\'s set-up page at
56`http://<server_ip>:<port>`. The application will ask you to
57create an administrator account and choose the database type for your
58storage. Personally, I opted to use SQLite.
53As long as no issues came up when starting the container, you should be able to
54visit the server's set-up page at `http://<server_ip>:<port>`. The application
55will ask you to create an administrator account and choose the database type for
56your storage. Personally, I opted to use SQLite.
5957
60Make sure the administrator credentials are adequate to protect against
61common attacks.
58Make sure the administrator credentials are adequate to protect against common
59attacks.
6260
6361# Creating Users
6462
65Once you\'ve set up the application, you will be greeted by the
66Dashboard page, which will show the version of the app, status of the
67admin/CalDAV/CardDAV services, and the number of users, calendars,
68events, address books, and contacts.
63Once you've set up the application, you will be greeted by the Dashboard page,
64which will show the version of the app, status of the admin/CalDAV/CardDAV
65services, and the number of users, calendars, events, address books, and
66contacts.
6967
7068![Baikal
7169Dashboard](https://img.cleberg.net/blog/20230608-baikal/baikal-dashboard.png)
7270
73To create a new user, navigate to the `Users and resources`
74page. This process is as simple as entering a username, password, and
75email.
71To create a new user, navigate to the `Users and resources` page. This process
72is as simple as entering a username, password, and email.
7673
77Once a user has been created, you can create any number of calendars and
78address books for user, as well as inspect their information.
74Once a user has been created, you can create any number of calendars and address
75books for user, as well as inspect their information.
7976
8077# Setting Up a Public URL
8178
82Once your application is working locally, you can open access remotely
83via a URL by using a reverse-proxy like Nginx.
79Once your application is working locally, you can open access remotely via a URL
80by using a reverse-proxy like Nginx.
8481
85As a prerequisite, you must own a domain name and set up DNS records to
86point a domain name to the server hosting Baikal.
82As a prerequisite, you must own a domain name and set up DNS records to point a
83domain name to the server hosting Baikal.
8784
88Start by navigating to your web server\'s configuration directory and
89create a new file for this application.
85Start by navigating to your web server's configuration directory and create a
86new file for this application.
9087
9188```sh
9289cd /etc/nginx/sites-available/
@@ -94,7 +91,7 @@ nano dav
9491```
9592
9693Within 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.
9895
9996``` conf
10097server {
@@ -128,33 +125,32 @@ server {
128125}
129126```
130127
131For Nginx on Ubuntu, you\'ll need to symlink the configuration file to
132the `sites-enabled` directory and then restart Nginx.
128For Nginx on Ubuntu, you'll need to symlink the configuration file to the
129`sites-enabled` directory and then restart Nginx.
133130
134131```sh
135132sudo ln -s /etc/nginx/sites-available/dav /etc/nginx/sites-enabled/dav
136133sudo systemctl restart nginx.service
137134```
138135
139At this point, the Baikal server should be available over the internet
140at the URL configured above!
136At this point, the Baikal server should be available over the internet at the
137URL configured above!
141138
142139# Configuring Clients
143140
144Lastly, configuring clients and applications is essential to making sure
145the DAV server is being fully utilized.
141Lastly, configuring clients and applications is essential to making sure the DAV
142server is being fully utilized.
146143
147You can also use the `Users and resources` page to inspect a
148user\'s personal link to their calendars and address books by clicking
149the info (i) button. It will show a URI like
150`/dav.php/calendars/your-user/default/`.
144You can also use the `Users and resources` page to inspect a user's personal
145link to their calendars and address books by clicking the info (i) button. It
146will show a URI like `/dav.php/calendars/your-user/default/`.
151147
152148However, I found that the following URL works for most applications:
153149`/dav.php/principals/your-user/`.
154150
155I used the `principals` URL above for Thunderbird (calendar,
156tasks, and contacts), as well as iOS (calendar, tasks, and contacts) and
157everything works flawlessly so far.
151I used the `principals` URL above for Thunderbird (calendar, tasks, and
152contacts), as well as iOS (calendar, tasks, and contacts) and everything works
153flawlessly so far.
158154
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
160156disruptions in the service or data integrity.
content/blog/2023-06-18-unifi-ip-blocklist.md +40 −48
@@ -7,82 +7,74 @@ draft = false
77
88# Identifying Abusive IPs
99
10If you\'re like me and use Unifi network equipment at the edge of the
11network you manage, you may know that Unifi is only somewhat decent at
12identifying and blocking IPs that represent abusive or threat actors.
10If you're like me and use Unifi network equipment at the edge of the network
11you manage, you may know that Unifi is only somewhat decent at identifying and
12blocking IPs that represent abusive or threat actors.
1313
1414While Unifi has a [threat
1515management](https://help.ui.com/hc/en-us/articles/360006893234-UniFi-Gateway-Threat-Management)
16tool inside their Network application, it can be lacking in
17functionality and identification. For example, I have my UDM Pro set to
18identify and block almost all categories of threats available within the
19Unifi settings. However, I regularly identify abusive actors on my web
20server via the server logs.
16tool inside their Network application, it can be lacking in functionality and
17identification. For example, I have my UDM Pro set to identify and block almost
18all categories of threats available within the Unifi settings. However, I
19regularly identify abusive actors on my web server via the server logs.
2120
22In addition, I have identified IP addresses and subnets directly within
23Unifi\'s logs that the UDM did not block for whatever reason.
21In addition, I have identified IP addresses and subnets directly within Unifi's
22logs that the UDM did not block for whatever reason.
2423
25This guide is meant to be another step in the process to manually block
26abusive IP addresses or subnets that you have identified but are not
27being automatically blocked yet.
24This guide is meant to be another step in the process to manually block abusive
25IP addresses or subnets that you have identified but are not being automatically
26blocked yet.
2827
2928# Create an IP Group Profile
3029
31To start, login to the Unifi machine\'s web GUI and navigate to the
32Network app \> Settings \> Profiles.
30To start, login to the Unifi machine's web GUI and navigate to the Network app
31> Settings > Profiles.
3332
34Within this page, choose the `IP Groups` tab and click
35`Create New`.
33Within this page, choose the `IP Groups` tab and click `Create New`.
3634
3735![Network
3836Profiles](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/unifi_profiles.png)
3937
4038Each IP Group profile can be used as one of three options:
4139
421. Port Group
432. IPv4 Address/Subnet
443. IPv6 Address/Subnet
401. Port Group
412. IPv4 Address/Subnet
423. IPv6 Address/Subnet
4543
46In this example, I\'m creating an IPv4 Address/Subnet group and adding a
47few different IP addresses and a subnet. Once you\'ve added all IP
48addresses and subnets, click the `Apply` button that should
49appear at the bottom.
44In this example, I'm creating an IPv4 Address/Subnet group and adding a few
45different IP addresses and a subnet. Once you've added all IP addresses and
46subnets, click the `Apply` button that should appear at the bottom.
5047
5148![Network Profile
5249IPs](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/abusive_ips.png)
5350
54At this point, the IPv4 Address/Subnet has been created but not yet
55used.
51At this point, the IPv4 Address/Subnet has been created but not yet used.
5652
5753# Drop IP Group Profile via the Unifi Firewall
5854
59To instruct the Unifi machine to block the profile we just created, we
60need to navigate to the Network app \> Settings \> Firewall & Security.
55To instruct the Unifi machine to block the profile we just created, we need to
56navigate to the Network app > Settings > Firewall & Security.
6157
62Within this screen, find the Firewall Rules table and click
63`Create Entry`. This entry should contain the following
64settings:
58Within this screen, find the Firewall Rules table and click `Create Entry`. This
59entry should contain the following settings:
6560
66- Type: `Internet In`
67- Description: `<Your Custom Rule>`
68- Rule Applied: `Before Predefined Rules`
69- Action: `Drop`
70- Source Type: `Port/IP Group`
71- IPv4 Address Group:
72 `<Name of the Group Profile You Created Above>`
61- Type: `Internet In`
62- Description: `<Your Custom Rule>`
63- Rule Applied: `Before Predefined Rules`
64- Action: `Drop`
65- Source Type: `Port/IP Group`
66- IPv4 Address Group: `<Name of the Group Profile You Created Above>`
7367
74Customize the remaining configurations to your liking, and then save and
75enable the firewall rule.
68Customize the remaining configurations to your liking, and then save and enable
69the firewall rule.
7670
7771![Firewall
7872Rule](https://img.cleberg.net/blog/20230618-unifi-ip-blocklist/firewall_drop_rule.png)
7973
80Once enabled, the Unifi machine will be able to drop all incoming
81connections from the defined IP addresses and subnets within the created
82profile.
74Once enabled, the Unifi machine will be able to drop all incoming connections
75from the defined IP addresses and subnets within the created profile.
8376
84> As a personal aside to this topic, I\'m looking for a convenient way
85> to update the firewall rules or profiles remotely (within the LAN)
86> from the web server to accelerate this process. If you have an idea on
87> how to automatically update Unifi IP groups or firewall rules, let me
88> know!
77> As a personal aside to this topic, I'm looking for a convenient way to update
78> the firewall rules or profiles remotely (within the LAN) from the web server
79> to accelerate this process. If you have an idea on how to automatically update
80> Unifi IP groups or firewall rules, let me know!
content/blog/2023-06-20-audit-review-template.md +57 −62
@@ -7,75 +7,70 @@ draft = false
77
88# Overview
99
10This post is a *very* brief overview on the basic process to review
11audit test results, focusing on work done as part of a financial
12statement audit (FSA) or service organization controls (SOC) report.
10This post is a *very* brief overview on the basic process to review audit test
11results, focusing on work done as part of a financial statement audit (FSA) or
12service organization controls (SOC) report.
1313
14While there are numerous different things to review and look for - all
15varying wildly depending on the report, client, and tester - this list
16serves as a solid base foundation for a reviewer.
14While there are numerous different things to review and look for - all varying
15wildly depending on the report, client, and tester - this list serves as a solid
16base foundation for a reviewer.
1717
18I have used this throughout my career as a starting point to my reviews,
19and it has worked wonders for creating a consistent and objective
20template to my reviews. The goal is to keep this base high-level enough
21to be used on a wide variety of engagements, while still ensuring that
22all key areas are covered.
18I have used this throughout my career as a starting point to my reviews, and it
19has worked wonders for creating a consistent and objective template to my
20reviews. The goal is to keep this base high-level enough to be used on a wide
21variety of engagements, while still ensuring that all key areas are covered.
2322
2423# Review Template
2524
261. [ ] Check all documents for spelling and grammar.
272. [ ] Ensure all acronyms are fully explained upon first use.
283. [ ] For all people referenced, use their full names and job titles
29 upon first use.
304. [ ] All supporting documents must cross-reference to the lead sheet
31 and vice-versa.
325. [ ] Verify that the control has been adequately tested:
33 - [ ] **Test of Design**: Did the tester obtain information
34 regarding how the control should perform normally and abnormally
35 (e.g., emergency scenarios)?
36 - [ ] **Test of Operating Effectiveness**: Did the tester inquire,
37 observe, inspect, or re-perform sufficient evidence to support
38 their conclusion over the control? Inquiry alone is not
39 adequate!
406. [ ] For any information used in the control, whether by the control
41 operator or by the tester, did the tester appropriately document the
42 source (system or person), extraction method, parameters, and
43 completeness and accuracy (C&A)?
44 - [ ] For any reports, queries, etc. used in the extraction, did
45 the tester include a copy and notate C&A considerations?
467. [ ] Did the tester document the specific criteria that the control
47 is being tested against?
488. [ ] Did the tester notate in the supporting documents where each
49 criterion was satisfied?
509. [ ] If testing specific policies or procedures, are the documents
51 adequate?
52 - [ ] e.g., a test to validate that a review of policy XYZ occurs
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.
251. [ ] Check all documents for spelling and grammar.
262. [ ] Ensure all acronyms are fully explained upon first use.
273. [ ] For all people referenced, use their full names and job titles upon first
28 use.
294. [ ] All supporting documents must cross-reference to the lead sheet and
30 vice-versa.
315. [ ] Verify that the control has been adequately tested:
32 - [ ] **Test of Design**: Did the tester obtain information regarding how
33 the control should perform normally and abnormally (e.g., emergency
34 scenarios)?
35 - [ ] **Test of Operating Effectiveness**: Did the tester inquire, observe,
36 inspect, or re-perform sufficient evidence to support their conclusion
37 over the control? Inquiry alone is not adequate!
386. [ ] For any information used in the control, whether by the control operator
39 or by the tester, did the tester appropriately document the source (system or
40 person), extraction method, parameters, and completeness and accuracy (C&A)?
41 - [ ] For any reports, queries, etc. used in the extraction, did the tester
42 include a copy and notate C&A considerations?
437. [ ] Did the tester document the specific criteria that the control is being
44 tested against?
458. [ ] Did the tester notate in the supporting documents where each criterion
46 was satisfied?
479. [ ] If testing specific policies or procedures, are the documents adequate?
48 - [ ] e.g., a test to validate that a review of policy XYZ occurs
49 periodically should also evaluate the sufficiency of the policy itself, if
50 meant to cover the risk that such a policy does not exist and is not
51 reviewed.
565210. [ ] Does the test cover the appropriate period under review?
57 - [ ] If the test is meant to cover only a portion of the audit
58 period, do other controls exist to mitigate the risks that exist
59 for the remainder of the period?
53 - [ ] If the test is meant to cover only a portion of the audit period, do
54 other controls exist to mitigate the risks that exist for the remainder of
55 the period?
605611. [ ] For any computer-aided audit tools (CAATs) or other automation
6157 techniques used in the test, is the use of such tools explained and
6258 appropriately documented?
6312. [ ] If prior-period documentation exists, are there any missing
64 pieces of evidence that would further enhance the quality of the
5912. [ ] If prior-period documentation exists, are there any missing pieces of
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
6567 test?
6613. [ ] Was any information discovered during the walkthrough or inquiry
67 phase that was not incorporated into the test?
6814. [ ] Are there new rules or expectations from your company\'s
69 internal guidance or your regulatory bodies that would affect the
70 audit approach for this control?
7115. [ ] Was an exception, finding, or deficiency identified as a result
72 of this test?
73 - [ ] Was the control deficient in design, operation, or both?
74 - [ ] What was the root cause of the finding?
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?
68 - [ ] Was the control deficient in design, operation, or both?
69 - [ ] What was the root cause of the finding?
70 - [ ] Does the finding indicate other findings or potential fraud?
71 - [ ] What's the severity and scope of the finding?
72 - [ ] Do other controls exist as a form of compensation against the
73 finding's severity, and do they mitigate the risk within the control
74 objective?
75 - [ ] Does the finding exist at the end of the period, or was it resolved
76 within the audit period?
content/blog/2023-06-23-byobu.md +13 −14
@@ -5,27 +5,26 @@ description = ""
55draft = false
66+++
77
8# Byobu {#byobu-1}
8# Byobu
99
10[byobu](https://www.byobu.org) is a command-line tool that allows you to
11use numerous screens within a single terminal emulator instance. More
12specifically, it\'s a text based window manager, using either
13`screen` or `tmux`.
10[byobu](https://www.byobu.org) is a command-line tool that allows you to use
11numerous screens within a single terminal emulator instance. More specifically,
12it's a text based window manager, using either `screen` or `tmux`.
1413
15This post is mostly just a self-reference as I explore byobu, so I may
16come back later and update this post with more content.
14This post is mostly just a self-reference as I explore byobu, so I may come back
15later and update this post with more content.
1716
1817## Screenshot
1918
20Take a look below at my current multi-window set-up in byobu while I
21write this blog post:
19Take a look below at my current multi-window set-up in byobu while I write this
20blog post:
2221
2322![byobu](https://img.cleberg.net/blog/20230623-byobu/byobu.png)
2423
2524### Keybindings
2625
27You can open the help menu with either of the following commands; they
28will both open the same manpage:
26You can open the help menu with either of the following commands; they will both
27open the same manpage:
2928
3029```sh
3130byobu --help
@@ -33,9 +32,9 @@ byobu --help
3332man byobu
3433```
3534
36While the manpage contains a ton of information about the functionality
37of byobu (such as status notifications, sessions, and windows), the
38first location to explore should be the keybindings section.
35While the manpage contains a ton of information about the functionality of byobu
36(such as status notifications, sessions, and windows), the first location to
37explore should be the keybindings section.
3938
4039The keybindings are configured as follows:
4140
content/blog/2023-06-23-self-hosting-convos.md +43 −51
@@ -7,36 +7,32 @@ draft = false
77
88# Convos
99
10[Convos](https://convos.chat/) is an always-online web client for IRC.
11It has a few features that made it attractive to me as a self-hosted
12option:
13
14- Extremely simple Docker Compose installation method.
15- Runs in the background and monitors chats even while you\'re not
16 logged in.
17- Neatly organized sidebar for conversation and client settings.
18- Ability to connect to different hosts and create profiles for hosts.
19- By default, registration is closed to the public. You can enable
20 public registration on the Settings page or generate invitation
21 links on the Users page.
22- Customization of the client theme, organization name and URL, admin
23 email, and video service.
10[Convos](https://convos.chat/) is an always-online web client for IRC. It has a
11few features that made it attractive to me as a self-hosted option:
12
13- Extremely simple Docker Compose installation method.
14- Runs in the background and monitors chats even while you're not logged in.
15- Neatly organized sidebar for conversation and client settings.
16- Ability to connect to different hosts and create profiles for hosts.
17- By default, registration is closed to the public. You can enable public
18 registration on the Settings page or generate invitation links on the Users
19 page.
20- Customization of the client theme, organization name and URL, admin email, and
21 video service.
2422
2523# Docker Installation
2624
27To install Convos, simply create a directory and a
28`docker-compose.yml` file:
25To install Convos, simply create a directory and a `docker-compose.yml` file:
2926
3027```sh
3128mkdir ~/convos && cd ~/convos
3229nano docker-compose.yml
3330```
3431
35With the `docker-compose.yml` file open, paste the
36configuration below into the file. You can customize the host port to be
37something unique, such as `21897:3000`. You can also change
38the `data` folder to be a docker volume instead, if you
39prefer.
32With the `docker-compose.yml` file open, paste the configuration below into the
33file. You can customize the host port to be something unique, such as
34`21897:3000`. You can also change the `data` folder to be a docker volume
35instead, if you prefer.
4036
4137``` config
4238version: '3'
@@ -53,29 +49,27 @@ services:
5349 restart: always
5450```
5551
56Save the `docker-compose.yml` file and bring the container
57up:
52Save the `docker-compose.yml` file and bring the container up:
5853
5954```sh
6055sudo docker-compose up -d
6156```
6257
63At this point, Convos is available at `<server_ip>:3000` but
64not available to the public.
58At this point, Convos is available at `<server_ip>:3000` but not available to
59the public.
6560
6661# Nginx Reverse Proxy
6762
68If you\'re using Nginx, you can create a configuration file for the
69convos application. Start by opening the file:
63If you're using Nginx, you can create a configuration file for the convos
64application. Start by opening the file:
7065
7166```sh
7267nano /etc/nginx/sites-available/convos
7368```
7469
75Within the nginx configuration file, paste the following content and be
76sure to update `convos.example.com` to match your domain and
77`127.0.0.1:3000` to match the port you opened in the
78`docker-compose.yml` file.
70Within the nginx configuration file, paste the following content and be sure to
71update `convos.example.com` to match your domain and `127.0.0.1:3000` to match
72the port you opened in the `docker-compose.yml` file.
7973
8074``` config
8175# Host and port where convos is running
@@ -117,8 +111,8 @@ server {
117111}
118112```
119113
120Once the file is saved, link it to the `sites-enabled`
121directory and restart Nginx.
114Once the file is saved, link it to the `sites-enabled` directory and restart
115Nginx.
122116
123117```sh
124118sudo ln -s /etc/nginx/sites-available/convos /etc/nginx/sites-enabled/convos
@@ -127,43 +121,41 @@ sudo systemctl restart nginx.service
127121
128122# Screenshots
129123
130See the screenshots below for an example of the Convos homepage and an
131excerpt of the chat screen.
124See the screenshots below for an example of the Convos homepage and an excerpt
125of the chat screen.
132126
133There are numerous themes to choose from; the theme shown in the images
134below is Dracula.
127There are numerous themes to choose from; the theme shown in the images below is
128Dracula.
135129
136![Convos
137Home](https://img.cleberg.net/blog/20230623-convos/convos_home.png)
130![Convos Home](https://img.cleberg.net/blog/20230623-convos/convos_home.png)
138131
139![Convos
140Chat](https://img.cleberg.net/blog/20230623-convos/convos_chat.png)
132![Convos Chat](https://img.cleberg.net/blog/20230623-convos/convos_chat.png)
141133
142134# Registering a Nickname
143135
144Hop into the server channel so that you can message NickServ. In the
145case of Convos, the default sever is libera.chat. Simply click the
146`libera` conversation at the top of the sidebar to open it.
147Once the chat is open, you can claim a nickname by typing:
136Hop into the server channel so that you can message NickServ. In the case of
137Convos, the default sever is libera.chat. Simply click the `libera` conversation
138at the top of the sidebar to open it. Once the chat is open, you can claim a
139nickname by typing:
148140
149141``` txt
150142/nick <nick>
151143```
152144
153If the nickname is available, and you\'d like to register the nickname
154to yourself, you\'ll need to type another command:
145If the nickname is available, and you'd like to register the nickname to
146yourself, you'll need to type another command:
155147
156148``` txt
157149/msg NickServ REGISTER
158150<password> <email>
159151```
160152
161On libera.chat, the server will send a confirmation email with a command
162that you must message in IRC to verify registration of the nickname:
153On libera.chat, the server will send a confirmation email with a command that
154you must message in IRC to verify registration of the nickname:
163155
164156``` txt
165157/msg NickServ VERIFY REGISTER <nick> <verification_code>
166158```
167159
168Once entered, the server should confirm registration of the nickname to
169the supplied email with the password specified.
160Once entered, the server should confirm registration of the nickname to the
161supplied email with the password specified.
content/blog/2023-06-28-backblaze-b2.md +66 −74
@@ -7,82 +7,77 @@ draft = false
77
88# Overview
99
10Backblaze [B2 Cloud
11Storage](https://www.backblaze.com/b2/cloud-storage.html) is an
12inexpensive and reliable on-demand cloud storage and backup solution.
10Backblaze [B2 Cloud Storage](https://www.backblaze.com/b2/cloud-storage.html) is
11an inexpensive and reliable on-demand cloud storage and backup solution.
1312
14The service starts at \$5/TB/month (\$0.005/GB/month) with a download
15rate of \$0.01/GB/month.
13The service starts at $5/TB/month ($0.005/GB/month) with a download rate of
14$0.01/GB/month.
1615
1716However, there are free tiers:
1817
19- The first 10 GB of storage is free.
20- The first 1 GB of data downloaded each day is free.
21- Class A transactions are free.
22- The first 2500 Class B transactions each day are free.
23- The first 2500 Class C transactions each day are free.
18- The first 10 GB of storage is free.
19- The first 1 GB of data downloaded each day is free.
20- Class A transactions are free.
21- The first 2500 Class B transactions each day are free.
22- The first 2500 Class C transactions each day are free.
2423
25You can see which API calls fall into categories A, B, or C here:
26[Pricing Organized by API
24You can see which API calls fall into categories A, B, or C here: [Pricing
25Organized by API
2726Calls](https://www.backblaze.com/b2/b2-transactions-price.html).
2827
29For someone like me, who wants an offsite backup of their server\'s
30`/home/` directory and various other server configs that fall
31under 10 GB total, Backblaze is a great solution from a financial
32perspective.
28For someone like me, who wants an offsite backup of their server's `/home/`
29directory and various other server configs that fall under 10 GB total,
30Backblaze is a great solution from a financial perspective.
3331
3432# Create An Account
3533
36To start with Backblaze, you\'ll need to [create a free
37account](https://www.backblaze.com/b2/sign-up.html) - no payment method
38is required to sign up.
34To start with Backblaze, you'll need to [create a free
35account](https://www.backblaze.com/b2/sign-up.html) - no payment method is
36required to sign up.
3937
40Once you have an account, you can test out the service with their web
41GUI, their mobile app, or their CLI tool. I\'m going to use the CLI tool
42below to test a file upload and then sync an entire directory to my
43Backblaze bucket.
38Once you have an account, you can test out the service with their web GUI, their
39mobile app, or their CLI tool. I'm going to use the CLI tool below to test a
40file upload and then sync an entire directory to my Backblaze bucket.
4441
4542# Create a Bucket
4643
47Before you can start uploading, you need to create a bucket. If you\'re
48familiar with other object storage services, this will feel familiar. If
49not, it\'s pretty simple to create one.
44Before you can start uploading, you need to create a bucket. If you're familiar
45with other object storage services, this will feel familiar. If not, it's
46pretty simple to create one.
5047
5148As their webpage says:
5249
53> A bucket is a container that holds files that are uploaded into B2
54> Cloud Storage. The bucket name must be globally unique and must have a
55> minimum of 6 characters. A limit of 100 buckets may be created per
56> account. An unlimited number of files may be uploaded into a bucket.
50> A bucket is a container that holds files that are uploaded into B2 Cloud
51> Storage. The bucket name must be globally unique and must have a minimum of 6
52> characters. A limit of 100 buckets may be created per account. An unlimited
53> number of files may be uploaded into a bucket.
5754
58Once you click the `Create a Bucket` button on their webpage
59or mobile app, you need to provide the following:
55Once you click the `Create a Bucket` button on their webpage or mobile app, you
56need to provide the following:
6057
61- Bucket Unique Name
62- Files in Bucket are: `Private` or `Public`
63- Default Encryption: `Disable` or `Enable`
64- Object Lock: `Disable` or `Enable`
58- Bucket Unique Name
59- Files in Bucket are: `Private` or `Public`
60- Default Encryption: `Disable` or `Enable`
61- Object Lock: `Disable` or `Enable`
6562
66For my bucket, I created a private bucket with encryption enabled and
67object lock disabled.
63For my bucket, I created a private bucket with encryption enabled and object
64lock disabled.
6865
69Once your bucket is created, you can test the upload/download feature on
70their web GUI or mobile app! At this point, you have a fully functional
71bucket and account.
66Once your bucket is created, you can test the upload/download feature on their
67web GUI or mobile app! At this point, you have a fully functional bucket and
68account.
7269
7370# Linux CLI Tool
7471
7572## Installation
7673
77To install the `b2` CLI tool, you\'ll need to download it
78from the [CLI
79Tools](https://www.backblaze.com/docs/cloud-storage-command-line-tools)
80page. I recommend copying the URL from the link that says
81`Linux` and using wget to download it, as shown below.
74To install the `b2` CLI tool, you'll need to download it from the [CLI
75Tools](https://www.backblaze.com/docs/cloud-storage-command-line-tools) page. I
76recommend copying the URL from the link that says `Linux` and using wget to
77download it, as shown below.
8278
83Once downloaded, make the file executable and move it to a location on
84your `$PATH`, so that you can execute that command from
85anywhere on the machine.
79Once downloaded, make the file executable and move it to a location on your
80`$PATH`, so that you can execute that command from anywhere on the machine.
8681
8782```sh
8883wget <b2_cli_url>
@@ -93,12 +88,10 @@ mv b2_linux /usr/bin/b2
9388## Log In
9489
9590The first step after installation is to log in. To do this, execute the
96following command and provide your `<applicationKeyId>` and
97`<applicationKey>`.
91following command and provide your `<applicationKeyId>` and `<applicationKey>`.
9892
99If you don\'t want to provide these values in the command itself, you
100can simply execute the base command and it will request them in an
101interactive prompt.
93If you don't want to provide these values in the command itself, you can simply
94execute the base command and it will request them in an interactive prompt.
10295
10396```sh
10497# if you want to provide the keys directly:
@@ -110,9 +103,9 @@ b2 authorize-account
110103
111104## Upload a Test File
112105
113In order to test the functionality of the CLI tool, I\'ll start by
114uploading a single test file to the bucket I created above. We can do
115this with the `upload_file` function.
106In order to test the functionality of the CLI tool, I'll start by uploading a
107single test file to the bucket I created above. We can do this with the
108`upload_file` function.
116109
117110The command is issued as follows:
118111
@@ -126,8 +119,8 @@ In my situation, I executed the following command with my username.
126119b2 upload_file my_unique_bucket /home/<user>/test.md test.md
127120```
128121
129To confirm that the file was uploaded successfully, list the files in
130your bucket:
122To confirm that the file was uploaded successfully, list the files in your
123bucket:
131124
132125```sh
133126b2 ls <bucket_name>
@@ -139,9 +132,9 @@ test.md
139132
140133## Sync a Directory
141134
142If you have numerous files, you can use the `sync` function
143to perform functionality similar to `rsync`, where you can
144check what\'s in your bucket and sync anything that is new or modified.
135If you have numerous files, you can use the `sync` function to perform
136functionality similar to `rsync`, where you can check what's in your bucket and
137sync anything that is new or modified.
145138
146139The command is issued as follows:
147140
@@ -149,8 +142,8 @@ The command is issued as follows:
149142b2 sync <source file location> <B2 bucket destination>
150143```
151144
152In my case, I can sync my user\'s entire home directory to my bucket
153without specifying any of the files directly:
145In my case, I can sync my user's entire home directory to my bucket without
146specifying any of the files directly:
154147
155148```sh
156149b2 sync /home/<user>/ "b2://<bucketName>/home/<user>"
@@ -160,22 +153,21 @@ b2 sync /home/<user>/ "b2://<bucketName>/home/<user>"
160153
161154## Timing of Updates to the Web GUI
162155
163When performing actions over a bucket, there is a slight delay in the
164web GUI when inspecting a bucket or its file. Note that simple actions
165such as uploading or deleting files may have a delay of a few minutes up
166to 24 hours. In my experience (\<10 GB and \~20,000 files), any actions
167took only a few minutes to update across clients.
156When performing actions over a bucket, there is a slight delay in the web GUI
157when inspecting a bucket or its file. Note that simple actions such as uploading
158or deleting files may have a delay of a few minutes up to 24 hours. In my
159experience (\<10 GB and ~20,000 files), any actions took only a few minutes to
160update across clients.
168161
169162## Symlinks
170163
171164Note that symlinks are resolved by b2, so if you have a link from
172`/home/<user>/nas-storage` that symlinks out to a
173`/mnt/nas-storage` folder that has 10TB of data,
174`b2` will resolve that link and start uploading all 10TB of
165`/home/<user>/nas-storage` that symlinks out to a `/mnt/nas-storage` folder that
166has 10TB of data, `b2` will resolve that link and start uploading all 10TB of
175167data linked within the folder.
176168
177If you\'re not sure if you have any symlinks, a symlink will look like
178this (note the `->` symbol):
169If you're not sure if you have any symlinks, a symlink will look like this
170(note the `->` symbol):
179171
180172```sh
181173> ls -lha
content/blog/2023-06-30-self-hosting-voyager.md +24 −28
@@ -7,12 +7,12 @@ draft = false
77
88# Installation Guide
99
10[Voyager](https://github.com/aeharding/voyager) is a mobile-first Lemmy
11web client, based on iOS design standards. It follows very closely to
12Apollo\'s design.
10[Voyager](https://github.com/aeharding/voyager) is a mobile-first Lemmy web
11client, based on iOS design standards. It follows very closely to Apollo's
12design.
1313
14This post is a guide showing how I was able to build and launch my own
15instance of Voyager via Docker Compose.
14This post is a guide showing how I was able to build and launch my own instance
15of Voyager via Docker Compose.
1616
1717## Clone the Repository
1818
@@ -25,26 +25,24 @@ cd voyager
2525
2626## Build the Image
2727
28With this repository, you can build the image yourself without any
29further configuration. When complete, it\'ll give you the image ID for
30you to run.
28With this repository, you can build the image yourself without any further
29configuration. When complete, it'll give you the image ID for you to run.
3130
3231```sh
3332sudo docker build .
3433# Successfully built 5f00723cb5be
3534```
3635
37With the image ID above, you can run the container and pass the
38requested port `5314` through or use a custom port, if you
39wish.
36With the image ID above, you can run the container and pass the requested port
37`5314` through or use a custom port, if you wish.
4038
41You can also set the `CUSTOM_LEMMY_SERVERS` environment
42variable if you want to add to the default suggested login servers. This
43must be set with a comma separated list of suggested servers. The first
44instance in the list will be the default view for logged-out users.
39You can also set the `CUSTOM_LEMMY_SERVERS` environment variable if you want to
40add to the default suggested login servers. This must be set with a comma
41separated list of suggested servers. The first instance in the list will be the
42default view for logged-out users.
4543
46I will be using a `docker-compose.yml` file to run this
47container, instead of a `docker run` command.
44I will be using a `docker-compose.yml` file to run this container, instead of a
45`docker run` command.
4846
4947```sh
5048nano docker-compose.yml
@@ -67,17 +65,16 @@ sudo docker-compose up -d
6765```
6866
6967The web app will now be available at the following address:
70`<machine_ip>:<custom_port>`. If you are running it on your
71local device, try `localhost:<custom_port>`.
68`<machine_ip>:<custom_port>`. If you are running it on your local device, try
69`localhost:<custom_port>`.
7270
7371## Reverse Proxy
7472
75If you want to visit this app via an external URL or domain name,
76you\'ll need to set up a reverse proxy. The example below uses Nginx as
77a reverse proxy.
73If you want to visit this app via an external URL or domain name, you'll need
74to set up a reverse proxy. The example below uses Nginx as a reverse proxy.
7875
79Simply create the configuration file, paste the contents below, save the
80file, symlink the file, and restart Nginx.
76Simply create the configuration file, paste the contents below, save the file,
77symlink the file, and restart Nginx.
8178
8279```sh
8380sudo 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
120117sudo systemctl restart nginx.service
121118```
122119
123The site will now be available at the `server_name` you
124specified above!
120The site will now be available at the `server_name` you specified above!
125121
126You can visit my instance at
127[voyager.cleberg.net](https://voyager.cleberg.net) for an example.
122You can visit my instance at [voyager.cleberg.net](https://voyager.cleberg.net)
123for an example.
content/blog/2023-07-12-wireguard-lan.md +29 −33
@@ -7,13 +7,13 @@ draft = false
77
88# Download Configuration Files from Mullvad
99
10To begin, you\'ll need [Wireguard configuration files from
11Mullvad](https://mullvad.net/account/wireguard-config). You can choose
12any of the options as you download them. For example, I enabled the kill
13switch, selected all countries, and selected a few content filters.
10To begin, you'll need [Wireguard configuration files from
11Mullvad](https://mullvad.net/account/wireguard-config). You can choose any of
12the options as you download them. For example, I enabled the kill switch,
13selected all countries, and selected a few content filters.
1414
15Once downloaded, unzip the files and move them to the Wireguard folder
16on your system.
15Once downloaded, unzip the files and move them to the Wireguard folder on your
16system.
1717
1818```sh
1919cd ~/Downloads
@@ -40,41 +40,38 @@ AllowedIPs = <redacted>
4040Endpoint = <redacted>
4141```
4242
43> Note: If you didn\'t select the kill switch option, you won\'t see the
44> `PostUp` and `PreDown` lines. In this case,
45> you\'ll need to modify the script below to simply append those lines
46> to the `[Interface]` block.
43> Note: If you didn't select the kill switch option, you won't see the
44> `PostUp` and `PreDown` lines. In this case, you'll need to modify the script
45> below to simply append those lines to the `[Interface]` block.
4746
4847# Editing the Configuration Files
4948
50Once you have the files, you\'ll need to edit them and replace the
51`PostUp` and `PreDown` lines to enable LAN access.
49Once you have the files, you'll need to edit them and replace the `PostUp` and
50`PreDown` lines to enable LAN access.
5251
53I recommend that you do this process as root, since you\'ll need to be
54able to access files in `/etc/wireguard`, which are generally
55owned by root. You can also try using `sudo` or
56`doas`, but I didn\'t test that scenario so you may need to
57adjust, as necessary.
52I recommend that you do this process as root, since you'll need to be able to
53access files in `/etc/wireguard`, which are generally owned by root. You can
54also try using `sudo` or `doas`, but I didn't test that scenario so you may
55need to adjust, as necessary.
5856
5957```sh
6058su
6159```
6260
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
6462configuration files.
6563
6664```sh
6765nano replace.py
6866```
6967
70Within the Python file, copy and paste the logic below. This script will
71open a directory, loop through every configuration file within the
72directory, and replace the `PostUp` and `PreDown`
73lines with the new LAN-enabled iptables commands.
68Within the Python file, copy and paste the logic below. This script will open a
69directory, loop through every configuration file within the directory, and
70replace the `PostUp` and `PreDown` lines with the new LAN-enabled iptables
71commands.
7472
75> Note: If your LAN is on a subnet other than
76> `192.168.1.0/24`, you\'ll need to update the Python script
77> below appropriately.
73> Note: If your LAN is on a subnet other than `192.168.1.0/24`, you'll need to
74> update the Python script below appropriately.
7875
7976``` python
8077import os
@@ -97,15 +94,15 @@ for file in os.listdir(dir):
9794print("--- done ---")
9895```
9996
100Once you\'re done, save and close the file. You can now run the Python
101script and watch as each file is updated.
97Once you're done, save and close the file. You can now run the Python script
98and watch as each file is updated.
10299
103100```sh
104101python3 replace.py
105102```
106103
107To confirm it worked, you can `cat` one of the configuration
108files to inspect the new logic and connect to one to test it out.
104To confirm it worked, you can `cat` one of the configuration files to inspect
105the new logic and connect to one to test it out.
109106
110107```sh
111108cat /etc/wireguard/us-chi-wg-001.conf
@@ -128,16 +125,15 @@ AllowedIPs = <redacted>
128125Endpoint = <redacted>
129126```
130127
131If you connect to a Wireguard interface, such as
132`us-chi-wg-001`, you can test your SSH functionality and see
133that it works even while on the VPN.
128If you connect to a Wireguard interface, such as `us-chi-wg-001`, you can test
129your SSH functionality and see that it works even while on the VPN.
134130
135131```sh
136132wg-quick up us-chi-wg-001
137133ssh user@lan-host
138134```
139135
140To confirm your VPN connection, you can curl Mullvad\'s connection API:
136To confirm your VPN connection, you can curl Mullvad's connection API:
141137
142138```sh
143139curl https://am.i.mullvad.net/connected
content/blog/2023-07-19-plex-transcoder-errors.md +17 −21
@@ -7,9 +7,8 @@ draft = false
77
88# Plex Transcoder Error
99
10Occasionally, you may see an error in your Plex client that references a
11failure with the transcoder conversion process. The specific error
12wording is:
10Occasionally, you may see an error in your Plex client that references a failure
11with the transcoder conversion process. The specific error wording is:
1312
1413``` txt
1514Conversion failed. The transcoder failed to start up.
@@ -17,14 +16,13 @@ Conversion failed. The transcoder failed to start up.
1716
1817# Debugging the Cause
1918
20In order to get a better look at what is causing the error, I\'m going
21to observe the Plex console while the error occurs. To do this, open the
22Plex web client, go to `Settings` \> `Manage` \>
23`Console`. Now, try to play the title again and watch to see
24which errors occur.
19In order to get a better look at what is causing the error, I'm going to
20observe the Plex console while the error occurs. To do this, open the Plex web
21client, go to `Settings` > `Manage` > `Console`. Now, try to play the title
22again and watch to see which errors occur.
2523
26In my case, you can see the errors below are related to a subtitle file
27(`.srt`) causing the transcoder to crash.
24In my case, you can see the errors below are related to a subtitle file (`.srt`)
25causing the transcoder to crash.
2826
2927``` txt
3028Jul 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)
3634
3735# Solving the Error
3836
39In my case, I simply removed the subtitle file because it was not
40critical to keep. You may also avoid this by turning off subtitles if
41you don\'t want to delete the file.
37In my case, I simply removed the subtitle file because it was not critical to
38keep. You may also avoid this by turning off subtitles if you don't want to
39delete the file.
4240
4341```sh
4442rm -rf "/movies/Movie Title (2021)/Movie Title (2021).srt"
4543```
4644
47Once the subtitle is removed from the directory or subtitles are turned
48off, try to play the title again. At this point, it should play without
49error. If not, reopen or refresh your Plex client and the Plex server:
45Once the subtitle is removed from the directory or subtitles are turned off, try
46to play the title again. At this point, it should play without error. If not,
47reopen or refresh your Plex client and the Plex server:
5048
5149```sh
5250sudo systemctl restart plexmediaserver.service
@@ -56,10 +54,8 @@ sudo systemctl restart plexmediaserver.service
5654
5755Looking at [a related Plex forum
5856post](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.
60However, Plex does not seem to have a resolution that fixes these
61errors.
57it seems that `.srt` subtitles are the core issue here. However, Plex does not
58seem to have a resolution that fixes these errors.
6259
6360Unfortunately, I would suggest converting subtitle formats, burning the
64subtitles into the title, or simply removing subtitles when they cause
65crashes.
61subtitles into the title, or simply removing subtitles when they cause crashes.
content/blog/2023-08-18-agile-auditing.md +101 −110
@@ -8,152 +8,143 @@ draft = false
88# What is Agile Auditing?
99
1010[Agile](https://en.wikipedia.org/wiki/Agile_software_development), the
11collaborative philosophy behind many software development methods, has
12been picking up steam as a beneficial tool to use in the external and
13internal auditing world.
11collaborative philosophy behind many software development methods, has been
12picking up steam as a beneficial tool to use in the external and internal
13auditing world.
1414
15This blog post will walk through commonly used terms within Agile,
16Scrum, and Kanban in order to translate these terms and roles into
17audit-specific terms.
15This blog post will walk through commonly used terms within Agile, Scrum, and
16Kanban in order to translate these terms and roles into audit-specific terms.
1817
19Whether your team is in charge of a financial statement audit, an
20attestation (SOC 1, SOC 2, etc.), or a unique internal audit, the terms
21used throughout this post should still apply.
18Whether your team is in charge of a financial statement audit, an attestation
19(SOC 1, SOC 2, etc.), or a unique internal audit, the terms used throughout this
20post should still apply.
2221
2322# Agile
2423
25To start, I\'ll take a look at Agile.
24To start, I'll take a look at Agile.
2625
27> The Agile methodology is a project management approach that involves
28> breaking the project into phases and emphasizes continuous
29> collaboration and improvement. Teams follow a cycle of planning,
30> executing, and evaluating.
26> The Agile methodology is a project management approach that involves breaking
27> the project into phases and emphasizes continuous collaboration and
28> improvement. Teams follow a cycle of planning, executing, and evaluating.
3129
32While this approach may seem familiar to what audit teams have
33historically done, an audit team must make distinct changes in their
34mentality and how they approach and manage a project.
30While this approach may seem familiar to what audit teams have historically
31done, an audit team must make distinct changes in their mentality and how they
32approach and manage a project.
3533
3634## Agile Values
3735
38The Agile Manifesto, written in 2001 at a summit in Utah, contain a set
39of four main values that comprise the Agile approach:
36The Agile Manifesto, written in 2001 at a summit in Utah, contain a set of four
37main values that comprise the Agile approach:
4038
411. Individuals and interactions over processes and tools.
422. Working software over comprehensive documentation.
433. Customer collaboration over contract negotiation.
444. Responding to change over following a plan.
391. Individuals and interactions over processes and tools.
402. Working software over comprehensive documentation.
413. Customer collaboration over contract negotiation.
424. Responding to change over following a plan.
4543
4644Beyond the four values, [twelve
47principles](https://agilemanifesto.org/principles.html) were also
48written as part of the summit.
45principles](https://agilemanifesto.org/principles.html) were also written as
46part of the summit.
4947
50In order to relate these values to an audit or attestation engagement,
51we need to shift the focus from software development to the main goal of
52an engagement: completing sufficient audit testing to address to
53relevant risks over the processes and controls at hand.
48In order to relate these values to an audit or attestation engagement, we need
49to shift the focus from software development to the main goal of an engagement:
50completing sufficient audit testing to address to relevant risks over the
51processes and controls at hand.
5452
5553Audit Examples:
5654
57- Engagement teams must value the team members, client contacts, and
58 their interactions over the historical processes and tools that have
59 been used.
60- Engagement teams must value a final report that contains sufficient
61 audit documentation over excessive documentation or scope creep.
62- Engagement teams must collaborate with the audit clients as much as
63 feasible to ensure that both sides are constantly updated with
64 current knowledge of the engagement\'s status and any potential
65 findings, rather than waiting for pre-set meetings or the end of the
66 engagement to communicate.
67- Engagement teams must be able to respond to change in an
68 engagement\'s schedule, scope, or environment to ensure that the
69 project is completed in a timely manner and that all relevant areas
70 are tested.
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.
55- Engagement teams must value the team members, client contacts, and their
56 interactions over the historical processes and tools that have been used.
57- Engagement teams must value a final report that contains sufficient audit
58 documentation over excessive documentation or scope creep.
59- Engagement teams must collaborate with the audit clients as much as feasible
60 to ensure that both sides are constantly updated with current knowledge of the
61 engagement's status and any potential findings, rather than waiting for
62 pre-set meetings or the end of the engagement to communicate.
63- Engagement teams must be able to respond to change in an engagement's
64 schedule, scope, or environment to ensure that the project is completed in a
65 timely manner and that all relevant areas are tested.
66 - In terms of an audit department's portfolio, they must be able to respond
67 to changes in their company's or client's environment and be able to
68 dynamically change their audit plan accordingly.
7569
7670# Scrum
7771
78The above section discusses the high-level details of the Agile
79philosophy and how an audit team can potentially mold that mindset into
80the audit world, but how does a team implement these ideas?
72The above section discusses the high-level details of the Agile philosophy and
73how an audit team can potentially mold that mindset into the audit world, but
74how does a team implement these ideas?
8175
8276There are many methods that use an Agile mindset, but I prefer
83[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)).
84Scrum is a framework based on Agile that enables a team to work through
85a project through a series of roles, ceremonies, artifacts, and values.
77[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)). Scrum is a
78framework based on Agile that enables a team to work through a project through a
79series of roles, ceremonies, artifacts, and values.
8680
87Let\'s dive into each of these individually.
81Let's dive into each of these individually.
8882
8983## Scrum Team
9084
91A scrum project is only as good as the team running the project.
92Standard scrum teams are separated into three distinct areas:
93
941. **Product Owner (Client Contact)**: The client contact is the audit
95 equivalent of the product owner in Scrum. They are responsible for
96 partnering with the engagement or audit team to ensure progress is
97 being made, priorities are established, and clear guidance is given
98 when questions or findings arise within each sprint.
992. **Scrum Master (Engagement Lead)**: The engagement or audit team
100 lead is responsible for coaching the team and the client contact on
101 the scrum process, tracking team progress against plan, scheduling
102 necessary resources, and helping remove obstacles.
1033. **Scrum Developers (Engagement Members)**: The engagement or audit
104 team is the set of team members responsible for getting the work
105 done. These team members will work on each task, report progress,
106 resolve obstacles, and collaborate with other team members and the
107 client contact to ensure goals are being met.
85A scrum project is only as good as the team running the project. Standard scrum
86teams are separated into three distinct areas:
87
881. **Product Owner (Client Contact)**: The client contact is the audit
89 equivalent of the product owner in Scrum. They are responsible for partnering
90 with the engagement or audit team to ensure progress is being made,
91 priorities are established, and clear guidance is given when questions or
92 findings arise within each sprint.
932. **Scrum Master (Engagement Lead)**: The engagement or audit team lead is
94 responsible for coaching the team and the client contact on the scrum
95 process, tracking team progress against plan, scheduling necessary resources,
96 and helping remove obstacles.
973. **Scrum Developers (Engagement Members)**: The engagement or audit team is
98 the set of team members responsible for getting the work done. These team
99 members will work on each task, report progress, resolve obstacles, and
100 collaborate with other team members and the client contact to ensure goals
101 are being met.
108102
109103## Scrum Ceremonies
110104
111105Scrum ceremonies are events that are performed on a regular basis.
112106
1131. **Sprint Planning**: The team works together to plan the upcoming
114 sprint goal and which user stories (tasks) will be added to the
115 sprint to achieve that goal.
1162. **Sprint**: The time period, typically at least one week and no more
117 than one month in length, where the team works on the stories and
118 anything in the backlog.
1193. **Daily Scrum**: A very short meeting held each day, typically 15
120 minutes, to quickly emphasize alignment on the sprint goal and plan
121 the next 24 hours. Each team member may share what they did the day
122 before, what they\'ll do today, and any obstacles to their work.
1234. **Sprint Review**: At the end of each sprint, the team will gather
124 and discuss the progress, obstacles, and backlog from the previous
125 sprint.
1265. **Sprint Retrospective**: More specific than the sprint review, the
127 retrospective is meant to discuss what worked and what did not work
128 during the sprint. This may be processes, tools, people, or even
129 things related to the Scrum ceremonies.
130
131One additional ceremony that may be applicable is organizing the
132backlog. This is typically the responsibility of the engagement leader
133and is meant to prioritize and clarify what needs to be done to complete
134items in the backlog.
1071. **Sprint Planning**: The team works together to plan the upcoming sprint goal
108 and which user stories (tasks) will be added to the sprint to achieve that
109 goal.
1102. **Sprint**: The time period, typically at least one week and no more than one
111 month in length, where the team works on the stories and anything in the
112 backlog.
1133. **Daily Scrum**: A very short meeting held each day, typically 15 minutes, to
114 quickly emphasize alignment on the sprint goal and plan the next 24 hours.
115 Each team member may share what they did the day before, what they'll do
116 today, and any obstacles to their work.
1174. **Sprint Review**: At the end of each sprint, the team will gather and
118 discuss the progress, obstacles, and backlog from the previous sprint.
1195. **Sprint Retrospective**: More specific than the sprint review, the
120 retrospective is meant to discuss what worked and what did not work during
121 the sprint. This may be processes, tools, people, or even things related to
122 the Scrum ceremonies.
123
124One additional ceremony that may be applicable is organizing the backlog. This
125is typically the responsibility of the engagement leader and is meant to
126prioritize and clarify what needs to be done to complete items in the backlog.
135127
136128## Artifacts
137129
138While artifacts are generally not customizable in the audit world (i.e.,
139each control test must include some kind of working paper with evidence
140supporting the test results), I wanted to include some quick notes on
141associating scrum artifact terms with an audit.
130While artifacts are generally not customizable in the audit world (i.e., each
131control test must include some kind of working paper with evidence supporting
132the test results), I wanted to include some quick notes on associating scrum
133artifact terms with an audit.
142134
1431. **Product Backlog**: This is the overall backlog of unfinished audit
144 tasks from all prior sprints.
1452. **Sprint Backlog**: This is the backlog of unfinished audit tasks
146 from one individual sprint.
1473. **Increment**: This is the output of each sprint - generally this is
148 best thought of as any documentation prepared during the sprint,
149 such as risk assessments, control working papers, deficiency
150 analysis, etc.
1351. **Product Backlog**: This is the overall backlog of unfinished audit tasks
136 from all prior sprints.
1372. **Sprint Backlog**: This is the backlog of unfinished audit tasks from one
138 individual sprint.
1393. **Increment**: This is the output of each sprint - generally this is best
140 thought of as any documentation prepared during the sprint, such as risk
141 assessments, control working papers, deficiency analysis, etc.
151142
152143# Kanban
153144
154Last but not least, Kanban is a methodology that relies on boards to
155categorize work into distinct, descriptive categories that allow an
156agile or scrum team to effectively plan the work of a sprint or project.
145Last but not least, Kanban is a methodology that relies on boards to categorize
146work into distinct, descriptive categories that allow an agile or scrum team to
147effectively plan the work of a sprint or project.
157148
158See Atlassian\'s [Kanban](https://www.atlassian.com/agile/kanban) page
159for more information.
149See Atlassian's [Kanban](https://www.atlassian.com/agile/kanban) page for more
150information.
content/blog/2023-09-15-self-hosting-gitweb.md +11 −14
@@ -7,14 +7,12 @@ draft = false
77
88# Overview
99
10[GitWeb](https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb) is a
11simple web-based visualizer for git repositories. By default, GitWeb
12will only run with the `lighttpd` or `webrick` web
13servers.
10[GitWeb](https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb) is a simple
11web-based visualizer for git repositories. By default, GitWeb will only run with
12the `lighttpd` or `webrick` web servers.
1413
15However, this guide will show you how to keep GitWeb running in the
16background and display information for all repositories in a chosen
17directory.
14However, this guide will show you how to keep GitWeb running in the background
15and display information for all repositories in a chosen directory.
1816
1917See below for the final result:
2018
@@ -22,7 +20,7 @@ See below for the final result:
2220
2321# Install Dependencies
2422
25To start, you\'ll need install the following packages:
23To start, you'll need install the following packages:
2624
2725```sh
2826sudo apt install git gitweb fcgiwrap nginx
@@ -57,21 +55,20 @@ server {
5755}
5856```
5957
60To make the configuration active, you need to symlink it and then
61restart Nginx.
58To make the configuration active, you need to symlink it and then restart Nginx.
6259
6360```sh
6461sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/git.example.com
6562sudo systemctl restart nginx.service
6663```
6764
68The GitWeb application should now be available via the URL you set in
69the Nginx configuration above.
65The GitWeb application should now be available via the URL you set in the Nginx
66configuration above.
7067
7168# Customize GitWeb
7269
73If you need to, you can customize many things about Gitweb by editing
74the [gitweb.conf](https://git-scm.com/docs/gitweb.conf) file.
70If you need to, you can customize many things about Gitweb by editing the
71[gitweb.conf](https://git-scm.com/docs/gitweb.conf) file.
7572
7673```sh
7774sudo nano /etc/gitweb.conf
content/blog/2023-09-19-audit-sql-scripts.md +33 −41
@@ -7,17 +7,16 @@ draft = false
77
88# Overview
99
10When you have to scope a database into your engagement, you may be
11curious how to best extract the information from the database. While
12there are numerous different methods to extract this type of
13information, I\'m going to show an example of how to gather all users
14and privileges from three main database types: Oracle, Microsoft SQL,
15and MySQL.
10When you have to scope a database into your engagement, you may be curious how
11to best extract the information from the database. While there are numerous
12different methods to extract this type of information, I'm going to show an
13example of how to gather all users and privileges from three main database
14types: Oracle, Microsoft SQL, and MySQL.
1615
1716# Oracle
1817
19You can use the following SQL script to see all users and their
20privileges in an Oracle database:
18You can use the following SQL script to see all users and their privileges in an
19Oracle database:
2120
2221``` sql
2322SELECT
@@ -37,23 +36,21 @@ WHERE
3736 grantee IN (SELECT DISTINCT grantee FROM dba_tab_privs);
3837```
3938
40This script queries the `dba_sys_privs` and
41`dba_tab_privs` views to retrieve system and table-level
42privileges respectively. It then combines the results using
43`UNION ALL` to show all users and their associated
44privileges. Please note that this method does not extract information
45from the `dba_role_privs` table - use the method below for
46that data.
39This script queries the `dba_sys_privs` and `dba_tab_privs` views to retrieve
40system and table-level privileges respectively. It then combines the results
41using `UNION ALL` to show all users and their associated privileges. Please note
42that this method does not extract information from the `dba_role_privs` table -
43use the method below for that data.
4744
48Please note that you might need appropriate privileges (e.g., DBA
49privileges) to access these views, and you should exercise caution when
50querying system tables in a production Oracle database.
45Please note that you might need appropriate privileges (e.g., DBA privileges) to
46access these views, and you should exercise caution when querying system tables
47in a production Oracle database.
5148
5249## Alternative Oracle Query
5350
54You can also extract each table\'s information separately and perform
55processing outside the database to explore and determine the information
56necessary for the audit:
51You can also extract each table's information separately and perform processing
52outside the database to explore and determine the information necessary for the
53audit:
5754
5855``` sql
5956SELECT ** FROM sys.dba_role_privs;
@@ -64,9 +61,8 @@ SELECT ** FROM sys.dba_users;
6461
6562# Microsoft SQL
6663
67You can use the following SQL script to see all users and their
68privileges in a Microsoft SQL Server database
69([source](https://stackoverflow.com/a/30040784)):
64You can use the following SQL script to see all users and their privileges in a
65Microsoft SQL Server database ([source](https://stackoverflow.com/a/30040784)):
7066
7167``` sql
7268/*
@@ -217,8 +213,8 @@ ORDER BY
217213
218214# MySQL
219215
220You can use the following SQL script to see all users and their
221privileges in a MySQL database:
216You can use the following SQL script to see all users and their privileges in a
217MySQL database:
222218
223219```sh
224220mysql -u root -p
@@ -230,26 +226,22 @@ Find all users and hosts with access to the database:
230226SELECT ** FROM information_schema.user_privileges;
231227```
232228
233This script retrieves user information and their associated
234database-level privileges from the
235`information_schema.user_privileges` table in MySQL. It lists
236various privileges such as SELECT, INSERT, UPDATE, DELETE, CREATE, and
229This script retrieves user information and their associated database-level
230privileges from the `information_schema.user_privileges` table in MySQL. It
231lists various privileges such as SELECT, INSERT, UPDATE, DELETE, CREATE, and
237232more for each user and database combination.
238233
239Please note that you may need appropriate privileges (e.g.,
240`SELECT` privileges on
241`information_schema.user_privileges`) to access this
242information in a MySQL database. Additionally, some privileges like
243GRANT OPTION, EXECUTE, EVENT, and TRIGGER may not be relevant for all
244users and databases.
234Please note that you may need appropriate privileges (e.g., `SELECT` privileges
235on `information_schema.user_privileges`) to access this information in a MySQL
236database. Additionally, some privileges like GRANT OPTION, EXECUTE, EVENT, and
237TRIGGER may not be relevant for all users and databases.
245238
246239## Alternative MySQL Query
247240
248You can also grab individual sets of data from MySQL if you prefer to
249join them after extraction. I have marked the queries below with
250`SELECT ...` and excluded most `WHERE` clauses for
251brevity. You should determine the relevant privileges in-scope and query
252for those privileges to reduce the length of time to query.
241You can also grab individual sets of data from MySQL if you prefer to join them
242after extraction. I have marked the queries below with `SELECT ...` and excluded
243most `WHERE` clauses for brevity. You should determine the relevant privileges
244in-scope and query for those privileges to reduce the length of time to query.
253245
254246``` sql
255247-- Global Permissions
content/blog/2023-10-04-digital-minimalism.md +65 −73
@@ -5,103 +5,95 @@ description = ""
55draft = false
66+++
77
8I\'ve written [a note about minimalism](file:///wiki/#digital-garden)
9before, but I wanted to dedicate some time to reflect on digital
10minimalism and how I\'ve been able to minimize the impact of digital
11devices in my life.
12
13> These changes crept up on us and happened fast, before we had a chance
14> to step back and ask what we really wanted out of the rapid advances
15> of the past decade. We added new technologies to the periphery of our
16> experience for minor reasons, then woke one morning to discover that
17> they had colonized the core of our daily life. We didn\'t, in other
18> words, sign up for the digital world in which we\'re currently
19> entrenched; we seem to have stumbled backward into it.
8I've written [a note about minimalism](file:///wiki/#digital-garden) before,
9but I wanted to dedicate some time to reflect on digital minimalism and how
10I've been able to minimize the impact of digital devices in my life.
11
12> These changes crept up on us and happened fast, before we had a chance to step
13> back and ask what we really wanted out of the rapid advances of the past
14> decade. We added new technologies to the periphery of our experience for minor
15> reasons, then woke one morning to discover that they had colonized the core of
16> our daily life. We didn't, in other words, sign up for the digital world in
17> which we're currently entrenched; we seem to have stumbled backward into it.
2018>
2119> *(Digital Minimalism, 2019)*
2220
2321# The Principles of Digital Minimalism
2422
25As noted in Cal Newport\'s book, *Digital Minimalism*, there are three
26main principles to digital minimalism that I tend to agree with:
23As noted in Cal Newport's book, *Digital Minimalism*, there are three main
24principles to digital minimalism that I tend to agree with:
2725
28261. Clutter is costly.
29 - Digital minimalists recognize that cluttering their time and
30 attention with too many devices, apps, and services creates an
31 overall negative cost that can swamp the small benefits that
32 each individual item provides in isolation.
27 - Digital minimalists recognize that cluttering their time and attention
28 with too many devices, apps, and services creates an overall negative cost
29 that can swamp the small benefits that each individual item provides in
30 isolation.
33312. Optimization is important.
34 - Digital minimalists believe that deciding a particular
35 technology supports something they value is only the first step.
36 To truly extract its full potential benefit, it\'s necessary to
37 think carefully about how they\'ll use the technology.
32 - Digital minimalists believe that deciding a particular technology supports
33 something they value is only the first step. To truly extract its full
34 potential benefit, it's necessary to think carefully about how they'll
35 use the technology.
38363. Intentionality is satisfying.
39 - Digital minimalists derive significant satisfaction from their
40 general commitment to being more intentional about how they
41 engage with new technologies. This source of satisfaction is
42 independent of the specific decisions they make and is one of
43 the biggest reasons that minimalism tends to be immensely
44 meaningful to its practitioners.
37 - Digital minimalists derive significant satisfaction from their general
38 commitment to being more intentional about how they engage with new
39 technologies. This source of satisfaction is independent of the specific
40 decisions they make and is one of the biggest reasons that minimalism
41 tends to be immensely meaningful to its practitioners.
4542
4643# Taking Action
4744
48In order to put the logic into practice, I\'ve created a few new habits
49and continued performing old habits that are working well:
45In order to put the logic into practice, I've created a few new habits and
46continued performing old habits that are working well:
5047
5148## Using Devices With Intention
5249
53- I already rarely use \"social media\", mostly limited to forums such
54 as Hacker News and Tildes, so I\'ve just tweaked my behavior to stop
55 looking for content in those places when I\'m bored.
56- Use devices with intention. Each time I pick up a digital device,
57 there should be an intention to use the device to improve my current
58 situation. No more endless scrolling or searching for something to
59 interest me.
50- I already rarely use "social media", mostly limited to forums such as Hacker
51 News and Tildes, so I've just tweaked my behavior to stop looking for content
52 in those places when I'm bored.
53- Use devices with intention. Each time I pick up a digital device, there should
54 be an intention to use the device to improve my current situation. No more
55 endless scrolling or searching for something to interest me.
6056
6157## Prevent Distractions
6258
63- Disable (most) notifications on all devices. I spent 15-30 minutes
64 going through the notifications on my phone, watch, and computer to
65 ensure that only a select few apps have the ability to interrupt me:
66 Calendar, Messages, Phone, Reminders, & Signal.
67- Disable badges for any apps except the ones mentioned in the bullet
68 above.
69- Set-up focus profiles across devices so that I can enable different
70 modes, such as Personal when I only want to see notifications from
71 people I care about or Do Not Disturb, where absolutely nothing can
72 interrupt me.
73- Clean up my home screens. This one was quite easy as I already
74 maintain a minimalist set-up, but I went extreme by limiting my
75 phone to just eight apps on the home screen and four in the dock. If
76 I need another app, I\'ll have to search or use the app library.
77- Remove the work profile from my phone. This was a tough decision as
78 having my work profile on my device definitely makes my life easier
79 at times, but it also has quite a negative effect when I\'m \"always
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.
59- Disable (most) notifications on all devices. I spent 15-30 minutes going
60 through the notifications on my phone, watch, and computer to ensure that only
61 a select few apps have the ability to interrupt me: Calendar, Messages, Phone,
62 Reminders, & Signal.
63- Disable badges for any apps except the ones mentioned in the bullet above.
64- Set-up focus profiles across devices so that I can enable different modes,
65 such as Personal when I only want to see notifications from people I care
66 about or Do Not Disturb, where absolutely nothing can interrupt me.
67- Clean up my home screens. This one was quite easy as I already maintain a
68 minimalist set-up, but I went extreme by limiting my phone to just eight apps
69 on the home screen and four in the dock. If I need another app, I'll have to
70 search or use the app library.
71- Remove the work profile from my phone. This was a tough decision as having my
72 work profile on my device definitely makes my life easier at times, but it
73 also has quite a negative effect when I'm "always online" and can see the
74 notifications and team activity 24/7. I believe creating a distinct barrier
75 between my work and personal devices will be beneficial in the end.
8376
8477## Creating Alternative Activities
8578
86This is the most difficult piece, as most of my hobbies and interests
87lie in the digital world. However, I\'m making a concerted effort to put
88devices down unless necessary and force myself to perform other
89activities in the physical world instead.
79This is the most difficult piece, as most of my hobbies and interests lie in the
80digital world. However, I'm making a concerted effort to put devices down
81unless necessary and force myself to perform other activities in the physical
82world instead.
9083
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:
9285
93- Do a chore, such as organizing or cleaning.
94- Read a book, study a piece of art, etc.
95- Exercise or get outdoors.
96- Participate in a hobby, such as photography, birding, disc golf,
97 etc.
98- Let yourself be bored and wander into creativity.
86- Do a chore, such as organizing or cleaning.
87- Read a book, study a piece of art, etc.
88- Exercise or get outdoors.
89- Participate in a hobby, such as photography, birding, disc golf, etc.
90- Let yourself be bored and wander into creativity.
9991
10092# Making Progress
10193
102I\'ll be taking notes as I continue down this journey and hope to see
103positive trends. I\'ve always been a minimalist in the physical world
104and it feels refreshing to filter out the clutter that has come to
105dominate my digital life over the years.
94I'll be taking notes as I continue down this journey and hope to see positive
95trends. I've always been a minimalist in the physical world and it feels
96refreshing to filter out the clutter that has come to dominate my digital life
97over the years.
10698
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
77
88# Overview
99
10[Authelia](https://www.authelia.com/) is an open-source authentication
11service that allows you to place a portal between end users on the
12internet and self-hosted services on your server.
10[Authelia](https://www.authelia.com/) is an open-source authentication service
11that allows you to place a portal between end users on the internet and
12self-hosted services on your server.
1313
14You can require one factor (username+password) or two factor
15authentication for any such user before allowing them to access a
16specific service on your domain.
14You can require one factor (username+password) or two factor authentication for
15any such user before allowing them to access a specific service on your domain.
1716
1817This guide will walk through a standard installation of Authelia for
19`example.com`, using `auth.example.com` as
20Authelia\'s authentication domain and `teddit.example.com` as
21the website we want to protect behind the authentication portal.
18`example.com`, using `auth.example.com` as Authelia's authentication domain and
19`teddit.example.com` as the website we want to protect behind the authentication
20portal.
2221
2322# Prerequisites
2423
2524This guide assumes you have the following already set-up:
2625
27- A registered domain with DNS pointing to your server.
28- A subdomain for Authelia (`auth.example.com`) and a
29 subdomain to protect via Authelia (`app.example.com`).
30- A working Nginx web server.
31- Docker and docker-compose installed.
26- A registered domain with DNS pointing to your server.
27- A subdomain for Authelia (`auth.example.com`) and a subdomain to protect via
28 Authelia (`app.example.com`).
29- A working Nginx web server.
30- Docker and docker-compose installed.
3231
3332# Installation
3433
35This guide will walk through each installation step one-by-one, starting
36with the container and finishing by cleaning up external access via an
37Nginx reverse proxy.
34This guide will walk through each installation step one-by-one, starting with
35the container and finishing by cleaning up external access via an Nginx reverse
36proxy.
3837
3938## Docker-Compose
4039
41To start, create a directory for Authelia and create a
42`docker-compose.yml` file.
40To start, create a directory for Authelia and create a `docker-compose.yml`
41file.
4342
4443```sh
4544mkdir ~/authelia
4645nano ~/authelia/docker-compose.yml
4746```
4847
49Within this file, paste the following content. If you prefer a different
50local port, modify the port on the left side of the colon on the
51`9091:9091` line. Be sure to modify the `TZ`
52variable to your timezone.
48Within this file, paste the following content. If you prefer a different local
49port, modify the port on the left side of the colon on the `9091:9091` line. Be
50sure to modify the `TZ` variable to your timezone.
5351
5452``` yml
5553version: '3.3'
@@ -72,45 +70,40 @@ Start the container with docker-compose:
7270sudo docker-compose up -d
7371```
7472
75After the first start, the container will automatically exit and require
76you to modify the app\'s configuration files before continuing. Read on
77to learn more.
73After the first start, the container will automatically exit and require you to
74modify the app's configuration files before continuing. Read on to learn more.
7875
7976## Authelia Configuration
8077
81To configure Authelia before we restart the container, we need to open
82the `config` directory and modify the files. Start by editing
83the `configuration.yml` file, where all of Authelia\'s
84settings are stored.
78To configure Authelia before we restart the container, we need to open the
79`config` directory and modify the files. Start by editing the
80`configuration.yml` file, where all of Authelia's settings are stored.
8581
86My personal preference is to copy the original configuration file to a
87backup file and edit a fresh copy.
82My personal preference is to copy the original configuration file to a backup
83file and edit a fresh copy.
8884
8985```sh
9086sudo cp ~/authelia/config/configuration.yml ~/authelia/config/configuration.yml.bk
9187sudo nano ~/authelia/config/configuration.yml
9288```
9389
94Within the blank `configuration.yml` file, paste the
95following information. You will need to make quite a few updates, so be
96sure to read each line carefully and modify as necessary.
90Within the blank `configuration.yml` file, paste the following information. You
91will need to make quite a few updates, so be sure to read each line carefully
92and modify as necessary.
9793
9894The major required changes are:
9995
100- Any instances of `example.com` should be replaced by your
101 domain.
102- `jwt_secret` - Use the `pwgen 40 1` command to
103 generate a secret for yourself.
104- `access_control` - Set the Authelia domain to bypass
105 here, as well as any subdomains you want to protect.
106- `session` \> `secret` - Use the
107 `pwgen 40 1` command to generate a secret for yourself.
108- `regulation` - Set the variables here to restrict login
109 attempts and bans.
110- `storage` \> `encryption_key` - Use the
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.
96- Any instances of `example.com` should be replaced by your domain.
97- `jwt_secret` - Use the `pwgen 40 1` command to generate a secret for yourself.
98- `access_control` - Set the Authelia domain to bypass here, as well as any
99 subdomains you want to protect.
100- `session` > `secret` - Use the `pwgen 40 1` command to generate a secret for
101 yourself.
102- `regulation` - Set the variables here to restrict login attempts and bans.
103- `storage` > `encryption_key` - Use the `pwgen 40 1` command to generate a
104 secret for yourself.
105- `smtp` - If you have access to an SMTP service, set up the information here to
106 active outgoing emails.
114107
115108``` yml
116109# yamllint disable rule:comments-indentation
@@ -211,14 +204,13 @@ Next, create the users file for authentication.
211204sudo nano ~/authelia/config/users_database.yml
212205```
213206
214Within the file, you will need to create an entry for each user that
215needs access to Authelia. The `my_username` entry will be the
216username used on the login page.
207Within the file, you will need to create an entry for each user that needs
208access to Authelia. The `my_username` entry will be the username used on the
209login page.
217210
218To generate the password, go to [Argon2 Hash
219Generator](https://argon2.online), generate a random salt, and make sure
220the rest of the settings match the `authentication_backend`
221section of `configuration.yml` file.
211To generate the password, go to [Argon2 Hash Generator](https://argon2.online),
212generate a random salt, and make sure the rest of the settings match the
213`authentication_backend` section of `configuration.yml` file.
222214
223215``` yaml
224216users:
@@ -242,8 +234,8 @@ sudo docker-compose down && sudo docker-compose up -d
242234
243235## Nginx: Authelia Domain
244236
245Once the container is running and configured, the final step is to
246configure external access to the server via Nginx reverse proxy.
237Once the container is running and configured, the final step is to configure
238external access to the server via Nginx reverse proxy.
247239
248240Start by creating the Authelia domain.
249241
@@ -252,9 +244,8 @@ sudo nano /etc/nginx/sites-available/auth
252244```
253245
254246Within this file, paste the following information and be sure to update
255`example.com` to your domain. Make sure the
256`$upstream_authelia` variable matches the location of your
257Authelia container.
247`example.com` to your domain. Make sure the `$upstream_authelia` variable
248matches the location of your Authelia container.
258249
259250``` conf
260251server {
@@ -310,8 +301,8 @@ server {
310301}
311302```
312303
313Next, symlink the file and restart Nginx. If there are errors, be sure
314to resolve those before moving on.
304Next, symlink the file and restart Nginx. If there are errors, be sure to
305resolve those before moving on.
315306
316307```sh
317308sudo ln -s /etc/nginx/sites-available/auth /etc/nginx/sites-enabled/auth
@@ -320,9 +311,9 @@ sudo systemctl restart nginx.service
320311
321312## Nginx: Protected Domain(s)
322313
323Now that Authelia is accessible externally, you need to configure the
324domain you intend to protect with Authelia. In this example, I\'m
325protecting `teddit.example.com`.
314Now that Authelia is accessible externally, you need to configure the domain you
315intend to protect with Authelia. In this example, I'm protecting
316`teddit.example.com`.
326317
327318Similar to the process above, paste the content and update the relevant
328319variables.
@@ -450,9 +441,9 @@ authentication domain and presented with the Authelia login portal.
450441![Authelia
451442Portal](https://img.cleberg.net/blog/20231010-authelia/authelia_portal.png)
452443
453Once you\'ve successfully authenticated, you can visit your
454authentication domain directly and see that you\'re currently
455authenticated to any domain protected by Authelia.
444Once you've successfully authenticated, you can visit your authentication
445domain directly and see that you're currently authenticated to any domain
446protected by Authelia.
456447
457448![Authelia
458449Success](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
88# Overview
99
1010This guide follows the standard
11[ssh-audit](https://www.ssh-audit.com/hardening_guides.html) hardening
12guide, tweaked for Alpine Linux.
11[ssh-audit](https://www.ssh-audit.com/hardening_guides.html) hardening guide,
12tweaked for Alpine Linux.
1313
1414# Hardening Guide
1515
16These steps must be performed as root. You can try to use
17`doas` or `sudo`, but there may be issues.
16These steps must be performed as root. You can try to use `doas` or `sudo`, but
17there may be issues.
1818
19191. Re-generate the RSA and ED25519 keys
2020
@@ -31,8 +31,8 @@ awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe
3131mv /etc/ssh/moduli.safe /etc/ssh/moduli
3232```
3333
343. Enable the RSA and ED25519 HostKey directives in the
35 /etc/ssh/sshd~config~ file
343. Enable the RSA and ED25519 HostKey directives in the /etc/ssh/sshd~config~
35 file
3636
3737```sh
3838sed -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
6565ssh-audit localhost
6666```
6767
68If everything succeeded, the results will show as all green. If anything
69is yellow, orange, or red, you may need to tweak additional settings.
68If everything succeeded, the results will show as all green. If anything is
69yellow, orange, or red, you may need to tweak additional settings.
7070
7171``` txt
7272#+caption: ssh audit
content/blog/2023-10-17-self-hosting-anonymousoverflow.md +17 −20
@@ -8,18 +8,17 @@ draft = false
88# Overview
99
1010I recently launched an instance of AnonymousOverflow at
11[ao.cleberg.net](https://ao.cleberg.net) and wanted to write a brief
12post on how easy it is to install with Docker Compose and Nginx.
11[ao.cleberg.net](https://ao.cleberg.net) and wanted to write a brief post on how
12easy it is to install with Docker Compose and Nginx.
1313
14This guide uses Ubuntu server, Docker Compose, and Nginx as a reverse
15proxy.
14This guide uses Ubuntu server, Docker Compose, and Nginx as a reverse proxy.
1615
1716# Installation
1817
1918## Docker Compose
2019
21To install AnonymousOverflow, start by creating a directory for the
22application and create its `docker-compose.yml` file.
20To install AnonymousOverflow, start by creating a directory for the application
21and create its `docker-compose.yml` file.
2322
2423```sh
2524mkdir ~/anonymousoverflow && cd ~/anonymousoverflow
@@ -27,8 +26,7 @@ nano docker-compose.yml
2726```
2827
2928Within this file, paste the following information. Be sure to change the
30`APP_URL`, `JWT_SIGNING_SECRET`, and
31`ports` to match your needs.
29`APP_URL`, `JWT_SIGNING_SECRET`, and `ports` to match your needs.
3230
3331``` yaml
3432version: '3'
@@ -45,8 +43,8 @@ services:
4543 restart: 'always'
4644```
4745
48Save and exit the file when complete. You can now launch the container
49and access it via your local network.
46Save and exit the file when complete. You can now launch the container and
47access it via your local network.
5048
5149```sh
5250sudo docker-compose up -d
@@ -54,19 +52,18 @@ sudo docker-compose up -d
5452
5553## Nginx Reverse Proxy
5654
57If you want to access this service outside the local network, I
58recommend using Nginx as a reverse proxy.
55If you want to access this service outside the local network, I recommend using
56Nginx as a reverse proxy.
5957
60Let\'s start by creating a configuration file.
58Let's start by creating a configuration file.
6159
6260```sh
6361sudo nano /etc/nginx/sites-available/ao
6462```
6563
66Within this file, paste the following content and repace
67`ao.example.com` with your URL. You may need to update the
68SSL certificate statements if your certificates are in a different
69location.
64Within this file, paste the following content and repace `ao.example.com` with
65your URL. You may need to update the SSL certificate statements if your
66certificates are in a different location.
7067
7168``` conf
7269server {
@@ -122,9 +119,9 @@ server {
122119}
123120```
124121
125Save and exit the file when complete. On Ubuntu, you will need to
126symlink the configuration file before it will be recognized by Nginx.
127Once complete, simply restart the web server.
122Save and exit the file when complete. On Ubuntu, you will need to symlink the
123configuration file before it will be recognized by Nginx. Once complete, simply
124restart the web server.
128125
129126```sh
130127sudo 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 = ""
55draft = false
66+++
77
8[scli](https://github.com/isamert/scli) is a command-line tool that
9allows you to connect to your Signal messenger account. This program
10utilizes a two-pane display that shows you chats on the left and the
11focused conversation on the right.
8[scli](https://github.com/isamert/scli) is a command-line tool that allows you
9to connect to your Signal messenger account. This program utilizes a two-pane
10display that shows you chats on the left and the focused conversation on the
11right.
1212
13This guide will show you how to install `scli` and its
14dependencies on Alpine Linux, which requires some extra work due to
15musl.
13This guide will show you how to install `scli` and its dependencies on Alpine
14Linux, which requires some extra work due to musl.
1615
17If you\'re using a non-musl system, you can likely following the
18`scli` README and download the packaged binaries for an
19easier installation process.
16If you're using a non-musl system, you can likely following the `scli` README
17and download the packaged binaries for an easier installation process.
2018
2119# Dependencies
2220
2321In order to use `scli`, you need a few dependencies:
2422
25- `openjdk17-jre` - Used as a dependency for the
26 `signal-cli` tool. Version may vary.
27- `signal-cli` - Used as the backbone of the
28 `scli` tool.
29- `findutils` - Replaces the standard Busybox version of
30 `xargs`.
31- `urwid` - A console user interface library for Python.
32- `urwid-readline` - For GNU emacs-like keybinds on the
33 input line.
34- `qrencode` - Displays a QR code in the terminal to link
35 the device using your phone. Not necessary if you\'re only linking
36 on desktop and can copy/paste the connection URL.
37
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.
23- `openjdk17-jre` - Used as a dependency for the `signal-cli` tool. Version may
24 vary.
25- `signal-cli` - Used as the backbone of the `scli` tool.
26- `findutils` - Replaces the standard Busybox version of `xargs`.
27- `urwid` - A console user interface library for Python.
28- `urwid-readline` - For GNU emacs-like keybinds on the input line.
29- `qrencode` - Displays a QR code in the terminal to link the device using your
30 phone. Not necessary if you're only linking on desktop and can copy/paste the
31 connection URL.
32
33Let's start by installing the packages available via Alpine's repositories. Be
34sure to install the latest version of `openjdk`. If you run into Java-related
35issues, uninstall `openjdk` and install an older version.
4236
4337```sh
4438doas apk add openjdk17-jre findutils qrencode
4539```
4640
47Next, let\'s install `signal-cli`. Be sure to export the
48version of `signal-cli` that you want. I use version
49`0.12.4` below, but that may be outdated by the time you\'re
50reading this.
41Next, let's install `signal-cli`. Be sure to export the version of `signal-cli`
42that you want. I use version `0.12.4` below, but that may be outdated by the
43time you're reading this.
5144
5245```sh
5346export VERSION="0.12.4"
@@ -56,8 +49,7 @@ doas tar xf signal-cli-"${VERSION}".tar.gz -C /opt
5649doas ln -sf /opt/signal-cli-${VERSION}"/bin/signal/cli /usr/local/bin
5750```
5851
59Finally, install the `urwid` packages using the Python
60packaging utility.
52Finally, install the `urwid` packages using the Python packaging utility.
6153
6254```sh
6355pip3 install urwid urwid-readline
@@ -65,25 +57,24 @@ pip3 install urwid urwid-readline
6557
6658# Installation
6759
68Now that we have all of the dependencies we need, we can install
69`scli`. Start by simply cloning the repository.
60Now that we have all of the dependencies we need, we can install `scli`. Start
61by simply cloning the repository.
7062
7163```sh
7264git clone https://github.com/isamert/scli
7365```
7466
75When I cloned this repository on 2023-11-08, I found a bug in the logic
76that required a fix. You must edit the `scli` file and
77replace the one instance of `RLIMIT_OFILE` with
78`RLIMIT_NOFILE`.
67When I cloned this repository on 2023-11-08, I found a bug in the logic that
68required a fix. You must edit the `scli` file and replace the one instance of
69`RLIMIT_OFILE` with `RLIMIT_NOFILE`.
7970
8071```sh
8172cd scli
8273nano scli
8374```
8475
85Once complete, you can move this program to anywhere on your
86`$PATH`. I chose the following directory.
76Once complete, you can move this program to anywhere on your `$PATH`. I chose
77the following directory.
8778
8879```sh
8980doas mv scli /usr/local/bin/scli
@@ -91,43 +82,41 @@ doas mv scli /usr/local/bin/scli
9182
9283# Initial Setup
9384
94Now that everything is installed, we can login and configure the client.
95Start by generating a connection link.
85Now that everything is installed, we can login and configure the client. Start
86by generating a connection link.
9687
9788```sh
9889signal-cli link -n "YOUR-DEVICE-NICKNAME" | tee >(xargs -L 1 qrencode -t utf8)
9990```
10091
101This will generate a connection link and related QR code for you to use
102to link the devices together. Once complete, **wait patiently\*** for
103the connection process to finish.
92This will generate a connection link and related QR code for you to use to link
93the devices together. Once complete, **wait patiently** for the connection
94process to finish.
10495
105Once it completes, it will exit and return you to the prompt. From here,
106you need to perform an initial `receive` command to start
107things off. The `USERNAME` variable should be your phone
108number, such as `+15551237890`.
96Once it completes, it will exit and return you to the prompt. From here, you
97need to perform an initial `receive` command to start things off. The `USERNAME`
98variable should be your phone number, such as `+15551237890`.
10999
110100```sh
111101signal-cli -u USERNAME receive
112102```
113103
114Also be sure to test the daemon to ensure it works properly. If no
115errors occur, it\'s working. If you run into errors because you\'re not
116running a DBUS session, see my notes below.
104Also be sure to test the daemon to ensure it works properly. If no errors occur,
105it's working. If you run into errors because you're not running a DBUS
106session, see my notes below.
117107
118108```sh
119109signal-cli -u USERNAME daemon
120110```
121111
122Once the initial reception is complete, you are ready to use
123`scli`.
112Once the initial reception is complete, you are ready to use `scli`.
124113
125This process will differ depending on your desktop environment (DE). If
126you are running a DE, you likely have a DBUS session running already and
127can simply launch the program.
114This process will differ depending on your desktop environment (DE). If you are
115running a DE, you likely have a DBUS session running already and can simply
116launch the program.
128117
129However, if you\'re like me and running your computer straight on the
130TTY without a DE, you\'ll need to start a DBUS session for this program.
118However, if you're like me and running your computer straight on the TTY
119without a DE, you'll need to start a DBUS session for this program.
131120
132121```sh
133122# If you're not running a DBUS session yet, you need to start one for scli
@@ -139,9 +128,9 @@ scli
139128
140129# Configuration
141130
142Lastly, there are a number of configuration options that you can pass
143via the command or in the `~/.config/sclirc` file. See the
144Github README for more information on configuration options.
131Lastly, there are a number of configuration options that you can pass via the
132command or in the `~/.config/sclirc` file. See the Github README for more
133information on configuration options.
145134
146135```sh
147136nano ~/.config/sclirc
@@ -154,5 +143,5 @@ wrap-at = 80
154143enable-notifications = true
155144```
156145
157That\'s it! Following this guide, I have a functional `scli`
158program that successfully sends messages to my contacts and myself!
146That's it! Following this guide, I have a functional `scli` program that
147successfully sends messages to my contacts and myself!
content/blog/2023-12-03-unifi-nextdns.md +31 −34
@@ -9,32 +9,31 @@ draft = false
99
1010I recently installed NextDNS on my Unifi Dream Machine router using the
1111[UnifiOS](https://github.com/nextdns/nextdns/wiki/UnifiOS) wiki page on
12NextDNS\'s GitHub repository.
12NextDNS's GitHub repository.
1313
14As a result of this, I wanted to write down the process in case the wiki
15or installer ever gets lost.
14As a result of this, I wanted to write down the process in case the wiki or
15installer ever gets lost.
1616
1717# Wiki
1818
19The following is copied from the wiki page linked above, with one
20difference in the `ssh` command.
19The following is copied from the wiki page linked above, with one difference in
20the `ssh` command.
2121
22Install instructions for Unifi Dream Machine (UDM) standard and pro
23routers.
22Install instructions for Unifi Dream Machine (UDM) standard and pro routers.
2423
2524## Install
2625
2726Enable SSH:
2827
29- Go to your unifi admin interface and select your device (not the
30 controller settings, but the Dream Machine settings)
31- Click on \"Settings\" at the bottom of the page
32- Go to the \"Advanced\" section on the left pan
33- Enable SSH
34- Set a SSH password
28- Go to your unifi admin interface and select your device (not the controller
29 settings, but the Dream Machine settings)
30- Click on "Settings" at the bottom of the page
31- Go to the "Advanced" section on the left pan
32- Enable SSH
33- Set a SSH password
3534
36Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with
37the password you configured.
35Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with the password you
36configured.
3837
3938Run the following command and follow the instructions:
4039
@@ -42,25 +41,24 @@ Run the following command and follow the instructions:
4241sh -c 'sh -c "$(curl -sL https://nextdns.io/install)"'
4342```
4443
45Note: Queries from the UDM itself won\'t be routed to NextDNS nor
46encrypted due to current system limitation. All traffic from other
47devices on then network will.
44Note: Queries from the UDM itself won't be routed to NextDNS nor encrypted due
45to current system limitation. All traffic from other devices on then network
46will.
4847
4948## Upgrade
5049
51To upgrade to the last version, simply re-run the installer above. If a
52new version is available, the upgrade action will added to the list of
53possible actions.
50To upgrade to the last version, simply re-run the installer above. If a new
51version is available, the upgrade action will added to the list of possible
52actions.
5453
5554## Uninstall
5655
57To uninstall, re-run the installer above and select \"Remove\" in the
58menu.
56To uninstall, re-run the installer above and select "Remove" in the menu.
5957
6058## Troubleshooting
6159
62If the installation fail, please the installer in debug mode and contact
63us at team@nextdns.io with the transcript of the installation:
60If the installation fail, please the installer in debug mode and contact us at
61team@nextdns.io with the transcript of the installation:
6462
6563```sh
6664sh -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)"'
6866
6967### Content Filtering Conflict
7068
71NextDNS CLI and the UDM Content Filtering or the Ad Blocking features
72are incompatible. If you want to use NextDNS CLI, please make sure they
73are disabled.
69NextDNS CLI and the UDM Content Filtering or the Ad Blocking features are
70incompatible. If you want to use NextDNS CLI, please make sure they are
71disabled.
7472
75To disable Content Filtering, go to Settings \> Network, then for each
76network, set the Content Filtering feature to None
73To disable Content Filtering, go to Settings > Network, then for each network,
74set the Content Filtering feature to None
7775
78To disable Ad Blocking, go to Settings \> Application Firewall. In the
79General tab, uncheck the Ad Blocking checkbox.
76To disable Ad Blocking, go to Settings > Application Firewall. In the General
77tab, uncheck the Ad Blocking checkbox.
8078
8179### APT Error
8280
@@ -96,8 +94,7 @@ sed -i -e 's/deb.debian.org/archive.debian.org/g' \
9694
9795## install.sh
9896
99Here are the contents of the `install.sh` file used above, as
100of 2023-12-03:
97Here are the contents of the `install.sh` file used above, as of 2023-12-03:
10198
10299```sh
103100#!/bin/sh
content/blog/2024-01-08-dont-say-hello.md +16 −16
@@ -5,25 +5,25 @@ description = ""
55draft = false
66+++
77
8I recently came back from a winter break and have started working
9again... only to immediately run into the dilemma of people sending me
10cliffhanger messages again.
8I recently came back from a winter break and have started working again... only
9to immediately run into the dilemma of people sending me cliffhanger messages
10again.
1111
1212# No Hello
1313
14A year or two ago, I discovered [no hello](https://nohello.net/en/) and
15have thought about it often since then. I\'ve even sent it to a few
16people since then (who wouldn\'t take offense to it).
14A year or two ago, I discovered [no hello](https://nohello.net/en/) and have
15thought about it often since then. I've even sent it to a few people since then
16(who wouldn't take offense to it).
1717
18I work in a fast-paced environment where efficiency is extremely
19valuable. Therefore, I have always held a deep displeasure for
20conversations where people start with \"Hello\" and then.
18I work in a fast-paced environment where efficiency is extremely valuable.
19Therefore, I have always held a deep displeasure for conversations where people
20start with "Hello" and then.
2121
22I searched back through my work messages and found that I received \~50
23messages from \~10 people last year from people that contained \"hi\",
24\"hey\", or \"hello\" and did not contain any indication of the purpose
25of the conversation. I also noticed that a few of the users were
26responsible for the large majority of the cliffhangers.
22I searched back through my work messages and found that I received ~50 messages
23from ~10 people last year from people that contained "hi", "hey", or
24"hello" and did not contain any indication of the purpose of the conversation.
25I also noticed that a few of the users were responsible for the large majority
26of the cliffhangers.
2727
28There\'s no real point to this post, just a desparate request for people
29to please stop doing this.
28There's no real point to this post, just a desparate request for people to
29please stop doing this.
content/blog/2024-01-09-macos-customization.md +60 −71
@@ -5,42 +5,38 @@ description = ""
55draft = false
66+++
77
8I have been using macOS more than Linux lately, so I wrote this post to
9describe some simple options to customize macOS beyond the normal
10built-in settings menu.
8I have been using macOS more than Linux lately, so I wrote this post to describe
9some simple options to customize macOS beyond the normal built-in settings menu.
1110
12While not all-encompassing, the options below should be a good start for
13anyone looking to dive down the rabbit hole.
11While not all-encompassing, the options below should be a good start for anyone
12looking to dive down the rabbit hole.
1413
1514# Basics
1615
1716## Package Management
1817
1918To install a lot of software on macOS, you will need
20[Homebrew](https://brew.sh/). You can use their installation script to
21get started. Simply open the `Terminal` application and paste
22the following snippet:
19[Homebrew](https://brew.sh/). You can use their installation script to get
20started. Simply open the `Terminal` application and paste the following snippet:
2321
2422```sh
2523/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
2624```
2725
28This will allow you to easily install and manage applications and other
29software easily through the `brew` command.
26This will allow you to easily install and manage applications and other software
27easily through the `brew` command.
3028
3129## Terminal
3230
33If you\'re serious about customizing your macOS system, I highly
34recommend installing a terminal emulator that you like and if you\'re
35not comfortable on the command line yet, start learning. A lot of
36customization options require you to edit hidden files, which is easiest
37in a terminal.
31If you're serious about customizing your macOS system, I highly recommend
32installing a terminal emulator that you like and if you're not comfortable on
33the command line yet, start learning. A lot of customization options require you
34to edit hidden files, which is easiest in a terminal.
3835
39There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the
40built-in Terminal app.
36There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the built-in
37Terminal app.
4138
42I use [iTerm2](https://iterm2.com/), which can be installed with
43Homebrew:
39I use [iTerm2](https://iterm2.com/), which can be installed with Homebrew:
4440
4541```sh
4642brew install iterm2
@@ -48,39 +44,37 @@ brew install iterm2
4844
4945![iTerm2](https://img.cleberg.net/blog/20240109-macos-customization/iterm2.png)
5046
51To install color schemes, such as the Dracula scheme shown in the
52screenshot above, you visit [iTerm
53Themes](https://iterm2colorschemes.com/) and follow their installation
54instructions to install any of the themes.
47To install color schemes, such as the Dracula scheme shown in the screenshot
48above, you visit [iTerm Themes](https://iterm2colorschemes.com/) and follow
49their installation instructions to install any of the themes.
5550
5651# Desktop
5752
5853## Window Management
5954
60[yabai](https://github.com/koekeishiya/yabai) is a tiling window manager
61for macOS. While other window managers exist, I found that most of them
62struggled to create logical layouts and to allow me to easily move
63windows around the screen.
55[yabai](https://github.com/koekeishiya/yabai) is a tiling window manager for
56macOS. While other window managers exist, I found that most of them struggled to
57create logical layouts and to allow me to easily move windows around the screen.
6458
65Some advanced settings for yabai are only available if partially disable
66System Integrity Protection (SIP). However, I chose not to do this and
67it hasn\'t affected my basic usage of yabai at all.
59Some advanced settings for yabai are only available if partially disable System
60Integrity Protection (SIP). However, I chose not to do this and it hasn't
61affected my basic usage of yabai at all.
6862
6963Refer to the [yabai
7064wiki](https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release))
71for installation instructions. You will need to ensure that yabai is
72allowed to access the accessibility and screen recording APIs.
65for installation instructions. You will need to ensure that yabai is allowed to
66access the accessibility and screen recording APIs.
7367
74You can see a basic three-pane layout atuomatically configured by yabai
75for me as I opened the windows below.
68You can see a basic three-pane layout atuomatically configured by yabai for me
69as I opened the windows below.
7670
7771![yabai window
7872manager](https://img.cleberg.net/blog/20240109-macos-customization/yabai.png)
7973
8074## Keyboard Shortcuts
8175
82[skhd](https://github.com/koekeishiya/skhd) is a simple hotkey daemon
83that allows you to define hotkeys in a file for usage on your system.
76[skhd](https://github.com/koekeishiya/skhd) is a simple hotkey daemon that
77allows you to define hotkeys in a file for usage on your system.
8478
8579Installation is simple:
8680
@@ -89,11 +83,10 @@ brew install koekeishiya/formulae/skhd
8983skhd --start-service
9084```
9185
92After installation, be sure to allow `skhd` access to the
93accessibility API in the macOS privacy settings.
86After installation, be sure to allow `skhd` access to the accessibility API in
87the macOS privacy settings.
9488
95You can configure your hotkeys in the `~/.config/skhd/skhdrc`
96file:
89You can configure your hotkeys in the `~/.config/skhd/skhdrc` file:
9790
9891```sh
9992nano ~/.config/skhd/skhdrc
@@ -112,14 +105,13 @@ cmd + shift - return : /Applications/LibreWolf.app/Contents/MacOS/librewolf
112105## Widgets
113106
114107[uebersicht](https://github.com/felixhageloh/uebersicht/) is a handy
115desktop-based widget tool with a plethora of community-made widgets
116available in the [widgets
117gallery](https://tracesof.net/uebersicht-widgets/). You can also write
118your own widgets with this tool.
108desktop-based widget tool with a plethora of community-made widgets available in
109the [widgets gallery](https://tracesof.net/uebersicht-widgets/). You can also
110write your own widgets with this tool.
119111
120112To install, simply download the latest release from the [uebersicht
121website](https://tracesof.net/uebersicht/) and copy it to the
122Applications folder.
113website](https://tracesof.net/uebersicht/) and copy it to the Applications
114folder.
123115
124116See below for an example of the
125117[Mond](https://tracesof.net/uebersicht-widgets/#Mond) widget in action.
@@ -137,22 +129,20 @@ You can browse a discussion where various users shared their
137129for inspiration or to copy their dotfiles.
138130
139131See below for a quick (& slightly broken) copy of
140[zer0yu\'s](https://github.com/zer0yu/dotfiles) SketchyBar
141configuration.
132[zer0yu's](https://github.com/zer0yu/dotfiles) SketchyBar configuration.
142133
143134![SketchyBar](https://img.cleberg.net/blog/20240109-macos-customization/sketchybar.png)
144135
145136## Dock
146137
147138The easiest way to customize the dock is to install
148[uBar](https://ubarapp.com/), which uses a Windows-like menu bar as the
149default style.
139[uBar](https://ubarapp.com/), which uses a Windows-like menu bar as the default
140style.
150141
151However, the built-in macOS dock cannot be disabled and can only be set
152to \"always hidden\". This can be annoying as it will pop out any time
153your mouse cursor passes closely to the dock edge of the screen. Because
154of this, I simply use the built-in dock instead of customizing it with
155third-party software.
142However, the built-in macOS dock cannot be disabled and can only be set to
143"always hidden". This can be annoying as it will pop out any time your mouse
144cursor passes closely to the dock edge of the screen. Because of this, I simply
145use the built-in dock instead of customizing it with third-party software.
156146
157147Regardless, see below for the default installation style of uBar.
158148
@@ -160,22 +150,21 @@ Regardless, see below for the default installation style of uBar.
160150
161151## Application Icons
162152
163You can also customize the icon of any application in macOS, which will
164show up in Finder, the Dock, Launchpad, search results, etc. I recommend
165using [macOSicons](https://macosicons.com/) to download icons you want,
166and then apply them by following this process.
167
1681. Open the Finder application.
1692. Navigate to the `Applications` folder.
1703. Right-click an application of your choice, and select
171 `Get Info`.
1724. Drag the image you downloaded on top of the application\'s icon at
173 the top of information window (you will see a green \"plus\" symbol
174 when you\'re hovering over it).
1755. Release the new icon on top of the old icon and it will update!
176
177You can see an example of me dragging a new `signal.icns`
178file onto my Signal.app information window to update it below:
153You can also customize the icon of any application in macOS, which will show up
154in Finder, the Dock, Launchpad, search results, etc. I recommend using
155[macOSicons](https://macosicons.com/) to download icons you want, and then apply
156them by following this process.
157
1581. Open the Finder application.
1592. Navigate to the `Applications` folder.
1603. Right-click an application of your choice, and select `Get Info`.
1614. Drag the image you downloaded on top of the application's icon at the top of
162 information window (you will see a green "plus" symbol when you're
163 hovering over it).
1645. Release the new icon on top of the old icon and it will update!
165
166You can see an example of me dragging a new `signal.icns` file onto my
167Signal.app information window to update it below:
179168
180169![replace macOS
181170icons](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
77
88# Requirements
99
10I\'ve recently started playing with large language models (LLMs), mostly
11in the popular chatbot form, as part of my job and have decided to see
12if there\'s a consistent and reliable way to interact with these models
13on Apple devices without sacrificing privacy or requiring in-depth
14technical setup.
10I've recently started playing with large language models (LLMs), mostly in the
11popular chatbot form, as part of my job and have decided to see if there's a
12consistent and reliable way to interact with these models on Apple devices
13without sacrificing privacy or requiring in-depth technical setup.
1514
1615My requirements for this test:
1716
18- Open source platform
19- On-device model files
20- Minimal required configuration
21- Preferably pre-built, but a simple build process is acceptable
17- Open source platform
18- On-device model files
19- Minimal required configuration
20- Preferably pre-built, but a simple build process is acceptable
2221
23I tested a handful of apps and have summarized my favorite (so far) for
24macOS and iOS below.
22I tested a handful of apps and have summarized my favorite (so far) for macOS
23and iOS below.
2524
26> TL;DR - Here are the two that met my requirements and I have found the
27> easiest to install and use so far:
25> TL;DR - Here are the two that met my requirements and I have found the easiest
26> to install and use so far:
2827
29- macOS: [Ollama](https://ollama.ai/)
30- iOS : [LLM Farm](https://llmfarm.site/)
28- macOS: [Ollama](https://ollama.ai/)
29- iOS : [LLM Farm](https://llmfarm.site/)
3130
3231# macOS
3332
34[Ollama](https://ollama.ai/) is a simple Go application for macOS and
35Linux that can run various LLMs locally.
33[Ollama](https://ollama.ai/) is a simple Go application for macOS and Linux that
34can run various LLMs locally.
3635
3736For macOS, you can download the pplication on the [Ollama download
3837page](https://ollama.ai/download/mac) and install it by unzipping the
39`Ollama.app` file and moving it to the
40`Applications` folder.
38`Ollama.app` file and moving it to the `Applications` folder.
4139
42If you prefer the command line, you can run these commands after the
43download finished:
40If you prefer the command line, you can run these commands after the download
41finished:
4442
4543```sh
4644cd ~/Downloads && \
@@ -48,64 +46,60 @@ unzip Ollama-darwin.zip && \
4846mv ~/Downloads/Ollama.app /Applications/
4947```
5048
51After running the app, the app will ask you to open a terminal and run
52the default `llama2` model, which will open an interactive
53chat session in the terminal. You can startfully using the application
54at this point.
49After running the app, the app will ask you to open a terminal and run the
50default `llama2` model, which will open an interactive chat session in the
51terminal. You can startfully using the application at this point.
5552
5653![Ollama](https://img.cleberg.net/blog/20240113-local-llm/ollama.png)
5754
58If you don\'t want to use the default `llama2` model, you can
59download and run additional models found on the
60[Models](https://ollama.ai/library) page.
55If you don't want to use the default `llama2` model, you can download and run
56additional models found on the [Models](https://ollama.ai/library) page.
6157
62To see the information for the currently-used model, you can run the
63`/show info` command in the chat.
58To see the information for the currently-used model, you can run the `/show
59info` command in the chat.
6460
65![Model
66Info](https://img.cleberg.net/blog/20240113-local-llm/ollama_info.png)
61![Model Info](https://img.cleberg.net/blog/20240113-local-llm/ollama_info.png)
6762
6863## Community Integrations
6964
7065I highly recommend browsing the [Community
7166Integrations](https://github.com/jmorganca/ollama#community-integrations)
72section of the project to see how you would prefer to extend Ollama
73beyond a simple command-line interface. There are options for APIs,
74browser UIs, advanced terminal configurations, and more.
67section of the project to see how you would prefer to extend Ollama beyond a
68simple command-line interface. There are options for APIs, browser UIs, advanced
69terminal configurations, and more.
7570
7671![Ollama
7772SwiftUI](https://img.cleberg.net/blog/20240113-local-llm/ollama-swiftui.png)
7873
7974# iOS
8075
81While there are a handful of decent macOS options, it was quite
82difficult to find an iOS app that offered an open source platform
83without an extensive configuration and building process. I found LLM
84Farm to be decent enough in quality to sit at the top of my list -
85however, it\'s definitely not user friendly enough for me to consider
86using it on a daily basis.
76While there are a handful of decent macOS options, it was quite difficult to
77find an iOS app that offered an open source platform without an extensive
78configuration and building process. I found LLM Farm to be decent enough in
79quality to sit at the top of my list - however, it's definitely not user
80friendly enough for me to consider using it on a daily basis.
8781
88[LLM Farm](https://llmfarm.site/) is available on TestFlight, so
89there\'s no manual build process required. However, you can view the
90[LLMFarm repository](https://github.com/guinmoon/LLMFarm) if you wish.
82[LLM Farm](https://llmfarm.site/) is available on TestFlight, so there's no
83manual build process required. However, you can view the [LLMFarm
84repository](https://github.com/guinmoon/LLMFarm) if you wish.
9185
92The caveat is that you will have to manually download the model files
93from the links in the
94[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md)
95file to your iPhone to use the app - there\'s currently no option in the
96app to reach out and grab the latest version of any supported model.
86The caveat is that you will have to manually download the model files from the
87links in the
88[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md) file to
89your iPhone to use the app - there's currently no option in the app to reach
90out and grab the latest version of any supported model.
9791
98Once you have a file downloaded, you simply create a new chat and select
99the downloaded model file and ensure the inference matches the
100requirement in the `models.md` file.
92Once you have a file downloaded, you simply create a new chat and select the
93downloaded model file and ensure the inference matches the requirement in the
94`models.md` file.
10195
10296See below for a test of the ORCA Mini v3 model:
10397
104 Chat List Chat
105 ------------------------------------------------------------------------- -------------------------------------------------------------------
106 ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png)
98| Chat List | Chat |
99|-------------------------------------------------------------------------|-------------------------------------------------------------------|
100| ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) | ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png) |
107101
108[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for
109private AI models, but it requires a public-facing Ollama API, which did
110not meet my \"on device requirement.\" Nonetheless, it\'s an interesting
111looking app and I will likely set it up to test soon.
102[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for private
103AI models, but it requires a public-facing Ollama API, which did not meet my
104"on device requirement." Nonetheless, it's an interesting looking app and I
105will likely set it up to test soon.
content/blog/2024-01-26-audit-dashboard.md +96 −107
@@ -5,9 +5,9 @@ description = ""
55draft = false
66+++
77
8Alteryx and Power BI are powerful tools that can help turn your
9old-school audit trackers into interactive tools that provide useful
10insights and potential action plans.
8Alteryx and Power BI are powerful tools that can help turn your old-school audit
9trackers into interactive tools that provide useful insights and potential
10action plans.
1111
1212With these tools, we are going to build the following dashboard:
1313
@@ -18,59 +18,57 @@ With these tools, we are going to build the following dashboard:
1818
1919This project assumes the following:
2020
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
23 analysis in Power BI instead of Alteryx.
24- Your data is in a format that can be imported into Alteryx and/or
25 Power BI.
26- You have a basic understanding of data types and visualization.
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 analysis
23 in Power BI instead of Alteryx.
24- Your data is in a format that can be imported into Alteryx and/or Power BI.
25- You have a basic understanding of data types and visualization.
2726
2827# Alteryx: Data Preparation & Analysis
2928
3029## Import Data
3130
32With Alteryx, importing data is easy with the use of the
33`Input Data` tool. Simply drag this tool onto the canvas from
34the `In/Out` tab in the Ribbon to create it as a node.
31With Alteryx, importing data is easy with the use of the `Input Data` tool.
32Simply drag this tool onto the canvas from the `In/Out` tab in the Ribbon to
33create it as a node.
3534
36You can choose the File Format manually or simply connect to your
37file/database and let Alteryx determine the format for you. For this
38example, we will be importing an Excel file and changing the
39`Start Data Import on Line` variable to `2`.
35You can choose the File Format manually or simply connect to your file/database
36and let Alteryx determine the format for you. For this example, we will be
37importing an Excel file and changing the `Start Data Import on Line` variable to
38`2`.
4039
4140![Alteryx Excel
4241Import](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_import.png)
4342
4443## Transform Data
4544
46Next, let\'s replace null data and remove whitespace to clean up our
47data. We can do this with the `Data Cleansing` tool in the
48`Preparation` tab in the Ribbon.
45Next, let's replace null data and remove whitespace to clean up our data. We
46can do this with the `Data Cleansing` tool in the `Preparation` tab in the
47Ribbon.
4948
5049Ensure that the following options are enabled:
5150
52- Replace Nulls
53 - Replace with Blanks (String Fields)
54 - Replace with 0 (Numeric Fields)
55- Remove Unwanted Characters
56 - Leading and Trailing Whitespace
51- Replace Nulls
52 - Replace with Blanks (String Fields)
53 - Replace with 0 (Numeric Fields)
54- Remove Unwanted Characters
55 - Leading and Trailing Whitespace
5756
5857![Data
5958Cleansing](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_cleansing.png)
6059
61For our next step, we will transform the date fields from strings to
62datetime format. Add a `Datetime` tool for each field you
63want to transform - in the example below, I am using the tool twice for
64the \"Started On\" and \"Submitted On\" fields.
60For our next step, we will transform the date fields from strings to datetime
61format. Add a `Datetime` tool for each field you want to transform - in the
62example below, I am using the tool twice for the "Started On" and "Submitted
63On" fields.
6564
6665![Data
6766Transformation](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_transformation.png)
6867
69Now that the dates are in the correct format, let\'s perform a
70calculation based on those fields. Start by adding a `Filter`
71tool, naming a new Output Column, and pasting the formula below into it
72(the two fields used in this formula must match the output of the
73`Datetime` tools above):
68Now that the dates are in the correct format, let's perform a calculation based
69on those fields. Start by adding a `Filter` tool, naming a new Output Column,
70and pasting the formula below into it (the two fields used in this formula must
71match the output of the `Datetime` tools above):
7472
7573``` txt
7674DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days")
@@ -81,8 +79,8 @@ Analysis](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_analysis
8179
8280## Export Data
8381
84Finalize the process by exporting the transformed data set to a new
85file, for use in the following visualization step.
82Finalize the process by exporting the transformed data set to a new file, for
83use in the following visualization step.
8684
8785![Data
8886Export](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
9189
9290## Import Data
9391
94To start, open the Power BI Desktop application. Upon first use, Power
95BI will ask if you want to open an existing dashboard or import new
96data.
92To start, open the Power BI Desktop application. Upon first use, Power BI will
93ask if you want to open an existing dashboard or import new data.
9794
98As we are creating our first dashboard, let\'s import our data. In my
99example below, I\'m importing data from the \"Tracker\" sheet of the
100Excel file I\'m using for this project.
95As we are creating our first dashboard, let's import our data. In my example
96below, I'm importing data from the "Tracker" sheet of the Excel file I'm
97using for this project.
10198
102During this process, I also imported the export from the Alteryx
103workflow above. Therefore, we have two different files available for use
104in our dashboard.
99During this process, I also imported the export from the Alteryx workflow above.
100Therefore, we have two different files available for use in our dashboard.
105101
106102![Excel
107103Tracker](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
111107
112108## Add Visuals
113109
114To create the dashboard below, you will need to follow the list
115instructions below and format as needed:
110To create the dashboard below, you will need to follow the list instructions
111below and format as needed:
116112
117113![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_01.png)
118114![](https://img.cleberg.net/blog/20240126-audit-dashboard/dashboard_02.png)
119115
120116Instructions to create the visuals above:
121117
122- `Text Box`: Explain the name and purpose of the
123 dashboard. You can also add images and logos at the top of the
124 dashboard.
125- `Donut Chart`: Overall status of the project.
126 - `Legend`: Status
127 - `Values`: Count of Status
128- `Stacked Column Chart`: Task count by assignee.
129 - `X-axis`: Preparer
130 - `Y-axis`: Count of Control ID
131 - `Legend`: Status
132- `Treemap`: Top N client submitters by average days to
133 submit.
134 - `Details`: Preparer
135 - `Values`: Sum of Avg~DaysToSubmit~
136- `Line Chart`: Projected vs. actual hours over time.
137- `Clustered Bar Chart`: Projected vs. actual hours per
138 person.
139- `Slicer & Table` - Upcoming due dates.
140 - `Slicer`:
141 - `Values`: Date Due
142 - `Table`:
143 - `Columns`: Count of Control ID, Date Due,
144 Preparer, Status
118- `Text Box`: Explain the name and purpose of the dashboard. You can also add
119 images and logos at the top of the dashboard.
120- `Donut Chart`: Overall status of the project.
121 - `Legend`: Status
122 - `Values`: Count of Status
123- `Stacked Column Chart`: Task count by assignee.
124 - `X-axis`: Preparer
125 - `Y-axis`: Count of Control ID
126 - `Legend`: Status
127- `Treemap`: Top N client submitters by average days to submit.
128 - `Details`: Preparer
129 - `Values`: Sum of Avg~DaysToSubmit~
130- `Line Chart`: Projected vs. actual hours over time.
131- `Clustered Bar Chart`: Projected vs. actual hours per person.
132- `Slicer & Table` - Upcoming due dates.
133 - `Slicer`:
134 - `Values`: Date Due
135 - `Table`:
136 - `Columns`: Count of Control ID, Date Due, Preparer, Status
145137
146138## Format the Dashboard
147139
148You can choose a theme in the View tab of the Ribbon. You can even
149browse for custom JSON files that define themes, such as ones found
150online or custom ones created by your organization.
151
152For each visual, you can click the `Format` button in the
153`Visualizations` side pane and explore the options. You can
154custom options such as:
155
156- Visual
157 - Legend
158 - Colors
159 - Data labels
160 - Category labels
161- General
162 - Properties
163 - Title
164 - Effects
165 - Header icons
166 - Tooltips
167 - Alt text
168
169You can always look online for inspiration when trying to decide how
170best to organize and style your dashboard.
140You can choose a theme in the View tab of the Ribbon. You can even browse for
141custom JSON files that define themes, such as ones found online or custom ones
142created by your organization.
143
144For each visual, you can click the `Format` button in the `Visualizations` side
145pane and explore the options. You can custom options such as:
146
147- Visual
148 - Legend
149 - Colors
150 - Data labels
151 - Category labels
152- General
153 - Properties
154 - Title
155 - Effects
156 - Header icons
157 - Tooltips
158 - Alt text
159
160You can always look online for inspiration when trying to decide how best to
161organize and style your dashboard.
171162
172163# Sharing the Results
173164
174Generally, you have a few different options for sharing your dashboards
175with others:
176
1771. Export the dashboard as a PDF in the file menu of Power BI. This
178 will export all tabs and visuals as they are set when the export
179 button is pressed. You will lose all interactivity with this option.
1802. Send the full Power BI file to those you wish to share the
181 dashboard. This will retain all settings and interactivity. However,
182 you will also need to send the source files if they need to refresh
183 the dashboard and you will need to re-send the files if you make
184 updates.
1853. Store the dashboard in a synced location, such as a shared drive or
186 Microsoft Teams. Depending on how a user configures their local
187 Windows paths, the data source paths may not be compatible for all
188 users with such a setup.
165Generally, you have a few different options for sharing your dashboards with
166others:
167
1681. Export the dashboard as a PDF in the file menu of Power BI. This will export
169 all tabs and visuals as they are set when the export button is pressed. You
170 will lose all interactivity with this option.
1712. Send the full Power BI file to those you wish to share the dashboard. This
172 will retain all settings and interactivity. However, you will also need to
173 send the source files if they need to refresh the dashboard and you will need
174 to re-send the files if you make updates.
1753. Store the dashboard in a synced location, such as a shared drive or Microsoft
176 Teams. Depending on how a user configures their local Windows paths, the data
177 source paths may not be compatible for all users with such a setup.
content/blog/2024-01-27-tableau-dashboard.md +48 −51
@@ -5,12 +5,12 @@ description = ""
55draft = false
66+++
77
8In this project, I am going to show you how to use Tableau Public for
9free to create simple dashboards.
8In this project, I am going to show you how to use Tableau Public for free to
9create simple dashboards.
1010
11I will be creating simple visuals from an Omaha crime data set and
12combining them to create the dashboard below. You can view this
13dashboard interactively online here: [Omaha Crime Data (2015 -
11I will be creating simple visuals from an Omaha crime data set and combining
12them to create the dashboard below. You can view this dashboard interactively
13online here: [Omaha Crime Data (2015 -
14142023)](https://public.tableau.com/app/profile/c.c7042/viz/OmahaCrimeData2015-2023/OmahaCrimeData2015-2023#1).
1515
1616![Tableau
@@ -27,10 +27,10 @@ Each file will be downloaded as a CSV file, approximately 3 MB - 8 MB.
2727
2828# Clean and Transform the Data
2929
30I have used Python to combine the files into a single CSV file, as well
31as adding a custom `datetime` column. You could do this step
32in any software you prefer, but I prefer Python as its free, easy to
33use, and has a plethora of support resources online.
30I have used Python to combine the files into a single CSV file, as well as
31adding a custom `datetime` column. You could do this step in any software you
32prefer, but I prefer Python as its free, easy to use, and has a plethora of
33support resources online.
3434
3535Start by opening a terminal, navigating to your Downloads directory, and
3636creating a python script.
@@ -77,90 +77,87 @@ Once pasted, save and close the file. You can execute the file like so:
7777python3 data_processing.py
7878```
7979
80After this, you should have a combined data file that contains all
81incidents between 2015 and 2023. Mine was approximately 55 MB.
80After this, you should have a combined data file that contains all incidents
81between 2015 and 2023. Mine was approximately 55 MB.
8282
8383# Tableau Public
8484
85[Tableau Public](https://public.tableau.com/) is a free-to-use web
86application that allows you to create visualizations by uploading data
87sources. Note that there\'s no way to keep the data and visualizations
88private, so don\'t upload anything private.
85[Tableau Public](https://public.tableau.com/) is a free-to-use web application
86that allows you to create visualizations by uploading data sources. Note that
87there's no way to keep the data and visualizations private, so don't upload
88anything private.
8989
90After creating an account, you can click the `Create` \>
91`Web Authoring` link to create your first visualization.
90After creating an account, you can click the `Create` > `Web Authoring` link to
91create your first visualization.
9292
9393![Create
9494Button](https://img.cleberg.net/blog/20240127-tableau-dashboard/create_button.png)
9595
9696## Upload the Data
9797
98Once you\'ve opened your first project, Tableau will ask you to connect
99to your data. For this project, click the
100`Upload from computer` button and select the CSV file
101previously combined in the step above.
98Once you've opened your first project, Tableau will ask you to connect to your
99data. For this project, click the `Upload from computer` button and select the
100CSV file previously combined in the step above.
102101
103102![Connect
104103Data](https://img.cleberg.net/blog/20240127-tableau-dashboard/connect_data.png)
105104
106Once connected, you can refresh the preview of the data with the
107`Refresh Data Source` button in the toolbar.
105Once connected, you can refresh the preview of the data with the `Refresh Data
106Source` button in the toolbar.
108107
109108![Data
110109Preview](https://img.cleberg.net/blog/20240127-tableau-dashboard/data_preview.png)
111110
112If you need to edit any of the data types, column names, etc., you can
113do so now. Once complete, generate an extract so that you can start
114creating visualizations.
111If you need to edit any of the data types, column names, etc., you can do so
112now. Once complete, generate an extract so that you can start creating
113visualizations.
115114
116115## Create Visualizations
117116
118117To start, create a worksheet in the toolbar at the bottom of the screen.
119118
120Within this screen, select a column from the `Data` side bar
121on the left and drag it into the `Columns` or
122`Rows` area of the canvas.
119Within this screen, select a column from the `Data` side bar on the left and
120drag it into the `Columns` or `Rows` area of the canvas.
123121
124122See below for the map visualization. You can recreate this by adding the
125123following fields:
126124
127- `Columns`: Lon
128- `Rows`: Lat
129- `Marks`:
130 - Description
131 - Datetime
132- `Filters`: Datetime
125- `Columns`: Lon
126- `Rows`: Lat
127- `Marks`:
128 - Description
129 - Datetime
130- `Filters`: Datetime
133131
134132![Worksheet
135133Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/worksheet_edit.png)
136134
137You can repeat this process for each visualization you want to create.
138Explore your options by dragging data fields to different areas and by
139opening the field options to explore what operations can be performed on
140different data types (e.g., average, count, etc.).
135You can repeat this process for each visualization you want to create. Explore
136your options by dragging data fields to different areas and by opening the field
137options to explore what operations can be performed on different data types
138(e.g., average, count, etc.).
141139
142140## Create Dashboard
143141
144To create a dashboard, click the button on the toolbar at the bottom of
145the screen. Within the dashboard, drag each sheet from the left side bar
146onto the dashboard canvas.
142To create a dashboard, click the button on the toolbar at the bottom of the
143screen. Within the dashboard, drag each sheet from the left side bar onto the
144dashboard canvas.
147145
148146![Dashboard
149147Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard_edit.png)
150148
151149## Formatting
152150
153You can explore a ton of different formatting options throughout the
154worksheets and dashboard. Specifically for maps, you can alter the map
155layers, background, and visible features through the `Map`
156menu in the top file menu of the editing screen.
151You can explore a ton of different formatting options throughout the worksheets
152and dashboard. Specifically for maps, you can alter the map layers, background,
153and visible features through the `Map` menu in the top file menu of the editing
154screen.
157155
158In the finished dashboard below, I opted for a dark mode with a map that
159showed county lines and city names.
156In the finished dashboard below, I opted for a dark mode with a map that showed
157county lines and city names.
160158
161There\'s a ton of other options available to be used in a dashboard like
162this, but this project shows a quick preview of what you can do in
163Tableau Public.
159There's a ton of other options available to be used in a dashboard like this,
160but this project shows a quick preview of what you can do in Tableau Public.
164161
165162![Tableau
166163Dashboard](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
88This post details the process I used to create ZFS pools, datasets, and
99snapshots on Ubuntu Server.
1010
11I found the following pages very helpful while going through this
12process:
11I found the following pages very helpful while going through this process:
1312
14- [Setup a ZFS storage
15 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool)
16- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS)
17- [ZFS for
18 Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/)
13- [Setup a ZFS storage
14 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool)
15- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS)
16- [ZFS for Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/)
1917
2018# Installation
2119
@@ -25,8 +23,7 @@ To start, I installed the ZFS package with the following command:
2523sudo apt install zfsutils-linux
2624```
2725
28Once installed, you can check the version to see if it installed
29correctly.
26Once installed, you can check the version to see if it installed correctly.
3027
3128```sh
3229> zsf --version
@@ -39,32 +36,32 @@ zfs-kmod-2.1.5-1ubuntu6~22.04.1
3936
4037Now that ZFS is installed, we can create and configure the pool.
4138
42You have various options for configuring ZFS pools that all come
43different pros and cons. I suggest visiting the links at the top of this
44post or searching online for the best configuration for your use-case.
39You have various options for configuring ZFS pools that all come different pros
40and cons. I suggest visiting the links at the top of this post or searching
41online for the best configuration for your use-case.
4542
46- Striped VDEVs (Raid0)
47- Mirrored VDEVs (Raid1)
48- Striped Mirrored VDEVs (Raid10)
49- RAIDz (Raid5)
50- RAIDz2 (Raidd6)
51- RAIDz3
52- Nested RAIDz (Raid50, Raid60)
43- Striped VDEVs (Raid0)
44- Mirrored VDEVs (Raid1)
45- Striped Mirrored VDEVs (Raid10)
46- RAIDz (Raid5)
47- RAIDz2 (Raidd6)
48- RAIDz3
49- Nested RAIDz (Raid50, Raid60)
5350
54I will be using Raid10 in this guide. However, the majority of the steps
55are the same regardless of your chosen pool configuration.
51I will be using Raid10 in this guide. However, the majority of the steps are the
52same regardless of your chosen pool configuration.
5653
5754## Creating the Pool
5855
59To start, let\'s list the disks available to use. You can use
60`fdisk` command to see all available disks.
56To start, let's list the disks available to use. You can use `fdisk` command to
57see all available disks.
6158
6259```sh
6360sudo fdisk -l
6461```
6562
66Or, if you currently have them mounted, you can use the `df`
67command to view your disks.
63Or, if you currently have them mounted, you can use the `df` command to view
64your disks.
6865
6966```sh
7067> sudo df -h
@@ -79,24 +76,23 @@ Filesystem Size Used Avail Use% Mounted on
7976/dev/sdf1 7.3T 28K 6.9T 1% /mnt/red-04
8077```
8178
82If you\'re going to use mounted disks, make sure to umount them before
83creating the pool.
79If you're going to use mounted disks, make sure to umount them before creating
80the pool.
8481
8582```sh
8683sudo umount /dev/sda1
8784sudo umount /dev/sdb1
8885```
8986
90Now that I\'ve identified the disks I want to use and have them
91unmounted, let\'s create the pool. For this example, I will call it
92`tank`.
87Now that I've identified the disks I want to use and have them unmounted,
88let's create the pool. For this example, I will call it `tank`.
9389
9490```sh
9591sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb
9692```
9793
98See below for the results of the new ZFS pool named `tank`,
99with a vdev automatically named `mirror-0`.
94See below for the results of the new ZFS pool named `tank`, with a vdev
95automatically named `mirror-0`.
10096
10197```sh
10298> zfs list
@@ -121,8 +117,8 @@ config:
121117errors: No known data errors
122118```
123119
124We can also look at the mounted filesystem to see where the pool is
125mounted and some quick stats.
120We can also look at the mounted filesystem to see where the pool is mounted and
121some quick stats.
126122
127123```sh
128124> df -h
@@ -134,28 +130,25 @@ tank 7.2T 128K 7.2T 1% /tank
134130
135131## Expanding the Pool
136132
137If you want to expand this pool, you will need to add a new VDEV to the
138pool. Since I am using 2 disks per VDEV, I will need to add a new 2-disk
139VDEV to the existing `tank` pool.
133If you want to expand this pool, you will need to add a new VDEV to the pool.
134Since I am using 2 disks per VDEV, I will need to add a new 2-disk VDEV to the
135existing `tank` pool.
140136
141137```sh
142138sudo zpool add tank mirror /dev/sdX /dev/sdY
143139```
144140
145If you\'re adding disks of different sizes, you\'ll need to use the
146`-f` flag. Keep in mind that the max size will be limited to
147the smallest disk added.
141If you're adding disks of different sizes, you'll need to use the `-f` flag.
142Keep in mind that the max size will be limited to the smallest disk added.
148143
149144```sh
150145sudo zpool add -f tank mirror /dev/sdX /dev/sdY
151146```
152147
153I added two 8TB hard drives and this process took around 10 seconds to
154complete.
148I added two 8TB hard drives and this process took around 10 seconds to complete.
155149
156When viewing the pool again, you can see that the pool has now doubled
157in size. We have 14.3 TB useable space and the same space used for
158mirroring.
150When viewing the pool again, you can see that the pool has now doubled in size.
151We have 14.3 TB useable space and the same space used for mirroring.
159152
160153```sh
161154> zfs list
@@ -168,8 +161,8 @@ tank/media 96K 14.3T 96K /tank/media
168161
169162### Converting Disks
170163
171Some disks, such as NTFS-formatted drives, will need to be partitioned
172and formatted prior to being added to the pool.
164Some disks, such as NTFS-formatted drives, will need to be partitioned and
165formatted prior to being added to the pool.
173166
174167Start by identifying the disks you want to format and add to the pool.
175168
@@ -177,18 +170,16 @@ Start by identifying the disks you want to format and add to the pool.
177170sudo fdisk -l | grep /dev
178171```
179172
180I am going to format my `/dev/sdc` and `/dev/sdd`
181disks with the `fdisk` command.
173I am going to format my `/dev/sdc` and `/dev/sdd` disks with the `fdisk`
174command.
182175
183See below for instructions on how to use `fdisk`. Here\'s
184what I did to create basic Linux formatted disks:
176See below for instructions on how to use `fdisk`. Here's what I did to create
177basic Linux formatted disks:
185178
186- `g` : Create GPT partition table
187- `n` : Create a new partition, hit Enter for all default
188 options
189- `t` : Change partition type to `20` for
190 `Linux filesystem`
191- `w` : Write the changes to disk and exit
179- `g` : Create GPT partition table
180- `n` : Create a new partition, hit Enter for all default options
181- `t` : Change partition type to `20` for `Linux filesystem`
182- `w` : Write the changes to disk and exit
192183
193184I repeated this process for both disks.
194185
@@ -247,9 +238,9 @@ sudo zpool add tank mirror /dev/sdc /dev/sdd
247238```
248239
249240When 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
251shown with `fdisk -l`, with a Raid10 configuration using 22TB
252for mirroring and 22TB of useable space.
241approximately 22TB. This represents my hard drives totalling 45.6TB when shown
242with `fdisk -l`, with a Raid10 configuration using 22TB for mirroring and 22TB
243of useable space.
253244
254245```sh
255246> zfs list
@@ -263,24 +254,22 @@ tank/media 145GT 21.7T 96K /tank/media
263254## Creating Datasets
264255
265256According to [ZFS
266Terminology](https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html),
267a `dataset` can refer to "clones, file systems, snapshots,
268and volumes.
257Terminology](https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html), a
258`dataset` can refer to "clones, file systems, snapshots, and volumes.
269259
270For this guide, I will use the `dataset` term to refer to
271file systems created under a pool.
260For this guide, I will use the `dataset` term to refer to file systems created
261under a pool.
272262
273Within my `tank` pool, I am going to create some datasets to
274help organize my files. This will give me location to store data rather
275than simply dumping everything at the `/tank/` location.
263Within my `tank` pool, I am going to create some datasets to help organize my
264files. This will give me location to store data rather than simply dumping
265everything at the `/tank/` location.
276266
277267```sh
278268sudo zfs create tank/cloud
279269sudo zfs create tank/media
280270```
281271
282Once created, you can see these datasets in the output of your pool
283list:
272Once created, you can see these datasets in the output of your pool list:
284273
285274```sh
286275> zfs list
@@ -292,9 +281,9 @@ tank/media 96K 7.14T 96K /tank/media
292281
293282## Creating Snapshots
294283
295Next, let\'s create our first snapshot. We can do this by calling the
296`snapshot` command and give it an output name. I will be
297throwing the current date and time into my example.
284Next, let's create our first snapshot. We can do this by calling the `snapshot`
285command and give it an output name. I will be throwing the current date and time
286into my example.
298287
299288```sh
300289sudo zfs snapshot tank@$(date '+%Y-%m-%d_%H-%M')
@@ -325,13 +314,10 @@ no datasets available
325314
326315# My Thoughts on ZFS So Far
327316
328- I sacrificed 25TB to be able to mirror my data, but I feel more
329 comfortable with the potential to save my data by quickly replacing
330 a disk if I need to.
331- The set-up was surprisingly easy and fast.
332- Disk I/O is fast as well. I was worried that the data transfer
333 speeds would be slower due to the RAID configuration.
334- Media streaming and transcoding has seen no noticeable drop in
335 performance.
336- My only limitation really is the number of HDD bays in my server HDD
337 cage.
317- I sacrificed 25TB to be able to mirror my data, but I feel more comfortable
318 with the potential to save my data by quickly replacing a disk if I need to.
319- 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
321 slower due to the RAID configuration.
322- Media streaming and transcoding has seen no noticeable drop in performance.
323- My only limitation really is the number of HDD bays in my server HDD cage.
content/blog/2024-02-13-ubuntu-emergency-mode.md +23 −26
@@ -7,12 +7,12 @@ draft = false
77
88# The Problem
99
10I recently [migrated my hard drives to a ZFS pool](../zfs/) and found
11myself stuck in Ubuntu\'s emergency mode after the first reboot I
12performed after creating the ZFS pool.
10I recently [migrated my hard drives to a ZFS pool](../zfs/) and found myself
11stuck in Ubuntu's emergency mode after the first reboot I performed after
12creating the ZFS pool.
1313
14My server was stuck in the boot process and showed the following error
15on the screen:
14My server was stuck in the boot process and showed the following error on the
15screen:
1616
1717``` txt
1818You are in emergency mode.
@@ -21,34 +21,33 @@ After logging in, type "journalctl -xb" to view system logs,
2121or ^D to try again to boot into default mode".
2222```
2323
24After rebooting the server and watching the logs scroll on a monitor, I
25noticed the root cause was related to a very long search for certain
26drives. I kept seeing errors like this:
24After rebooting the server and watching the logs scroll on a monitor, I noticed
25the root cause was related to a very long search for certain drives. I kept
26seeing errors like this:
2727
2828``` txt
2929[ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid]
3030```
3131
32I realized that I had not removed the `/etc/fstab` references
33that asked Ubuntu to mount two disks on boot, but I had recently changed
34those disks to be part of my ZFS pool instead. Therefore, Ubuntu was
35trying to identify and mount a disk that was not available.
32I realized that I had not removed the `/etc/fstab` references that asked Ubuntu
33to mount two disks on boot, but I had recently changed those disks to be part of
34my ZFS pool instead. Therefore, Ubuntu was trying to identify and mount a disk
35that was not available.
3636
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.
3838
3939# The Solution
4040
41In order to fix the issue, I waited until I was allowed to type the root
42user\'s password, and then I executed the following command:
41In order to fix the issue, I waited until I was allowed to type the root user's
42password, and then I executed the following command:
4343
4444```sh
4545nano /etc/fstab
4646```
4747
48Within the `fstab` file, I needed to comment/remove the
49following lines at the bottom of the file. You can comment-out a line by
50prepending a `#` symbol at the beginning of the line. You can
51also delete the line entirely.
48Within the `fstab` file, I needed to comment/remove the following lines at the
49bottom of the file. You can comment-out a line by prepending a `#` symbol at the
50beginning of the line. You can also delete the line entirely.
5251
5352``` conf
5453# 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
6059# UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0
6160```
6261
63Once removing the lines above from the `/etc/fstab` file,
64save and exit the file by hitting the `Ctrl` + `x`
65key combo.
62Once removing the lines above from the `/etc/fstab` file, save and exit the file
63by hitting the `Ctrl` + `x` key combo.
6664
67You can now hit `Ctrl` + `D` to continue, or
68reboot:
65You can now hit `Ctrl` + `D` to continue, or reboot:
6966
7067```sh
7168systemctl reboot
7269```
7370
74Once rebooted, I was able to watch the machine boot properly and launch
75to the TTY login screen without errors!
71Once rebooted, I was able to watch the machine boot properly and launch to the
72TTY login screen without errors!
content/blog/2024-02-21-self-hosting-otter-wiki.md +27 −31
@@ -7,33 +7,32 @@ draft = false
77
88# An Otter Wiki
99
10[An Otter Wiki](https://otterwiki.com/) is an easy to use wiki software
11that takes almost no effort to set up and maintain.
10[An Otter Wiki](https://otterwiki.com/) is an easy to use wiki software that
11takes almost no effort to set up and maintain.
1212
1313# Installation
1414
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
17via a subdomain I own.
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 via a
17subdomain I own.
1818
1919## Docker Compose
2020
21Start by creating a directory for the container\'s files.
21Start by creating a directory for the container's files.
2222
2323```sh
2424mkdir ~/otterwiki
2525```
2626
27Next, create the `docker-compose.yml` file to define the
28container\'s parameters.
27Next, create the `docker-compose.yml` file to define the container's
28parameters.
2929
3030```sh
3131nano ~/otterwiki/docker-compose.yml
3232```
3333
34Within the file, paste the following content. You can read the
35project\'s documentation if you want to further override or customize
36the container.
34Within the file, paste the following content. You can read the project's
35documentation if you want to further override or customize the container.
3736
3837``` conf
3938version: '3'
@@ -56,23 +55,22 @@ cd ~/otterwiki
5655sudo docker-compose up -d
5756```
5857
59The container is now available at `localhost:8337`. Next, we
60will use Nginx to serve this app externally.
58The container is now available at `localhost:8337`. Next, we will use Nginx to
59serve this app externally.
6160
6261## Nginx
6362
64To access the app externally, let\'s set up a reverse proxy. I\'ll start
65by creating the Nginx configuration file for my wiki.
63To access the app externally, let's set up a reverse proxy. I'll start by
64creating the Nginx configuration file for my wiki.
6665
6766```sh
6867sudo nano /etc/nginx/sites-available/wiki
6968```
7069
71Within the file, I have saved the following content. This assumes you
72already have a TLS/SSL cert to use with this subdomain. If not, simply
73remove the `ssl_*` variables, remove the `80`
74server block, and change the `443` server block to
75`80` to serve the app without SSL.
70Within the file, I have saved the following content. This assumes you already
71have a TLS/SSL cert to use with this subdomain. If not, simply remove the
72`ssl_*` variables, remove the `80` server block, and change the `443` server
73block to `80` to serve the app without SSL.
7674
7775``` conf
7876server {
@@ -110,15 +108,14 @@ server {
110108}
111109```
112110
113Save and close the configuration file. On Nginx, we need to symlink the
114file to enable it.
111Save and close the configuration file. On Nginx, we need to symlink the file to
112enable it.
115113
116114```sh
117115sudo ln -s /etc/nginx/sites-available/wiki /etc/nginx/sites-enabled/wiki
118116```
119117
120Once enabled, restart the Nginx server to start serving the app
121externally.
118Once enabled, restart the Nginx server to start serving the app externally.
122119
123120```sh
124121sudo systemctl restart nginx.service
@@ -126,18 +123,17 @@ sudo systemctl restart nginx.service
126123
127124# Screenshots
128125
129In the screenshot below, you can see the initial launch screen for An
130Otter Wiki. Start by creating your admin account and configure the app
131as necessary.
126In the screenshot below, you can see the initial launch screen for An Otter
127Wiki. Start by creating your admin account and configure the app as necessary.
132128
133129![An Otter Wiki - Initial
134130Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki.png)
135131
136You can also see the default editing screen for creating and editing
137pages. It\'s as easy as typing Markdown and hitting the save button.
132You can also see the default editing screen for creating and editing pages.
133It's as easy as typing Markdown and hitting the save button.
138134
139135![An Otter Wiki - Editing
140136Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki-edit.png)
141137
142Overall, I like An Otter Wiki and will be looking forward to seeing how
143much use I get out of it going forward.
138Overall, I like An Otter Wiki and will be looking forward to seeing how much use
139I get out of it going forward.
content/blog/2024-03-13-doom-emacs.md +134 −153
@@ -7,12 +7,11 @@ draft = false
77
88## Screenshots
99
10These screenshots are showing a project opened with projectile, a
11treemacs side pane open with the project contents, multiple buffers
12tiled next to each other, and the help pane open at the bottomm.
10These screenshots are showing a project opened with projectile, a treemacs side
11pane open with the project contents, multiple buffers tiled next to each other,
12and the help pane open at the bottomm.
1313
14The themes are `doom-homage-white` and
15`doom-homage-black`.
14The themes are `doom-homage-white` and `doom-homage-black`.
1615
1716![Doom Emacs Light
1817Mode](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)
2423
2524I have been switching back and forth between
2625[markdown](https://en.wikipedia.org/wiki/Markdown) and
27[org-mode](https://en.wikipedia.org/wiki/Org-mode) recently for my
28personal note taking, wiki, and even this blog. As a result, I have been
29stumbling further into the world of Emacs and found myself at a point
30where I now prefer to do most of my basic editing within Emacs.
31
32I\'ll leave the markdown vs. org-mode debate for another post, but I
33love org-mode\'s extensibility and interactive nature within Emacs, but
34it becomes very unwieldy in any other client implementation of
35org-mode - especially on iOS. On the flip side, markdown is limited in
36functionality and fractured into different standards, but it\'s simple
37and popular enough that there are a plethora of great clients to choose
38from that will get the job done.
39
40For now, I want to focus on how I have been using Emacs and some of the
41things that would have helped me learn it faster had I known where to
42start.
26[org-mode](https://en.wikipedia.org/wiki/Org-mode) recently for my personal note
27taking, wiki, and even this blog. As a result, I have been stumbling further
28into the world of Emacs and found myself at a point where I now prefer to do
29most of my basic editing within Emacs.
30
31I'll leave the markdown vs. org-mode debate for another post, but I love
32org-mode's extensibility and interactive nature within Emacs, but it becomes
33very unwieldy in any other client implementation of org-mode - especially on
34iOS. On the flip side, markdown is limited in functionality and fractured into
35different standards, but it's simple and popular enough that there are a
36plethora of great clients to choose from that will get the job done.
37
38For now, I want to focus on how I have been using Emacs and some of the things
39that would have helped me learn it faster had I known where to start.
4340
4441### Installation
4542
46This post focuses on [Doom
47Emacs](https://github.com/doomemacs/doomemacs), which is an Emacs
48framework that provides an alternative experience to the vanilla [GNU
49Emacs](https://www.gnu.org/software/emacs/).
43This post focuses on [Doom Emacs](https://github.com/doomemacs/doomemacs), which
44is an Emacs framework that provides an alternative experience to the vanilla
45[GNU Emacs](https://www.gnu.org/software/emacs/).
5046
5147The [Getting Start
5248Guide](https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org)
53has an extremely detailed walkthrough of installation for all systems,
54so please refer to that guide for up-to-date instructions.
49has an extremely detailed walkthrough of installation for all systems, so please
50refer to that guide for up-to-date instructions.
5551
5652I chose to install on macOS, using the Homebrew option with the
5753`railwaycat/emacsmacport` version of Emacs.
5854
59Once the program is installed, you can run the program by typing
60`emacs` in a terminal. If you installed a version of Emacs
61that supports both a GUI and TUI, you will have to run
62`emacs -nw` to get the TUI instead of the default GUI.
55Once the program is installed, you can run the program by typing `emacs` in a
56terminal. If you installed a version of Emacs that supports both a GUI and TUI,
57you will have to run `emacs -nw` to get the TUI instead of the default GUI.
6358
6459### Configuration
6560
@@ -68,13 +63,13 @@ Once installed, you can configure Doom by editing the files within the
6863
69641. `config.el` - Personal configuration file
70652. `custom.el` - Custom set variables
713. `init.el` - Doom modules and load order, must run
72 `doom sync` after modifying
734. `packages.el` - Declare packages to install in this file,
74 then run `doom sync` to install
663. `init.el` - Doom modules and load order, must run `doom sync` after
67 modifying
684. `packages.el` - Declare packages to install in this file, then run `doom
69 sync` to install
7570
76I only needed a few customizations for my configuration, so I\'ll list
77them below.
71I only needed a few customizations for my configuration, so I'll list them
72below.
7873
7974```lisp
8075;; ~/.doom.d/config.el
@@ -148,140 +143,127 @@ them below.
148143 (default +bindings +smartparens))
149144```
150145
151If you\'re editing these files within Doom directly, remember to run
152`SPC h r r` to reload the configuration. Also remember to run
153`doom sync` for any changes to the `init.el` or
154`packages.el` files.
146If you're editing these files within Doom directly, remember to run `SPC h r r`
147to reload the configuration. Also remember to run `doom sync` for any changes to
148the `init.el` or `packages.el` files.
155149
156150## Basic Functionality
157151
158I kept a cheat sheet note open at first with all of the basic functions
159typed out, copied as I went through the tutorial. After a little while,
160I no longer needed it. I highly recommend writing down the most
161applicable shortcuts for your preferred functionality and refer back to
162it until you\'ve memorized it.
163
164Memorizing the shortcuts will differ based on the type of Emacs
165framework being used. Personally, migrating from vanilla Emacs to Doom
166Emacs simplified everything by a large factor and instantly enabled me
167to start working on my projects, eliminating most of the hurdles I was
168running into. The vanilla emacs hotkeys became obnoxious and I actually
169stopped using Emacs entirely for about a month before trying Doom.
170
171For me, the first logical step is to interact with the local filesystem.
172To do this, I needed to know how to open directories, open files, save
173files, discard changes, close files, and switch between open files. Here
174are some example shortcuts I\'ve written down in order to accomplish
175file-based actions.
176
177 Doom Hotkey Emacs Hotkey Description
178 ---------------------------- --------------------------- ----------------------------------------
179 `SPC :` `C-x` Run functions
180 `SPC f f` `C-x f` Open file in buffer
181 `SPC f d` `C-x d` Open directory with `dired`
182 `i` `C-x C-q` Edit current buffer (insert mode)
183 `q` `C-x C-q` Quit out of insert mode
184 `SPC f s` `C-x s` Save current buffer
185 `SPC b k` `C-x k` Kill current buffer
186 `SPC w h/j/k/l` `C-x o`\[^1^\] Move left/down/up/right to next buffer
187
188\[^1^\] Doom\'s evil-window functionality is a bit different from GNU
189Emacs, but you can always switch to the \"other\" buffer with
190`C-x o` or `C-x b` to get a list of buffers to
191select.
192
193In general, when in Doom, you can press `SPC` and wait a
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.
152I kept a cheat sheet note open at first with all of the basic functions typed
153out, copied as I went through the tutorial. After a little while, I no longer
154needed it. I highly recommend writing down the most applicable shortcuts for
155your preferred functionality and refer back to it until you've memorized it.
156
157Memorizing the shortcuts will differ based on the type of Emacs framework being
158used. Personally, migrating from vanilla Emacs to Doom Emacs simplified
159everything by a large factor and instantly enabled me to start working on my
160projects, eliminating most of the hurdles I was running into. The vanilla emacs
161hotkeys became obnoxious and I actually stopped using Emacs entirely for about a
162month before trying Doom.
163
164For me, the first logical step is to interact with the local filesystem. To do
165this, I needed to know how to open directories, open files, save files, discard
166changes, close files, and switch between open files. Here are some example
167shortcuts I've written down in order to accomplish file-based actions.
168
169| Doom Hotkey | Emacs Hotkey | Description |
170|-----------------|--------------|----------------------------------------|
171| `SPC :` | `C-x` | Run functions |
172| `SPC f f` | `C-x f` | Open file in buffer |
173| `SPC f d` | `C-x d` | Open directory with `dired` |
174| `i` | `C-x C-q` | Edit current buffer (insert mode) |
175| `q` | `C-x C-q` | Quit out of insert mode |
176| `SPC f s` | `C-x s` | Save current buffer |
177| `SPC b k` | `C-x k` | Kill current buffer |
178| `SPC w h/j/k/l` | `C-x o`[^1] | Move left/down/up/right to next buffer |
179
180[^1]: Doom's evil-window functionality is a bit different from GNU Emacs, but
181you can always switch to the "other" buffer with `C-x o` or `C-x b` to get a
182list of buffers to select.
183
184In general, when in Doom, you can press `SPC` and wait a second for the help
185pane to appear with all available hotkey options. For example, you can press
186`SPC`, wait for the help pane, and then select a key such as `g` to enter the
187git help pane and explore further command options.
198188
199189## Editing
200190
201Next in my process is to dive into editing for any languages I\'m
202currently using. In this post, I will just cover Markdown and Org-Mode
203but I have also been slowly adoping some Python and general web dev
204tools as well.
191Next in my process is to dive into editing for any languages I'm currently
192using. In this post, I will just cover Markdown and Org-Mode but I have also
193been slowly adoping some Python and general web dev tools as well.
205194
206195### Markdown
207196
208197![Markdown
209198Preview](https://img.cleberg.net/blog/20240314-doom-emacs/markdown.png)
210199
211Markdown is fairly simple as the syntax is limited, so just make sure
212the `~/.doom.d/init.el` includes the `markdown`
213declaration in the `:lang` section.
200Markdown is fairly simple as the syntax is limited, so just make sure the
201`~/.doom.d/init.el` includes the `markdown` declaration in the `:lang` section.
214202
215This package includes the following hotkey menus. The insert and toggle
216menu expands further, allowing you to insert various markdown elements
217and toggle things like link hiding.
203This package includes the following hotkey menus. The insert and toggle menu
204expands further, allowing you to insert various markdown elements and toggle
205things like link hiding.
218206
219 Doom Hotkey Function
220 ----------------------------------------- --------------------------
221 `SPC m '` markdown-edit-code-block
222 `SPC m e` markdown-export
223 `SPC m i` +insert
224 `SPC m o` markdown-open
225 `SPC m p` markdown-preview
226 `SPC m t` +toggle
227 `SPC : markdown-table-align` markdown-table-align
207| Doom Hotkey | Function |
208|------------------------------|--------------------------|
209| `SPC m '` | markdown-edit-code-block |
210| `SPC m e` | markdown-export |
211| `SPC m i` | +insert |
212| `SPC m o` | markdown-open |
213| `SPC m p` | markdown-preview |
214| `SPC m t` | +toggle |
215| `SPC : markdown-table-align` | markdown-table-align |
228216
229217### Org-Mode
230218
231![Org-Mode
232Preview](https://img.cleberg.net/blog/20240314-doom-emacs/org.png)
233
234Similar to the markdown section above, ensure that the
235`~/.doom.d/init.el` includes the `org` declaration
236in the `:lang` section.
237
238There are a few hot keys, but a quick search with `SPC : org`
239shows that there are 865 possible org-related functions you can run. I
240won\'t possibly be able to list them all, so I will simply cover a few
241of the basic commands I use myself.
242
243 Doom Hotkey Function
244 --------------------------- ---------------------------------------
245 `SPC m t` org-todo
246 `SPC n t` org-todo-list
247 `SPC o A` org-agenda
248 `SPC X` org-capture
249 `SPC m p p` org-priority
250 `SPC m d s` org-schedule
251 `TAB` org-cycle
252 `SHIFT TAB` Collapse/open all headings in buffer
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
219![Org-Mode Preview](https://img.cleberg.net/blog/20240314-doom-emacs/org.png)
220
221Similar to the markdown section above, ensure that the `~/.doom.d/init.el`
222includes the `org` declaration in the `:lang` section.
223
224There are a few hot keys, but a quick search with `SPC : org` shows that there
225are 865 possible org-related functions you can run. I won't possibly be able to
226list them all, so I will simply cover a few of the basic commands I use myself.
227
228| Doom Hotkey | Function |
229|----------------|---------------------------------------|
230| `SPC m t` | org-todo |
231| `SPC n t` | org-todo-list |
232| `SPC o A` | org-agenda |
233| `SPC X` | org-capture |
234| `SPC m p p` | org-priority |
235| `SPC m d s` | org-schedule |
236| `TAB` | org-cycle |
237| `SHIFT TAB` | Collapse/open all headings in buffer |
238| `M-q` | Format/wrap current section |
239| `M-Left/Right` | Demote/promote current heading |
240| `M-Down/Up` | Shift current heading section down/up |
256241
2572421. Org-Publish
258243
259244 Org includes a [publishing management
260 system](https://orgmode.org/manual/Publishing.html) by default that
261 allows you to export org files to Org, iCalendar, HTML, LaTex,
262 Markdown, ODT, and Plain Text. Most of these can be exported into
263 another buffer and opened, or simply to an external file.
264
265 While inside an org file, simply run `SPC m e` or
266 `M-x org-export-dispatch` to open the export menu. This
267 menu will show all options and ask you to select an option. If you
268 want to export to HTML, simply press `h` and then
269 `H` (As HTML buffer), `h` (As HTML file), or
270 `o` (As HTML file and open).
245 system](https://orgmode.org/manual/Publishing.html) by default that allows
246 you to export org files to Org, iCalendar, HTML, LaTex, Markdown, ODT, and
247 Plain Text. Most of these can be exported into another buffer and opened, or
248 simply to an external file.
249
250 While inside an org file, simply run `SPC m e` or `M-x org-export-dispatch`
251 to open the export menu. This menu will show all options and ask you to
252 select an option. If you 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).
271254
2722552. Projects
273256
274 Some publishing options are easier with a defined project in Emacs.
275 To create a project within Emacs, I use two methods:
257 Some publishing options are easier with a defined project in Emacs. To
258 create a project within Emacs, I use two methods:
276259
277 1. Add the project via the projectile command `SPC p a`.
278 Does not always work for me.
279 2. Add an empty `.projectile` file in the project root.
260 1. Add the project via the projectile command `SPC p a`. Does not always
261 work for me.
262 2. Add an empty `.projectile` file in the project root.
280263
281 Once a project has been created, you can create custom publishing
282 actions within your `~/.doom.d/config.el` file. For
283 example, here\'s a test project I created to try and convert this
284 blog to org-mode recently.
264 Once a project has been created, you can create custom publishing actions
265 within your `~/.doom.d/config.el` file. For example, here's a test project
266 I created to try and convert this blog to org-mode recently.
285267
286268 ```lisp
287269 ;; org-publish
@@ -352,11 +334,10 @@ of the basic commands I use myself.
352334
353335## General Thoughts
354336
355I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely
356continue to use it as my main editor for the time being. Org-Mode is
357certainly the largest factor here, as I far prefer it over Markdown due
358to its inherent features and detailed markup options. However, working
359with org-mode on iOS has been a pain and I will have to see if there\'s
360an easier way to resolve those issues or if going back to separate
361Markdown, Reminders, and Calendar apps is easier to work with than an
362all-in-one org solution.
337I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely continue to
338use it as my main editor for the time being. Org-Mode is certainly the largest
339factor here, as I far prefer it over Markdown due to its inherent features and
340detailed markup options. However, working with org-mode on iOS has been a pain
341and I will have to see if there's an easier way to resolve those issues or if
342going back to separate Markdown, Reminders, and Calendar apps is easier to work
343with than an all-in-one org solution.
content/blog/2024-03-15-self-hosting-ddns-updater.md +51 −63
@@ -8,25 +8,22 @@ draft = false
88![DDNS Updater Web
99View](https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png)
1010
11[DDNS Updater](https://github.com/qdm12/ddns-updater) is a program to
12keep DNS A and/or AAAA records updated for multiple DNS providers.
11[DDNS Updater](https://github.com/qdm12/ddns-updater) is a program to keep DNS A
12and/or AAAA records updated for multiple DNS providers.
1313
14If you\'ve read any of my other posts, you\'ll notice that I have been
15searching for and using a few different DDNS updating solutions for
16years. You\'ll also notice that I love any projects that offer a Docker
17Compose solution.
14If you've read any of my other posts, you'll notice that I have been searching
15for and using a few different DDNS updating solutions for years. You'll also
16notice that I love any projects that offer a Docker Compose solution.
1817
1918Luckily, DDNS Upater fits both of these preferences.
2019
2120## Installation
2221
23To get started, always make sure to review the project\'s
24[README](https://github.com/qdm12/ddns-updater/blob/master/README.md).
25I\'ll be documenting my steps below, but they may have changed by the
26time you read this.
22To get started, always make sure to review the project's
23[README](https://github.com/qdm12/ddns-updater/blob/master/README.md). I'll be
24documenting my steps below, but they may have changed by the time you read this.
2725
28The first step is to set up the directories and files required for the
29project.
26The first step is to set up the directories and files required for the project.
3027
3128```sh
3229mkdir ~/ddns-updater
@@ -36,46 +33,38 @@ touch ~/ddns-updater/data/config.json
3633
3734### Configuration
3835
39The main configuration you need to update is the
40`data/config.json` file. There is a large list of supported
41providers in the README, but I\'m going to use Cloudflare in this
42example.
36The main configuration you need to update is the `data/config.json` file. There
37is a large list of supported providers in the README, but I'm going to use
38Cloudflare in this example.
4339
4440```sh
4541nano ~/ddns-updater/data/config.json
4642```
4743
48When setting up the configuration for Cloudflare, you\'ll need the
49following:
50
51- Required Parameters
52 - `"zone_identifier"` is the Zone ID of your site from
53 the domain overview page
54 - `"host"` is your host and can be `"@"`, a
55 subdomain or the wildcard `"*"`. See [this issue
56 comment for
57 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949).
58 - `"ttl"` integer value for record TTL in seconds
59 (specify 1 for automatic)
60 - One of the following ([how to find API
61 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)):
62 - Email `"email"` and Global API Key
63 `"key"`
64 - User service key `"user_service_key"`
65 - API Token `"token"`, configured with DNS edit
66 permissions for your DNS name\'s zone
67- Optional Parameters
68 - `"proxied"` can be set to `true` to use
69 the proxy services of Cloudflare
70 - `"ip_version"` can be `ipv4` (A records),
71 or `ipv6` (AAAA records) or
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.
44When setting up the configuration for Cloudflare, you'll need the following:
45
46- Required Parameters
47 - `"zone_identifier"` is the Zone ID of your site from the domain overview
48 page
49 - `"host"` is your host and can be `"@"`, a subdomain or the wildcard `"*"`.
50 See [this issue comment for
51 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949).
52 - `"ttl"` integer value for record TTL in seconds (specify 1 for automatic)
53 - One of the following ([how to find API
54 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)):
55 - Email `"email"` and Global API Key `"key"`
56 - User service key `"user_service_key"`
57 - API Token `"token"`, configured with DNS edit permissions for your DNS
58 name's zone
59- Optional Parameters
60 - `"proxied"` can be set to `true` to use the proxy services of Cloudflare
61 - `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or
62 `ipv4 or ipv6` (update one of the two, depending on the public ip
63 found). It defaults to `ipv4 or ipv6`.
64 - `"ipv6_suffix"` is the IPv6 interface identifier suffix to use. It can be
65 for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults
66 to no suffix and the raw public IPv6 address obtained is used in the
67 record updating.
7968
8069``` conf
8170{
@@ -95,8 +84,8 @@ following:
9584}
9685```
9786
98Once you have configured the provider of your choice, correct the file
99and directory permissions and ownership.
87Once you have configured the provider of your choice, correct the file and
88directory permissions and ownership.
10089
10190```sh
10291cd ~/ddns_updater
@@ -110,8 +99,8 @@ chmod 400 data/config.json
11099
111100### Docker Compose
112101
113After creating the project structure, let\'s create the
114`docker-compose.yml` file.
102After creating the project structure, let's create the `docker-compose.yml`
103file.
115104
116105```sh
117106nano ~/ddns_-pdater/docker-compose.yml
@@ -155,22 +144,22 @@ services:
155144 restart: always
156145```
157146
158After configuring your preferences in the
159`docker-compose.yml`, launch the container.
147After configuring your preferences in the `docker-compose.yml`, launch the
148container.
160149
161150```sh
162151cd ~/ddns-updater
163152sudo docker-compose up -d
164153```
165154
166If you\'ve launched this on your local machine, you can launch
167`localhost:8097` in your browser to see the results.
155If you've launched this on your local machine, you can launch `localhost:8097`
156in your browser to see the results.
168157
169158### Nginx Reverse Proxy
170159
171If you launched this service on a server, other machine, or just want to
172access it remotely via a domain name, you can use Nginx as a reverse
173proxy to expose the service publicly.
160If you launched this service on a server, other machine, or just want to access
161it remotely via a domain name, you can use Nginx as a reverse proxy to expose
162the service publicly.
174163
175164Start by creating the Nginx configuration file.
176165
@@ -178,7 +167,7 @@ Start by creating the Nginx configuration file.
178167sudo nano /etc/nginx/sites-available/ddns
179168```
180169
181Here\'s a basic example that should work properly.
170Here's a basic example that should work properly.
182171
183172``` conf
184173server {
@@ -198,8 +187,8 @@ server {
198187}
199188```
200189
201Here\'s a full example that uses my Authelia authentication service to
202require authentication before someone can access the web page.
190Here's a full example that uses my Authelia authentication service to require
191authentication before someone can access the web page.
203192
204193``` conf
205194server {
@@ -317,5 +306,4 @@ sudo ln -s /etc/nginx/sites-available/ddns /etc/nginx/sites-enabled/ddns
317306sudo systemctl restart nginx.service
318307```
319308
320Your ddns-updater service will now be available via
321`ddns.example.com`!
309Your ddns-updater service will now be available via `ddns.example.com`!
content/blog/2024-03-29-org-blog.md +60 −72
@@ -5,49 +5,45 @@ description = ""
55draft = false
66+++
77
8First and foremost, apologies to those who subscribe via RSS as I know
9that my feed duplicated itself when I moved this blog over to org-mode
10last night.
8First and foremost, apologies to those who subscribe via RSS as I know that my
9feed duplicated itself when I moved this blog over to org-mode last night.
1110
12This post focuses specifically on the configuration and tools I use to
13blog from Emacs with Org-Mode and does not focus on Emacs or Org-Mode
14themselves. Refer to the post I wrote about [Doom Emacs &
15Org-Mode](file:///blog/doom-emacs-org-mode.html) for more information
16about my base Emacs configuration.
11This post focuses specifically on the configuration and tools I use to blog from
12Emacs with Org-Mode and does not focus on Emacs or Org-Mode themselves. Refer to
13the post I wrote about [Doom Emacs &
14Org-Mode](file:///blog/doom-emacs-org-mode.html) for more information about my
15base Emacs configuration.
1716
1817# Weblorg
1918
20The first step in blogging with Org-Mode is to choose a method to
21convert the source files to HTML and publish them. The Worg site
22maintains a nice list of [Blogs and Wikis with
23Org](https://orgmode.org/worg/org-blog-wiki.html), but the tools are
24inevitably different and opinionated, so you\'ll need to find what works
25for you.
26
27I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and
28the native org-publish functions before finally settling on Weblorg. For
29one reason or another, the other solutions were a drastic step down from
30my previous workflow that used [Zola](https://www.getzola.org/) with
31Markdown content.
32
33[Weblorg](https://github.com/emacs-love/weblorg) is a static site
34generator for [org-mode](https://orgmode.org/), built for use within
35[Emacs](https://www.gnu.org/software/emacs/). Since it\'s written in
36Emacs Lisp, there\'s no need to install other languages or frameworks to
37get started. More than that, you can write in any editor you please and
38simply invoke the Emacs build process with the `--script`
39parameter instead of requiring you to blog inside Emacs.
19The first step in blogging with Org-Mode is to choose a method to convert the
20source files to HTML and publish them. The Worg site maintains a nice list of
21[Blogs and Wikis with Org](https://orgmode.org/worg/org-blog-wiki.html), but the
22tools are inevitably different and opinionated, so you'll need to find what
23works for you.
24
25I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and the
26native org-publish functions before finally settling on Weblorg. For one reason
27or another, the other solutions were a drastic step down from my previous
28workflow that used [Zola](https://www.getzola.org/) with Markdown content.
29
30[Weblorg](https://github.com/emacs-love/weblorg) is a static site generator for
31[org-mode](https://orgmode.org/), built for use within
32[Emacs](https://www.gnu.org/software/emacs/). Since it's written in Emacs Lisp,
33there's no need to install other languages or frameworks to get started. More
34than that, you can write in any editor you please and simply invoke the Emacs
35build process with the `--script` parameter instead of requiring you to blog
36inside Emacs.
4037
4138## Installation
4239
43The [Getting Started](https://emacs.love/weblorg/doc/index.html) page
44details broad installation requirements. I am using Doom Emacs on macOS,
45which requires you to add the package to the
46`~/.doom.d/packages.el` file and configure the
40The [Getting Started](https://emacs.love/weblorg/doc/index.html) page details
41broad installation requirements. I am using Doom Emacs on macOS, which requires
42you to add the package to the `~/.doom.d/packages.el` file and configure the
4743`publish.el` file slightly differently.
4844
49To start, add the `htmlize` and `weblorg` packages
50to Doom, sync the changes, and reload.
45To start, add the `htmlize` and `weblorg` packages to Doom, sync the changes,
46and reload.
5147
5248```sh
5349nano ~/.doom.d/packages.el
@@ -62,23 +58,20 @@ nano ~/.doom.d/packages.el
6258doom sync
6359```
6460
65Either re-open Emacs or hit `SPC h r r` to reload the
66changes.
61Either re-open Emacs or hit `SPC h r r` to reload the changes.
6762
6863## Configuration
6964
70Now that I\'ve installed weblorg, I need to configure the project. I\'ll
71start by navigating to my site\'s source code and creating a
72`publish.el` file.
65Now that I've installed weblorg, I need to configure the project. I'll start
66by navigating to my site's source code and creating a `publish.el` file.
7367
7468```sh
7569cd ~/Source/cleberg.net && nano publish.el
7670```
7771
78Since I\'m using Doom, Emacs will not automatically load the packages I
79need later in the build process. To compensate, my
80`publish.el` file needs to explicitly tell Emacs where Doom
81stores the `htmlize`, `weblorg`, and
72Since I'm using Doom, Emacs will not automatically load the packages I need
73later in the build process. To compensate, my `publish.el` file needs to
74explicitly tell Emacs where Doom stores the `htmlize`, `weblorg`, and
8275`templatel` packages.
8376
8477```lisp
@@ -189,12 +182,10 @@ stores the `htmlize`, `weblorg`, and
189182## Structure
190183
191184The project structure for weblorg is highly customizable and the main
192restriction is that the `publish.el` file must point to the
193correct paths.
185restriction is that the `publish.el` file must point to the correct paths.
194186
195For my blog, I prefer to keep the blog content out of the top-level
196directory. This results in the following structure (shortened for
197brevity):
187For my blog, I prefer to keep the blog content out of the top-level directory.
188This results in the following structure (shortened for brevity):
198189
199190``` txt
200191.build/
@@ -222,17 +213,17 @@ build.sh
222213publish.el
223214```
224215
225This is simply my preferred structure and you can alter it to fit your
226needs. The key here really is that you can customize at will, as long as
227the `publish.el` file matches.
216This is simply my preferred structure and you can alter it to fit your needs.
217The key here really is that you can customize at will, as long as the
218`publish.el` file matches.
228219
229220## Build & Deploy
230221
231Once you\'re content with the status of the project, you\'re ready to
232build and deploy the blog.
222Once you're content with the status of the project, you're ready to build and
223deploy the blog.
233224
234My process utilizes a `build.sh` script that combines the
235steps I take every time.
225My process utilizes a `build.sh` script that combines the steps I take every
226time.
236227
237228```sh
238229touch build.sh && chmod +x build.sh && nano build.sh
@@ -240,14 +231,12 @@ touch build.sh && chmod +x build.sh && nano build.sh
240231
241232Within this script, I do the following:
242233
2431. Remove any files within the `.build` directory that I use
244 to store published files.
2452. Set the environment variable to `prod` to ensure the
246 `base_url` matches my configuration in
247 `publish.el`.
2483. Build the site with Emacs & `publish.el`.
2494. Use `scp` to copy files to my site\'s public directory on
250 my server.
2341. Remove any files within the `.build` directory that I use to store published
235 files.
2362. Set the environment variable to `prod` to ensure the `base_url` matches my
237 configuration in `publish.el`.
2383. Build the site with Emacs & `publish.el`.
2394. Use `scp` to copy files to my site's public directory on my server.
251240
252241```sh
253242rm -rf .build/* && \
@@ -259,13 +248,12 @@ scp -r .build/* ubuntu:/var/www/cleberg.net/
259248
260249My only current complaints are:
261250
2621. Errors messages are not helpful. It takes work to determine what the
263 error is and where it\'s coming from. I generally have to sit and
264 watch the build process to see the file that weblorg pubslishes
265 right before the error occurred.
2662. The build process re-builds every single file on each run, which
267 takes a long time for a blog of my size. See below for the last time
268 I measured.
2511. Errors messages are not helpful. It takes work to determine what the error is
252 and where it's coming from. I generally have to sit and watch the build
253 process to see the file that weblorg pubslishes right before the error
254 occurred.
2552. The build process re-builds every single file on each run, which takes a long
256 time for a blog of my size. See below for the last time I measured.
269257
270258```sh
271259> time ./build.sh
@@ -273,5 +261,5 @@ My only current complaints are:
273261./build.sh 35.46s user 0.59s system 85% cpu 41.965 total
274262```
275263
276Overall, I have thoroughly enjoyed using weblog and will continue to use
277it going forward until I find something better.
264Overall, I have thoroughly enjoyed using weblog and will continue to use it
265going forward until I find something better.
content/blog/2024-04-06-convert-onenote-to-markdown.md +46 −54
@@ -5,25 +5,23 @@ description = ""
55draft = false
66+++
77
8If you\'re looking to convert your OneNote content to another format,
9such as Markdown or Org-Mode, you\'re in luck. I use a solution that
10doesn\'t require other programs, such as Evernote or Notion. Personally,
11I used this solution on a managed corporate laptop that doesn\'t allow
12installation of other programs like these.
8If you're looking to convert your OneNote content to another format, such as
9Markdown or Org-Mode, you're in luck. I use a solution that doesn't require
10other programs, such as Evernote or Notion. Personally, I used this solution on
11a managed corporate laptop that doesn't allow installation of other programs
12like these.
1313
1414This solution uses OneNote and Pandoc on Windows 10.
1515
1616# Export OneNote Content to Word
1717
18To start, export any pages or tabs from OneNote to the Word format
19(`.docx`):
18To start, export any pages or tabs from OneNote to the Word format (`.docx`):
2019
211. Open OneNote desktop.
222. Select `File` and then `Export`.
233. Select the scope of content to export, such as `Tab` or
24 `Page`.
254. Name and save the file in an easy to remember location. I recommend
26 your Downloads or Desktop folder.
201. Open OneNote desktop.
212. Select `File` and then `Export`.
223. Select the scope of content to export, such as `Tab` or `Page`.
234. Name and save the file in an easy to remember location. I recommend your
24 Downloads or Desktop folder.
2725
2826See below for a visual walkthrough of the export process.
2927
@@ -39,46 +37,42 @@ Document](https://img.cleberg.net/blog/20240406-convert-onenote-to-markdown/word
3937# Download Pandoc
4038
4139Start by downloading Pandoc from their [GitHub
42releases](https://github.com/jgm/pandoc/releases) page. I cannot install
43`.msi` files on my corporate laptop, so I downloaded the
44`pandoc-3.1.12.3-windows-x86_64.zip` file, which contains a
45simple `.exe` file that you do not need to install - you will
46simply run it from the command line below.
40releases](https://github.com/jgm/pandoc/releases) page. I cannot install `.msi`
41files on my corporate laptop, so I downloaded the
42`pandoc-3.1.12.3-windows-x86_64.zip` file, which contains a simple `.exe` file
43that you do not need to install - you will simply run it from the command line
44below.
4745
48Once downloaded, unzip the archive and move the `pandoc.exe`
49file to the same folder where your Word documents were saved above. If
50you prefer, you can move this file to an easier location, such as
51`C:\Users\youruser\Downloads`.
46Once downloaded, unzip the archive and move the `pandoc.exe` file to the same
47folder where your Word documents were saved above. If you prefer, you can move
48this file to an easier location, such as `C:\Users\youruser\Downloads`.
5249
5350# Convert Word to Markdown
5451
55In this example, I will be converting the Word documents to Markdown,
56but Pandoc supports [a ton of different formats for
52In this example, I will be converting the Word documents to Markdown, but Pandoc
53supports [a ton of different formats for
5754conversion](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
59needed.
55Choose the format you prefer and then modify the following commands as needed.
6056
61To perform the conversion, open the Command Prompt. If you can\'t find
62it, open the start menu and search for it.
57To perform the conversion, open the Command Prompt. If you can't find it, open
58the start menu and search for it.
6359
64Within the command prompt, navigate to the directory where you stored
65the `pandoc.exe` file and the Word documents.
60Within the command prompt, navigate to the directory where you stored the
61`pandoc.exe` file and the Word documents.
6662
6763```ps1
6864cd "C:\Users\yourusername\Downloads"
6965```
7066
71You can verify that you\'re in the correct directory with the
72`dir` command.
67You can verify that you're in the correct directory with the `dir` command.
7368
7469```ps1
7570dir
7671```
7772
78Once you have verified that you have the command prompt open in the
79correct directory with the `pandoc.exe` and the Word
80documents, you can run the following loop to convert all Word documents
81to Markdown.
73Once you have verified that you have the command prompt open in the correct
74directory with the `pandoc.exe` and the Word documents, you can run the
75following loop to convert all Word documents to Markdown.
8276
8377```ps1
8478for %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.
8680
8781This loop will perform the following actions:
8882
891. Find all documents matching the pattern `*.docx`, which
90 means all Word documents ending with that file extension.
912. Iterate through all files found in step 1.
923. For each file, perform the pandoc command.
934. Within the pandoc command, `--extract-media` saves all
94 media found in the files to the current folder, with pandoc
95 automatically creating a `media` subfolder to hold all
96 images.
975. Within the pandoc command, `--wrap=preserve` will attempt
98 to prseerve the wrapping from the source document.
996. Within the pandoc command, the final step is to specify the output
100 path with `-o`. This option adds the `.md`
101 file extension to recognize the output files as Markdown files.
831. Find all documents matching the pattern `*.docx`, which means all Word
84 documents ending with that file extension.
852. Iterate through all files found in step 1.
863. For each file, perform the pandoc command.
874. Within the pandoc command, `--extract-media` saves all media found in the
88 files to the current folder, with pandoc automatically creating a `media`
89 subfolder to hold all images.
905. Within the pandoc command, `--wrap=preserve` will attempt to prseerve the
91 wrapping from the source document.
926. Within the pandoc command, the final step is to specify the output path with
93 `-o`. This option adds the `.md` file extension to recognize the output files
94 as Markdown files.
10295
10396![Pandoc
10497Conversion](https://img.cleberg.net/blog/20240406-convert-onenote-to-markdown/command.png)
10598
106If you want to export to another format, simply specify the
107`-f=`/`--from=` and `-t=`/`--to=` options.
99If you want to export to another format, simply specify the `-f=`/`--from=` and
100`-t=`/`--to=` options.
108101
109For example, you can convert the Word document to org-mode. You can also
110convert to one format and subsequently convert to other formats as
111needed.
102For example, you can convert the Word document to org-mode. You can also convert
103to one format and subsequently convert to other formats as needed.
112104
113105```ps1
114106pandoc.exe -f docx -t org file.docx
content/blog/2024-04-08-docker-local-web-server.md +49 −58
@@ -5,56 +5,52 @@ description = ""
55draft = false
66+++
77
8When developing websites locally, I often use a simple Python web server
9to observe the changes.
8When developing websites locally, I often use a simple Python web server to
9observe the changes.
1010
1111```sh
1212python3 -m http.server
1313```
1414
15However, this approach has its limitations. For example, this approach
16does not enable logging or access controls. You also need to customize
17`SimpleHTTPServer` if you have advanced needs from your web
18server.
15However, this approach has its limitations. For example, this approach does not
16enable logging or access controls. You also need to customize `SimpleHTTPServer`
17if you have advanced needs from your web server.
1918
20So, I went to find an alternative that is almost as easy and far more
21extensible and found Docker Desktop to be a suitable replacement.
19So, I went to find an alternative that is almost as easy and far more extensible
20and found Docker Desktop to be a suitable replacement.
2221
2322# Docker Desktop
2423
2524## Installation
2625
27[Docker Desktop](https://www.docker.com/products/docker-desktop/) is a
28desktop GUI for the phenomenal Docker container software. This allows
29you to manage containers, images, volumes, environments, and extensions
30via an easy-to-use GUI.
26[Docker Desktop](https://www.docker.com/products/docker-desktop/) is a desktop
27GUI for the phenomenal Docker container software. This allows you to manage
28containers, images, volumes, environments, and extensions via an easy-to-use
29GUI.
3130
32To install, open the link above and click the `Download`
33button for your platform. I\'m going through this process on an M2
34Macbook, so I downloaded the Mac - Apple Chip version.
31To install, open the link above and click the `Download` button for your
32platform. I'm going through this process on an M2 Macbook, so I downloaded the
33Mac - Apple Chip version.
3534
36Open the installer and follow the installation process until the
37application finishes the installation process.
35Open the installer and follow the installation process until the application
36finishes the installation process.
3837
3938![Docker Desktop on
4039macOS](https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png)
4140
4241## Creating an Nginx Container
4342
44I prefer to use the command line to create containers, so the following
45commands will be input via the terminal.
43I prefer to use the command line to create containers, so the following commands
44will be input via the terminal.
4645
47The following command will create a container, using the
48`nginx` image:
46The following command will create a container, using the `nginx` image:
4947
501. `-d`: Run this container as a daemon (detach)
512. `-p`: Allocate a port in the format
52 `<external>:<internal>`
533. `-i`: Keep STDIN open even if not attached
544. `-t`: Allocate a pseudo-TTY
555. `-p`: Allocate a port in the format
56 `<external>:<internal>`
576. `--rm`: Remove the container once it\'s done running
481. `-d`: Run this container as a daemon (detach)
492. `-p`: Allocate a port in the format `<external>:<internal>`
503. `-i`: Keep STDIN open even if not attached
514. `-t`: Allocate a pseudo-TTY
525. `-p`: Allocate a port in the format `<external>:<internal>`
536. `--rm`: Remove the container once it's done running
5854
5955```sh
6056docker 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
6763
6864## Customizing the Nginx Container
6965
70Now that I have a container running the Nginx web server, I need to link
71some volumes so that I can modify the site configuration and provide the
72web files to serve.
66Now that I have a container running the Nginx web server, I need to link some
67volumes so that I can modify the site configuration and provide the web files to
68serve.
7369
74Let\'s start with the new command, which adds two volumes:
70Let's start with the new command, which adds two volumes:
7571
761. `<your_content>:/usr/share/nginx/html`: This is the
77 directory where you will provide the web pages for the server to
78 serve.
792. `<your_config>:/etc/nginx/conf.d/default.conf`: This is
80 the Nginx configuration file for your site.
721. `<your_content>:/usr/share/nginx/html`: This is the directory where you will
73 provide the web pages for the server to serve.
742. `<your_config>:/etc/nginx/conf.d/default.conf`: This is the Nginx
75 configuration file for your site.
8176
82To see the updates, you can delete the previous container in the GUI or
83run `docker stop web` to stop the container. Once stopped,
84you can run the new `docker run` command below.
77To see the updates, you can delete the previous container in the GUI or run
78`docker stop web` to stop the container. Once stopped, you can run the new
79`docker run` command below.
8580
8681```sh
8782docker 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
8883```
8984
90Here\'s an example of my development configuration file.
85Here's an example of my development configuration file.
9186
9287``` conf
9388# nginx-config.conf
@@ -114,19 +109,16 @@ server {
114109
115110# Customizing Deployment Actions
116111
117I am currently blogging with [weblorg](https://emacs.love/weblorg/),
118which uses a custom `publish.el` file to build the static
119site. Within this file, I have configured my deployment process to check
120for the `ENV` variable in thesh and if it\'s set to
121`prod`, the script will set the base URLs to
122`https://cleberg.net`. If not, it sets the base URLs to
123`localhost:8000` (which matches the port used in the
124container above).
112I am currently blogging with [weblorg](https://emacs.love/weblorg/), which uses
113a custom `publish.el` file to build the static site. Within this file, I have
114configured my deployment process to check for the `ENV` variable in thesh and if
115it's set to `prod`, the script will set the base URLs to `https://cleberg.net`.
116If not, it sets the base URLs to `localhost:8000` (which matches the port used
117in the container above).
125118
126Therefore, I have modified my `build.sh` script to build with
127`localhost` URLs if `ENV` is not set to
128`prod`. It also prevents the build process from sending the
129built files to the production web server.
119Therefore, I have modified my `build.sh` script to build with `localhost` URLs
120if `ENV` is not set to `prod`. It also prevents the build process from sending
121the built files to the production web server.
130122
131123```sh
132124#!/bin/bash
@@ -143,7 +135,6 @@ else
143135fi
144136```
145137
146You can modify the container in numerous ways and this approach allows
147you to create complex scenarios for your web development purposes. I
148highly recommend switching over to a container-based approach for
149simple, local web development.
138You can modify the container in numerous ways and this approach allows you to
139create complex scenarios for your web development purposes. I highly recommend
140switching over to a container-based approach for simple, local web development.
content/blog/2024-04-18-mu4e.md +45 −54
@@ -6,19 +6,18 @@ draft = false
66+++
77
88This post was heavily inspired by [Email setup in Emacs with Mu4e on
9macOS](https://macowners.club/posts/email-emacs-mu4e-macos/), but with
10my own tweaks for a single-account configuration and some Doom-specific
11configurations.
9macOS](https://macowners.club/posts/email-emacs-mu4e-macos/), but with my own
10tweaks for a single-account configuration and some Doom-specific configurations.
1211
1312# Overview
1413
15[Mu4e](https://github.com/emacsmirror/mu4e) is an Emacs-based email
16client based on [mu](https://www.djcbsoftware.nl/code/mu/), an indexer
17that stores email in the Maildir format.
14[Mu4e](https://github.com/emacsmirror/mu4e) is an Emacs-based email client based
15on [mu](https://www.djcbsoftware.nl/code/mu/), an indexer that stores email in
16the Maildir format.
1817
19This blog post covers the installation of Mu4e in Doom Emacs on macOS.
20This guide should be very similar to GNU Emacs and Linux-based systems,
21with a few tweaks required in the various configuration files.
18This blog post covers the installation of Mu4e in Doom Emacs on macOS. This
19guide should be very similar to GNU Emacs and Linux-based systems, with a few
20tweaks required in the various configuration files.
2221
2322# Installation
2423
@@ -36,33 +35,32 @@ mkdir ~/.maildir/certificates # used to store system root certificates
3635
3736### Store Email Account Passwords in macOS Keychain
3837
39Next, I will be using the macOS Keychain to store my email account
40passwords using the command below.
38Next, I will be using the macOS Keychain to store my email account passwords
39using the command below.
4140
4241```sh
4342security add-generic-password -s mu4e-example -a you@example.com -w
4443```
4544
4645This 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
48later in the IMAP and SMTP configuration files.
46`mu4e-example` name in mind, as you will need to reference it later in the IMAP
47and SMTP configuration files.
4948
5049### Store Root Certificates
5150
52In order to use IMAP and SMTP, we need to provide certificates to the
53local services. We will use the macOS defaults for this.
51In order to use IMAP and SMTP, we need to provide certificates to the local
52services. We will use the macOS defaults for this.
5453
551. Open `Keychain Access.app`.
562. Select `System Roots` in the sidebar.
573. Select all items with `CMD + a`.
584. Export selected items with `SHIFT + CMD + a` to the file
59 `~/.maildir/certificates/root-certificates.pem`.
541. Open `Keychain Access.app`.
552. Select `System Roots` in the sidebar.
563. Select all items with `CMD + a`.
574. Export selected items with `SHIFT + CMD + a` to the file
58 `~/.maildir/certificates/root-certificates.pem`.
6059
6160### Install Dependencies
6261
63Install `mbsync` (via `isync`) to fetch emails via
64IMAP, `mu` to index emails, and `msmtp` to send
65emails via SMTP.
62Install `mbsync` (via `isync`) to fetch emails via IMAP, `mu` to index emails,
63and `msmtp` to send emails via SMTP.
6664
6765```sh
6866brew install mu isync msmtp
@@ -76,9 +74,8 @@ Within Doom Emacs, we can install Mu4e by enabling the package.
7674nano ~/.doom.d/init.el
7775```
7876
79In this file, uncomment the `mu4e` line within the
80`:email` section. You can also enable the `+org`
81and `+gmail` options if you prefer.
77In this file, uncomment the `mu4e` line within the `:email` section. You can
78also enable the `+org` and `+gmail` options if you prefer.
8279
8380```lisp
8481(doom! :input
@@ -92,9 +89,9 @@ and `+gmail` options if you prefer.
9289
9390# Configuration
9491
95As an overall suggestion, I create the following configuration files in
96the `~/.maildir` directory and using symlinks to their proper
97locations so that I can backup and restore these files easily.
92As an overall suggestion, I create the following configuration files in the
93`~/.maildir` directory and using symlinks to their proper locations so that I
94can backup and restore these files easily.
9895
9996```sh
10097touch ~/.maildir/.mbsyncrc && \
@@ -103,14 +100,13 @@ ln -s /Users/username/.maildir/.mbsyncrc /Users/username/.mbsyncrc && \
103100ln -s /Users/username/.maildir/.msmtprc /Users/username/.msmtprc
104101```
105102
106You can also create these files in your home directory and skip the
107symlinking process above.
103You can also create these files in your home directory and skip the symlinking
104process above.
108105
109106## IMAP
110107
111Next, let\'s configure `mbsync` in the file created above.
112Paste the following information and customize it to match your mail
113provider\'s information.
108Next, let's configure `mbsync` in the file created above. Paste the following
109information and customize it to match your mail provider's information.
114110
115111```sh
116112nano ~/.maildir/.mbsyncrc
@@ -146,9 +142,8 @@ SyncState *
146142
147143## SMTP
148144
149Next, let\'s configured `msmtprc` in the file created above.
150Paste the following information and customize it to match your mail
151provider\'s information.
145Next, let's configured `msmtprc` in the file created above. Paste the following
146information and customize it to match your mail provider's information.
152147
153148```sh
154149nano ~/.maildir/.msmtprc
@@ -180,8 +175,8 @@ account default : startmail
180175
181176## Doom Emacs
182177
183Finally, we need to configure Doom Emacs to use the proper packages and
184set some variables and functions.
178Finally, we need to configure Doom Emacs to use the proper packages and set some
179variables and functions.
185180
186181```sh
187182nano ~/.doom.d/config.el
@@ -279,14 +274,12 @@ Be sure to sync Doom to update the current configurations.
279274doom sync
280275```
281276
282If you have Doom open, execute `SPC h r r` to reload the new
283configurations.
277If you have Doom open, execute `SPC h r r` to reload the new configurations.
284278
285279# Initial Sync
286280
287Once you have configured all of the relevant files, you can perform an
288initial sync. Note that you can perform syncing within Mu4e itself afer
289this.
281Once you have configured all of the relevant files, you can perform an initial
282sync. Note that you can perform syncing within Mu4e itself afer this.
290283
291284```sh
292285mbsync -aV
@@ -303,21 +296,19 @@ The emails will now to be ready to use!
303296
304297# Screenshots
305298
306You can now launch Doom and open Mu4e with `SPC o m`. You can
307also explore the Mu4e options with `SPC : mu4e`.
299You can now launch Doom and open Mu4e with `SPC o m`. You can also explore the
300Mu4e options with `SPC : mu4e`.
308301
309The home page shows various options and metdata about the account
310you\'ve opened.
302The home page shows various options and metdata about the account you've
303opened.
311304
312305![Mu4e Home Page](https://img.cleberg.net/blog/20240418-mu4e/mu4e.png)
313306
314When composing an email, you can see the metadata fields at the top and
315compose the message below the indicator line.
307When composing an email, you can see the metadata fields at the top and compose
308the message below the indicator line.
316309
317![Composition
318Screen](https://img.cleberg.net/blog/20240418-mu4e/draft.png)
310![Composition Screen](https://img.cleberg.net/blog/20240418-mu4e/draft.png)
319311
320When in a folder, you can view emails in a pane and perform actions as
321needed.
312When in a folder, you can view emails in a pane and perform actions as needed.
322313
323314![Inbox](https://img.cleberg.net/blog/20240418-mu4e/inbox.png)
content/services.md +2 −2
@@ -8,9 +8,9 @@ draft = false
88- [FileArchive](https://files.cleberg.net/) - An interesting file archive
99- [FlashPaper](https://paste.cleberg.net/) - One-time encrypted password/secret sharing
1010- [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
1212- [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
1414- [Org-Live](https://org.cleberg.net/) - A basic org-mode editor for the web I built
1515- [SearXNG](https://search.cleberg.net/) - A privacy-respecting, open metasearch engine
1616
content/wiki/blogroll.md +1 −1
@@ -27,7 +27,7 @@ A list of various plaintext websites and lists.
2727
2828## Webrings
2929
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.
3131
3232## Everything Else
3333
content/wiki/hardware.md +1 −1
@@ -47,7 +47,7 @@ and quiet as my top priorities.
4747
4848### IoT
4949
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.
5151
5252- Other Appliances (washer, dryer, humidifier, fans, etc.)
5353 - [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:
5151- Disable:
5252 - Analytics & Improvements
5353 - Apple Advertising
54 - Apple ID \> Sign-In & Security \> Two-Factor Authentication
55 - Location Services \> System Services \> Product Improvement
56 - Tracking \> Allow Apps to Request to Track
57 - Safari \> Advanced \> Privacy Preserving Ad Measurement
54 - Apple ID > Sign-In & Security > Two-Factor Authentication
55 - Location Services > System Services > Product Improvement
56 - Tracking > Allow Apps to Request to Track
57 - Safari > Advanced > Privacy Preserving Ad Measurement
5858- Enable:
59 - Apple ID \> iCloud \> Advanced Data Protection
60 - Apple ID \> Personal Information \> Communication Preferences
59 - Apple ID > iCloud > Advanced Data Protection
60 - Apple ID > Personal Information > Communication Preferences
6161 - App Privacy Report
6262 - Location Services only for Camera, Find My, UDisc, & WiFiman
6363 (`While Using`)
64 - Safari \> Prevent Cross-Site Tracking
65 - Safari \> Hide IP Address
66 - Safari \> Advanced \> Advanced Tracking and Fingerprinting
64 - Safari > Prevent Cross-Site Tracking
65 - Safari > Hide IP Address
66 - Safari > Advanced > Advanced Tracking and Fingerprinting
6767 Protection
6868
6969## Native Apps
@@ -92,7 +92,7 @@ Here's the baseline I start with:
9292
9393### Music
9494
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
9696- [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
9797
9898### News
@@ -109,7 +109,7 @@ Here's the baseline I start with:
109109- [beorg](https://apps.apple.com/us/app/beorg-to-do-list-agenda/id1238649962) - An org-mode editor, outline, and scheduler with paid extensions
110110- [Bitwarden](https://apps.apple.com/us/app/bitwarden-password-manager/id1137397744) (`*`) - An open source password manager
111111- [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
113113- [Strongbox](https://apps.apple.com/us/app/strongbox-password-manager/id897283731) - Keepass password manager for iOS & macOS
114114- [UniFi Network](https://apps.apple.com/us/app/unifi/id1057750338) - View and manage most UniFi Network settings
115115
@@ -130,7 +130,7 @@ Here's the baseline I start with:
130130
131131### Sports
132132
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
134134- [UDisc](https://apps.apple.com/us/app/udisc-disc-golf/id1072228953) - Disc golf course maps, score cards, and more
135135
136136### Utilities
content/wiki/macos.md +2 −2
@@ -92,7 +92,7 @@ echo "yabai configuration loaded.."
9292
9393### Communications
9494
95- [Element](https://element.io/) (`*`) - Matrix\'s default GUI client
95- [Element](https://element.io/) (`*`) - Matrix's default GUI client
9696- [gomuks](https://github.com/tulir/gomuks) - A terminal based Matrix client
9797- [Thunderbird](https://www.thunderbird.net/) (`*`) - An open source email client by Mozilla
9898- [Signal](https://signal.org/) (`*`) - A simple, powerful, and secure messenger
@@ -103,7 +103,7 @@ echo "yabai configuration loaded.."
103103 - [open-webui](https://github.com/open-webui/open-webui) - User-friendly WebUI for LLMs
104104- [iTerm2](https://iterm2.com/) (`*`) - The best terminal for macOS, hands down
105105- [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
107107- [zsh](https://en.wikipedia.org/wiki/Z_shell) (`*`) - My shell preference due to its plugin and theme community
108108 - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) - Fish-like autosuggestions for zsh
109109 - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) - Fish shell like syntax highlighting for Zsh