Commit 51a7a02f0c

51a7a02f0c96d49b68fbcc155414c218207fa270

parent: 7d3e80ebf1

Unsigned

cmc <hello@cleberg.net> · 2025-11-12 04:49 UTC

fix grammar in 2022 posts

Layout: unified · split

content/blog/2022-02-10-leaving-the-office.org +132 −150
@@ -5,126 +5,114 @@
5 5
6* The Working World is Changing 6* The Working World is Changing
7 7
8There has been a trend for the past few years of companies slowly 8There has been a trend for the past few years of companies slowly realizing that
9realizing that the pandemic is not just a temporary state that will go 9the pandemic is not just a temporary state that will go away eventually and let
10away eventually and let everything return to the way it was before. In 10everything return to the way it was before. In terms of business and employment,
11terms of business and employment, this means that more and more jobs are 11this means that more and more jobs are being offered as permanently remote
12being offered as permanently remote roles. 12roles.
13 13
14I had always dreamt of working from home but thought of it as a fantasy, 14I had always dreamt of working from home but thought of it as a fantasy,
15especially since I did not want to move over into the software 15especially since I did not want to move over into the software development
16development field. However, I have found that almost all roles being 16field. However, I have found that almost all roles being sent to me via
17sent to me via recruiters are permanently remote (although most are 17recruiters are permanently remote (although most are limited to US citizens or
18limited to US citizens or even region-locked for companies who only 18even region-locked for companies who only operate in select states).
19operate in select states).
20 19
21I decided to take a look back at my relatively short career so far and 20I decided to take a look back at my relatively short career so far and compare
22compare the positive and negative effects of the different work 21the positive and negative effects of the different work environments I've been
23environments I've been in. 22in.
24 23
25* In-Person Offices 24* In-Person Offices
26 25
27** Retail Internship 26** Retail Internship
28 27
29I started my first job as a management intern at a busy retail pharmacy, 28I started my first job as a management intern at a busy retail pharmacy, working
30working my 40-hour weeks on my feet. As these retail stores don't 29my 40-hour weeks on my feet. As these retail stores don't believe in resting or
31believe in resting or sitting down, you can guarantee that you will 30sitting down, you can guarantee that you will spend entire shifts standing,
32spend entire shifts standing, walking, or running around the store. 31walking, or running around the store. Unfortunately, I worked at a time when our
33Unfortunately, I worked at a time when our store didn't have enough 32store didn't have enough managers, so I spent the majority of my tenure at the
34managers, so I spent the majority of my tenure at the store running and 33store running and breaking a sweat.
35breaking a sweat. 34
36 35Now, things aren't all bad in retail stores like this. It is definitely tiring
37Now, things aren't all bad in retail stores like this. It is definitely 36and inefficient to force employees to work constantly, or pretend to work if
38tiring and inefficient to force employees to work constantly, or pretend 37there's nothing to do, and not allow anyone to sit down. However, if you are
39to work if there's nothing to do, and not allow anyone to sit down. 38able to operate a retail store with a limited crew and provide enough comfort
40However, if you are able to operate a retail store with a limited crew 39and support, I believe these jobs could be both comfortable and efficient.
41and provide enough comfort and support, I believe these jobs could be
42both comfortable and efficient.
43 40
44** Semi-Private Cubicles 41** Semi-Private Cubicles
45 42
46After about a year, I was able to find another internship - this time, 43After about a year, I was able to find another internship - this time, it was in
47it was in my field of interest: internal auditing. This was for a life 44my field of interest: internal auditing. This was for a life insurance company
48insurance company that was well over 100 years old. The age of the 45that was well over 100 years old. The age of the company shows if you work
49company shows if you work there, as most people in management are well 46there, as most people in management are well into their 40s-60s with little to
50into their 40s-60s with little to no youthful leadership in the company. 47no youthful leadership in the company. Likewise, they owned a large headquarters
51Likewise, they owned a large headquarters in a nice area of town with 48in a nice area of town with plenty of space, parking, etc.
52plenty of space, parking, etc. 49
53 50One upside is that each person gets their own large L-shaped desk, formed into
54One upside is that each person gets their own large L-shaped desk, 51cubicles that house 4 desks/employees. These "pods" of 4-person cubicles are
55formed into cubicles that house 4 desks/employees. These "pods" of 52linked throughout each floor of the headquarters (except the sales people, who
564-person cubicles are linked throughout each floor of the headquarters 53had that open-floor concept going on). The walls of the cubicle were tall and
57(except the sales people, who had that open-floor concept going on). The 54provided a lot of privacy and sound-proofing, except when I used the standing
58walls of the cubicle were tall and provided a lot of privacy and 55desk feature (I'm over 6 feet tall, so probably not an issue for most people).
59sound-proofing, except when I used the standing desk feature (I'm over 6
60feet tall, so probably not an issue for most people).
61 56
62I loved this environment, it allowed me to focus on my work with minimal 57I loved this environment, it allowed me to focus on my work with minimal
63distractions, but also allowed easy access, so I could spin around in my 58distractions, but also allowed easy access, so I could spin around in my chair
64chair and chat with my friends without leaving my chair. This is the 59and chat with my friends without leaving my chair. This is the closest I've been
65closest I've been to a home office environment (which is my personal 60to a home office environment (which is my personal favorite, as I'll get to
66favorite, as I'll get to later in this post). 61later in this post).
67 62
68** Semi-Open Floor Concept 63** Semi-Open Floor Concept
69 64
70When I shifted to my first full-time internal audit job out of college, 65When I shifted to my first full-time internal audit job out of college, I was
71I was working at a company that was headquartered on a floor in a 66working at a company that was headquartered on a floor in a downtown high-rise
72downtown high-rise building. The company was only about 20 years old 67building. The company was only about 20 years old when I worked there and were
73when I worked there and were trying a lot of new things to attract young 68trying a lot of new things to attract young talent, one of which was a semi-open
74talent, one of which was a semi-open floor concept for the office. My 69floor concept for the office. My department worked just around the hallway
75department worked just around the hallway corner from the executive 70corner from the executive offices and used that "modern" layout young tech
76offices and used that "modern" layout young tech companies started using 71companies started using in the 2000s/2010s.
77in the 2000s/2010s. 72
78 73Each desk was brief, and you could look most coworkers in the face without
79Each desk was brief, and you could look most coworkers in the face 74moving from your chair, I hated this so much. Directly to my left was the Chief
80without moving from your chair, I hated this so much. Directly to my 75Audit Executive (our department's leading boss), and his desk was pointed so
81left was the Chief Audit Executive (our department's leading boss), and 76that his face would stare straight at my desk all day. I spent more time
82his desk was pointed so that his face would stare straight at my desk 77thinking about who was looking at me or checking on me than actually working.
83all day. I spent more time thinking about who was looking at me or 78
84checking on me than actually working. 79The other annoying part of the open concept they used was that the kitchen area
85 80and pathways were too close to everyone's desks (since the desks were spread
86The other annoying part of the open concept they used was that the 81out, to provide space or something), so noise and conversation would be constant
87kitchen area and pathways were too close to everyone's desks (since the 82throughout the day while you try to work. For someone like me, who needs silence
88desks were spread out, to provide space or something), so noise and 83to get work done, that was a non-starter.
89conversation would be constant throughout the day while you try to work.
90For someone like me, who needs silence to get work done, that was a
91non-starter.
92 84
93** Hotel Office Concept 85** Hotel Office Concept
94 86
95I currently work for a company remotely (for now) and travel to the 87I currently work for a company remotely (for now) and travel to the office every
96office every once in a while for events and to help coach the staff 88once in a while for events and to help coach the staff underneath me. The office
97underneath me. The office I visit uses the hotel desk concept, where you 89I visit uses the hotel desk concept, where you need to check in at a touch
98need to check in at a touch screen when you enter the office and "rent" 90screen when you enter the office and "rent" a desk for the day. The same goes
99a desk for the day. The same goes for offices and meeting rooms. 91for offices and meeting rooms.
100 92
101These desks are flat-top only and do not have any walls at all. In 93These desks are flat-top only and do not have any walls at all. In addition,
102addition, they're stacked with one row of 4 desks facing another row of 94they're stacked with one row of 4 desks facing another row of 4 desks. These
1034 desks. These pairs of desk rows are repeated through the office. 95pairs of desk rows are repeated through the office.
104 96
105This means that when I go, I need to rent a random desk or try to 97This means that when I go, I need to rent a random desk or try to remember the
106remember the unique ID numbers on desks I like. Once I rent it, I have 98unique identification (ID) numbers on desks I like. Once I rent it, I have to
107to make sure no one sat down in that desk without renting it. Then, I 99make sure no one sat down in that desk without renting it. Then, I can sit down
108can sit down and work, but will probably need to adjust the monitors so 100and work, but will probably need to adjust the monitors so that I'm not staring
109that I'm not staring in the face of the person across from me all day. 101in the face of the person across from me all day. Finally, I need to wear
110Finally, I need to wear headphones as this environment does nothing to 102headphones as this environment does nothing to provide you with peace or quiet.
111provide you with peace or quiet.
112 103
113Luckily, you can rent offices with doors that offer quiet and privacy, 104Luckily, you can rent offices with doors that offer quiet and privacy, which can
114which can be very nice if you have a lot of meetings or webinars on a 105be very nice if you have a lot of meetings or webinars on a certain day.
115certain day.
116 106
117* Home Office 107* Home Office
118 108
119Okay, now let's finally get to the home office concept. I have worked 109Okay, now let's finally get to the home office concept. I have worked from home
120from home for a little over two years at this point, across three 110for a little over two years at this point, across three different
121different jobs/employers. Over this time, I have experimented with a 111jobs/employers. Over this time, I have experimented with a plethora of different
122plethora of different organizational ideas, desks, and room layouts to 112organizational ideas, desks, and room layouts to find what works best for me.
123find what works best for me.
124 113
125These things might not apply to you, and that's fine. Everyone has a 114These things might not apply to you, and that's fine. Everyone has a different
126different situation, and I really don't think you'll know what works 115situation, and I really don't think you'll know what works until you try.
127until you try.
128 116
129** Tip #1 117** Tip #1
130 118
@@ -134,16 +122,15 @@ Let's start with my top rule for a home office:
134If you live with others, working in a shared space is not effective. 122If you live with others, working in a shared space is not effective.
135#+end_quote 123#+end_quote
136 124
137It just does not work. If you have another person sleeping in your 125It just does not work. If you have another person sleeping in your bedroom, it
138bedroom, it is difficult to manage your work schedule with their 126is difficult to manage your work schedule with their sleeping/work/school
139sleeping/work/school schedule. If they wake up after you need to start 127schedule. If they wake up after you need to start work, you might wake them up
140work, you might wake them up or have to suffer the agony of staring at 128or have to suffer the agony of staring at bright screens in a dark room.
141bright screens in a dark room.
142 129
143In a similar vein, working from a location such as the living room 130In a similar vein, working from a location such as the living room likely won't
144likely won't work either. Distractions will come far more frequently: 131work either. Distractions will come far more frequently: televisions, cooking,
145televisions, cooking, cleaning, deliveries, etc. If you're like me, 132cleaning, deliveries, etc. If you're like me, you'll end up playing a game
146you'll end up playing a game instead of actually doing any work. 133instead of actually doing any work.
147 134
148** Tip #2 135** Tip #2
149 136
@@ -154,39 +141,38 @@ Use the pomodoro method (or something similar) to balance work tasks
154with personal tasks. 141with personal tasks.
155#+end_quote 142#+end_quote
156 143
157I use a very casual version of the pomodoro method where I will work for 144I use a very casual version of the pomodoro method where I will work for 1-2
1581-2 hours (usually set in strict intervals like 1, 1.5, 2 hours) and 145hours (usually set in strict intervals like 1, 1.5, 2 hours) and then will allow
159then will allow myself 30-60 minutes for personal tasks. This schedule 146myself 30-60 minutes for personal tasks. This schedule works for me, since my
160works for me, since my work schedule really only comes to 3-6 hours of 147work schedule really only comes to 3-6 hours of work per day.
161work per day.
162 148
163In this case, I'll work through my list of tasks for an hour or two and 149In this case, I'll work through my list of tasks for an hour or two and then
164then give myself personal time to get drinks and food, wash dishes, put 150give myself personal time to get drinks and food, wash dishes, put clothes in
165clothes in the washer, get the mail, etc. If you're in a convenient 151the washer, get the mail, etc. If you're in a convenient location, this usually
166location, this usually gives time for things like getting groceries (as 152gives time for things like getting groceries (as long as you're not a slow
167long as you're not a slow shopper). 153shopper).
168 154
169** Tip #3 155** Tip #3
170 156
171While I listed this one as number three, I don't think I'd accomplish 157While I listed this one as number three, I don't think I'd accomplish anything
172anything without it: 158without it:
173 159
174#+begin_quote 160#+begin_quote
175Document everything: even things you didn't before - such as task lists 161Document everything: even things you didn't before - such as task lists
176and notes from casual calls or meetings. 162and notes from casual calls or meetings.
177#+end_quote 163#+end_quote
178 164
179I've noticed that staying in an office gave me more constant reminders 165I've noticed that staying in an office gave me more constant reminders of
180of outstanding tasks or facts I had learned in a conversation. 166outstanding tasks or facts I had learned in a conversation. Translating
181Translating everything to a digital world has made me lose a bit of that 167everything to a digital world has made me lose a bit of that focus (perhaps
182focus (perhaps since I don't have visual reminders?). 168since I don't have visual reminders?).
183 169
184Keeping a running task list of all things I have to do - even potential 170Keeping a running task list of all things I have to do - even potential tasks! -
185tasks! - has helped me keep up without missing anything small. Likewise, 171has helped me keep up without missing anything small. Likewise, keeping notes
186keeping notes for ALL meetings and calls, no matter how casual/quick, 172for ALL meetings and calls, no matter how casual/quick, has improved my
187has improved my retention immensely. Beyond helping my mental 173retention immensely. Beyond helping my mental recollection, it has saved me
188recollection, it has saved me numerous times when I need to do a keyword 174numerous times when I need to do a keyword search for some topic that was
189search for some topic that was discussed 6+ months ago. 175discussed 6+ months ago.
190 176
191** Tip #4 177** Tip #4
192 178
@@ -196,36 +182,32 @@ Okay, last one for now.
196Keep your work area clean. 182Keep your work area clean.
197#+end_quote 183#+end_quote
198 184
199This one is straightforward, but I know some people struggle with 185This one is straightforward, but I know some people struggle with cleanliness or
200cleanliness or may not believe it makes a difference. Trust me, keeping 186may not believe it makes a difference. Trust me, keeping your desk area clean
201your desk area clean and organized makes a huge difference, both 187and organized makes a huge difference, both mentally and emotionally.
202mentally and emotionally.
203 188
204Just think about it, you walk into your home office and see a clean desk 189Just think about it, you walk into your home office and see a clean desk with a
205with a laptop, dock, monitors, keyboard, mouse, and a notepad with a pen 190laptop, dock, monitors, keyboard, mouse, and a notepad with a pen on top.
206on top.
207 191
208Now imagine the opposite, there's an office with the same equipment, but 192Now imagine the opposite, there's an office with the same equipment, but there
209there are clothes hanging on the chair, empty drink bottles, candy 193are clothes hanging on the chair, empty drink bottles, candy wrappers and dirty
210wrappers and dirty plates. This can take both a mental and emotional 194plates. This can take both a mental and emotional toll by bringing constant
211toll by bringing constant disarray and stress into your working 195disarray and stress into your working environment.
212environment.
213 196
214Just keep things clean each day, and you won't need to do any big 197Just keep things clean each day, and you won't need to do any big cleaning days
215cleaning days to recover. 198to recover.
216 199
217* My Preferences 200* My Preferences
218 201
219I've talked about the different environments I've worked in and 202I've talked about the different environments I've worked in and expressed some
220expressed some honest thoughts on pros or cons to each, but what do I 203honest thoughts on pros or cons to each, but what do I prefer? Well, if you're
221prefer? Well, if you're reading along, you should be able to tell that I 204reading along, you should be able to tell that I much prefer a home office above
222much prefer a home office above all else. 205all else.
223 206
224Being able to control my own day and allot my time as needed has brought 207Being able to control my own day and allot my time as needed has brought a
225a calmness to my life and has allowed me to maximize each day. I feel 208calmness to my life and has allowed me to maximize each day. I feel far more
226far more effective and efficient in a home office than any other office, 209effective and efficient in a home office than any other office, especially
227especially open-office layouts. 210open-office layouts.
228 211
229If I do need to return to an office part-time in the future, I really 212If I do need to return to an office part-time in the future, I really hope the
230hope the office will have privacy and quietness in order for me to get 213office will have privacy and quietness in order for me to get my work done.
231my work done.
content/blog/2022-02-10-njalla-dns-api.org +45 −51
@@ -5,47 +5,43 @@
5 5
6* Njalla's API 6* Njalla's API
7 7
8As noted in my recent post about 8As noted in my recent post about [[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from Cloudflare]], I was
9[[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from 9searching for a way to replace my [[https://cleberg.net/blog/cloudflare-dns-api.html][bash script]] to update my domain's =A= record
10Cloudflare]], I was searching for a way to replace my very easy-to-use 10with my home's internet protocol (IP) address dynamically.
11bash script to [[https://cleberg.net/blog/cloudflare-dns-api/][update Cloudflare's
12DNS via their API]].
13 11
14To reiterate what I said in those posts, this is a common necessity for 12To reiterate what I said in those posts, this is a common necessity for those of
15those of us who have non-static IP addresses that can change at any 13us who have non-static IP addresses that can change at any moment due to
16moment due to ISP policy. 14internet service provider (ISP) policy.
17 15
18In order to keep a home server running smoothly, the server admin needs 16In order to keep a home server running smoothly, the server admin needs to have
19to have a process to constantly monitor their public IP address and 17a process to constantly monitor their public IP address and update their
20update their domain's DNS records if it changes. 18domain's DNS records if it changes.
21 19
22This post explains how to use Python to update Njalla's DNS records 20This post explains how to use Python to update Njalla's DNS (domain name system)
23whenever a machine's public IP address changes. 21records whenever a machine's public IP address changes.
24 22
25** Creating a Token 23** Creating a Token
26 24
27To use Njalla's API, you will first need to create a token that will be 25To use Njalla's API, you will first need to create a token that will be used to
28used to authenticate you every time you call the API. Luckily, this is 26authenticate you every time you call the API (application programming
29very easy to do if you have an account with Njalla. 27interface). Luckily, this is very easy to do if you have an account with Njalla.
30 28
31Simply go the [[https://njal.la/settings/api/][API Settings]] page and 29Simply go the [[https://njal.la/settings/api/][API Settings]] page and click the =Add Token= button. Next, enter a
32click the =Add Token= button. Next, enter a name for the token and click 30name for the token and click =Add=.
33=Add=.
34 31
35Finally, click the =Manage= button next to your newly created token and 32Finally, click the =Manage= button next to your newly created token and copy the
36copy the =API Token= field. 33=API Token= field.
37 34
38** Finding the Correct API Request 35** Finding the Correct API Request
39 36
40Once you have a token, you're ready to call the Njalla API for any 37Once you have a token, you're ready to call the Njalla API for any number of
41number of requests. For a full listing of available requests, see the 38requests. For a full listing of available requests, see the [[https://njal.la/api/][Njalla API
42[[https://njal.la/api/][Njalla API Documentation]]. 39Documentation]].
43 40
44For this demo, we are using the =list-records= and =edit-record= 41For this demo, we are using the =list-records= and =edit-record= requests.
45requests.
46 42
47The =list-records= request requires the following payload to be sent 43The =list-records= request requires the following payload to be sent when
48when calling the API: 44calling the API:
49 45
50#+begin_src txt 46#+begin_src txt
51params: { 47params: {
@@ -53,8 +49,8 @@ params: {
53} 49}
54#+end_src 50#+end_src
55 51
56The =edit-record= request requires the following payload to be sent when 52The =edit-record= request requires the following payload to be sent when calling
57calling the API: 53the API:
58 54
59#+begin_src txt 55#+begin_src txt
60params: { 56params: {
@@ -66,14 +62,14 @@ params: {
66 62
67* Server Set-Up 63* Server Set-Up
68 64
69To create this script, we will be using Python. By default, I use Python 65To create this script, we will be using Python. By default, I use Python 3 on my
703 on my servers, so please note that I did not test this in Python 2, 66servers, so please note that I did not test this in Python 2, and I do not know
71and I do not know if Python 2 will work for this. 67if Python 2 will work for this.
72 68
73** Creating the Script 69** Creating the Script
74 70
75First, find a suitable place to create your script. Personally, I just 71First, find a suitable place to create your script. Personally, I just create a
76create a directory called =ddns= in my home directory: 72directory called =ddns= in my home directory:
77 73
78#+begin_src sh 74#+begin_src sh
79mkdir ~/ddns 75mkdir ~/ddns
@@ -85,20 +81,18 @@ Next, create a Python script file:
85nano ~/ddns/ddns.py 81nano ~/ddns/ddns.py
86#+end_src 82#+end_src
87 83
88The following code snippet is quite long, so I won't go into depth on 84The following code snippet is quite long, so I won't go into depth on each part.
89each part. However, I suggest you read through the entire script before 85However, I suggest you read through the entire script before running it; it is
90running it; it is quite simple and contains comments to help explain 86quite simple and contains comments to help explain each code block.
91each code block.
92 87
93:warning: *Note*: You will need to update the following variables for 88*Note*: You will need to update the following variables for this to work:
94this to work:
95 89
96- =token=: This is the Njalla API token you created earlier. 90- =token=: This is the Njalla API token you created earlier.
97- =user_domain=: This is the top-level domain you want to modify. 91- =user_domain=: This is the top-level domain you want to modify.
98- =include_subdomains=: Set this to =True= if you also want to modify 92- =include_subdomains=: Set this to =True= if you also want to modify subdomains
99 subdomains found under the TLD. 93 found under the TLD (top-level domain).
100- =subdomains=: If =include_subdomains= = =True=, you can include your 94- =subdomains=: If =include_subdomains= = =True=, you can include your list of
101 list of subdomains to be modified here. 95 subdomains to be modified here.
102 96
103#+begin_src python 97#+begin_src python
104#!/usr/bin/python 98#!/usr/bin/python
@@ -183,8 +177,8 @@ for record in data['records']:
183 177
184** Running the Script 178** Running the Script
185 179
186Once you've created the script and are ready to test it, run the 180Once you've created the script and are ready to test it, run the following
187following command: 181command:
188 182
189#+begin_src sh 183#+begin_src sh
190python3 ~/ddns/ddns.py 184python3 ~/ddns/ddns.py
@@ -192,15 +186,15 @@ python3 ~/ddns/ddns.py
192 186
193** Setting the Script to Run Automatically 187** Setting the Script to Run Automatically
194 188
195To make sure the scripts run automatically, add it to the =cron= file so 189To make sure the scripts run automatically, add it to the =cron= file so that it
196that it will run on a schedule. To do this, open the =cron= file: 190will run on a schedule. To do this, open the =cron= file:
197 191
198#+begin_src sh 192#+begin_src sh
199crontab -e 193crontab -e
200#+end_src 194#+end_src
201 195
202In the cron file, paste the following at the bottom of the editor in 196In the cron file, paste the following at the bottom of the editor in order to
203order to check the IP every five minutes: 197check the IP every five minutes:
204 198
205#+begin_src sh 199#+begin_src sh
206*/5 * * * * python3 /home/<your_username>/ddns/ddns.py 200*/5 * * * * python3 /home/<your_username>/ddns/ddns.py
content/blog/2022-02-16-debian-and-nginx.org +57 −64
@@ -3,34 +3,31 @@
3#+description: Step-by-step protocol for transitioning web server infrastructure to Debian operating system, including installation, configuration, and security hardening of Nginx and Agate services. 3#+description: Step-by-step protocol for transitioning web server infrastructure to Debian operating system, including installation, configuration, and security hardening of Nginx and Agate services.
4#+slug: debian-and-nginx 4#+slug: debian-and-nginx
5 5
6* Server OS: Debian 6* Server Operating System (OS): Debian
7 7
8I've used various Linux distributions throughout the years, but I've 8I've used various Linux distributions throughout the years, but I've never used
9never used anything except Ubuntu for my servers. Why? I really have no 9anything except Ubuntu for my servers. Why? I really have no idea, mostly just
10idea, mostly just comfort around the commands and software availability. 10comfort around the commands and software availability.
11 11
12However, I have always wanted to try Debian as a server OS after testing 12However, I have always wanted to try Debian as a server OS after testing it out
13it out in a VM a few years ago (side-note: I'd love to try Alpine too, 13in a VM a few years ago (side-note: I'd love to try Alpine too, but I always
14but I always struggle with compatibility). So, I decided to launch a new 14struggle with compatibility). So, I decided to launch a new VPS and use [[https://www.debian.org][Debian]]
15VPS and use [[https://www.debian.org][Debian]] 11 as the OS. Spoiler 1511 as the operating system (OS). Spoiler alert: it feels identical to Ubuntu for my purposes.
16alert: it feels identical to Ubuntu for my purposes.
17 16
18I did the normal things when first launching the VPS, such as adding a 17I did the normal things when first launching the VPS (virtual private server),
19new user, locking down SSH, etc. If you want to see that level of 18such as adding a new user, locking down SSH (secure shell protocol), etc. If you
20detail, read my other post about 19want to see that level of detail, read my other post about [[https://cleberg.net/blog/how-to-set-up-a-vps-web-server/][How to Set Up a VPS
21[[https://cleberg.net/blog/how-to-set-up-a-vps-web-server/][How to Set 20Web Server]].
22Up a VPS Web Server]].
23 21
24All of this has been similar, apart from small things such as the 22All of this has been similar, apart from small things such as the location of
25location of users' home folders. No complaints at all from me - Debian 23users' home folders. No complaints at all from me - Debian seems great.
26seems great.
27 24
28* Web Server: Nginx 25* Web Server: Nginx
29 26
30Once I had the baseline server configuration set-up for Debian, I moved 27Once I had the baseline server configuration set-up for Debian, I moved on to
31on to trying out [[https://nginx.org][Nginx]] as my web server software. 28trying out [[https://nginx.org][Nginx]] as my web server software. This required me to install the
32This required me to install the =nginx= and =ufw= packages, as well as 29=nginx= and =ufw= packages, as well as setting up the initial UFW (Uncomplicated
33setting up the initial UFW config: 30Firewall) config:
34 31
35#+begin_src sh 32#+begin_src sh
36sudo apt install nginx ufw 33sudo apt install nginx ufw
@@ -41,9 +38,9 @@ sudo ufw status
41sudo systemctl status nginx 38sudo systemctl status nginx
42#+end_src 39#+end_src
43 40
44Once I had the firewall set, I moved on to creating the directories and 41Once I had the firewall set, I moved on to creating the directories and files
45files for my website. This is very easy and is basically the same as 42for my website. This is very easy and is basically the same as setting up an
46setting up an Apache server, so no struggles here. 43Apache server, so no struggles here.
47 44
48#+begin_src sh 45#+begin_src sh
49sudo mkdir -p /var/www/your_domain/html 46sudo mkdir -p /var/www/your_domain/html
@@ -52,17 +49,17 @@ sudo chmod -R 755 /var/www/your_domain
52nano /var/www/your_domain/html/index.html 49nano /var/www/your_domain/html/index.html
53#+end_src 50#+end_src
54 51
55The next part, creating the Nginx configuration files, is quite a bit 52The next part, creating the Nginx configuration files, is quite a bit different
56different from Apache. First, you need to create the files in the 53from Apache. First, you need to create the files in the =sites-available= folder
57=sites-available= folder and symlink it the =sites-enabled= folder. 54and symlink it the =sites-enabled= folder.
58 55
59Creating the config file for your domain: 56Creating the configuration file for your domain:
60 57
61#+begin_src sh 58#+begin_src sh
62sudo nano /etc/nginx/sites-available/your_domain 59sudo nano /etc/nginx/sites-available/your_domain
63#+end_src 60#+end_src
64 61
65Default content for an Nginx config file: 62Default content for an Nginx configuration file:
66 63
67#+begin_src sh 64#+begin_src sh
68server { 65server {
@@ -87,9 +84,9 @@ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
87#+end_src 84#+end_src
88 85
89This will make your site available to the public (as long as you have 86This will make your site available to the public (as long as you have
90=your_domain= DNS records pointed at the server's IP address)! 87=your_domain= DNS (Domain Name System) records pointed at the server's IP address)!
91 88
92Next, I used [[https://certbot.eff.org/][certbot]] to issue an HTTPS 89Next, I used [[https://certbot.eff.org/][certbot]] to issue an HTTPS (Hypertext Transfer Protocol Secure)
93certificate for my domains using the following commands: 90certificate for my domains using the following commands:
94 91
95#+begin_src sh 92#+begin_src sh
@@ -99,16 +96,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
99sudo certbot --nginx 96sudo certbot --nginx
100#+end_src 97#+end_src
101 98
102Now that certbot ran successfully and updated my Nginx config files to 99Now that =certbot= ran successfully and updated my Nginx configuration files to
103include a =443= server block of code, I went back in and edited the 100include a =443= server block of code, I went back in and edited the
104config file to include security HTTP headers. This part is optional, but 101configuration file to include security HTTP headers. This part is optional, but
105is recommended for security purposes; you can even test a website's HTTP 102is recommended for security purposes; you can even test a website's HTTP header
106header security at [[https://securityheaders.com/][Security Headers]]. 103security at [[https://securityheaders.com/][Security Headers]].
107 104
108The configuration below shows a set-up where you only want your website 105The configuration below shows a set-up where you only want your website to serve
109to serve content from its own domain, except for images and scripts, 106content from its own domain, except for images and scripts, which may come from
110which may come from =nullitics.com=. All other content would be blocked 107=nullitics.com=. All other content would be blocked from loading in a browser.
111from loading in a browser.
112 108
113#+begin_src sh 109#+begin_src sh
114sudo nano /etc/nginx/sites-available/your_domain 110sudo nano /etc/nginx/sites-available/your_domain
@@ -133,35 +129,32 @@ sudo systemctl restart nginx
133 129
134** Nginx vs. Apache 130** Nginx vs. Apache
135 131
136As I stated at the beginning, my historical hesitation with trying Nginx 132As I stated at the beginning, my historical hesitation with trying Nginx was
137was that the differences in configuration formats scared me away from 133that the differences in configuration formats scared me away from leaving
138leaving Apache. However, I prefer Nginx to Apache for a few reasons: 134Apache. However, I prefer Nginx to Apache for a few reasons:
139 135
1401. Nginx uses only one config file (=your_domain=) vs. Apache's two-file 1361. Nginx uses only one configuration file (=your_domain=) vs. Apache's two-file
141 approach for HTTP vs. HTTPS (=your_domain.conf= and 137 approach for HTTP vs. HTTPS (=your_domain.conf= and
142 =your_domain-le-ssl.conf=). 138 =your_domain-le-ssl.conf=).
1432. Symlinking new configurations files and reloading Nginx are way 1392. Symlinking new configurations files and reloading Nginx are way easier than
144 easier than Apache's process of having to enable headers with 140 Apache's process of having to enable headers with =a2enmod mod_headers=,
145 =a2enmod mod_headers=, enable PHP with =a2enmod php= (plus any other 141 enable PHP with =a2enmod php= (plus any other mods you need), and then
146 mods you need), and then enabling sites with =a2ensite=, and THEN 142 enabling sites with =a2ensite=, and THEN reloading Apache.
147 reloading Apache. 1433. The contents of the Nginx configuration files seem more organized and logical
1483. The contents of the Nginx config files seem more organized and 144 with the curly-bracket approach. This is a minor reason, but everything just
149 logical with the curly-bracket approach. This is a minor reason, but 145 felt cleaner while I was installing my sites and that had a big quality of
150 everything just felt cleaner while I was installing my sites and that 146 life impact on the installation for me.
151 had a big quality of life impact on the installation for me. 147
152 148They're both great software packages, but Nginx just seems more organized and
153They're both great software packages, but Nginx just seems more 149easier to use these days. I will certainly be exploring the Nginx docs to see
154organized and easier to use these days. I will certainly be exploring 150what other fun things I can do with all of this.
155the Nginx docs to see what other fun things I can do with all of this.
156 151
157* Gemini Server: Agate 152* Gemini Server: Agate
158 153
159Finally, I set up the Agate software on this server again to host my 154Finally, I set up the Agate software on this server again to host my Gemini
160Gemini server content, using Rust as I have before. You can read my 155server content, using Rust as I have before. You can read my other post for more
161other post for more information on installing Agate: 156information on installing Agate: [[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini Server]].
162[[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini
163Server]].
164 157
165All in all, Debian + Nginx is very slick and I prefer it over my old 158All in all, Debian + Nginx is very slick and I prefer it over my old combination
166combination of Ubuntu + Apache (although it's really just Nginx > Apache 159of Ubuntu + Apache (although it's really just Nginx > Apache for me, since
167for me, since Debian seems mostly the same as Ubuntu is so far). 160Debian seems mostly the same as Ubuntu is so far).
content/blog/2022-02-17-exiftool.org +18 −20
@@ -5,14 +5,14 @@
5 5
6** Why Strip Metadata? 6** Why Strip Metadata?
7 7
8Okay, so you want to strip metadata from your photos. Perhaps you take 8Okay, so you want to strip metadata from your photos. Perhaps you take pictures
9pictures of very rare birds, and the location metadata is a gold mine 9of very rare birds, and the location metadata is a gold mine for poachers, or
10for poachers, or perhaps you're just privacy-oriented like me and prefer 10perhaps you're just privacy-oriented like me and prefer to strip metadata from
11to strip metadata from publicly-available images. 11publicly-available images.
12 12
13There are various components of image metadata that you may want to 13There are various components of image metadata that you may want to delete
14delete before releasing a photo to the public. Here's an incomplete list 14before releasing a photo to the public. Here's an incomplete list of things I
15of things I could easily see just by inspecting a photo on my laptop: 15could easily see just by inspecting a photo on my laptop:
16 16
17- Location (Latitude & Longitude) 17- Location (Latitude & Longitude)
18- Dimensions 18- Dimensions
@@ -25,15 +25,14 @@ of things I could easily see just by inspecting a photo on my laptop:
25- Metering Mode 25- Metering Mode
26- F Number 26- F Number
27 27
28Regardless of your reasoning, I'm going to explain how I used the 28Regardless of your reasoning, I'm going to explain how I used the =exiftool=
29=exiftool= package in Linux to automatically strip metadata from all 29package in Linux to automatically strip metadata from all images in a directory
30images in a directory (+ subdirectories). 30(+ subdirectories).
31 31
32** Installing =exiftool= 32** Installing =exiftool=
33 33
34First things first: we need to install the tool. I'm running Debian 11 34First things first: we need to install the tool. I'm running Debian 11 on my
35on my server (Ubuntu will work the same), so the command is as simple 35server (Ubuntu will work the same), so the command is as simple as:
36as:
37 36
38#+begin_src sh 37#+begin_src sh
39sudo apt install exiftool 38sudo apt install exiftool
@@ -44,16 +43,15 @@ distributions, but I really only care to test out this one package.
44 43
45** Recursively Strip Data 44** Recursively Strip Data
46 45
47I actually use this tool extensively to strip any photos uploaded to the 46I actually use this tool extensively to strip any photos uploaded to the website
48website that serves all the images for my blog (=img.cleberg.net=). 47that serves all the images for my blog (=img.cleberg.net=).
49 48
50The following command is incredibly useful and can be modified to 49The following command is incredibly useful and can be modified to include any
51include any image extensions that =exiftool= supports: 50image extensions that =exiftool= supports:
52 51
53#+begin_src sh 52#+begin_src sh
54exiftool -r -all= -ext jpg -ext png /path/to/directory/ 53exiftool -r -all= -ext jpg -ext png /path/to/directory/
55#+end_src 54#+end_src
56 55
57The output of the command will let you know how many directories were 56The output of the command will let you know how many directories were scanned,
58scanned, how many images were updated, and how many images were 57how many images were updated, and how many images were unchanged.
59unchanged.
content/blog/2022-02-20-nginx-caching.org +31 −37
@@ -5,16 +5,15 @@
5 5
6* Update Your Nginx Config to Cache Static Files 6* Update Your Nginx Config to Cache Static Files
7 7
8If you run a website on Nginx that serves static content (i.e., content 8If you run a website on Nginx that serves static content (i.e., content that is
9that is not dynamic and changing with interactions from the user), you 9not dynamic and changing with interactions from the user), you would likely
10would likely benefit from caching that content on the client-side. If 10benefit from caching that content on the client-side. If you're used to Apache
11you're used to Apache and looking for the Nginx equivalent, this post 11and looking for the Nginx equivalent, this post should help.
12should help.
13 12
14Luckily, setting up the cache is as easy as identifying the file types 13Luckily, setting up the cache is as easy as identifying the file types you want
15you want to cache and determining the expiration length. To include more 14to cache and determining the expiration length. To include more file types,
16file types, simply use the bar separator (=|=) and type the new file 15simply use the bar separator (=|=) and type the new file extension you want to
17extension you want to include. 16include.
18 17
19#+begin_src config 18#+begin_src config
20server { 19server {
@@ -28,41 +27,36 @@ server {
28} 27}
29#+end_src 28#+end_src
30 29
31I have seen some people who prefer to set =expires= as =365d= or even 30I have seen some people who prefer to set =expires= as =365d= or even =max=, but
32=max=, but that is only for stable, infrequently changing websites. As 31that is only for stable, infrequently changing websites. As my site often
33my site often changes (i.e., I'm never content with my website), I need 32changes (i.e., I'm never content with my website), I need to know that my
34to know that my readers are seeing the new content without waiting too 33readers are seeing the new content without waiting too long.
35long.
36 34
37So, I went ahead and set the expiration date at =30d=, which is short 35So, I went ahead and set the expiration date at =30d=, which is short enough to
38enough to refresh for readers but long enough that clients/browsers 36refresh for readers but long enough that clients/browsers won't be re-requesting
39won't be re-requesting the static files too often, hopefully resulting 37the static files too often, hopefully resulting in faster loading times, as
40in faster loading times, as images should be the only thing slowing down 38images should be the only thing slowing down my site.
41my site.
42 39
43* Testing Results 40* Testing Results
44 41
45To test my changes to the Nginx configuration, I used the 42To test my changes to the Nginx configuration, I used the [[https://addons.mozilla.org/en-US/firefox/addon/http-header-live/][HTTP Header Live]]
46[[https://addons.mozilla.org/en-US/firefox/addon/http-header-live/][HTTP 43extension on my Gecko browser and used the sidebar to inspect the headers of a
47Header Live]] extension on my Gecko browser and used the sidebar to 44recent image from my blog.
48inspect the headers of a recent image from my blog.
49 45
50In the image below, you can see that the =Cache-Control= header is now 46In the image below, you can see that the =Cache-Control= header is now present
51present and set to 2592000, which is 30 days represented in seconds (30 47and set to 2592000, which is 30 days represented in seconds (30 days _ 24
52days _ 24 hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000 48hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds).
53seconds).
54 49
55The =Expires= field is now showing 22 March 2022, which is 30 days from 50The =Expires= field is now showing 22 March 2022, which is 30 days from the day
56the day of this post, 20 February 2022. 51of this post, 20 February 2022.
57 52
58* Caveats 53* Caveats
59 54
60Remember that this caching system is *client-side*, which means that 55Remember that this caching system is *client-side*, which means that content is
61content is only cached for as long as a client allows it. For example, 56only cached for as long as a client allows it. For example, my browser purges
62my browser purges all caches, data, etc. upon exit, so this caching 57all caches, data, etc. upon exit, so this caching policy will only work as long
63policy will only work as long as my browser remains open and running. 58as my browser remains open and running.
64 59
65If you need to test updates to your site, you'll need to clear the cache 60If you need to test updates to your site, you'll need to clear the cache to see
66to see updates for any file extension you configured. This can often be 61updates for any file extension you configured. This can often be done with the
67done with the =Shift + F5= or =Ctrl + F5= key combinations in most 62=Shift + F5= or =Ctrl + F5= key combinations in most browsers.
68browsers.
content/blog/2022-02-22-tuesday.org +20 −27
@@ -5,34 +5,27 @@
5 5
6* Tuesday, Twosday 6* Tuesday, Twosday
7 7
8I'm taking a break from my usual technology-related posts and writing 8I'm taking a break from my usual technology-related posts and writing about
9about something a little more enjoyable today. 9something a little more enjoyable today.
10 10
11Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is 11Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is Twosday.
12Twosday.
13 12
14Let's look at everything that fell in place today: 13Let's look at everything that fell in place today:
15 14
161. Written in the =m-dd-yy= or =dd-m-yy= formats, today is 2-22-22 or 151. Written in the =m-dd-yy= or =dd-m-yy= formats, today is 2-22-22 or 22-2-22,
17 22-2-22, which is a neat little palindrome in either format. (The 16 which is a neat little palindrome in either format. (The last ubiquitous
18 last ubiquitous six-digit palindrome was 1-11-11.) 17 six-digit palindrome was 1-11-11.)
192. Today is Tuesday, which is why everyone is using the nickname Twosday 182. Today is Tuesday, which is why everyone is using the nickname Twosday to call
20 to call out these similarities. 19 out these similarities.
213. Falling on Tuesday means today is the 2nd day of the week (for most 203. Falling on Tuesday means today is the 2nd day of the week (for most cultures.
22 cultures. For the US, it's the 3rd day of the week since we start on 21 For the US, it's the 3rd day of the week since we start on Sunday).
23 Sunday). 224. The only culture I could find with a connection to a =2= is that some Slavic
244. The only culture I could find with a connection to a =2= is that some 23 languages derived their version of Tuesday from the Old Church Slavonic word
25 Slavic languages derived their version of Tuesday from the Old Church 24 =въторъ=, meaning "the second."
26 Slavonic word =въторъ=, meaning "the second." 255. Written in the classic monospaced, digital font (think of digital clocks from
275. Written in the classic monospaced, digital font (think of digital 26 the 80s/90s), there is nice symmetry to the numbers ([[https://img.cleberg.net/blog/20220222-tuesday/digital_font.webp][view the image here]]!).
28 clocks from the 80s/90s), there is nice symmetry to the numbers 276. This one isn't naturally-occurring, but it seems people around the world are
29 ([[https://img.cleberg.net/blog/20220222-tuesday/digital_font.webp][view 28 celebrating the day. For example, a group is putting together [[https://www.eventbrite.com/e/2-22-22-a-collective-wedding-ceremony-at-the-state-capitol-tickets-211434605597][a wedding of
30 the image here]]!). 29 222 couples at the California State Capitol in Sacramento]], concluding at
316. This one isn't naturally-occurring, but it seems people around the 30 exactly 2:22 PM. These couples will record their marriage dates as 2-22-22
32 world are celebrating the day. For example, a group is putting 31 2:22 PM. Tickets were on sale for $222.22.
33 together
34 [[https://www.eventbrite.com/e/2-22-22-a-collective-wedding-ceremony-at-the-state-capitol-tickets-211434605597][a
35 wedding of 222 couples at the California State Capitol in
36 Sacramento]], concluding at exactly 2:22 PM. These couples will
37 record their marriage dates as 2-22-22 2:22 PM. Tickets were on sale
38 for $222.22.
content/blog/2022-03-02-reliable-notes.org +80 −105
@@ -4,154 +4,129 @@
4#+slug: reliable-notes 4#+slug: reliable-notes
5 5
6* Choosing Durable File Formats 6* Choosing Durable File Formats
7:PROPERTIES:
8:CUSTOM_ID: choosing-durable-file-formats
9:END:
10 7
11#+begin_quote 8#+begin_quote
12TL;DR: Write in a format that can be easily rendered and read in 9TL;DR (Too Long; Didn't Read): Write in a format that can be easily rendered and
13plain-text mode (e.g., =.txt=, =.md=, etc.). 10read in plain-text mode (e.g., =.txt=, =.md=, etc.).
14#+end_quote 11#+end_quote
15 12
16As I've written more and more over the years, I've found that my love of 13As I've written more and more over the years, I've found that my love of
17note-taking is always growing. Everything I learn or need to remember 14note-taking is always growing. Everything I learn or need to remember can be
18can be written down in a note and saved digitally, with no cost to 15written down in a note and saved digitally, with no cost to myself. Unlike paper
19myself. Unlike paper copies that need physical storage space, digital 16copies that need physical storage space, digital files simply need space on your
20files simply need space on your local disk or cloud storage, which is 17local disk or cloud storage, which is fairly abundant these days.
21fairly abundant these days. 18
22 19However, I had a historical struggle with migration of notes between different
23However, I had a historical struggle with migration of notes between 20apps that require different formats and applied proprietary styling. This meant
24different apps that require different formats and applied proprietary 21that I had to go through each note during migration and edit the file to look
25styling. This meant that I had to go through each note during migration 22presentable again.
26and edit the file to look presentable again. 23
27 24For the last year or two, I have written everything exclusively in [[https://en.wikipedia.org/wiki/Markdown][Markdown]]
28For the last year or two, I have written everything exclusively in 25format. Small notes, long-form writings, and even these blog posts are all
29[[https://en.wikipedia.org/wiki/Markdown][Markdown]] format. Small 26written in Markdown.
30notes, long-form writings, and even these blog posts are all written in 27
31Markdown. 28Why Markdown? While I do appreciate the simplicity of plain-text files without
32 29any formatting, I often need visual cues such as heading and code blocks to keep
33Why Markdown? While I do appreciate the simplicity of plain-text files 30my thoughts straight. Markdown provides a minimal set of styling indicators for
34without any formatting, I often need visual cues such as heading and 31me to style my notes without adding any proprietary, embedded data into the
35code blocks to keep my thoughts straight. Markdown provides a minimal 32files. If I want a top-level heading, I simply add a hash (=#=) before the line.
36set of styling indicators for me to style my notes without adding any 33An added bonus is that even if a system doesn't understand Markdown, it will
37proprietary, embedded data into the files. If I want a top-level 34render it as plain-text and I can read it just as easily.
38heading, I simply add a hash (=#=) before the line. An added bonus is 35
39that even if a system doesn't understand Markdown, it will render it as 36For example, here's how TextEdit on macOS will open and display a Markdown file
40plain-text and I can read it just as easily. 37in plain-text, since it does contain any features to preview Markdown as HTML:
41
42For example, here's how TextEdit on macOS will open and display a
43Markdown file in plain-text, since it does contain any features to
44preview Markdown as HTML:
45 38
46#+caption: Plain Text Markdown 39#+caption: Plain Text Markdown
47[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.webp]] 40[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.webp]]
48 41
49** Saving & Syncing Files 42** Saving & Syncing Files
50:PROPERTIES:
51:CUSTOM_ID: saving-syncing-files
52:END:
53In order to read and edit my notes across platforms, I use my personal
54cloud storage through Tresorit due to its native integration with macOS
55and iOS file managers. In addition, Tresorit works well on Debian-based
56Linux distros, which I used before macOS (and will likely switch back to
57in a few years).
58 43
59You can use whatever sync software you want - syncing plain-text or 44In order to read and edit my notes across platforms, I use my personal cloud
60markdown files is incredibly easy and fast, since the files are 45storage through Tresorit due to its native integration with macOS and iOS file
61generally tiny. 46managers. In addition, Tresorit works well on Debian-based Linux distributions,
47which I used before macOS (and will likely switch back to in a few years).
62 48
63Since the cloud storage syncs files automatically, there is no need for 49You can use whatever sync software you want - syncing plain-text or markdown
64me to sync anything manually or kick-off a sync job to update my files. 50files is incredibly easy and fast, since the files are generally tiny.
65This means that I can edit on mobile, and it takes about 5-10 seconds to 51
66see 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.
67 56
68*** Version Control with Git 57*** Version Control with Git
69:PROPERTIES: 58:PROPERTIES:
70:CUSTOM_ID: version-control-with-git 59:CUSTOM_ID: version-control-with-git
71:END: 60:END:
72A different approach I've contemplated is storing my notes and 61A different approach I've contemplated is storing my notes and attachments is
73attachments is using a hosted Git repository to track changes to the 62using a hosted Git repository to track changes to the files. However, I don't
74files. However, I don't want to rely on an external service that could 63want to rely on an external service that could potentially see into my data,
75potentially see into my data, even if the repository is private. 64even if the repository is private.
76 65
77I might just do =git init= locally and then commit my changes each time 66I might just do =git init= locally and then commit my changes each time I write
78I write or update a note, but that seems to be a lot of work just for 67or update a note, but that seems to be a lot of work just for tracking changes -
79tracking changes - which I don't necessarily care to know. 68which I don't necessarily care to know.
80 69
81*** Backups! 70*** Backups!
82:PROPERTIES: 71:PROPERTIES:
83:CUSTOM_ID: backups 72:CUSTOM_ID: backups
84:END: 73:END:
85One small addition to the storage/sync conversation is the idea of 74One small addition to the storage/sync conversation is the idea of backups.
86backups. Personally, I manually create periodic backups of my entire 75Personally, I manually create periodic backups of my entire cloud storage,
87cloud storage, compress it into an archive, and store it on my home 76compress it into an archive, and store it on my home server.
88server.
89 77
90To improve my workflow, I am going to be exploring options to 78To improve my workflow, I am going to be exploring options to automatically
91automatically compress the mounted cloud directory and send it over to 79compress the mounted cloud directory and send it over to my server on a set
92my server on a set schedule. 80schedule.
93 81
94** Writing on Desktop 82** Writing on Desktop
95:PROPERTIES:
96:CUSTOM_ID: writing-on-desktop
97:END:
98 83
99#+begin_quote 84#+begin_quote
100*Update (06.14.22)*: Since writing this post, I have reverted to simply 85*Update (06.14.22)*: Since writing this post, I have reverted to simply keeping
101keeping my =notes= folder open and opening notes individually in 86my =notes= folder open and opening notes individually in TextEdit for a more
102TextEdit for a more minimal and relaxing writing experience on the 87minimal and relaxing writing experience on the desktop.
103desktop.
104#+end_quote 88#+end_quote
105 89
106The bulk of my writing occurs in a desktop environment, with a full 90The bulk of my writing occurs in a desktop environment, with a full keyboard
107keyboard layout and wide screen. I don't illustrate with a smart pen, I 91layout and wide screen. I don't illustrate with a smart pen, I rarely use
108rarely use embedded images, and I love being able to see all of my 92embedded images, and I love being able to see all of my notes/directories in a
109notes/directories in a sidebar. 93sidebar.
110 94
111With this simple set of requirements, I chose 95With this simple set of requirements, I chose [[https://obsidian.md][Obsidian]] as my desktop text
112[[https://obsidian.md][Obsidian]] as my desktop text editor. Obsidian 96editor. Obsidian has some in-depth tools like a graph view, command palette,
113has some in-depth tools like a graph view, command palette, mentions, 97mentions, etc., but I've found that using it as a simple Markdown editor is
114etc., but I've found that using it as a simple Markdown editor is
115incredibly easy and straightforward. 98incredibly easy and straightforward.
116 99
117Here's an example of how my Markdown notes look when opened in 100Here's an example of how my Markdown notes look when opened in plain-text mode:
118plain-text mode:
119 101
120#+caption: Obsidian Markdown Source Mode 102#+caption: Obsidian Markdown Source Mode
121[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.webp]] 103[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.webp]]
122 104
123Here's the "live preview" version, where the Markdown is rendered into 105Here's the "live preview" version, where the Markdown is rendered into its HTML
124its HTML format: 106format:
125 107
126#+caption: Obsidian Markdown Live Preview 108#+caption: Obsidian Markdown Live Preview
127[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.webp]] 109[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.webp]]
128 110
129*** Programming on Desktop 111*** Programming on Desktop
130:PROPERTIES: 112
131:CUSTOM_ID: programming-on-desktop 113While I was writing this, I realized I should specify that I don't use the same
132:END: 114editor for writing notes and for writing code. For programming purposes, I use
133While I was writing this, I realized I should specify that I don't use 115[[https://vscodium.com][VSCodium]] as my development IDE.
134the same editor for writing notes and for writing code. For programming
135purposes, I use [[https://vscodium.com][VSCodium]] as my development
136IDE.
137 116
138** Writing on Mobile 117** Writing on Mobile
139:PROPERTIES: 118
140:CUSTOM_ID: writing-on-mobile 119Personally, I write very little on mobile, except when needing to take important
141:END: 120notes on-the-go. Any long-form writing, journals, etc. are done at home, where I
142Personally, I write very little on mobile, except when needing to take 121always have my laptop available.
143important notes on-the-go. Any long-form writing, journals, etc. are 122
144done at home, where I always have my laptop available. 123I wanted a simple and foolproof editor for iOS, preferably open-source. After a
145 124long journey of testing the few (& terrible) open-source iOS note-taking apps, I
146I wanted a simple and foolproof editor for iOS, preferably open-source. 125finally found a phenomenal one: [[https://github.com/simonbs/runestone][Runestone]]. This app is fantastic for
147After a long journey of testing the few (& terrible) open-source iOS 126note-taking, has plenty of optional features, and integrates natively with the
148note-taking apps, I finally found a phenomenal one: 127iOS file manager.
149[[https://github.com/simonbs/runestone][Runestone]]. This app is 128
150fantastic for note-taking, has plenty of optional features, and 129This app opens the iOS file manager and allows you to click any file you want,
151integrates natively with the iOS file manager. 130opens it up in an editor, and lets me save and close out of that note.
152
153This app opens the iOS file manager and allows you to click any file you
154want, opens it up in an editor, and lets me save and close out of that
155note.
156 131
157Quite simple but effective. 132Quite simple but effective.
content/blog/2022-03-03-financial-database.org +69 −90
@@ -4,60 +4,49 @@
4#+slug: financial-database 4#+slug: financial-database
5 5
6* Personal Financial Tracking 6* Personal Financial Tracking
7:PROPERTIES: 7
8:CUSTOM_ID: personal-financial-tracking 8For the last 6-ish years, I've tracked my finances in a spreadsheet. This is
9:END: 9common practice in the business world, but any good dev will cringe at the
10For the last 6-ish years, I've tracked my finances in a spreadsheet. 10thought of storing long-term data in a spreadsheet. A spreadsheet is not for
11This is common practice in the business world, but any good dev will 11long-term storage or as a source of data to pull data/reports.
12cringe at the thought of storing long-term data in a spreadsheet. A 12
13spreadsheet is not for long-term storage or as a source of data to pull 13As I wanted to expand the functionality of my financial data (e.g., adding more
14data/reports. 14reports), I decided to migrate the data into a database. To run reports, I would
15 15query the database and use a language like Python or Javascript to process the
16As I wanted to expand the functionality of my financial data (e.g., 16data, perform calculations, and visualize the data.
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.
21 17
22* SQLite 18* SQLite
23:PROPERTIES: 19
24:CUSTOM_ID: sqlite 20When choosing the type of database I wanted to use for this project, I was split
25:END: 21between three options:
26When choosing the type of database I wanted to use for this project, I 22
27was split between three options: 231. MySQL: The database I have the most experience with and have used for years.
28
291. MySQL: The database I have the most experience with and have used for
30 years.
312. PostgreSQL: A database I'm new to, but want to learn. 242. PostgreSQL: A database I'm new to, but want to learn.
323. SQLite: A database that I've used for a couple projects and have 253. SQLite: A database that I've used for a couple projects and have moderate
33 moderate experience. 26 experience.
34 27
35I ended up choosing SQLite since it can be maintained within a single 28I ended up choosing SQLite since it can be maintained within a single =.sqlite=
36=.sqlite= file, which allows me more flexibility for storage and backup. 29file, which allows me more flexibility for storage and backup. I keep this file
37I keep this file in my cloud storage and pull it up whenever needed. 30in my cloud storage and pull it up whenever needed.
38 31
39** GUI Editing 32** Visual Editing
40:PROPERTIES: 33
41:CUSTOM_ID: gui-editing 34Since I didn't want to try and import 1000--1500 records into my new database
42:END: 35via the command line, I opted to use [[https://sqlitebrowser.org/][DB Browser for SQLite (DB4S)]] as a GUI
43Since I didn't want to try and import 1000--1500 records into my new 36(graphical user interface) tool. This application is excellent, and I don't see
44database via the command line, I opted to use 37myself going back to the CLI (command line interface) when working in this
45[[https://sqlitebrowser.org/][DB Browser for SQLite (DB4S)]] as a GUI 38database.
46tool. This application is excellent, and I don't see myself going back
47to the CLI when working in this database.
48 39
49DB4S allows you to copy a range of cells from a spreadsheet and paste it 40DB4S allows you to copy a range of cells from a spreadsheet and paste it
50straight into the SQL table. I used this process for all 36 accounts, 41straight into the SQL table. I used this process for all 36 accounts, 1290
511290 account statements, and 126 pay statements. Overall, I'm guessing 42account statements, and 126 pay statements. Overall, I'm guessing this took
52this took anywhere between 4--8 hours. In comparison, it probably took 43anywhere between 4--8 hours. In comparison, it probably took me 2-3 days to
53me 2-3 days to initially create the spreadsheet. 44initially create the spreadsheet.
54 45
55** Schema 46** Schema
56:PROPERTIES: 47
57:CUSTOM_ID: schema 48The schema for this database is actually extremely simple and involves only
58:END: 49three tables (for now):
59The schema for this database is actually extremely simple and involves
60only three tables (for now):
61 50
621. Accounts 511. Accounts
632. Statements 522. Statements
@@ -65,9 +54,9 @@ only three tables (for now):
65 54
66*Accounts* 55*Accounts*
67 56
68The Accounts table contains summary information about an account, such 57The Accounts table contains summary information about an account, such as a car
69as a car loan or a credit card. By viewing this table, you can find 58loan or a credit card. By viewing this table, you can find high-level data, such
70high-level data, such as interest rate, credit line, or owner. 59as interest rate, credit line, or owner.
71 60
72#+begin_src sql 61#+begin_src sql
73CREATE TABLE "Accounts" ( 62CREATE TABLE "Accounts" (
@@ -85,10 +74,10 @@ CREATE TABLE "Accounts" (
85 74
86*Statements* 75*Statements*
87 76
88The Statements table uses the same unique identifier as the Accounts 77The Statements table uses the same unique identifier as the Accounts table,
89table, meaning you can join the tables to find a monthly statement for 78meaning you can join the tables to find a monthly statement for any of the
90any of the accounts listed in the Accounts table. Each statement has an 79accounts listed in the Accounts table. Each statement has an account identified
91account ID, statement date, and total balance. 80(ID), statement date, and total balance.
92 81
93#+begin_src sql 82#+begin_src sql
94CREATE TABLE "Statements" ( 83CREATE TABLE "Statements" (
@@ -103,10 +92,10 @@ CREATE TABLE "Statements" (
103 92
104*Payroll* 93*Payroll*
105 94
106The Payroll table is a separate entity, unrelated to the Accounts or 95The Payroll table is a separate entity, unrelated to the Accounts or Statements
107Statements tables. This table contains all information you would find on 96tables. This table contains all information you would find on a pay statement
108a pay statement from an employer. As you change employers or obtain new 97from an employer. As you change employers or obtain new perks/benefits, just add
109perks/benefits, just add new columns to adapt to the new data. 98new columns to adapt to the new data.
110 99
111#+begin_src sql 100#+begin_src sql
112CREATE TABLE "Payroll" ( 101CREATE TABLE "Payroll" (
@@ -141,23 +130,18 @@ CREATE TABLE "Payroll" (
141#+end_src 130#+end_src
142 131
143** Python Reporting 132** Python Reporting
144:PROPERTIES:
145:CUSTOM_ID: python-reporting
146:END:
147Once I created the database tables and imported all my data, the only
148step left was to create a process to report and visualize on various
149aspects of the data.
150 133
151In order to explore and create the reports I'm interested in, I utilized 134Once I created the database tables and imported all my data, the only step left
152a two-part process involving Jupyter Notebooks and Python scripts. 135was to create a process to report and visualize on various aspects of the data.
136
137In order to explore and create the reports I'm interested in, I utilized a
138two-part process involving Jupyter Notebooks and Python scripts.
153 139
154*** Step 1: Jupyter Notebooks 140*** Step 1: Jupyter Notebooks
155:PROPERTIES: 141
156:CUSTOM_ID: step-1-jupyter-notebooks
157:END:
158When I need to explore data, try different things, and re-run my code 142When I need to explore data, try different things, and re-run my code
159cell-by-cell, I use Jupyter Notebooks. For example, I explored the 143cell-by-cell, I use Jupyter Notebooks. For example, I explored the =Accounts=
160=Accounts= table until I found the following useful information: 144table until I found the following useful information:
161 145
162#+begin_src python 146#+begin_src python
163import sqlite3 147import sqlite3
@@ -182,12 +166,9 @@ df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type',
182#+end_src 166#+end_src
183 167
184*** Step 2: Python Scripts 168*** Step 2: Python Scripts
185:PROPERTIES: 169
186:CUSTOM_ID: step-2-python-scripts 170Once I explored enough through the notebooks and had a list of reports I wanted,
187:END: 171I moved on to create a Python project with the following structure:
188Once I explored enough through the notebooks and had a list of reports I
189wanted, I moved on to create a Python project with the following
190structure:
191 172
192#+begin_src txt 173#+begin_src txt
193finance/ 174finance/
@@ -212,16 +193,15 @@ This structure allows me to:
212 193
2131. Compile all required python packages into =requirements.txt= for easy 1941. Compile all required python packages into =requirements.txt= for easy
214 installation if I move to a new machine. 195 installation if I move to a new machine.
2152. Activate a virtual environment in =venv/= so I don't need to maintain 1962. Activate a virtual environment in =venv/= so I don't need to maintain a
216 a system-wide Python environment just for this project. 197 system-wide Python environment just for this project.
2173. Keep my =notebooks/= folder to continuously explore the data as I see 1983. Keep my =notebooks/= folder to continuously explore the data as I see fit.
218 fit.
2194. Maintain a local copy of the database in =src/= for easy access. 1994. Maintain a local copy of the database in =src/= for easy access.
2205. Export reports, images, HTML files, etc. to =public/=. 2005. Export reports, images, HTML files, etc. to =public/=.
221 201
222Now, onto the differences between the code in a Jupyter Notebook and the 202Now, onto the differences between the code in a Jupyter Notebook and the actual
223actual Python files. To create the report in the Notebook snippet above, 203Python files. To create the report in the Notebook snippet above, I created the
224I created the following function inside =process.py=: 204following function inside =process.py=:
225 205
226#+begin_src python 206#+begin_src python
227# Create summary pie chart 207# Create summary pie chart
@@ -258,11 +238,10 @@ Other charts generated by this project include:
258 238
259- Charts of account balances over time. 239- Charts of account balances over time.
260- Line chart of effective tax rate (taxes divided by taxable income). 240- Line chart of effective tax rate (taxes divided by taxable income).
261- Salary projections and error limits using past income and inflation 241- Salary projections and error limits using past income and inflation rates.
262 rates.
263- Multi-line chart of gross income, taxable income, and net income. 242- Multi-line chart of gross income, taxable income, and net income.
264 243
265The best thing about this project? I can improve it at any given time, 244The best thing about this project? I can improve it at any given time, shaping
266shaping it into whatever helps me the most for that time. I imagine that 245it into whatever helps me the most for that time. I imagine that I will be
267I will be introducing an asset tracking table soon to track the 246introducing an asset tracking table soon to track the depreciating value of
268depreciating value of cars, houses, etc. Who knows what's next? 247cars, houses, etc. Who knows what's next?
content/blog/2022-03-08-plex-migration.org +101 −137
@@ -4,18 +4,15 @@
4#+slug: plex-migration 4#+slug: plex-migration
5 5
6* Migration Phases 6* Migration Phases
7:PROPERTIES: 7
8:CUSTOM_ID: migration-phases 8I recently decided to migrate my server from an old OptiPlex desktop machine to
9:END: 9a custom-built tower with better hardware in every category. In order to do
10I recently decided to migrate my server from an old OptiPlex desktop 10this, I would need to properly migrate a full Plex installation.
11machine to a custom-built tower with better hardware in every category. 11
12In order to do this, I would need to properly migrate a full Plex 12The second part of this migration is that the new server uses an Nvidia GPU
13installation. 13(graphics processing unit) and does not have any integrated graphics, which
14 14requires extra work for installation, but provides much better hardware
15The second part of this migration is that the new server uses an Nvidia 15transcoding options for Plex.
16GPU and does not have any integrated graphics, which requires extra work
17for installation, but provides much better hardware transcoding options
18for Plex.
19 16
20Therefore, I have broken this migration down into three phases: 17Therefore, I have broken this migration down into three phases:
21 18
@@ -24,50 +21,41 @@ Therefore, I have broken this migration down into three phases:
243. Configure GPU Transcoding 213. Configure GPU Transcoding
25 22
26* Phase 1: Configure the New Server 23* Phase 1: Configure the New Server
27:PROPERTIES: 24
28:CUSTOM_ID: phase-1-configure-the-new-server 25** Choosing an Operating System (OS)
29:END: 26
30** Choosing an OS
31:PROPERTIES:
32:CUSTOM_ID: choosing-an-os
33:END:
34In order to migrate Plex to my new server, I first needed to choose an 27In order to migrate Plex to my new server, I first needed to choose an
35appropriate operating system (OS) and install it on the machine. Given 28appropriate OS and install it on the machine. Given that I have encountered
36that I have encountered numerous issues installing other Linux 29numerous issues installing other Linux distributions properly with Nvidia
37distributions properly with Nvidia graphics, I chose 30graphics, I chose [[https://ubuntu.com/download/server][Ubuntu Server]].
38[[https://ubuntu.com/download/server][Ubuntu Server]].
39 31
40The first step is to create a bootable USB with Ubuntu Server. This is 32The first step is to create a bootable USB (universal serial bus) with Ubuntu
41easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on 33Server. This is easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on many different platforms.
42many different platforms. Just download the Ubuntu Server =.iso= image, 34Just download the Ubuntu Server =.iso= image, launch Etcher, and install the
43launch Etcher, and install the =.iso= on the USB. 35=.iso= on the USB.
44 36
45Once the USB is created, insert it into my server, reboot, and click 37Once the USB is created, insert it into my server, reboot, and click =Esc= (or
46=Esc= (or any of the =F1-12= keys) until the BIOS menu appears. Finally, 38any of the =F1-12= keys) until the BIOS (Basic Input/Output System) menu
47launch the USB boot drive. 39appears. Finally, launch the USB boot drive.
48 40
49** Booting with Nvidia 41** Booting with Nvidia
50:PROPERTIES: 42
51:CUSTOM_ID: booting-with-nvidia
52:END:
53In order to install Ubuntu Server with an Nvidia Graphics card (and no 43In order to install Ubuntu Server with an Nvidia Graphics card (and no
54integrated graphics on this device for some reason), you'll have to 44integrated graphics on this device for some reason), you'll have to configure
55configure the boot menu to allow different graphics drivers to be 45the boot menu to allow different graphics drivers to be loaded.
56loaded.
57 46
58When booting from the USB, the machine will launch the initial 47When booting from the USB, the machine will launch the initial installation
59installation menu. From this menu, type =e= to view the default command 48menu. From this menu, type =e= to view the default command options that come
60options that come with the device - it's a good idea to take a photo of 49with the device - it's a good idea to take a photo of this screen, so you can
61this screen, so you can enter these commands on the next screen (along 50enter these commands on the next screen (along with adding support for Nvidia).
62with adding support for Nvidia).
63 51
64Finally, type =Ctrl + C= to enter the command line. From this command 52Finally, type =Ctrl + C= to enter the command line. From this command line,
65line, enter the commands found on the =e= screen. /Remember to add 53enter the commands found on the =e= screen. Remember to add =nomodeset= to the
66=nomodeset= to the =linux ...= line so that your Nvidia device will 54=linux ...= line so that your Nvidia device will display the installation
67display the installation screens properly!/ 55screens properly!
68 56
69Here's an example of the commands I pulled from the =e= screen and 57Here's an example of the commands I pulled from the =e= screen and entered on
70entered on the command line. 58the command line.
71 59
72#+begin_src sh 60#+begin_src sh
73setparams 'Install Ubuntu Server' 61setparams 'Install Ubuntu Server'
@@ -77,12 +65,11 @@ initrd /casper/initrd
77boot 65boot
78#+end_src 66#+end_src
79 67
80Once the machine is rebooted, enter the =e= screen again and add 68Once the machine is rebooted, enter the =e= screen again and add =nomodeset= to
81=nomodeset= to the =linux ...= line again and press =Ctrl + X= to save 69the =linux ...= line again and press =Ctrl + X= to save the boot options.
82the boot options.
83 70
84The machine is now fully installed and can properly display on an 71The machine is now fully installed and can properly display on an external
85external display using the Nvidia GPU. 72display using the Nvidia GPU.
86 73
87Always remember to update and upgrade on a new installation: 74Always remember to update and upgrade on a new installation:
88 75
@@ -91,40 +78,29 @@ sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
91#+end_src 78#+end_src
92 79
93* Phase 2: Migrate Plex Data & Devices 80* Phase 2: Migrate Plex Data & Devices
94:PROPERTIES: 81
95:CUSTOM_ID: phase-2-migrate-plex-data-devices 82This phase uses the great Plex article on migrations ([[https://support.plex.tv/articles/201370363-move-an-install-to-another-system/][Move an Installation to
96:END: 83Another System]]) and adds a bit more information to help with commands and
97This phase uses the great Plex article on migrations 84context.
98([[https://support.plex.tv/articles/201370363-move-an-install-to-another-system/][Move
99an Installation to Another System]]) and adds a bit more information to
100help with commands and context.
101 85
102** Terminology 86** Terminology
103:PROPERTIES: 87
104:CUSTOM_ID: terminology 88- *Source:* The original server that is being replaced.
105:END: 89- *Destination:* The new server.
106*Source:* The original server that is being replaced.\\ 90- *Client:* Any application that can be used to modify settings for both
107*Destination:* The new server.\\ 91 source/destination.
108*Client:* Any application that can be used to modify settings for both
109source/destination.
110 92
111** Step 01: [Client] Update Settings 93** Step 01: [Client] Update Settings
112:PROPERTIES: 94
113:CUSTOM_ID: step-01-client-update-settings 95Open up a Plex app and /disable/ the =Account= > =Library= > =Empty trash
114:END: 96automatically after every scan= preference for the source server.
115Open up a Plex app and /disable/ the =Account= > =Library= >
116=Empty trash automatically after every scan= preference for the source
117server.
118 97
119** Step 02: [Destination] Install Plex 98** Step 02: [Destination] Install Plex
120:PROPERTIES:
121:CUSTOM_ID: step-02-destination-install-plex
122:END:
123Open up the [[https://www.plex.tv/media-server-downloads/][Plex Media
124Server download page]] and copy the link for the appropriate platform.
125 99
126Execute the following commands on the destination server to install 100Open up the [[https://www.plex.tv/media-server-downloads/][Plex Media Server download page]] and copy the link for the
127Plex: 101appropriate platform.
102
103Execute the following commands on the destination server to install Plex:
128 104
129#+begin_src sh 105#+begin_src sh
130wget <url> 106wget <url>
@@ -133,50 +109,44 @@ sudo systemctl stop plexmediaserver.service
133#+end_src 109#+end_src
134 110
135** Step 03: [Source] Stop Plex & Migrate Data 111** Step 03: [Source] Stop Plex & Migrate Data
136:PROPERTIES: 112
137:CUSTOM_ID: step-03-source-stop-plex-migrate-data 113First, stop the Plex service so that no data is created or modified during the
138:END: 114migration.
139First, stop the Plex service so that no data is created or modified
140during the migration.
141 115
142#+begin_src sh 116#+begin_src sh
143sudo systemctl stop plexmediaserver.service 117sudo systemctl stop plexmediaserver.service
144#+end_src 118#+end_src
145 119
146Next, copy the data to the new server. To find where the Plex data 120Next, copy the data to the new server. To find where the Plex data directory is
147directory is located, Plex has another excellent article available: 121located, Plex has another excellent article available: [[https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/][Where is the Plex Media
148[[https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/][Where 122Server data directory located?]].
149is the Plex Media Server data directory located?]].
150 123
151There are many ways to copy the data to the new server and will largely 124There are many ways to copy the data to the new server and will largely depend
152depend on the size of the folder being copied. Personally, my data 125on the size of the folder being copied. Personally, my data folder was ~23GB and
153folder was ~23GB and I opted to simply use the =scp= command to copy the 126I opted to simply use the =scp= command to copy the files over SSH (Secure Shell
154files over SSH. 127Protocol).
155 128
156This process was throttled by the old server's slow HDD and ports and 129This process was throttled by the old server's slow hard disk and ports and took
157took approximately 90 minutes to complete. In comparison, moving the 130approximately 90 minutes to complete. In comparison, moving the data from the
158data from the new server's =home/user/= directory to the 131new server's =home/user/= directory to the =/var/.../Plex Media Server=
159=/var/.../Plex Media Server= directory took 2-3 minutes. 132directory took 2-3 minutes.
160 133
161#+begin_src sh 134#+begin_src sh
162scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'" 135scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'"
163#+end_src 136#+end_src
164 137
165** Step 04: [Destination] Update File Permissions 138** Step 04: [Destination] Update File Permissions
166:PROPERTIES: 139
167:CUSTOM_ID: step-04-destination-update-file-permissions 140In case you move the data directory to a common area on the new server, it will
168:END: 141have to be moved to the proper location before Plex can function properly:
169In case you move the data directory to a common area on the new server,
170it will have to be moved to the proper location before Plex can function
171properly:
172 142
173#+begin_src sh 143#+begin_src sh
174mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/ 144mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/
175#+end_src 145#+end_src
176 146
177To ensure permissions were retained properly, the server will need to 147To ensure permissions were retained properly, the server will need to show that
178show that all files and folders in the data directory are owned by 148all files and folders in the data directory are owned by =plex:plex= (or
179=plex:plex= (or whichever user is running the Plex application). 149whichever user is running the Plex application).
180 150
181#+begin_src sh 151#+begin_src sh
182sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" 152sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"
@@ -190,43 +160,37 @@ sudo systemctl status plexmediaserver.service
190#+end_src 160#+end_src
191 161
192** Step 05: [Client] Update Libraries & Metadata 162** Step 05: [Client] Update Libraries & Metadata
193:PROPERTIES: 163
194:CUSTOM_ID: step-05-client-update-libraries-metadata 164The first step - now that the new server is up and running - is to sign out of
195:END: 165the client and sign back in. Once this is done, update any library locations, if
196The first step - now that the new server is up and running - is to sign 166necessary. This was unnecessary in my case since I simply moved my storage
197out of the client and sign back in. Once this is done, update any 167drives from the source server to the destination server.
198library locations, if necessary. This was unnecessary in my case since I
199simply moved my storage drives from the source server to the destination
200server.
201 168
202Next, perform the following actions in the client: 169Next, perform the following actions in the client:
203 170
2041. On the left sidebar, click =More= > Three-Dot Menu > 1711. On the left sidebar, click =More= > Three-Dot Menu > =Scan Library Files=
205 =Scan Library Files= 1722. /Enable/ the =Account= > =Library= > =Empty trash automatically after every
2062. /Enable/ the =Account= > =Library= > 173 scan= preference for the source server.
207 =Empty trash automatically after every scan= preference for the 1743. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Empty
208 source server. 175 Trash=
2093. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= 1764. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Clean
210 > =Empty Trash= 177 Bundles=
2114. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= 1785. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= >
212 > =Clean Bundles= 179 =Optimize Database=
2135. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server=
214 > =Optimize Database=
215 180
216Finally, double-check the Remote Access settings to make sure no changes 181Finally, double-check the Remote Access settings to make sure no changes have
217have caused issues with accessing the server from outside the network. 182caused issues with accessing the server from outside the network.
218 183
219In my case, I use a single port forwarding rule in my router and needed 184In my case, I use a single port forwarding rule in my router and needed to
220to update the Local LAN IP Address to the new server IP address. 185update the Local LAN (local area network) IP (internet protocol) Address to the
186new server IP address.
221 187
222* Phase 3: Configure GPU Transcoding 188* Phase 3: Configure GPU Transcoding
223:PROPERTIES: 189
224:CUSTOM_ID: phase-3-configure-gpu-transcoding 190The final piece to the migration is enabling hardware transcoding so that Plex
225:END: 191can fully utilize the new Nvidia GPU available in the server. The first step is
226The final piece to the migration is enabling hardware transcoding so 192to install Nvidia graphics drivers. This process may take a few minutes, but the
227that Plex can fully utilize the new Nvidia GPU available in the server. 193commands are pretty simple:
228The first step is to install Nvidia graphics drivers. This process may
229take a few minutes, but the commands are pretty simple:
230 194
231#+begin_src sh 195#+begin_src sh
232sudo add-apt-repository ppa:graphics-drivers/ppa 196sudo add-apt-repository ppa:graphics-drivers/ppa
@@ -248,5 +212,5 @@ following command to view the available GPUs, statistics, and processes:
248sudo nvidia-smi 212sudo nvidia-smi
249#+end_src 213#+end_src
250 214
251Finally, enable hardware transcoding settings in the Plex application to 215Finally, enable hardware transcoding settings in the Plex application to finish
252finish the process. 216the process.
content/blog/2022-03-23-cloudflare-dns-api.org +20 −22
@@ -7,15 +7,15 @@
7:PROPERTIES: 7:PROPERTIES:
8:CUSTOM_ID: ddns-dynamic-dns 8:CUSTOM_ID: ddns-dynamic-dns
9:END: 9:END:
10If you're hosting a service from a location with dynamic DNS (where your 10If you're hosting a service from a location with DDNS (Dynamic Domain Name
11IP may change at any time), you must have a solution to update the DNS 11System), where your internet protocol (IP)address may change at any time, you
12so that you can access your service even when the IP of the server 12must have a solution to update the DNS (Domain Name System) so that you can
13changes. 13access your service even when the IP of the server changes.
14 14
15The process below uses the [[https://api.cloudflare.com/][Cloudflare 15The process below uses the [[https://api.cloudflare.com/][Cloudflare API]] (application programming interface) to
16API]] to update DNS =A= and =AAAA= records with the server's current IP. 16update DNS =A= and =AAAA= records with the server's current IP. If you use
17If you use another DNS provider, you will have to find a way to update 17another DNS provider, you will have to find a way to update your DNS (or find a
18your DNS (or find a way to get a static IP). 18way to get a static IP).
19 19
20First, install =jq= since we will use it in the next script: 20First, install =jq= since we will use it in the next script:
21 21
@@ -23,18 +23,16 @@ First, install =jq= since we will use it in the next script:
23sudo apt install jq 23sudo apt install jq
24#+end_src 24#+end_src
25 25
26Next, create a location for your DDNS update scripts and open the first 26Next, create a location for your DDNS update scripts and open the first script:
27script:
28 27
29#+begin_src sh 28#+begin_src sh
30mkdir ~/ddns 29mkdir ~/ddns
31nano ~/ddns/update.sh 30nano ~/ddns/update.sh
32#+end_src 31#+end_src
33 32
34The following =update.sh= script will take all of your domains and 33The following =update.sh= script will take all of your domains and subdomains
35subdomains and check Cloudflare to see if the current =A= and =AAAA= 34and check Cloudflare to see if the current =A= and =AAAA= records match your
36records match your server's IP address. If not, it will update the 35server's IP address. If not, it will update the records.
37records.
38 36
39#+begin_src sh 37#+begin_src sh
40# file: update.sh 38# file: update.sh
@@ -60,16 +58,16 @@ do
60done 58done
61#+end_src 59#+end_src
62 60
63Next, open up the =ddns.sh= script. Paste the following into the script 61Next, open up the =ddns.sh= script. Paste the following into the script and
64and update the =api_token= and =email= variables. 62update the =api_token= and =email= variables.
65 63
66#+begin_src sh 64#+begin_src sh
67nano ~/ddns/ddns.sh 65nano ~/ddns/ddns.sh
68#+end_src 66#+end_src
69 67
70*Note*: If you want your DNS records to be proxied through Cloudflare, 68*Note*: If you want your DNS records to be proxied through Cloudflare, find and
71find and update the following snippet: ="proxied":false}"= to say =true= 69update the following snippet: ="proxied":false}"= to say =true= instead of
72instead of =false=. 70=false=.
73 71
74#+begin_src sh 72#+begin_src sh
75# file: ddns.sh 73# file: ddns.sh
@@ -179,14 +177,14 @@ You can test the script by running it manually:
179./update.sh 177./update.sh
180#+end_src 178#+end_src
181 179
182To make sure the scripts run automatically, add it to the =cron= file so 180To make sure the scripts run automatically, add it to the =cron= file so that it
183that it will run on a schedule. To do this, open the cron file: 181will run on a schedule. To do this, open the cron file:
184 182
185#+begin_src sh 183#+begin_src sh
186crontab -e 184crontab -e
187#+end_src 185#+end_src
188 186
189In the cron file, paste the following at the bottom of the editor: 187In the =cron= file, paste the following at the bottom of the editor:
190 188
191#+begin_src sh 189#+begin_src sh
192,*/5 ** ** ** ** bash /home/<your_username>/ddns/update.sh 190,*/5 ** ** ** ** bash /home/<your_username>/ddns/update.sh
content/blog/2022-03-23-nextcloud-on-ubuntu.org +28 −33
@@ -7,8 +7,8 @@
7:PROPERTIES: 7:PROPERTIES:
8:CUSTOM_ID: what-is-nextcloud 8:CUSTOM_ID: what-is-nextcloud
9:END: 9:END:
10[[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for 10[[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for storage, communications, editing,
11storage, communications, editing, calendar, contacts, and more. 11calendar, contacts, and more.
12 12
13This tutorial assumes that you have an Ubuntu server and a domain name 13This tutorial assumes that you have an Ubuntu server and a domain name
14configured to point toward the server. 14configured to point toward the server.
@@ -29,16 +29,14 @@ sudo apt install php7.4-gmp php7.4-bcmath php-imagick php7.4-xml php7.4-zip
29:PROPERTIES: 29:PROPERTIES:
30:CUSTOM_ID: set-up-mysql 30:CUSTOM_ID: set-up-mysql
31:END: 31:END:
32Next, you will need to log in to MySQL as the =root= user of the 32Next, you will need to log in to MySQL as the =root= user of the machine.
33machine.
34 33
35#+begin_src sh 34#+begin_src sh
36sudo mysql -uroot -p 35sudo mysql -uroot -p
37#+end_src 36#+end_src
38 37
39Once you've logged in, you must create a new user so that Nextcloud can 38Once you've logged in, you must create a new user so that Nextcloud can manage
40manage the database. You will also create a =nextcloud= database and 39the database. You will also create a =nextcloud= database and assign privileges:
41assign privileges:
42 40
43#+begin_src sql 41#+begin_src sql
44CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; 42CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
@@ -52,15 +50,12 @@ quit;
52:PROPERTIES: 50:PROPERTIES:
53:CUSTOM_ID: download-install-nextcloud 51:CUSTOM_ID: download-install-nextcloud
54:END: 52:END:
55To download Nextcloud, go the 53To download Nextcloud, go the [[https://nextcloud.com/install/#instructions-server][Nextcloud downloads page]], click on =Archive File=
56[[https://nextcloud.com/install/#instructions-server][Nextcloud 54and right-click the big blue button to copy the link.
57downloads page]], click on =Archive File= and right-click the big blue
58button to copy the link.
59 55
60Then, go to your server and enter the following commands to download, 56Then, go to your server and enter the following commands to download, unzip, and
61unzip, and move the files to your destination directory. This example 57move the files to your destination directory. This example uses =example.com= as
62uses =example.com= as the destination, but you can put it wherever you 58the destination, but you can put it wherever you want to server your files from.
63want to server your files from.
64 59
65#+begin_src sh 60#+begin_src sh
66wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip 61wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip
@@ -73,9 +68,9 @@ sudo cp -r nextcloud /var/www/example.com
73:PROPERTIES: 68:PROPERTIES:
74:CUSTOM_ID: configure-the-apache-web-server 69:CUSTOM_ID: configure-the-apache-web-server
75:END: 70:END:
76Now that the database is set up and Nextcloud is installed, you need to 71Now that the database is set up and Nextcloud is installed, you need to set up
77set up the Apache configuration files to tell the server how to handle 72the Apache configuration files to tell the server how to handle requests for
78requests for =example.com/nextcloud=. 73=example.com/nextcloud=.
79 74
80First, open the following file in the editor: 75First, open the following file in the editor:
81 76
@@ -83,8 +78,8 @@ First, open the following file in the editor:
83sudo nano /etc/apache2/sites-available/nextcloud.conf 78sudo nano /etc/apache2/sites-available/nextcloud.conf
84#+end_src 79#+end_src
85 80
86Once the editor is open, paste the following information in. Then, save 81Once the editor is open, paste the following information in. Then, save and
87and close the file. 82close the file.
88 83
89#+begin_src config 84#+begin_src config
90<VirtualHost *:80> 85<VirtualHost *:80>
@@ -113,14 +108,14 @@ Once the file is saved, enable it with Apache:
113sudo a2ensite nextcloud.conf 108sudo a2ensite nextcloud.conf
114#+end_src 109#+end_src
115 110
116Next, enable the Apache mods required by Nextcloud: 111Next, enable the Apache modules required by Nextcloud:
117 112
118#+begin_src sh 113#+begin_src sh
119sudo a2enmod rewrite headers env dir mime 114sudo a2enmod rewrite headers env dir mime
120#+end_src 115#+end_src
121 116
122Finally, restart Apache. If any errors arise, you must solve those 117Finally, restart Apache. If any errors arise, you must solve those before
123before continuing. 118continuing.
124 119
125#+begin_src sh 120#+begin_src sh
126sudo systemctl restart apache2 121sudo systemctl restart apache2
@@ -137,20 +132,20 @@ sudo chown -R www-data:www-data /var/www/example.com/nextcloud/
137:PROPERTIES: 132:PROPERTIES:
138:CUSTOM_ID: dns 133:CUSTOM_ID: dns
139:END: 134:END:
140If you do not have a static IP address, you will need to update your DNS 135If you do not have a static internet protocol (IP) address, you will need to
141settings (at your DNS provider) whenever your dynamic IP address 136update your DNS (Domain Name System) settings (at your DNS provider) whenever
142changes. 137your dynamic IP address changes.
143 138
144For an example on how I do that with Cloudflare, see my other post: 139For an example on how I do that with Cloudflare, see my other post: [[https://cleberg.net/blog/cloudflare-dns-api.html][Dynamic DNS
145[[../updating-dynamic-dns-with-cloudflare-api/][Updating Dynamic DNS 140Record Updates via Cloudflare API]].
146with Cloudflare API]]
147 141
148* Certbot 142* Certbot
149:PROPERTIES: 143:PROPERTIES:
150:CUSTOM_ID: certbot 144:CUSTOM_ID: certbot
151:END: 145:END:
152If you want to serve Nextcloud from HTTPS rather than plain HTTP, use 146If you want to serve Nextcloud from HTTPS (Hypertext Transfer Protocol Secure)
153the following commands to issue Let's Encrypt SSL certificates: 147rather than plain HTTP (Hypertext Transfer Protocol), use the following commands
148to issue Let's Encrypt SSL (Secure Socket Layer) certificates:
154 149
155#+begin_src sh 150#+begin_src sh
156sudo apt install snapd 151sudo apt install snapd
@@ -165,5 +160,5 @@ sudo certbot --apache
165:PROPERTIES: 160:PROPERTIES:
166:CUSTOM_ID: results 161:CUSTOM_ID: results
167:END: 162:END:
168Voilà! You're all done and should be able to access Nextcloud from your 163Voilà! You're all done and should be able to access Nextcloud from your domain
169domain or IP address. 164or IP address.
content/blog/2022-03-24-server-hardening.org +62 −57
@@ -27,8 +27,9 @@ have to think about the transport of data from =server= to =client=.
27Let's start with the actual server itself. Think about the following: 27Let's start with the actual server itself. Think about the following:
28 28
29- Do I have a firewall enabled? Do I need to update this to allow new ports or 29- Do I have a firewall enabled? Do I need to update this to allow new ports or
30 IPs? 30 internet protocol (IP) addresses?
31- Do I have an IPS/IDS that may prevent outside traffic? 31- Do I have an intrusion prevention system (IPS) or intrusion detection system
32 (IDS) that may prevent outside traffic?
32- Do I have any other security software installed? 33- Do I have any other security software installed?
33- Are the services hosted inside Docker containers, behind a reverse proxy, or 34- Are the services hosted inside Docker containers, behind a reverse proxy, or
34 virtualized? If so, are they configured to allow outside traffic? 35 virtualized? If so, are they configured to allow outside traffic?
@@ -37,7 +38,7 @@ Once the data leaves the server, where does it go? In my case, it goes to a
37managed switch. In this case, I asked the following: 38managed switch. In this case, I asked the following:
38 39
39- What configurations is the switch using? 40- What configurations is the switch using?
40- Am I using VLANs? 41- Am I using VLANs (virtual local area networks)?
41 - Yes, I am using 802.1Q VLANs. 42 - Yes, I am using 802.1Q VLANs.
42- Are the VLANs configured properly? 43- Are the VLANs configured properly?
43 - Yes, as shown in the Switch section below, I have a separate VLAN to allow 44 - Yes, as shown in the Switch section below, I have a separate VLAN to allow
@@ -47,7 +48,7 @@ managed switch. In this case, I asked the following:
47At this point, the data has been processed through the switch. Where does it go 48At this point, the data has been processed through the switch. Where does it go
48next? In my case, it's pretty simple: it goes to the router/modem device. 49next? In my case, it's pretty simple: it goes to the router/modem device.
49 50
50- Does my ISP block any ports that I need? 51- Does my internet service provider (ISP) block any ports that I need?
51 - This is an important step that a lot of people run into when self-hosting at 52 - This is an important step that a lot of people run into when self-hosting at
52 home. Use an online port-checker tool for your IP or call your ISP if you 53 home. Use an online port-checker tool for your IP or call your ISP if you
53 think ports are blocked. 54 think ports are blocked.
@@ -59,9 +60,9 @@ next? In my case, it's pretty simple: it goes to the router/modem device.
59- Are there any other settings affecting inbound/outbound traffic? 60- Are there any other settings affecting inbound/outbound traffic?
60 - Schedules or access blocks 61 - Schedules or access blocks
61 - Static Routing 62 - Static Routing
62 - QoS 63 - QoS (Quality of Service)
63 - Port Forwarding 64 - Port Forwarding
64 - DMZ Hosting 65 - DMZ (demilitarized zone) hosting
65 - Remote Management (this can sometimes mess with services that also require 66 - Remote Management (this can sometimes mess with services that also require
66 the use of ports 80 and 443) 67 the use of ports 80 and 443)
67 68
@@ -70,27 +71,31 @@ publicly.
70 71
71*** Server 72*** Server
72 73
73The services I run on my server are installed straight into the OS, without any 74The services I run on my server are installed straight into the operating system
74use of Docker or VMs, so I don't need any extra application configuration to 75(OS), without any use of Docker or virtual machines (VMs), so I don't need any
75make them accessible to the outside world.+ 76extra application configuration to make them accessible to the outside world.
76 77
78#+BEGIN_QUOTE
77As of 2022-10-04, the paragraph above is no longer true as I now run a reverse 79As of 2022-10-04, the paragraph above is no longer true as I now run a reverse
78proxy with Nginx and host many services inside Docker. However, it doesn't 80proxy with Nginx and host many services inside Docker. However, it doesn't
79change anything regarding this post as I still just need to open ports 80 & 443 81change anything regarding this post as I still just need to open ports 80 & 443
80and create the necessary website configuration files. 82and create the necessary website configuration files.
83#+END_QUOTE
81 84
82When creating new services - either installed directly on bare metal or within 85When creating new services - either installed directly on bare metal or within
83something like Docker - I ensure that I read through the documentation 86something like Docker - I ensure that I read through the documentation
84thoroughly to understand a few key things: - What network activities should this 87thoroughly to understand a few key things:
85app perform (if any)? Using which ports and protocols? - Does this app require 88
86any commands/services to be run as =root=? - Does this app log errors, 89- What network activities should this app perform (if any)? Using which ports
87authentication failures/successes, or anything else that would be useful for an 90 and protocols?
88investigation? 91- Does this app require any commands/services to be run as =root=?
92- Does this app log errors, authentication failures/successes, or anything else
93 that would be useful for an investigation?
89 94
90For extra security, I use limit all incoming connections to SSH connections 95For extra security, I use limit all incoming connections to SSH connections
91through my server firewall (=ufw=) and disable common SSH settings. After all of 96through my server firewall [=ufw= (Uncomplicated Firewall)] and disable common
92that, I use =fail2ban= as a preventative measure against brute-force login 97SSH (Secure Shell Protocol) settings. After all of that, I use =fail2ban= as a
93attempts. 98preventative measure against brute-force login attempts.
94 99
95As another piece of security, you can randomize your SSH port to ensure that 100As another piece of security, you can randomize your SSH port to ensure that
96random scanners or attackers can't easily try to force their way into your 101random scanners or attackers can't easily try to force their way into your
@@ -101,8 +106,8 @@ via your randomized port.
101 106
102** =ufw= 107** =ufw=
103 108
104To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your 109To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your Network with the
105Network with the Uncomplicated Firewall]]. 110Uncomplicated Firewall]].
106 111
107The general notion with an on-device firewall is that you want to deny all 112The general notion with an on-device firewall is that you want to deny all
108incoming connections by default and then selectively open certain ports for 113incoming connections by default and then selectively open certain ports for
@@ -178,7 +183,7 @@ sudo ufw enable
178 lock yourself out at some point and will need to use a recovery method (e.g., 183 lock yourself out at some point and will need to use a recovery method (e.g.,
179 hooking monitor up to home server) to get yourself back in. 184 hooking monitor up to home server) to get yourself back in.
180 185
1813. Enable MFA for =ssh= 1863. Enable Multi-Factor Authentication (MFA) for =ssh=
182 187
183 This part is optional, but I highly recommend it. So far, we've ensured that 188 This part is optional, but I highly recommend it. So far, we've ensured that
184 no one can log into our user on the server without using our secret key, and 189 no one can log into our user on the server without using our secret key, and
@@ -187,8 +192,7 @@ sudo ufw enable
187 192
188 This process involves editing a couple files and installing an MFA package, 193 This process involves editing a couple files and installing an MFA package,
189 so I will not include all the details in this post. To see how to configure 194 so I will not include all the details in this post. To see how to configure
190 MFA for =ssh=, see my other post: [[https://cleberg.net/blog/ssh-mfa.html][Enabling MFA for 195 MFA for =ssh=, see my other post: [[https://cleberg.net/blog/ssh-mfa.html][Enabling MFA for SSH]].
191 SSH]].
192 196
193** =fail2ban= 197** =fail2ban=
194 198
@@ -224,8 +228,8 @@ the server to manage it.
224 228
225| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports | 229| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports |
226|---------+-----------+--------------+--------------+----------------| 230|---------+-----------+--------------+--------------+----------------|
227| 1 | Default | 1-24 | 1-24 | | 231| 1 | Default | 1-24 | 1-24 | |
228| 2 | Server | 1,8,23 | 1,8,23 | | 232| 2 | Server | 1,8,23 | 1,8,23 | |
229 233
230** 802.1Q VLAN PVID Setting 234** 802.1Q VLAN PVID Setting
231 235
@@ -235,30 +239,30 @@ any related ports (in this case, see that ports =8= and =23= have a PVID of
235 239
236| Port | PVID | 240| Port | PVID |
237|------+------| 241|------+------|
238| 1 | 1 | 242| 1 | 1 |
239| 2 | 1 | 243| 2 | 1 |
240| 3 | 1 | 244| 3 | 1 |
241| 4 | 1 | 245| 4 | 1 |
242| 5 | 1 | 246| 5 | 1 |
243| 6 | 1 | 247| 6 | 1 |
244| 7 | 1 | 248| 7 | 1 |
245| 8 | 2 | 249| 8 | 2 |
246| 9 | 1 | 250| 9 | 1 |
247| 10 | 1 | 251| 10 | 1 |
248| 11 | 1 | 252| 11 | 1 |
249| 12 | 1 | 253| 12 | 1 |
250| 13 | 1 | 254| 13 | 1 |
251| 14 | 1 | 255| 14 | 1 |
252| 15 | 1 | 256| 15 | 1 |
253| 16 | 1 | 257| 16 | 1 |
254| 17 | 1 | 258| 17 | 1 |
255| 18 | 1 | 259| 18 | 1 |
256| 19 | 1 | 260| 19 | 1 |
257| 20 | 1 | 261| 20 | 1 |
258| 21 | 1 | 262| 21 | 1 |
259| 22 | 1 | 263| 22 | 1 |
260| 23 | 2 | 264| 23 | 2 |
261| 24 | 1 | 265| 24 | 1 |
262 266
263* Router 267* Router
264 268
@@ -266,9 +270,9 @@ On my router, the configuration was as easy as opening the firewall settings and
266unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL, 270unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL,
267etc.). 271etc.).
268 272
269Since I'm relying on an ISP-provided modem/router combo for now (not by 273Since I'm relying on an ISP-provided modem/router combo for now (not by choice),
270choice), I do not use any other advanced settings on my router that would 274I do not use any other advanced settings on my router that would inhibit any
271inhibit any valid traffic to these services. 275valid traffic to these services.
272 276
273The paragraph above regarding the ISP-owned router is no longer accurate as I 277The paragraph above regarding the ISP-owned router is no longer accurate as I
274now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I 278now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I
@@ -287,10 +291,10 @@ physical security. However, physical security is very important for everyone who
287hosts a server like this. Exactly /how/ important it is depends on the server 291hosts a server like this. Exactly /how/ important it is depends on the server
288use/purpose. 292use/purpose.
289 293
290If you self-host customer applications that hold protected data (HIPAA, GDPR, 294If you self-host customer applications that hold protected data, then physical
291COPPA, etc.), then physical security is extremely important and cannot be 295security is extremely important and cannot be ignored. If you simply host a blog
292ignored. If you simply host a blog and some hobby sites, then it's a relatively 296and some hobby sites, then it's a relatively minor consideration, but one you
293minor consideration, but one you still need to think about. 297still need to think about.
294 298
295** Location 299** Location
296 300
@@ -312,8 +316,9 @@ Secondly, consider the hardware itself:
312- Are any other users able to access the server, even if your data/space is 316- Are any other users able to access the server, even if your data/space is
313 segregated? 317 segregated?
314- If you're utilizing a third party, do they have any documentation to show 318- If you're utilizing a third party, do they have any documentation to show
315 responsibility? This could be a SOC 1/2/3 report, ISO compliance report, 319 responsibility? This could be a Service Organization Controls (SOC) 1/2/3
316 internal security/safety documentation. 320 report, International Organization for Standardization (ISO) compliance
321 report, internal security/safety documentation.
317 322
318** Physical Controls 323** Physical Controls
319 324
content/blog/2022-03-26-ssh-mfa.org +34 −35
@@ -3,31 +3,29 @@
3#+description: Step-by-step deployment guide for enabling TOTP multi-factor authentication on SSH services using Google Authenticator and Pluggable Authentication Module (PAM) integration. 3#+description: Step-by-step deployment guide for enabling TOTP multi-factor authentication on SSH services using Google Authenticator and Pluggable Authentication Module (PAM) integration.
4#+slug: ssh-mfa 4#+slug: ssh-mfa
5 5
6* Why Do I Need MFA for SSH? 6* Why Do I Need Multi-Factor Authentication (MFA) for SSH (Secure Shell Protocol)?
7 7
8If you are a sysadmin of a server anywhere (that includes at home!), you 8If you are a sysadmin of a server anywhere (that includes at home!), you may
9may want an added layer of protection against intruders. This is not a 9want an added layer of protection against intruders. This is not a replacement
10replacement for other security measures, such as: 10for other security measures, such as:
11 11
12- Disable root SSH 12- Disable root SSH
13- Disable SSH password authentication 13- Disable SSH password authentication
14- Allow only certain users to login via SSH 14- Allow only certain users to login via SSH
15- Allow SSH only from certain IPs 15- Allow SSH only from certain internet protocol (IP) addressess
16 16
17However, MFA can be added as an additional security measure to ensure 17However, MFA can be added as an additional security measure to ensure that your
18that your server is protected. This is especially important if you need 18server is protected. This is especially important if you need to allow password
19to allow password authentication for SSH. 19authentication for SSH.
20 20
21For more guidance on server security measures, see my other post: 21For more guidance on server security measures, see my other post: [[https://cleberg.net/blog/server-hardening.html][Step-by-Step
22[[../hardening-a-public-facing-home-server/][Hardening a Public-Facing 22Guide to Securing Your Home Server with Firewalls, SSH, and VLANs]].
23Home Server]].
24 23
25* Install MFA PAM Module 24* Install MFA PAM Module
26 25
27PAM, which stands for Pluggable Authentication Module, is an 26PAM (Pluggable Authentication Module) is an authentication infrastructure used
28authentication infrastructure used on Linux systems to authenticate a 27on Linux systems to authenticate a user. In order to use this technology, let's
29user. In order to use this technology, let's install the 28install the =libpam-google-authenticator= package:
30=libpam-google-authenticator= package:
31 29
32#+begin_src sh 30#+begin_src sh
33sudo apt-get update 31sudo apt-get update
@@ -41,16 +39,17 @@ sudo apt-get install libpam-google-authenticator
41 39
42** Interactive Method 40** Interactive Method
43 41
44Once the package is installed, initialize it and following the 42Once the package is installed, initialize it and following the interactive
45interactive prompts to generate your OTP or TOTP: 43prompts to generate your OTP (One-Time Password) or TOTP (Time-based One-Time
44Password):
46 45
47#+begin_src sh 46#+begin_src sh
48google-authenticator 47google-authenticator
49#+end_src 48#+end_src
50 49
51If you are not sure how to answer, read the prompts carefully and think 50If you are not sure how to answer, read the prompts carefully and think about
52about having to how each situation would affect your normal login 51having to how each situation would affect your normal login attempts. If you are
53attempts. If you are still not sure, use my default responses below. 52still not sure, use my default responses below.
54 53
55#+begin_src txt 54#+begin_src txt
56OUTPUT 55OUTPUT
@@ -58,8 +57,8 @@ OUTPUT
58Do you want authentication tokens to be time-based (y/n) y 57Do you want authentication tokens to be time-based (y/n) y
59#+end_src 58#+end_src
60 59
61At this point, use an authenticator app somewhere one of your devices to 60At this point, use an authenticator app somewhere one of your devices to scan
62scan the QR code. Any future login attempts after our upcoming 61the QR (quick-response) code. Any future login attempts after our upcoming
63configuration changes will require that TOTP. 62configuration changes will require that TOTP.
64 63
65#+begin_src txt 64#+begin_src txt
@@ -134,23 +133,23 @@ google-authenticator [<options>]
134 -e, --emergency-codes=N Number of emergency codes to generate 133 -e, --emergency-codes=N Number of emergency codes to generate
135#+end_src 134#+end_src
136 135
137This fully configures the authenticator, saves it to a file, and then 136This fully configures the authenticator, saves it to a file, and then outputs
138outputs the secret key, QR code, and recovery codes. (If you add the 137the secret key, QR code, and recovery codes. (If you add the flag =-q=, then
139flag =-q=, then there won't be any output). If you use this command in 138there won't be any output). If you use this command in an automated fashion,
140an automated fashion, make sure your script captures the secret key 139make sure your script captures the secret key and/or recovery codes and makes
141and/or recovery codes and makes them available to the user. 140them available to the user.
142 141
143* PAM Configuration Settings 142* PAM Configuration Settings
144 143
145Once you've enabled the T/OTP and have it saved to an MFA app on your 144Once you've enabled MFA and have it saved to an MFA app on your phone or other
146phone or other device, open the PAM =sshd= file: 145device, open the PAM =sshd= file:
147 146
148#+begin_src sh 147#+begin_src sh
149sudo nano /etc/pam.d/sshd 148sudo nano /etc/pam.d/sshd
150#+end_src 149#+end_src
151 150
152You need to do two things in this file. First, add the following lines 151You need to do two things in this file. First, add the following lines to the
153to the bottom of the file: 152bottom of the file:
154 153
155#+begin_src config 154#+begin_src config
156auth required pam_google_authenticator.so nullok 155auth required pam_google_authenticator.so nullok
@@ -159,8 +158,8 @@ auth required pam_permit.so
159 158
160Second, comment-out the following line near the top of the file. 159Second, comment-out the following line near the top of the file.
161 160
162If you leave this line uncommented, every SSH login attempt will ask for 161If you leave this line uncommented, every SSH login attempt will ask for the
163the following three authentication factors: 162following three authentication factors:
164 163
1651. Publickey 1641. Publickey
1662. Password 1652. Password
@@ -178,8 +177,8 @@ Finally, edit the =sshd_config= file again:
178sudo nano /etc/ssh/sshd_config 177sudo nano /etc/ssh/sshd_config
179#+end_src 178#+end_src
180 179
181You'll need to change =ChallengeResponseAuthentication= to yes and add 180You'll need to change =ChallengeResponseAuthentication= to yes and add the
182the =AuthenticationMethods= line to the bottom of the file. 181=AuthenticationMethods= line to the bottom of the file.
183 182
184#+begin_src config 183#+begin_src config
185ChallengeResponseAuthentication yes 184ChallengeResponseAuthentication yes
content/blog/2022-04-02-nginx-reverse-proxy.org +64 −71
@@ -5,10 +5,10 @@
5 5
6* What is a Reverse Proxy? 6* What is a Reverse Proxy?
7 7
8A reverse proxy is a server that is placed between local servers or 8A reverse proxy is a server that is placed between local servers or services and
9services and clients/users (e.g., the internet). The reverse proxy 9clients/users (e.g., the internet). The reverse proxy intercepts all requests
10intercepts all requests from clients at the network edge and uses its 10from clients at the network edge and uses its configuration files to determine
11configuration files to determine where each request should be sent. 11where each request should be sent.
12 12
13** A Brief Example 13** A Brief Example
14 14
@@ -18,23 +18,21 @@ For example, let's say that I run three servers in my home:
18- Server02 (=service01.example.com=) 18- Server02 (=service01.example.com=)
19- Server03 (=service02.example.com=) 19- Server03 (=service02.example.com=)
20 20
21I also run a reverse proxy in my home that intercepts all public 21I also run a reverse proxy in my home that intercepts all public traffic:
22traffic:
23 22
24- Reverse Proxy 23- Reverse Proxy
25 24
26Assume that I have a domain name (=example.com=) that allows clients to 25Assume that I have a domain name (=example.com=) that allows clients to request
27request websites or services from my home servers. 26websites or services from my home servers.
28 27
29In this case, the reverse proxy will intercept all traffic from 28In this case, the reverse proxy will intercept all traffic from =example.com=
30=example.com= that enters my network and determine if the client is 29that enters my network and determine if the client is requesting valid data,
31requesting valid data, based on my configuration. 30based on my configuration.
32 31
33If the user is requesting =example.com= and my configuration files say 32If the user is requesting =example.com= and my configuration files say that
34that Server_{01} holds that data, Nginx will send the user to 33Server_{01} holds that data, Nginx will send the user to Server_{01}. If I were
35Server_{01}. If I were to change the configuration so that =example.com= 34to change the configuration so that =example.com= is routed to Server_{02}, that
36is routed to Server_{02}, that same user would be sent to Server_{02} 35same user would be sent to Server_{02} instead.
37instead.
38 36
39#+begin_src txt 37#+begin_src txt
40┌──────┐ ┌───────────┐ 38┌──────┐ ┌───────────┐
@@ -50,9 +48,9 @@ instead.
50 48
51* Reverse Proxy Options 49* Reverse Proxy Options
52 50
53There are a lot of options when it comes to reverse proxy servers, so 51There are a lot of options when it comes to reverse proxy servers, so I'm just
54I'm just going to list a few of the options I've heard recommended over 52going to list a few of the options I've heard recommended over the last few
55the last few years: 53years:
56 54
57- [[https://nginx.com][Nginx]] 55- [[https://nginx.com][Nginx]]
58- [[https://caddyserver.com][Caddy]] 56- [[https://caddyserver.com][Caddy]]
@@ -60,42 +58,41 @@ the last few years:
60- [[https://www.haproxy.org/][HAProxy]] 58- [[https://www.haproxy.org/][HAProxy]]
61- [[https://ubuntu.com/server/docs/proxy-servers-squid][Squid]] 59- [[https://ubuntu.com/server/docs/proxy-servers-squid][Squid]]
62 60
63In this post, we will be using Nginx as our reverse proxy, running on 61In this post, we will be using Nginx as our reverse proxy, running on Ubuntu
64Ubuntu Server 20.04.4 LTS. 62Server 20.04.4 LTS.
65 63
66* Nginx Reverse Proxy Example 64* Nginx Reverse Proxy Example
67 65
68** Local Applications 66** Local Applications
69 67
70You may be like me and have a lot of applications running on your local 68You may be like me and have a lot of applications running on your local network
71network that you'd like to expose publicly with a domain. 69that you'd like to expose publicly with a domain.
72 70
73In my case, I have services running in multiple Docker containers within 71In my case, I have services running in multiple Docker containers within a
74a single server and want a way to visit those services from anywhere 72single server and want a way to visit those services from anywhere with a URL.
75with a URL. For example, on my local network, 73For example, on my local network, [[https://dashy.to][Dashy]] runs through port 4000
76[[https://dashy.to][Dashy]] runs through port 4000 (=localhost:4000=) 74(=localhost:4000=) and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs through port 3001 (=localhost:3001=).
77and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs
78through port 3001 (=localhost:3001=).
79 75
80In order to expose these services to the public, I will need to do the 76In order to expose these services to the public, I will need to do the
81following: 77following:
82 78
831. Set up DNS records for a domain or subdomain (one per service) to 791. Set up DNS (Domain Name System) records for a domain or subdomain (one per
84 point toward the IP address of the server. 80 service) to point toward the internet protocol (IP) address of the server.
852. Open up the server network's HTTP and HTTPS ports (80 & 443) so that 812. Open up the server network's HTTP (Hypertext Transfer Protocol) and HTTPS
86 the reverse proxy can accept traffic and determine where to send it. 82 (Hypertext Transfer Protocol Secure) ports (80 & 443) so that the reverse
83 proxy can accept traffic and determine where to send it.
873. Install the reverse proxy software. 843. Install the reverse proxy software.
884. Configure the reverse proxy to recognize which service should get 854. Configure the reverse proxy to recognize which service should get traffic
89 traffic from any of the domains or subdomains. 86 from any of the domains or subdomains.
90 87
91** Step 1: DNS Configuration 88** Step 1: DNS Configuration
92 89
93To start, update your DNS configuration so that you have an =A= record 90To start, update your DNS configuration so that you have an =A= record for each
94for each domain or subdomain. 91domain or subdomain.
95 92
96The =A= records should point toward the public IP address of the server. 93The =A= records should point toward the public IP address of the server. If you
97If you don't know the public IP address, log in to the server and run 94don't know the public IP address, log in to the server and run the following
98the following command: 95command:
99 96
100#+begin_src sh 97#+begin_src sh
101curl ifconfig.co 98curl ifconfig.co
@@ -111,34 +108,30 @@ dashy.example.com A xxx.xxx.xxx.xxx
111www CNAME example.com 108www CNAME example.com
112#+end_src 109#+end_src
113 110
114Finally, ensure the DNS has propagated correctly with 111Finally, ensure the DNS has propagated correctly with [[https://dnschecker.org][DNS Checker]] by entering
115[[https://dnschecker.org][DNS Checker]] by entering your domains or 112your domains or subdomains in the search box and ensuring the results are
116subdomains in the search box and ensuring the results are showing the 113showing the correct IP address.
117correct IP address.
118 114
119** Step 2: Open Network Ports 115** Step 2: Open Network Ports
120 116
121This step will be different depending on which router you have in your 117This step will be different depending on which router you have in your home. If
122home. If you're not sure, try to visit 118you're not sure, try to visit [[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials are
123[[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials 119usually written on a sticker somewhere on your modem/router.
124are usually written on a sticker somewhere on your modem/router.
125 120
126Once you're able to log in to your router, find the Port Forwarding 121Once you're able to log in to your router, find the Port Forwarding settings.
127settings. You will need to forward ports =80= and =443= to whichever 122You will need to forward ports =80= and =443= to whichever machine is running
128machine is running the reverse proxy. 123the reverse proxy.
129 124
130In my case, the table below shows the port-forwarding rules I've 125In my case, the table below shows the port-forwarding rules I've created. In
131created. In this table, =xxx.xxx.xxx.xxx= is the local device IP of the 126this table, =xxx.xxx.xxx.xxx= is the local device IP of the reverse proxy
132reverse proxy server, it will probably be an IP between =192.168.1.1= 127server, it will probably be an IP between =192.168.1.1= and =192.168.1.255=.
133and =192.168.1.255=.
134 128
135| NAME | FROM PORT | DEST PORT/IP | ENABLED | 129| NAME | FROM PORT | DEST PORT/IP | ENABLED |
136|-------+-----------+-----------------+---------| 130|-------+-----------+-----------------+---------|
137| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE | 131| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE |
138| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE | 132| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE |
139 133
140Once configured, these rules will direct all web traffic to your reverse 134Once configured, these rules will direct all web traffic to your reverse proxy.
141proxy.
142 135
143** Step 3: Nginx Installation 136** Step 3: Nginx Installation
144 137
@@ -148,11 +141,11 @@ To install Nginx, simply run the following command:
148sudo apt install nginx 141sudo apt install nginx
149#+end_src 142#+end_src
150 143
151If you have a firewall enabled, open up ports =80= and =443= on your 144If you have a firewall enabled, open up ports =80= and =443= on your server so
152server so that Nginx can accept web traffic from the router. 145that Nginx can accept web traffic from the router.
153 146
154For example, if you want to use =ufw= for web traffic and SSH, run the 147For example, if you want to use =ufw= for web traffic and SSH, run the following
155following commands: 148commands:
156 149
157#+begin_src sh 150#+begin_src sh
158sudo ufw allow 'Nginx Full' 151sudo ufw allow 'Nginx Full'
@@ -162,9 +155,8 @@ sudo ufw enable
162 155
163** Step 4: Nginx Configuration 156** Step 4: Nginx Configuration
164 157
165Now that we have domains pointing toward the server, the only step left 158Now that we have domains pointing toward the server, the only step left is to
166is to configure the reverse proxy to direct traffic from domains to 159configure the reverse proxy to direct traffic from domains to local services.
167local services.
168 160
169To start, you'll need to create a configuration file for each domain in 161To start, you'll need to create a configuration file for each domain in
170=/etc/nginx/sites-available/=. They will look identical except for the 162=/etc/nginx/sites-available/=. They will look identical except for the
@@ -204,22 +196,23 @@ server {
204} 196}
205#+end_src 197#+end_src
206 198
207Once the configuration files are created, you will need to enable them 199Once the configuration files are created, you will need to enable them with the
208with the =symlink= command: 200=symlink= command:
209 201
210#+begin_src sh 202#+begin_src sh
211sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/ 203sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/
212#+end_src 204#+end_src
213 205
214Voilà! Your local services should now be available through their URLs. 206Voilà! Your local services should now be available through their URLs (uniform
207resource locators).
215 208
216* HTTPS with Certbot 209* HTTPS with Certbot
217 210
218If you've followed along, you'll notice that your services are only 211If you've followed along, you'll notice that your services are only available
219available via HTTP (not HTTPS). 212via HTTP (not HTTPS).
220 213
221If you want to enable HTTPS for your new domains, you will need to 214If you want to enable HTTPS for your new domains, you will need to generate TLS
222generate SSL/TLS certificates for them. The easiest way to generate 215(Transport Layer Security) certificates for them. The easiest way to generate
223certificates on Nginx is [[https://certbot.eff.org][Certbot]]: 216certificates on Nginx is [[https://certbot.eff.org][Certbot]]:
224 217
225#+begin_src sh 218#+begin_src sh
content/blog/2022-04-09-pinetime.org +57 −65
@@ -7,17 +7,15 @@
7 7
8** Overview 8** Overview
9 9
10The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source 10The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally
11smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally 11announced in September 2019, this ARM-based watch is a fantastic option for
12announced in September 2019, this ARM-based watch is a fantastic option 12users who want the benefits of a modern smartwatch with the backing of
13for users who want the benefits of a modern smartwatch with the backing 13open-source components and software.
14of open-source components and software.
15 14
16** Product Specifications 15** Product Specifications
17 16
18I won't dive into too many details that you can find on 17I won't dive into too many details that you can find on [[https://www.pine64.org/pinetime/][the product page]], but I
19[[https://www.pine64.org/pinetime/][the product page]], but I wanted to 18wanted to point out the prices for each watch and the primary functions:
20point out the prices for each watch and the primary functions:
21 19
221. Price: 201. Price:
23 21
@@ -38,52 +36,48 @@ point out the prices for each watch and the primary functions:
38 36
39* Unboxing 37* Unboxing
40 38
41Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and 39Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and was
42was delivered on 2022-03-23. With the current delays on shipping times 40delivered on 2022-03-23. With the current delays on shipping times around the
43around the world (and the semiconductor shortage), a month for delivery 41world (and the semiconductor shortage), a month for delivery from China seems
44from China seems reasonable to me. 42reasonable to me.
45 43
46The packaging is simple, and the watch comes with instructions, 44The packaging is simple, and the watch comes with instructions, technical
47technical information, the watch, and a charger (it does not include a 45information, the watch, and a charger (it does not include a USB wall adapter).
48USB wall adapter).
49 46
50The watch itself was able to turn on immediately when I pulled it out of 47The watch itself was able to turn on immediately when I pulled it out of the
51the box, but the battery was depleted and required charging right away. 48box, but the battery was depleted and required charging right away.
52 49
53* Software 50* Software
54 51
55** Watch OS: InfiniTime 52** Watch Operating System (OS): InfiniTime
56 53
57While turning on the watch for the first time, some of the main design 54While turning on the watch for the first time, some of the main design choices
58choices you can see in the watch OS, 55you can see in the watch OS, [[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are:
59[[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are:
60 56
61- A square bezel, not too thin against the sides of the watch. 57- A square bezel, not too thin against the sides of the watch.
62- A simple, rubber band. 58- A simple, rubber band.
63- Basic font and screen pixel design. 59- Basic font and screen pixel design.
64- Swipe gestures to access other screens. 60- Swipe gestures to access other screens.
65 61
66The OS itself is fantastic in terms of functionality for me. It does 62The OS itself is fantastic in terms of functionality for me. It does exactly
67exactly what a smartwatch should do - track time, steps, heart rates, 63what a smartwatch should do - track time, steps, heart rates, and connect to
68and connect to another smart device, without being overly burdensome to 64another smart device, without being overly burdensome to the user.
69the user.
70 65
71My only gripe so far is that it's /really/ difficult to swipe to 66My only gripe so far is that it's /really/ difficult to swipe to different
72different screens, such as pulling down the notification tray. I'm not 67screens, such as pulling down the notification tray. I'm not sure if this is an
73sure if this is an OS or hardware issue, but it makes it quite hard to 68OS or hardware issue, but it makes it quite hard to quickly move around the
74quickly move around the screens. 69screens.
75 70
76However, my absolute favorite design choice is that the button the side 71However, my absolute favorite design choice is that the button the side turns
77turns the screen on and off and tilting/waving my wrist doesn't 72the screen on and off and tilting/waving my wrist doesn't accidentally turn on
78accidentally turn on the screen. With other watches, I absolutely hated 73the screen. With other watches, I absolutely hated not being able to turn off
79not being able to turn off the raise-to-wake or wave features (i.e., 74the raise-to-wake or wave features (i.e., blinding myself while wearing a watch
80blinding myself while wearing a watch at night because I moved my arm). 75at night because I moved my arm).
81 76
82** iOS App: InfiniLink 77** iOS App: InfiniLink
83 78
84Since I am using iOS as my primary mobile device OS, I am using the 79Since I am using iOS as my primary mobile device OS, I am using the [[https://github.com/xan-m/InfiniLink][InfiniLink]]
85[[https://github.com/xan-m/InfiniLink][InfiniLink]] app to connect my 80app to connect my watch.
86watch.
87 81
88This app provides the following for PineTime owners: 82This app provides the following for PineTime owners:
89 83
@@ -92,47 +86,45 @@ This app provides the following for PineTime owners:
92- Charts 86- Charts
93- Notifications 87- Notifications
94 88
95Another big feature of InfiniLink is the ability to track pedometer 89Another big feature of InfiniLink is the ability to track pedometer steps in a
96steps in a collection of beautiful graphs, with the option to change 90collection of beautiful graphs, with the option to change your step goal and add
97your step goal and add in manual steps. 91in manual steps.
98 92
99Finally, there are charts to display the battery percentage and heart 93Finally, there are charts to display the battery percentage and heart rates over
100rates over time. This area also comes with an option to clear data. 94time. This area also comes with an option to clear data.
101 95
102* Final Thoughts 96* Final Thoughts
103 97
104** Pros 98** Pros
105 99
106After wearing my watch for a few weeks, I have mostly positive thoughts 100After wearing my watch for a few weeks, I have mostly positive thoughts about
107about the watch so far. In the past, I have owned smartwatches by 101the watch so far. In the past, I have owned smartwatches by FitBit, Fossil,
108FitBit, Fossil, Apple, etc. - *but I prefer the PineTime over all of 102Apple, etc. - *but I prefer the PineTime over all of those watches*.
109those watches*.
110 103
111The PineTime strips out all the unnecessary features and performs the 104The PineTime strips out all the unnecessary features and performs the functions
112functions that it provides effectively and efficiently. 105that it provides effectively and efficiently.
113 106
114The battery life is amazing on this device. By default, the watch seems 107The battery life is amazing on this device. By default, the watch seems to last
115to last anywhere from a few days to a week before dying. 108anywhere from a few days to a week before dying.
116 109
117And of course, it's open source and backed by some of the most dedicated 110And of course, it's open source and backed by some of the most dedicated
118enthusiasts and developers I've seen. Watching the Matrix channel, 111enthusiasts and developers I've seen. Watching the Matrix channel, forums, and
119forums, and website have been exciting to see. 112website have been exciting to see.
120 113
121** Cons 114** Cons
122 115
123If I had to complain about anything, it would simply be the small bugs 116If I had to complain about anything, it would simply be the small bugs in some
124in some features that can be contributed to the companion apps more than 117features that can be contributed to the companion apps more than the watch
125the watch itself. 118itself.
126 119
127A regular user would want native notification support out-of-the-box, 120A regular user would want native notification support out-of-the-box, which is
128which is the biggest item not working for me at the moment. 121the biggest item not working for me at the moment.
129 122
130My only other complaint is that the battery indicator on the watch 123My only other complaint is that the battery indicator on the watch doesn't seem
131doesn't seem accurate when it's nearing depletion - it seems that 124accurate when it's nearing depletion - it seems that there's a bit of battery
132there's a bit of battery life left and then my watch is dead very 125life left and then my watch is dead very suddenly after. This could just be me
133suddenly after. This could just be me misinterpreting the battery level 126misinterpreting the battery level icons, but it has fooled me a few times into
134icons, but it has fooled me a few times into thinking I had more battery 127thinking I had more battery left than I actually did.
135left than I actually did.
136 128
137Other than those small items, I really do love this watch and am glad I 129Other than those small items, I really do love this watch and am glad I replaced
138replaced my Apple Watch with the PineTime. 130my Apple Watch with the PineTime.
content/blog/2022-06-01-ditching-cloudflare.org +49 −56
@@ -5,91 +5,84 @@
5 5
6* Registrar 6* Registrar
7 7
8After spending a year or so using Cloudflare for DNS only - no proxying 8After spending a year or so using Cloudflare for DNS (Domain Name System) only -
9or applications - I spent the last few months using Cloudflare Tunnels 9no proxying or applications - I spent the last few months using Cloudflare
10and Cloudflare Access to protect my self-hosted websites and 10Tunnels and Cloudflare Access to protect my self-hosted websites and
11applications via their proxy traffic model. 11applications via their proxy traffic model.
12 12
13However, I have never liked using Cloudflare due to their increasingly 13However, I have never liked using Cloudflare due to their increasingly large
14large share of control over web traffic, as well as their business model 14share of control over web traffic, as well as their business model of being a
15of being a MITM for all of your traffic. 15MITM (man-in-the-middle) for all of your traffic.
16 16
17So, as of today, I have switched over to [[https://njal.la][Njalla]] as 17So, as of today, I have switched over to [[https://njal.la][Njalla]] as my registrar and DNS manager.
18my registrar and DNS manager. I was able to easily transfer my domains 18I was able to easily transfer my domains over rapidly, with only one domain
19over rapidly, with only one domain taking more than 15-30 minutes to 19taking more than 15-30 minutes to propagate.
20propagate.
21 20
22+I do still have two domains sitting at Cloudflare for the moment while 21+I do still have two domains sitting at Cloudflare for the moment while I decide
23I decide if they're worth the higher rates (one domain is 30€ and the 22if they're worth the higher rates (one domain is 30€ and the other is 45€).+
24other is 45€).+
25 23
26#+begin_quote 24#+begin_quote
27*Update (2022.06.03)*: I ended up transferring my final two domains over 25*Update (2022.06.03)*: I ended up transferring my final two domains over to
28to Njalla, clearing my Cloudflare account of personal data, and deleting 26Njalla, clearing my Cloudflare account of personal data, and deleting the
29the Cloudflare account entirely. /I actually feel relieved to have moved 27Cloudflare account entirely. /I actually feel relieved to have moved on to a
30on to a provider I trust./ 28provider I trust./
31#+end_quote 29#+end_quote
32 30
33* DNS 31* DNS
34 32
35As noted above, I'm using Njalla exclusively for DNS configurations on 33As noted above, I'm using Njalla exclusively for DNS configurations on my
36my domains. 34domains.
37 35
38However, the transfer process was not ideal. As soon as the domains 36However, the transfer process was not ideal. As soon as the domains transferred
39transferred over, I switched the nameservers from Cloudflare to Njalla 37over, I switched the nameservers from Cloudflare to Njalla and lost most of the
40and lost most of the associated DNS records. So, the majority of the 38associated DNS records. So, the majority of the time spent during the migration
41time spent during the migration was simply re-typing all the DNS records 39was simply re-typing all the DNS records back in one-by-one.
42back in one-by-one.
43 40
44This would be much simpler if I were able to edit the plain-text format 41This would be much simpler if I were able to edit the plain-text format of the
45of the DNS configuration. I was able to do that at a past registrar 42DNS configuration. I was able to do that at a past registrar (perhaps it was
46(perhaps it was [[https://gandi.net/][Gandi.net]]?) and it made life a 43[[https://gandi.net/][Gandi.net]]?) and it made life a lot easier.
47lot easier.
48 44
49** Dynamic DNS Updates 45** Dynamic DNS Updates
50 46
51I have built an easy Python script to run (or set-up in =cron= to run 47I have built an easy Python script to run (or set-up in =cron= to run
52automatically) that will check my server's IPv4 and IPv6, compare it to 48automatically) that will check my server's IPv4 (Internet Protocol version 4)and
53Njalla, and update the DNS records if they don't match. You can see the 49IPv6 (Internet Protocol version 6), compare it to Njalla, and update the DNS
54full script and process in my other post: [[../njalla-dns-api/][Updating 50records if they don't match. You can see the full script and process in my other
55Dynamic DNS with Njalla API]]. 51post: [[https://cleberg.net/blog/njalla-dns-api.html][Automating Dynamic DNS Record Updates via Njalla API]].
56 52
57I haven't used this other method, but I do know that you can create 53I haven't used this other method, but I do know that you can create =Dynamic=
58=Dynamic= DNS records with Njalla that 54DNS records with Njalla that [[https://njal.la/docs/ddns/][work for updating dynamic subdomains]].
59[[https://njal.la/docs/ddns/][work for updating dynamic subdomains]].
60 55
61** Njalla's DNS Tool 56** Njalla's DNS Tool
62 57
63One neat upside to Njalla is that they have a 58One neat upside to Njalla is that they have a [[https://check.njal.la/dns/][DNS lookup tool]] that provides a
64[[https://check.njal.la/dns/][DNS lookup tool]] that provides a lot of 59lot of great information for those of you (AKA: me) who hate using the =dig=
65great information for those of you (AKA: me) who hate using the =dig=
66command. 60command.
67 61
68This was very useful for monitoring a couple of my transferred domains 62This was very useful for monitoring a couple of my transferred domains to see
69to see when the changes in nameservers, records, and DNSSEC went into 63when the changes in nameservers, records, and DNSSEC (Domain Name System
70effect. 64Security Extensions) went into effect.
71 65
72* Tunnel 66* Tunnel
73 67
74Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on 68Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on
75Cloudflare's servers) and allowed me to mask the private IP address of 69Cloudflare's servers) and allowed me to mask the private internet protocol (IP)
76the server hosting my various websites and apps. 70address of the server hosting my various websites and apps.
77 71
78However, as I was moving away from Cloudflare, I was not able to find a 72However, as I was moving away from Cloudflare, I was not able to find a suitable
79suitable replacement that was both inexpensive and simple. So, I simply 73replacement that was both inexpensive and simple. So, I simply went back to
80went back to hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own 74hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own reverse proxy with Nginx]]. With the recent additions of Unifi
81reverse proxy with Nginx]]. With the recent additions of Unifi hardware 75hardware in my server/network rack, I am much more protected against spam and
82in my server/network rack, I am much more protected against spam and
83malicious attacks at the network edge than I was before I switched to 76malicious attacks at the network edge than I was before I switched to
84Cloudflare. 77Cloudflare.
85 78
86* Access 79* Access
87 80
88Cloudflare Access, another app I used in combination with Cloudflare 81Cloudflare Access, another app I used in combination with Cloudflare Tunnel,
89Tunnel, provided an authentication screen that required you to enter 82provided an authentication screen that required you to enter valid credentials
90valid credentials before Cloudflare would forward you to the actual 83before Cloudflare would forward you to the actual website or app (if the
91website or app (if the website/app has their own authentication, you'd 84website/app has their own authentication, you'd then have to authenticate a
92then have to authenticate a second time). 85second time).
93 86
94I did not replace this service with anything since I only host a handful 87I did not replace this service with anything since I only host a handful of
95of non-sensitive apps that don't require duplicate authentication. 88non-sensitive apps that don't require duplicate authentication.
content/blog/2022-06-07-self-hosting-freshrss.org +71 −81
@@ -3,47 +3,43 @@
3#+description: Stepwise instructions for installing FreshRSS using Docker and configuring Nginx as a reverse proxy to enable secure and synchronized RSS feed access. 3#+description: Stepwise instructions for installing FreshRSS using Docker and configuring Nginx as a reverse proxy to enable secure and synchronized RSS feed access.
4#+slug: self-hosting-freshrss 4#+slug: self-hosting-freshrss
5 5
6* Why RSS? 6* Why Use Really Simple Syndication (RSS)?
7 7
8After noticing that I have collected 50+ blogs as bookmarks, I decided 8After noticing that I have collected 50+ blogs as bookmarks, I decided to
9to migrate back to using RSS feeds to stay up-to-date with my favorite 9migrate back to using RSS feeds to stay up-to-date with my favorite websites.
10websites. Using RSS allows me to read all of these posts in a single app 10Using RSS allows me to read all of these posts in a single app (on both mobile &
11(on both mobile & desktop) and allows me to be notified when new posts 11desktop) and allows me to be notified when new posts are available.
12are available.
13 12
14However, I ran into one issue: syncing subscriptions and read/unread 13However, I ran into one issue: syncing subscriptions and read/unread posts
15posts across devices. Since I want to be able to easily read on both 14across devices. Since I want to be able to easily read on both mobile and
16mobile and desktop, I decided to look for a self-hosted RSS solution. 15desktop, I decided to look for a self-hosted RSS solution.
17 16
18Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to 17Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to successfully install it on my server in
19successfully install it on my server in about 30 minutes. 18about 30 minutes.
20 19
21* Documentation 20* Documentation
22 21
23While it's certainly not robust, the 22While it's certainly not robust, the [[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is helpful for
24[[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is 23figuring out basic information about the service.
25helpful for figuring out basic information about the service.
26 24
27However, I wanted to install this service as a Docker container and 25However, I wanted to install this service as a Docker container and stumbled
28stumbled across the 26across the [[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]] within the GitHub repository.
29[[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]]
30within the GitHub repository.
31 27
32This README was the documentation I actually needed. However, as you'll 28This README was the documentation I actually needed. However, as you'll see
33see below, I still had to manually edit one file (=config.php=) to 29below, I still had to manually edit one file (=config.php=) to access the API
34access the API externally via my RSS apps. 30externally via my RSS apps.
35 31
36* Installation 32* Installation
37 33
38** DNS 34** DNS
39 35
40The first step, as required by any external web service, was assigning a 36The first step, as required by any external web service, was assigning a domain
41domain name to use. I chose to use a subdomain, like =rss.example.com=. 37name to use. I chose to use a subdomain, like =rss.example.com=.
42 38
43To assign this, I created an =A= record in my DNS settings with the IPv4 39To assign this, I created an =A= record in my DNS settings with the IPv4
44address of the server and an =AAAA= record with the IPv6 address of the 40(Internet Protocol version 4) address of the server and an =AAAA= record with
45server. Note: assigning an IPv6 (=AAAA=) record is optional, but I like 41the IPv6 (Internet Protocol version 6) address of the server. Note: assigning an
46to enable IPV6 for my services. 42IPv6 (=AAAA=) record is optional, but I like to enable IPV6 for my services.
47 43
48#+begin_src config 44#+begin_src config
49rss.example.com A xxx.xxx.xxx.xxx 45rss.example.com A xxx.xxx.xxx.xxx
@@ -52,11 +48,10 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx
52 48
53** Docker 49** Docker
54 50
55I initially tried to set up a =docker-compose.yml= file with a =.env= 51I initially tried to set up a =docker-compose.yml= file with a =.env= file
56file because I prefer to have a file I can look back at later to see how 52because I prefer to have a file I can look back at later to see how I initially
57I initially started the container, but it simply wouldn't work for me. 53started the container, but it simply wouldn't work for me. I'm not sure why, but
58I'm not sure why, but I assume I wasn't telling =docker-compose= where 54I assume I wasn't telling =docker-compose= where the =.env= file was.
59the =.env= file was.
60 55
61Regardless, I chose to simply run the service with =docker run=. See the 56Regardless, I chose to simply run the service with =docker run=. See the
62following command for my =docker run= configuration: 57following command for my =docker run= configuration:
@@ -72,25 +67,24 @@ sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
72 freshrss/freshrss 67 freshrss/freshrss
73#+end_src 68#+end_src
74 69
75This started the container successfully and allowed me to visit the 70This started the container successfully and allowed me to visit the FreshRSS
76FreshRSS instance at =localhost:8080=. 71instance at =localhost:8080=.
77 72
78** Fresh RSS Set-Up 73** Fresh RSS Set-Up
79 74
80I *HIGHLY* suggest that you set up your user account prior to exposing 75I *HIGHLY* suggest that you set up your user account prior to exposing this
81this service to the public. It's unlikely that someone is trying to 76service to the public. It's unlikely that someone is trying to access the exact
82access the exact domain or IP/port you're assigning here, but as soon as 77domain or IP/port you're assigning here, but as soon as you expose this service,
83you expose this service, the first person to open the URL will be able 78the first person to open the URL will be able to create the administrative user.
84to create the admin user.
85 79
86In order to set up your FreshRSS service, open the =localhost:8080= URL 80In order to set up your FreshRSS service, open the =localhost:8080= URL in your
87in your browser (you may need to use a local IP instead of =localhost= 81browser (you may need to use a local internet protocol (IP) instead of
88if you're accessing the page from a different machine on the network - 82=localhost= if you're accessing the page from a different machine on the
89e.g., =192.168.1.20:8080=). 83network - e.g., =192.168.1.20:8080=).
90 84
91Once the page loads, set up your default user with a strong username and 85Once the page loads, set up your default user with a strong username and
92password. You may also choose to configure other settings prior to 86password. You may also choose to configure other settings prior to exposing this
93exposing this service. 87service.
94 88
95** Nginx Reverse-Proxy 89** Nginx Reverse-Proxy
96 90
@@ -103,7 +97,7 @@ First, I created a new Nginx configuration file:
103sudo nano /etc/nginx/sites-available/rss.example.com 97sudo nano /etc/nginx/sites-available/rss.example.com
104#+end_src 98#+end_src
105 99
106Within the config file, I pasted the following code: 100Within the configuration file, I pasted the following code:
107 101
108#+begin_src config 102#+begin_src config
109upstream freshrss { 103upstream freshrss {
@@ -136,8 +130,7 @@ server {
136} 130}
137#+end_src 131#+end_src
138 132
139Finally, restart Nginx and you will be able to access your service via 133Finally, restart Nginx and you will be able to access your service via HTTP (Hypertext Transfer Protocol):
140HTTP:
141 134
142#+begin_src sh 135#+begin_src sh
143sudo systemctl restart nginx.service 136sudo systemctl restart nginx.service
@@ -145,49 +138,46 @@ sudo systemctl restart nginx.service
145 138
146** HTTPS 139** HTTPS
147 140
148However, I don't want to access my RSS feeds via HTTP. I want it 141However, I don't want to access my RSS feeds via HTTP. I want it available only
149available only via HTTPS. In order to do this, I ran the 142via HTTPS (Hypertext Transfer Protocol Secure). In order to do this, I ran the
150[[https://certbot.eff.org/][certbot]] program to generate SSL 143[[https://certbot.eff.org/][certbot]] program to generate SSL (Secure Socket Layer) certificates for me:
151certificates for me:
152 144
153#+begin_src sh 145#+begin_src sh
154sudo certbot --nginx 146sudo certbot --nginx
155#+end_src 147#+end_src
156 148
157This process will automatically generate an SSL certificate for you and 149This process will automatically generate an SSL certificate for you and modify
158modify the Nginx configuration file to include a redirect from HTTP to 150the Nginx configuration file to include a redirect from HTTP to HTTPS.
159HTTPS.
160 151
161* Post-Installation Fixes 152* Post-Installation Fixes
162 153
163At this point, we have a functional FreshRSS website, available from 154At this point, we have a functional FreshRSS website, available from anywhere
164anywhere and secured with HTTPS. However, attempting to connect this 155and secured with HTTPS. However, attempting to connect this service to an RSS
165service to an RSS app resulted in many errors regarding unavailable URLs 156app resulted in many errors regarding unavailable URLs and incorrect
166and incorrect credentials. 157credentials.
167 158
168** API Set-Up 159** API Set-Up
169 160
170First, you need to open your user profile in FreshRSS (=Settings= > 161First, you need to open your user profile in FreshRSS (=Settings= > =Profile=)
171=Profile=) and set an API password in the field at the bottom. This is 162and set an API password in the field at the bottom. This is the password you
172the password you will need to provide to your RSS apps. 163will need to provide to your RSS apps.
173 164
174Once that is set and saved, click the link below the API password field 165Once that is set and saved, click the link below the API password field to open
175to open the API check tool. It should look something like 166the API (application programming interface) check tool. It should look something
176=https://localhost:8080/api/= or =https://rss.example.com/api/=. 167like =https://localhost:8080/api/= or =https://rss.example.com/api/=.
177 168
178Within this page, you /should/ see your correct external URL and "PASS" 169Within this page, you /should/ see your correct external URL and "PASS" at the
179at the bottom of each API type. This would mean everything is set up 170bottom of each API type. This would mean everything is set up correctly, and you
180correctly, and you can now move on and login to any RSS apps that 171can now move on and login to any RSS apps that support self-hosted options.
181support self-hosted options.
182 172
183In my case, the URL showed an internal URL and I had a warning that the 173In my case, the URL showed an internal URL and I had a warning that the
184=base_url= variable may be misconfigured. If this is the case, see the 174=base_url= variable may be misconfigured. If this is the case, see the next
185next section for a fix. 175section for a fix.
186 176
187** Base URL Fix 177** Base URL Fix
188 178
189In order to fix the =base_url= for the API, I opened up my docker 179In order to fix the =base_url= for the API, I opened up my docker container with
190container with the following command: 180the following command:
191 181
192#+begin_src sh 182#+begin_src sh
193sudo docker exec -it freshrss bash 183sudo docker exec -it freshrss bash
@@ -206,9 +196,10 @@ Finally, open up =config.php= in the =data= directory:
206nano data/config.php 196nano data/config.php
207#+end_src 197#+end_src
208 198
209Within =config.php=, you will need to update the =base_url= variable and 199Within =config.php=, you will need to update the =base_url= variable and update
210update it to match your external URL. In my case, I simply commented-out 200it to match your external URL (uniform resource locator). In my case, I simply
211the incorrect URL with =//= and added the correct one on a new line: 201commented-out the incorrect URL with =//= and added the correct one on a new
202line:
212 203
213#+begin_src php 204#+begin_src php
214<?php 205<?php
@@ -221,8 +212,8 @@ the incorrect URL with =//= and added the correct one on a new line:
221> 212>
222#+end_src 213#+end_src
223 214
224You can now exit the file with =Ctrl + x=, press =y= to save the file, 215You can now exit the file with =Ctrl + x=, press =y= to save the file, and then
225and then click =Enter= to keep the same file name. 216click =Enter= to keep the same file name.
226 217
227Finally, just exit out of the docker container: 218Finally, just exit out of the docker container:
228 219
@@ -236,8 +227,7 @@ Next, just restart the container:
236sudo docker restart freshrss 227sudo docker restart freshrss
237#+end_src 228#+end_src
238 229
239Voilà! Your API check should now "PASS" and you should be able to use 230Voilà! Your API check should now "PASS" and you should be able to use one of the
240one of the API URLs in your RSS apps. 231API URLs in your RSS apps.
241 232
242In my case, I use [[https://netnewswire.com][NetNewsWire]] on my desktop 233In my case, I use [[https://netnewswire.com][NetNewsWire]] on my desktop and phone.
243and phone.
content/blog/2022-06-16-terminal-lifestyle.org +97 −115
@@ -5,29 +5,27 @@
5 5
6* Text-Based Simplicity 6* Text-Based Simplicity
7 7
8I've detailed my views on web-based minimalism and related topics in 8I've detailed my views on web-based minimalism and related topics in other posts
9other posts throughout the years; e.g., JavaScript/CSS bloat slowing 9throughout the years; e.g., JavaScript/CSS (Cascading Style Sheets) bloat
10down websites that are essentially a text document. However, I have 10slowing down websites that are essentially a text document. However, I have
11never really expanded beyond talking about the web and describing how I 11never really expanded beyond talking about the web and describing how I focus on
12focus on minimizing distractions in other digital environments. 12minimizing distractions in other digital environments.
13 13
14This post is going to set the baseline for how I /try/ to live my 14This post is going to set the baseline for how I /try/ to live my digital life.
15digital life. It does not necessarily get into my physical life, which 15It does not necessarily get into my physical life, which is often harder to
16is often harder to control and contain all the noise in our modern 16control and contain all the noise in our modern world.
17world. 17
18 18While there are new things to do every day in our digital world, I find that
19While there are new things to do every day in our digital world, I find 19keeping a core set of values and interests can ground you and keep you mindful
20that keeping a core set of values and interests can ground you and keep 20of /why/ you are participating in the digital world. For example, if - at your
21you mindful of /why/ you are participating in the digital world. For 21core - you have no interest in what strangers think about random topics, it
22example, if - at your core - you have no interest in what strangers 22would be unwise to start participating in social media. However, I am someone
23think about random topics, it would be unwise to start participating in 23who has been dragged in by effective advertising to participate in communities
24social media. However, I am someone who has been dragged in by effective 24that I realize I do not care for.
25advertising to participate in communities that I realize I do not care 25
26for. 26I won't dive much further into explaining the philosophy of all this, but I will
27 27link a few helpful articles that may pique your interest if you're in search of
28I won't dive much further into explaining the philosophy of all this, 28more meaningful experiences:
29but I will link a few helpful articles that may pique your interest if
30you're in search of more meaningful experiences:
31 29
32- [[https://en.wikipedia.org/wiki/Mindfulness][Mindfulness]] 30- [[https://en.wikipedia.org/wiki/Mindfulness][Mindfulness]]
33- [[https://en.wikipedia.org/wiki/Minimalism][Minimalism]] 31- [[https://en.wikipedia.org/wiki/Minimalism][Minimalism]]
@@ -35,125 +33,111 @@ you're in search of more meaningful experiences:
35 33
36* Living Life in the Terminal 34* Living Life in the Terminal
37 35
38My personal approach to reducing digital distractions and increasing my 36My personal approach to reducing digital distractions and increasing my focus on
39focus on the task at hand is to use a terminal for as much as I possibly 37the task at hand is to use a terminal for as much as I possibly can.
40can.
41 38
42Most days, this means that I have a few tabs open constantly in my 39Most days, this means that I have a few tabs open constantly in my terminal:
43terminal:
44 40
451. A web browser 411. A web browser
462. A chat client 422. A chat client
473. An email client 433. An email client
484. An RSS feed reader 444. An RSS (Really Simple Syndication) feed reader
495. A local shell for navigating my computer's files 455. A local shell for navigating my computer's files
506. A remote shell for managing servers and other machines 466. A remote shell for managing servers and other machines
51 47
52Beyond this, I rarely open other tabs or GUI applications, unless 48Beyond this, I rarely open other tabs or graphical applications, unless
53absolutely necessary. If you look, you may be surprised what can be 49absolutely necessary. If you look, you may be surprised what can be accomplished
54accomplished in the terminal. 50in the terminal.
55 51
56For example, I have moved my music and entertainment downloads to the 52For example, I have moved my music and entertainment downloads to the terminal,
57terminal, along with my device VPN connections. I am exploring options 53along with my device virtual private network (VPN) connections. I am exploring
58for moving my RSS subscriptions to something like 54options for moving my RSS subscriptions to something like [[https://newsboat.org/][Newsboat]], so that I
59[[https://newsboat.org/][Newsboat]], so that I can read my daily 55can read my daily articles without all the fuss.
60articles without all the fuss.
61 56
62Now that we have some examples out of the way, let's dive into the 57Now that we have some examples out of the way, let's dive into the specifics.
63specifics.
64 58
65** Browsing the Web 59** Browsing the Web
66 60
67I'm going to start off with a hard topic for those who prefer to live in 61I'm going to start off with a hard topic for those who prefer to live in the
68the terminal: web browsing. This task is made hard mostly by websites 62terminal: web browsing. This task is made hard mostly by websites and web apps
69and web apps that require JavaScript to run. The other difficult part is 63that require JavaScript to run. The other difficult part is that if you're using
70that if you're using a text-based browser, that means images won't load 64a text-based browser, that means images won't load (hopefully that's obvious).
71(hopefully that's obvious).
72 65
73I am using [[https://lynx.invisible-island.net][Lynx]], a text-based 66I am using [[https://lynx.invisible-island.net][Lynx]], a text-based browser that runs quickly and easily in the
74browser that runs quickly and easily in the terminal. Lynx allows me to 67terminal. Lynx allows me to browser most websites by simply typing =g= and then
75browser most websites by simply typing =g= and then typing in the URL I 68typing in the URL I want.
76want.
77 69
78If you need a search engine while in Lynx, I recommend 70If you need a search engine while in Lynx, I recommend [[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which
79[[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which allows 71allows you to search the web using their text-only interface.
80you to search the web using their text-only interface.
81 72
82Eventually, you will run into websites that don't work (or are just too 73Eventually, you will run into websites that don't work (or are just too ugly and
83ugly and messy) in a text-only mode, and you'll be forced to switch over 74messy) in a text-only mode, and you'll be forced to switch over to a GUI browser
84to a GUI browser to look at that site. Personally, I don't mind this as 75to look at that site. Personally, I don't mind this as it doesn't happen as
85it doesn't happen as often as I thought it would. 76often as I thought it would.
86 77
87The only time I need to do this is when I want to browse an 78The only time I need to do this is when I want to browse an image/video-focused
88image/video-focused webpage or if I need to log in to a site, and it 79webpage or if I need to log in to a site, and it doesn't support a text-only
89doesn't support a text-only login page. For example, I am able to easily 80login page. For example, I am able to easily log in to [[https://sr.ht][Sourcehut]] in lynx.
90log in to [[https://sr.ht][Sourcehut]] in lynx.
91 81
92** Chatting with Friends 82** Chatting with Friends
93 83
94After web browsing activities, my main form of terminal communication is 84After web browsing activities, my main form of terminal communication is Matrix.
95Matrix. I use the [[https://docs.mau.fi/gomuks/][gomuks]] client 85I use the [[https://docs.mau.fi/gomuks/][gomuks]] client currently.
96currently.
97 86
98This was incredibly easy to install on macOS (but I will need to see if 87This was incredibly easy to install on macOS (but I will need to see if it'll be
99it'll be just as easy on Linux when my new laptop arrives): 88just as easy on Linux when my new laptop arrives):
100 89
101#+begin_src sh 90#+begin_src sh
102brew install gomuks 91brew install gomuks
103#+end_src 92#+end_src
104 93
105Once you launch gomuks, it will sync and require your username and 94Once you launch gomuks, it will sync and require your username and password to
106password to login. After doing so, the only problem I ran into was 95login. After doing so, the only problem I ran into was verifying my gomuks
107verifying my gomuks client so that I could participate in rooms with 96client so that I could participate in rooms with E2EE (end-to-end encryption).
108E2EE.
109 97
110Finally, I was able to verify the session by opening the Element desktop 98Finally, I was able to verify the session by opening the Element desktop app (I
111app (I assume you can do this in the browser and mobile app too, but I'm 99assume you can do this in the browser and mobile app too, but I'm not sure) and
112not sure) and manually verifying myself with this process: 100manually verifying myself with this process:
113 101
1141. Open the Element desktop app 1021. Open the Element desktop app
1152. Open a room I was a member of 1032. Open a room I was a member of
1163. Open the =Room Info= pane 1043. Open the =Room Info= pane
1174. Open the =People= menu and search for myself 1054. Open the =People= menu and search for myself
1185. Click on my profile name 1065. Click on my profile name
1196. Click on the session link under the =Security= section and follow the 1076. Click on the session link under the =Security= section and follow the prompts
120 prompts to manually verify the session 108 to manually verify the session
121 109
122Overall, I like gomuks and am able to enjoy all the features I was using 110Overall, I like gomuks and am able to enjoy all the features I was using in
123in Element. The only hiccup I have occurred is manually downloading 111Element. The only hiccup I have occurred is manually downloading images to view
124images to view them, which can be annoying. 112them, which can be annoying.
125 113
126** Email 114** Email
127 115
128Moving email to the terminal has been the hardest of the tasks for me. 116Moving email to the terminal has been the hardest of the tasks for me. Unlike
129Unlike web browsing, where I can simply decide to not look at a website 117web browsing, where I can simply decide to not look at a website that does not
130that does not work in the terminal, I cannot simply ignore emails sent 118work in the terminal, I cannot simply ignore emails sent to me.
131to me.
132 119
133Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as 120Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as a potential email client.
134a potential email client.
135 121
136However, this requires a *TON* of configuration and tweaking to get 122However, this requires a *TON* of configuration and tweaking to get right. Even
137right. Even when I was able to set up neomutt, configure my email 123when I was able to set up neomutt, configure my email account, and customize a
138account, and customize a few personal preferences, a lot of emails still 124few personal preferences, a lot of emails still do not display correctly (mostly
139do not display correctly (mostly due to HTML and images). 125due to HTML (Hypertext Markup Language) and images).
140 126
141I won't get into the details of configuring =neomutt=; I mostly followed 127I won't get into the details of configuring =neomutt=; I mostly followed this
142this blog post: 128blog post: [[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the Terminal: Configuring Neomutt]].
143[[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the
144Terminal: Configuring Neomutt]].
145 129
146Finally, I have yet to figure out how to connect my GPG keys to 130Finally, I have yet to figure out how to connect my PGP (Pretty Good Privacy)
147=neomutt=, but that's a problem for another day. 131keys to =neomutt=, but that's a problem for another day.
148 132
149** RSS Feed Reader 133** RSS Feed Reader
150 134
151I have just started using [[https://newsboat.org/][Newsboat]] to read 135I have just started using [[https://newsboat.org/][Newsboat]] to read articles in my terminal and have
152articles in my terminal and have found quick success with it. 136found quick success with it.
153 137
154The configuration was super easy for this app; I simply installed the 138The configuration was super easy for this app; I simply installed the app,
155app, created a file for URLs, and imported my OPML subscriptions that I 139created a file for URLs, and imported my OPML (Outline Processor Markup
156had exported out of my old feed reader: 140Language) subscriptions that I had exported out of my old feed reader:
157 141
158#+begin_src sh 142#+begin_src sh
159brew install newsboat 143brew install newsboat
@@ -169,13 +153,12 @@ newsboat -i=my_subscriptions.opml
169 153
170** Writing & Programming 154** Writing & Programming
171 155
172Unfortunately, the weak link in my terminal-based environment right now 156Unfortunately, the weak link in my terminal-based environment right now is my
173is my grasp of the possibilities of editing files within a shell. 157grasp of the possibilities of editing files within a shell.
174 158
175I am used to the easy extensions found in VSCodium and Kate, so I am 159I am used to the easy extensions found in VSCodium and Kate, so I am slowly
176slowly learning how to mold the default editing tools to my needs. 160learning how to mold the default editing tools to my needs. Currently, this
177Currently, this means I am using =nano= with the following 161means I am using =nano= with the following configuration:
178configuration:
179 162
180#+begin_src config 163#+begin_src config
181set breaklonglines 164set breaklonglines
@@ -187,15 +170,14 @@ set fill 80
187#+end_src 170#+end_src
188 171
189This configuration allows nano to automatically hard-wrap lines at 80 172This configuration allows nano to automatically hard-wrap lines at 80
190characters, autoindent the wrapped lines (if the previous line was 173characters, autoindent the wrapped lines (if the previous line was indented),
191indented), use 2 spaces per tab, and display line numbers within each 174use 2 spaces per tab, and display line numbers within each file I open.
192file I open. 175
193 176I am currently looking to see if =vim= or =emacs= would be more useful for my
194I am currently looking to see if =vim= or =emacs= would be more useful 177current needs, but I'm not in any rush, so I don't expect to find an answer
195for my current needs, but I'm not in any rush, so I don't expect to find 178anytime soon.
196an answer anytime soon. 179
197 180With my current life demands, I am not programming at the moment and have not
198With my current life demands, I am not programming at the moment and 181explored the best terminal set-up for programming. However, I have seen many
199have not explored the best terminal set-up for programming. However, I 182peers find success configuring =vim= and =emacs=, so that's where I will start
200have seen many peers find success configuring =vim= and =emacs=, so 183when I pick my projects back up.
201that's where I will start when I pick my projects back up.
content/blog/2022-06-22-daily-poetry.org +35 −39
@@ -14,8 +14,8 @@ I use to email myself plaintext poems daily, visit the repository:
14Most of my programming projects are small, random projects that are made 14Most of my programming projects are small, random projects that are made
15strictly to fix some small problem I have or enhance my quality of life. 15strictly to fix some small problem I have or enhance my quality of life.
16 16
17In this case, I was looking for a simply and easy way to get a daily 17In this case, I was looking for a simply and easy way to get a daily dose of
18dose of literature or poetry to read in the mornings. 18literature or poetry to read in the mornings.
19 19
20However, I don't want to sign up for a random mailing list on just any 20However, I don't want to sign up for a random mailing list on just any
21website. I also don't want to have to work to find the reading content 21website. I also don't want to have to work to find the reading content
@@ -29,21 +29,20 @@ a daily basis, and scheduled to deliver automatically.
29This solution uses Python and email, so the following process requires 29This solution uses Python and email, so the following process requires
30the following to be installed: 30the following to be installed:
31 31
321. An SMTP server, which can be as easy as installing =mailutils= if 321. A Simple Mail Transfer Protocol (SMTP) server, which can be as easy as
33 you're on a Debian-based distro. 33 installing =mailutils= if you're on a Debian-based distribution.
342. Python (& pip!) 342. Python (& pip!)
353. The following Python packages: =email=, =smtplib=, =json=, and 353. The following Python packages: =email=, =smtplib=, =json=, and =requests=
36 =requests=
37 36
38* Breaking Down the Logic 37* Breaking Down the Logic
39 38
40I want to break down the logic for this program, as it's quite simple 39I want to break down the logic for this program, as it's quite simple and
41and informational. 40informational.
42 41
43** Required Packages 42** Required Packages
44 43
45This program starts with a simple import of the required packages, so I 44This program starts with a simple import of the required packages, so I wanted
46wanted to explain why each package is used: 45to explain why each package is used:
47 46
48#+begin_src python 47#+begin_src python
49from email.mime.text import MIMEText # Required for translating MIMEText 48from email.mime.text import MIMEText # Required for translating MIMEText
@@ -54,15 +53,15 @@ import requests # Required to send out a request to the API
54 53
55** Sending the API Request 54** Sending the API Request
56 55
57Next, we need to actually send the API request. In my case, I'm calling 56Next, we need to actually send the application programming interface (API)
58a random poem from the entire API. If you want, you can call specific 57request. In my case, I'm calling a random poem from the entire API. If you want,
59poems or authors from this API. 58you can call specific poems or authors from this API.
60 59
61#+begin_src python 60#+begin_src python
62json_data = requests.get('https://poetrydb.org/random').json() 61json_data = requests.get('https://poetrydb.org/random').json()
63#+end_src 62#+end_src
64 63
65This gives us the following result in JSON: 64This gives us the following result in JSON (JavaScript Object Notation):
66 65
67#+begin_src json 66#+begin_src json
68[ 67[
@@ -94,12 +93,12 @@ This gives us the following result in JSON:
94 93
95** Parsing the API Results 94** Parsing the API Results
96 95
97In order to parse this into a readable format, we need to use the =json= 96In order to parse this into a readable format, we need to use the =json= package
98package and extract the fields we want. In the example below, I am 97and extract the fields we want. In the example below, I am grabbing every field
99grabbing every field presented by the API. 98presented by the API.
100 99
101For the actual poem content, we need to loop over each line in the 100For the actual poem content, we need to loop over each line in the =lines=
102=lines= variable since each line is a separate string by default. 101variable since each line is a separate string by default.
103 102
104#+begin_quote 103#+begin_quote
105You /could/ also extract the title or author and make another call out 104You /could/ also extract the title or author and make another call out
@@ -125,21 +124,20 @@ for line in json_data[0]['lines']:
125 124
126** Composing the Email 125** Composing the Email
127 126
128Now that I have all the data I need, I just need to compose it into a 127Now that I have all the data I need, I just need to compose it into a message
129message and prepare the message metadata. 128and prepare the message metadata.
130 129
131For my daily email, I want to see the title of the poem first, followed 130For my daily email, I want to see the title of the poem first, followed by the
132by the author, then a blank line, and finally the full poem. This code 131author, then a blank line, and finally the full poem. This code snippet combines
133snippet combines that data and packages it into a MIMEText container, 132that data and packages it into a MIMEText container, ready to be emailed.
134ready to be emailed.
135 133
136#+begin_src python 134#+begin_src python
137msg_body = title + "\n" + author + "\n\n" + lines 135msg_body = title + "\n" + author + "\n\n" + lines
138msg = MIMEText(msg_body) 136msg = MIMEText(msg_body)
139#+end_src 137#+end_src
140 138
141Before we send the email, we need to prepare the metadata (subject, 139Before we send the email, we need to prepare the metadata (subject, from, to,
142from, to, etc.): 140etc.):
143 141
144#+begin_src python 142#+begin_src python
145sender_email = 'example@server.local' 143sender_email = 'example@server.local'
@@ -151,10 +149,9 @@ msg['To'] = recipient_email
151 149
152** Sending the Email 150** Sending the Email
153 151
154Now that I have everything ready to be emailed, the last step is to 152Now that I have everything ready to be emailed, the last step is to simply
155simply connect to an SMTP server and send the email out to the 153connect to an SMTP server and send the email out to the recipients. In my case,
156recipients. In my case, I installed =mailutils= on Ubuntu and let my 154I installed =mailutils= on Ubuntu and let my SMTP server be =localhost=.
157SMTP server be =localhost=.
158 155
159#+begin_src python 156#+begin_src python
160smtp_server = 'localhost' 157smtp_server = 'localhost'
@@ -165,9 +162,8 @@ s.quit()
165 162
166* The Result! 163* The Result!
167 164
168Instead of including a screenshot, I've copied the contents of the email 165Instead of including a screenshot, I've copied the contents of the email that
169that was delivered to my inbox below since I set this process up in 166was delivered to my inbox below since I set this process up in plaintext format.
170plaintext format.
171 167
172#+begin_src txt 168#+begin_src txt
173Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC) 169Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
@@ -200,16 +196,16 @@ Some, wise in show, more fools indeed than they.
200* Scheduling the Daily Email 196* Scheduling the Daily Email
201 197
202Last, but not least, is scheduling this Python script with =crontab=. To 198Last, but not least, is scheduling this Python script with =crontab=. To
203schedule a script to run daily, you can add it to the =crontab= file. To 199schedule a script to run daily, you can add it to the =crontab= file. To do
204do this, open =crontab= in editing mode: 200this, open =crontab= in editing mode:
205 201
206#+begin_src sh 202#+begin_src sh
207crontab -e 203crontab -e
208#+end_src 204#+end_src
209 205
210In the file, simply paste the following snippet at the bottom of the 206In the file, simply paste the following snippet at the bottom of the file and
211file and ensure that the file path is correctly pointing to wherever you 207ensure that the file path is correctly pointing to wherever you saved your
212saved your Python script: 208Python script:
213 209
214#+begin_src config 210#+begin_src config
2150 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py 2110 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py
content/blog/2022-06-24-fedora-i3.org +53 −57
@@ -5,61 +5,57 @@
5 5
6* Leaving macOS 6* Leaving macOS
7 7
8As I noted [[../foss-macos-apps][in a recent post]], I have been 8As I noted in a recent post, I have been planning on migrating from macOS back
9planning on migrating from macOS back to a Linux-based OS. I am happy to 9to a Linux-based operating system (OS). I am happy to say that I have finally
10say that I have finally completed my migration and am now stuck in the 10completed my migration and am now stuck in the wonderful world of Linux again.
11wonderful world of Linux again.
12 11
13My decision to leave macOS really came down to just a few important 12My decision to leave macOS really came down to just a few important
14things: 13things:
15 14
16- Apple Security (Gatekeeper) restricting me from running any software I 15- Apple Security (Gatekeeper) restricting me from running any software I want.
17 want. Even if you disable Gatekeeper and allow software to bypass the 16 Even if you disable Gatekeeper and allow software to bypass the rest of the
18 rest of the device installation security, you still have to repeat 17 device installation security, you still have to repeat that process every time
19 that process every time the allowed software is updated. 18 the allowed software is updated.
20- macOS sends out nearly constant connections, pings, telemetry, etc. to 19- macOS sends out nearly constant connections, pings, telemetry, etc. to a
21 a myriad of mysterious Apple services. I'm not even going to dive into 20 myriad of mysterious Apple services. I'm not even going to dive into how many
22 how many macOS apps have constant telemetry on, as well. 21 macOS apps have constant telemetry on, as well.
23- Lastly, I just /really/ missed the customization and freedom that 22- Lastly, I just /really/ missed the customization and freedom that comes with
24 comes with Linux. Being able to switch to entirely new kernel, OS, or 23 Linux. Being able to switch to entirely new kernel, OS, or desktop within
25 desktop within minutes is a freedom I took for granted when I switched 24 minutes is a freedom I took for granted when I switched to macOS.
26 to macOS. 25
27 26Now that I've covered macOS, I'm going to move on to more exciting topics: my
28Now that I've covered macOS, I'm going to move on to more exciting 27personal choice of OS, desktop environment (DE), and various customizations I'm
29topics: my personal choice of OS, DE, and various customizations I'm
30using. 28using.
31 29
32* Fedora 30* Fedora
33 31
34After trying a ton of distros (I think I booted and tested around 20-25 32After trying a ton of distributions (I think I booted and tested around 20-25
35distros), I finally landed on [[https://getfedora.org/][Fedora Linux]]. 33distributions), I finally landed on [[https://getfedora.org/][Fedora Linux]]. I have quite a bit of experience
36I have quite a bit of experience with Fedora and enjoy the =dnf= package 34with Fedora and enjoy the =dnf= package manager. Fedora allows me to keep
37manager. Fedora allows me to keep up-to-date with recent software (I'm 35up-to-date with recent software (I'm looking at you, Debian), but still provides
38looking at you, Debian), but still provides a level of stability you 36a level of stability you don't find in every distribution.
39don't find in every distro. 37
40 38In a very close second place was Arch Linux, as well as its spin-off: Garuda
41In a very close second place was Arch Linux, as well as its spin-off: 39Linux (Garuda w/ sway is /beautiful/). Arch is great for compatibility and the
42Garuda Linux (Garuda w/ sway is /beautiful/). Arch is great for 40massive community it has, but I have just never had the time to properly sit
43compatibility and the massive community it has, but I have just never 41down and learn the methodology behind their packaging systems.
44had the time to properly sit down and learn the methodology behind their 42
45packaging systems. 43Basically, everything else I tested was unacceptable in at least one way or
46 44another. Void (=glibc=) was great, but doesn't support all the software I need.
47Basically, everything else I tested was unacceptable in at least one way 45Slackware worked well as a text-based user interface (TUI), but I wasn't skilled
48or another. Void (=glibc=) was great, but doesn't support all the
49software I need. Slackware worked well as a tui, but I wasn't skilled
50enough to get a tiling window manager (WM) working on it. 46enough to get a tiling window manager (WM) working on it.
51 47
52** i3 48** i3
53 49
54One of the reasons I settled on Fedora is that it comes with an official 50One of the reasons I settled on Fedora is that it comes with an official i3
55i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of 51spin. Being able to use a tiling WM, such as i3 or sway, is one of the biggest
56the biggest things I wanted to do as soon as I adopted Linux again. 52things I wanted to do as soon as I adopted Linux again.
57 53
58I will probably set up a dotfile repository soon, so that I don't lose 54I will probably set up a dotfile repository soon, so that I don't lose any of my
59any of my configurations, but nothing big has been configured thus far. 55configurations, but nothing big has been configured thus far.
60 56
61The two main things I have updated in i3wm are natural scrolling and 57The two main things I have updated in i3wm are natural scrolling and binding my
62binding my brightness keys to the =brightnessctl= program. 58brightness keys to the =brightnessctl= program.
63 59
641. Natural Scrolling 601. Natural Scrolling
65 61
@@ -69,8 +65,8 @@ binding my brightness keys to the =brightnessctl= program.
69 sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf 65 sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf
70 #+end_src 66 #+end_src
71 67
72 Within the =40-libinput.conf= file, find the following input sections 68 Within the =40-libinput.conf= file, find the following input sections and
73 and enable the natural scrolling option. 69 enable the natural scrolling option.
74 70
75 This is the =pointer= section: 71 This is the =pointer= section:
76 72
@@ -98,10 +94,10 @@ binding my brightness keys to the =brightnessctl= program.
98 94
992. Enabling Brightness Keys 952. Enabling Brightness Keys
100 96
101 Likewise, enabling brightness key functionality is as simple as 97 Likewise, enabling brightness key functionality is as simple as binding the
102 binding the keys to the =brightnessctl= program. 98 keys to the =brightnessctl= program.
103 99
104 To do this, open up your i3 config file. Mine is located here: 100 To do this, open up your i3 configuration file. Mine is located here:
105 101
106 #+begin_src sh 102 #+begin_src sh
107 nano /home/<my-user>/.config/i3/config 103 nano /home/<my-user>/.config/i3/config
@@ -115,24 +111,24 @@ binding my brightness keys to the =brightnessctl= program.
115 111
1163. =polybar= 1123. =polybar=
117 113
118 Instead of using the default =i3status= bar, I have opted to use 114 Instead of using the default =i3status= bar, I have opted to use =polybar=
119 =polybar= instead (as you can also see in the screenshot above). 115 instead (as you can also see in the screenshot above).
120 116
121 My config for this menu bar is basically just the default settings 117 My configuration for this menu bar is basically just the default settings
122 with modified colors and an added battery block to quickly show me 118 with modified colors and an added battery block to quickly show me the
123 the machine's battery info. 119 machine's battery info.
124 120
1254. =alacritty= 1214. =alacritty=
126 122
127 Not much to say on this part yet, as I haven't configured it much, 123 Not much to say on this part yet, as I haven't configured it much, but I
128 but I installed =alacritty= as my default terminal, and I am using 124 installed =alacritty= as my default terminal, and I am using =zsh= and the
129 =zsh= and the shell. 125 shell.
130 126
131* Software Choices 127* Software Choices
132 128
133Again, I'm not going to say much that I haven't said yet in other blog 129Again, I'm not going to say much that I haven't said yet in other blog posts, so
134posts, so I'll just do a quick rundown of the apps I installed 130I'll just do a quick rundown of the apps I installed immediately after I set up
135immediately after I set up the environment. 131the environment.
136 132
137Flatpak Apps: 133Flatpak Apps:
138 134
content/blog/2022-07-01-git-server.org +139 −156
@@ -5,56 +5,55 @@
5 5
6* My Approach to Self-Hosting Git 6* My Approach to Self-Hosting Git
7 7
8I have often tried to self-host my Git repositories, but have always 8I have often tried to self-host my Git repositories, but have always fallen
9fallen short when I tried to find a suitable web interface to show on 9short when I tried to find a suitable web interface to show on the front-end.
10the front-end.
11 10
12After a few years, I have finally found a combination of methods that 11After a few years, I have finally found a combination of methods that allow me
13allow me to easily self-host my projects, view them on the web, and 12to easily self-host my projects, view them on the web, and access them from
14access them from anywhere. 13anywhere.
15 14
16Before I dive into the details, I want to state a high-level summary of 15Before I dive into the details, I want to state a high-level summary of my
17my self-hosted Git approach: 16self-hosted Git approach:
18 17
19- This method uses the =ssh://= (read & write) and =git://= (read-only) 18- This method uses the =ssh://= (read & write) and =git://= (read-only)
20 protocols for push and pull access. 19 protocols for push and pull access.
21 - For the =git://= protocol, I create a =git-daemon-export-ok= file in 20 - For the =git://= protocol, I create a =git-daemon-export-ok= file in any
22 any repository that I want to be cloneable by anyone. 21 repository that I want to be cloneable by anyone.
23 - The web interface I am using (=cgit=) allows simple HTTP cloning by 22 - The web interface I am using (=cgit=) allows simple HTTP cloning by default.
24 default. I do not disable this setting as I want beginners to be 23 I do not disable this setting as I want beginners to be able to clone one of
25 able to clone one of my repositories even if they don't know the 24 my repositories even if they don't know the proper method.
26 proper method. 25- I am not enabling Smart HTTPS (Hypertext Transfer Protocol Secure) for any
27- I am not enabling Smart HTTPS for any repositories. Updates to 26 repositories. Updates to repositories must be pushed via SSH (Secure Shell
28 repositories must be pushed via SSH. 27 Protocol).
29- Beyond the actual repository management, I am using =cgit= for the 28- Beyond the actual repository management, I am using =cgit= for the front-end
30 front-end web interface. 29 web interface.
31 - If you use the =scan-path=<path>= configuration in the =cgitrc= 30 - If you use the =scan-path=<path>= configuration in the =cgitrc=
32 configuration file to automatically find repositories, you can't 31 configuration file to automatically find repositories, you can't exclude a
33 exclude a repository from =cgit= if it's stored within the path that 32 repository from =cgit= if it's stored within the path that =cgit= reads. To
34 =cgit= reads. To host private repositories, you'd need to set up 33 host private repositories, you'd need to set up another directory that
35 another directory that =cgit= can't read. 34 =cgit= can't read.
36 35
37* Assumptions 36* Assumptions
38 37
39For the purposes of this walkthrough, I am assuming you have a URL 38For the purposes of this walkthrough, I am assuming you have a URL
40(=git.example.com=) or IP address (=207.84.26.991=) addressed to the 39(=git.example.com=) or internet protocol (IP) address (=207.84.26.991=)
41server that you will be using to host your git repositories. 40addressed to the server that you will be using to host your git repositories.
42 41
43* Adding a Git User 42* Adding a Git User
44 43
45In order to use the SSH method associated with git, we will need to add 44In order to use the SSH method associated with Git, we will need to add a user
46a user named =git=. If you have used the SSH method for other git 45named =git=. If you have used the SSH method for other git hosting sites, you
47hosting sites, you are probably used to the following syntax: 46are probably used to the following syntax:
48 47
49#+begin_src sh 48#+begin_src sh
50git clone [user@]server:project.git 49git clone [user@]server:project.git
51#+end_src 50#+end_src
52 51
53The syntax above is an =scp=-like syntax for using SSH on the =git= user 52The syntax above is an =scp=-like syntax for using SSH on the =git= user on the
54on the server to access your repository. 53server to access your repository.
55 54
56Let's delete any remnants of an old =git= user, if any, and create the 55Let's delete any remnants of an old =git= user, if any, and create the new user
57new user account: 56account:
58 57
59#+begin_src sh 58#+begin_src sh
60sudo deluser --remove-home git 59sudo deluser --remove-home git
@@ -63,8 +62,8 @@ sudo adduser git
63 62
64** Import Your SSH Keys to the Git User 63** Import Your SSH Keys to the Git User
65 64
66Once the =git= user is created, you will need to copy your public SSH 65Once the =git= user is created, you will need to copy your public SSH key on
67key on your local development machine to the =git= user on the server. 66your local development machine to the =git= user on the server.
68 67
69If you don't have an SSH key yet, create one with this command: 68If you don't have an SSH key yet, create one with this command:
70 69
@@ -72,11 +71,10 @@ If you don't have an SSH key yet, create one with this command:
72ssh-keygen 71ssh-keygen
73#+end_src 72#+end_src
74 73
75Once you create the key pair, the public should be saved to 74Once you create the key pair, the public should be saved to =~/.ssh/id_rsa.pub=.
76=~/.ssh/id_rsa.pub=.
77 75
78If your server still has password-based authentication available, you 76If your server still has password-based authentication available, you can copy
79can copy it over to your user's home directory like this: 77it over to your user's home directory like this:
80 78
81#+begin_src sh 79#+begin_src sh
82ssh-copy-id git@server 80ssh-copy-id git@server
@@ -88,8 +86,8 @@ Otherwise, copy it over to any user that you can access.
88scp ~/.ssh/id_rsa.pub your_user@your_server: 86scp ~/.ssh/id_rsa.pub your_user@your_server:
89#+end_src 87#+end_src
90 88
91Once on the server, you will need to copy the contents into the =git= 89Once on the server, you will need to copy the contents into the =git= user's
92user's =authorized_keys= file: 90=authorized_keys= file:
93 91
94#+begin_src sh 92#+begin_src sh
95cat id_rsa.pub > /home/git/.ssh/authorized_keys 93cat id_rsa.pub > /home/git/.ssh/authorized_keys
@@ -97,16 +95,15 @@ cat id_rsa.pub > /home/git/.ssh/authorized_keys
97 95
98** (Optional) Disable Password-Based SSH 96** (Optional) Disable Password-Based SSH
99 97
100If you want to lock down your server and ensure that no one can 98If you want to lock down your server and ensure that no one can authenticate in
101authenticate in via SSH with a password, you will need to edit your SSH 99via SSH with a password, you will need to edit your SSH configuration.
102configuration.
103 100
104#+begin_src sh 101#+begin_src sh
105sudo nano /etc/ssh/sshd_config 102sudo nano /etc/ssh/sshd_config
106#+end_src 103#+end_src
107 104
108Within this file, find the following settings and set them to the values 105Within this file, find the following settings and set them to the values I am
109I am showing below: 106showing below:
110 107
111#+begin_src conf 108#+begin_src conf
112PermitRootLogin no 109PermitRootLogin no
@@ -114,18 +111,17 @@ PasswordAuthentication no
114AuthenticationMethods publickey 111AuthenticationMethods publickey
115#+end_src 112#+end_src
116 113
117You may have other Authentication Methods required in your personal 114You may have other Authentication Methods required in your personal set-up, so
118set-up, so the key here is just to ensure that =AuthenticationMethods= 115the key here is just to ensure that =AuthenticationMethods= does not allow
119does not allow passwords. 116passwords.
120 117
121*** Setting up the Base Directory 118*** Setting up the Base Directory
122 119
123Now that we have set up a =git= user to handle all transport methods, we 120Now that we have set up a =git= user to handle all transport methods, we need to
124need to set up the directory that we will be using as our base of all 121set up the directory that we will be using as our base of all repositories.
125repositories.
126 122
127In my case, I am using =/git= as my source folder. To create this folder 123In my case, I am using =/git= as my source folder. To create this folder and
128and assign it to the user we created, execute the following commands: 124assign it to the user we created, execute the following commands:
129 125
130#+begin_src sh 126#+begin_src sh
131sudo mkdir /git 127sudo mkdir /git
@@ -134,15 +130,15 @@ sudo chown -R git:git /git
134 130
135*** Creating a Test Repository 131*** Creating a Test Repository
136 132
137On your server, switch over to the =git= user in order to start managing 133On your server, switch over to the =git= user in order to start managing git
138git files. 134files.
139 135
140#+begin_src sh 136#+begin_src sh
141su git 137su git
142#+end_src 138#+end_src
143 139
144Once logged-in as the =git= user, go to your base directory and create a 140Once logged-in as the =git= user, go to your base directory and create a test
145test repository. 141repository.
146 142
147#+begin_src sh 143#+begin_src sh
148cd /git 144cd /git
@@ -150,9 +146,9 @@ mkdir test.git && cd test.git
150git init --bare 146git init --bare
151#+end_src 147#+end_src
152 148
153If you want to make this repo viewable/cloneable to the public via the 149If you want to make this repo viewable/cloneable to the public via the =git://=
154=git://= protocol, you need to create a =git-daemon-export-ok= file 150protocol, you need to create a =git-daemon-export-ok= file inside the
155inside the repository. 151repository.
156 152
157#+begin_src sh 153#+begin_src sh
158touch git-daemon-export-ok 154touch git-daemon-export-ok
@@ -160,34 +156,33 @@ touch git-daemon-export-ok
160 156
161* Change the Login Shell for =git= 157* Change the Login Shell for =git=
162 158
163To make sure that the =git= user is only used for git operations and 159To make sure that the =git= user is only used for git operations and nothing
164nothing else, you need to change the user's login shell. To do this, 160else, you need to change the user's login shell. To do this, simply use the
165simply use the =chsh= command: 161=chsh= command:
166 162
167#+begin_src sh 163#+begin_src sh
168sudo chsh git 164sudo chsh git
169#+end_src 165#+end_src
170 166
171The interactive prompt will ask which shell you want the =git= user to 167The interactive prompt will ask which shell you want the =git= user to use. You
172use. You must use the following value: 168must use the following value:
173 169
174#+begin_src sh 170#+begin_src sh
175/usr/bin/git-shell 171/usr/bin/git-shell
176#+end_src 172#+end_src
177 173
178Once done, no one will be able to SSH to the =git= user or execute 174Once done, no one will be able to SSH to the =git= user or execute commands
179commands other than the standard git commands. 175other than the standard git commands.
180 176
181* Opening the Firewall 177* Opening the Firewall
182 178
183Don't forget to open up ports on the device firewall and network 179Don't forget to open up ports on the device firewall and network firewall if you
184firewall if you want to access these repositories publicly. If you're 180want to access these repositories publicly. If you're using default ports,
185using default ports, forward ports =22= (ssh) and =9418= (git) from your 181forward ports =22= (ssh) and =9418= (git) from your router to your server's IP
186router to your server's IP address. 182address.
187 183
188If your server also has a firewall, ensure that the firewall allows the 184If your server also has a firewall, ensure that the firewall allows the same
189same ports that are forwarded from the router. For example, if you use 185ports that are forwarded from the router. For example, if you use =ufw=:
190=ufw=:
191 186
192#+begin_src sh 187#+begin_src sh
193sudo ufw allow 22 188sudo ufw allow 22
@@ -196,12 +191,12 @@ sudo ufw allow 9418
196 191
197** Non-Standard SSH Ports 192** Non-Standard SSH Ports
198 193
199If you use a non-standard port for SSH, such as =9876=, you will need to 194If you use a non-standard port for SSH, such as =9876=, you will need to create
200create an SSH configuration file on your local development machine in 195an SSH configuration file on your local development machine in order to connect
201order to connect to your server's git repositories. 196to your server's git repositories.
202 197
203To do this, you'll need to define your custom port on your client 198To do this, you'll need to define your custom port on your client machine in
204machine in your =~/.ssh/config= file: 199your =~/.ssh/config= file:
205 200
206#+begin_src sh 201#+begin_src sh
207nano ~/.ssh/config 202nano ~/.ssh/config
@@ -222,8 +217,8 @@ There are two main syntaxes you can use to manage git over SSH:
222- =git clone [user@]server:project.git= 217- =git clone [user@]server:project.git=
223- =git clone ssh://[user@]server/project.git= 218- =git clone ssh://[user@]server/project.git=
224 219
225I prefer the first, which is an =scp=-like syntax. To test it, try to 220I prefer the first, which is an =scp=-like syntax. To test it, try to clone the
226clone the test repository you set up on the server: 221test repository you set up on the server:
227 222
228#+begin_src sh 223#+begin_src sh
229git clone git@git.example.com:/git/test.git 224git clone git@git.example.com:/git/test.git
@@ -231,9 +226,8 @@ git clone git@git.example.com:/git/test.git
231 226
232* Enabling Read-Only Access 227* Enabling Read-Only Access
233 228
234If you want people to be able to clone any repository where you've 229If you want people to be able to clone any repository where you've placed a
235placed a =git-daemon-export-ok= file, you will need to start the git 230=git-daemon-export-ok= file, you will need to start the git daemon.
236daemon.
237 231
238To do this on a system with =systemd=, create a service file: 232To do this on a system with =systemd=, create a service file:
239 233
@@ -271,8 +265,7 @@ sudo systemctl enable git-daemon.service
271sudo systemctl start git-daemon.service 265sudo systemctl start git-daemon.service
272#+end_src 266#+end_src
273 267
274To clone read-only via the =git://= protocol, you can use the following 268To clone read-only via the =git://= protocol, you can use the following syntax:
275syntax:
276 269
277#+begin_src sh 270#+begin_src sh
278git clone git://git.example.com/test.git 271git clone git://git.example.com/test.git
@@ -283,9 +276,9 @@ git clone git://git.example.com/test.git
283At this point, we have a working git server that works with both SSH and 276At this point, we have a working git server that works with both SSH and
284read-only access. 277read-only access.
285 278
286For each of the repositories I had hosted a different provider, I 279For each of the repositories I had hosted a different provider, I executed the
287executed the following commands in order to place a copy on my server as 280following commands in order to place a copy on my server as my new source of
288my new source of truth: 281truth:
289 282
290Server: 283Server:
291 284
@@ -308,20 +301,20 @@ git push
308 301
309* Optional Web View: =cgit= 302* Optional Web View: =cgit=
310 303
311If you want a web viewer for your repositories, you can use various 304If you want a web viewer for your repositories, you can use various tools, such
312tools, such as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its 305as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its simple interface and
313simple interface and fairly easy set-up (compared to others). Not to 306fairly easy set-up (compared to others). Not to mention that the [[https://git.kernel.org/][Linux kernel
314mention that the [[https://git.kernel.org/][Linux kernel uses =cgit=]]. 307uses =cgit=]].
315 308
316** Docker Compose 309** Docker Compose
317 310
318Instead of using my previous method of using a =docker run= command, 311Instead of using my previous method of using a =docker run= command, I've
319I've updated this section to use =docker-compose= instead for an easier 312updated this section to use =docker-compose= instead for an easier installation
320installation and simpler management and configuration. 313and simpler management and configuration.
321 314
322In order to use Docker Compose, you will set up a =docker-compose.yml= 315In order to use Docker Compose, you will set up a =docker-compose.yml= file to
323file to automatically connect resources like the repositories, =cgitrc=, 316automatically connect resources like the repositories, =cgitrc=, and various
324and various files or folders to the =cgit= container you're creating: 317files or folders to the =cgit= container you're creating:
325 318
326#+begin_src sh 319#+begin_src sh
327mkdir ~/cgit && cd ~/cgit 320mkdir ~/cgit && cd ~/cgit
@@ -352,16 +345,16 @@ Then, just start the container:
352sudo docker-compose up -d 345sudo docker-compose up -d
353#+end_src 346#+end_src
354 347
355Once it's finished installing, you can access the site at 348Once it's finished installing, you can access the site at =<SERVER_IP>:8763= or
356=<SERVER_IP>:8763= or use a reverse-proxy service to forward =cgit= to a 349use a reverse-proxy service to forward =cgit= to a URL, such as
357URL, such as =git.example.com=. See the next section for more details on 350=git.example.com=. See the next section for more details on reverse proxying a
358reverse proxying a URL to a local port. 351URL to a local port.
359 352
360** Nginx Reverse Proxy 353** Nginx Reverse Proxy
361 354
362I am using Nginx as my reverse proxy so that the =cgit= Docker container 355I am using Nginx as my reverse proxy so that the =cgit= Docker container can use
363can use =git.example.com= as its URL. To do so, I simply created the 356=git.example.com= as its uniform resource locator (URL). To do so, I simply
364following configuration file: 357created the following configuration file:
365 358
366#+begin_src sh 359#+begin_src sh
367sudo nano /etc/nginx/sites-available/git.example.com 360sudo nano /etc/nginx/sites-available/git.example.com
@@ -410,29 +403,26 @@ sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/
410sudo systemctl restart nginx.service 403sudo systemctl restart nginx.service
411#+end_src 404#+end_src
412 405
413As we can see below, my site at =git.example.com= is available and 406As we can see below, my site at =git.example.com= is available and running:
414running:
415 407
416** Settings Up Git Details 408** Settings Up Git Details
417 409
418Once you have =cgit= running, you can add some small details, such as 410Once you have =cgit= running, you can add some small details, such as repository
419repository owners and descriptions by editing the following files within 411owners and descriptions by editing the following files within each repository.
420each repository.
421 412
422Alternatively, you can use the =cgitrc= file to edit these details if 413Alternatively, you can use the =cgitrc= file to edit these details if you only
423you only care to edit them for the purpose of seeing them on your 414care to edit them for the purpose of seeing them on your website.
424website.
425 415
426The =description= file within the repository on your server will display 416The =description= file within the repository on your server will display the
427the description online. 417description online.
428 418
429#+begin_src sh 419#+begin_src sh
430cd /git/example.git 420cd /git/example.git
431nano description 421nano description
432#+end_src 422#+end_src
433 423
434You can add a =[gitweb]= block to the =config= file in order to display 424You can add a =[gitweb]= block to the =config= file in order to display the
435the owner of the repository. 425owner of the repository.
436 426
437#+begin_src sh 427#+begin_src sh
438cd /git/example.git 428cd /git/example.git
@@ -444,22 +434,20 @@ nano config
444 owner = "YourName" 434 owner = "YourName"
445#+end_src 435#+end_src
446 436
447Note that you can ignore the configuration within each repository and 437Note that you can ignore the configuration within each repository and simply set
448simply set up this information in the =cgitrc= file, if you want to do 438up this information in the =cgitrc= file, if you want to do it that way.
449it that way.
450 439
451** Editing =cgit= 440** Editing =cgit=
452 441
453In order to edit certain items within =cgit=, you need to edit the 442In order to edit certain items within =cgit=, you need to edit the =cgitrc=
454=cgitrc= file. 443file.
455 444
456#+begin_src sh 445#+begin_src sh
457nano ~/cgit/cgitrc 446nano ~/cgit/cgitrc
458#+end_src 447#+end_src
459 448
460Below is an example configuration for =cgitrc=. You can find all the 449Below is an example configuration for =cgitrc=. You can find all the
461configuration options within the [configuration manual] 450configuration options within the [[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt][configuration manual]].
462([[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt]]).
463 451
464#+begin_src conf 452#+begin_src conf
465css=/cgit.css 453css=/cgit.css
@@ -537,15 +525,14 @@ repo.desc=An example repository!
537 525
538** Final Fixes: Syntax Highlighting & README Rendering 526** Final Fixes: Syntax Highlighting & README Rendering
539 527
540After completing my initial install and playing around with it for a few 528After completing my initial install and playing around with it for a few days, I
541days, I noticed two issues: 529noticed two issues:
542 530
5431. Syntax highlighting did not work when viewing the source code within 5311. Syntax highlighting did not work when viewing the source code within a file.
544 a file.
5452. The =about= tab within a repository was not rendered to HTML. 5322. The =about= tab within a repository was not rendered to HTML.
546 533
547The following process fixes these issues. To start, let's go to the 534The following process fixes these issues. To start, let's go to the =cgit=
548=cgit= directory where we were editing our configuration file earlier. 535directory where we were editing our configuration file earlier.
549 536
550#+begin_src sh 537#+begin_src sh
551cd ~/cgit 538cd ~/cgit
@@ -575,14 +562,12 @@ curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html
575chmod 755 md2html 562chmod 755 md2html
576#+end_src 563#+end_src
577 564
578If you need other filters or html-converters found within 565If you need other filters or html-converters found within [[https://git.zx2c4.com/cgit/tree/filters][the cgit project
579[[https://git.zx2c4.com/cgit/tree/filters][the cgit project files]], 566files]], repeat the =curl= and =chmod= process above for whichever files you need.
580repeat the =curl= and =chmod= process above for whichever files you
581need.
582 567
583However, formatting will not work quite yet since the Docker cgit 568However, formatting will not work quite yet since the Docker cgit container
584container we're using doesn't have the formatting package installed. You 569we're using doesn't have the formatting package installed. You can install this
585can install this easily by install Python 3+ and the =pygments= package: 570easily by install Python 3+ and the =pygments= package:
586 571
587#+begin_src sh 572#+begin_src sh
588# Enter the container's command line 573# Enter the container's command line
@@ -601,8 +586,8 @@ exit
601*You will need to enter the cgit docker container and re-run these =yum= 586*You will need to enter the cgit docker container and re-run these =yum=
602commands every time you kill and restart the container!* 587commands every time you kill and restart the container!*
603 588
604If not done already, we need to add the following variables to our 589If not done already, we need to add the following variables to our =cgitrc= file
605=cgitrc= file in order for =cgit= to know where our filtering files are: 590in order for =cgit= to know where our filtering files are:
606 591
607#+begin_src conf 592#+begin_src conf
608# Highlight source code with python pygments-based highlighter 593# Highlight source code with python pygments-based highlighter
@@ -613,26 +598,24 @@ source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
613about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh 598about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
614#+end_src 599#+end_src
615 600
616Now you should see that syntax highlighting and README rendering to the 601Now you should see that syntax highlighting and README rendering to the =about=
617=about= tab is fixed. 602tab is fixed.
618 603
619** Theming 604** Theming
620 605
621I won't go into much detail in this section, but you can fully theme 606I won't go into much detail in this section, but you can fully theme your
622your installation of =cgit= since you have access to the =cgit.css= file 607installation of =cgit= since you have access to the =cgit.css= file in your web
623in your web root. This is another file you can add as a volume to the 608root. This is another file you can add as a volume to the =docker-compose.yml=
624=docker-compose.yml= file if you want to edit this without entering the 609file if you want to edit this without entering the container's command line.
625container's command line.
626 610
627*** :warning: Remember to Back Up Your Data! 611*** Remember to Back Up Your Data!
628 612
629The last thing to note is that running services on your own equipment 613The last thing to note is that running services on your own equipment means that
630means that you're assuming a level of risk that exists regarding data 614you're assuming a level of risk that exists regarding data loss, catastrophes,
631loss, catastrophes, etc. In order to reduce the impact of any such 615etc. In order to reduce the impact of any such occurrence, I suggest backing up
632occurrence, I suggest backing up your data regularly. 616your data regularly.
633 617
634Backups can be automated via =cron=, by hooking your base directory up 618Backups can be automated via =cron=, by hooking your base directory up to a
635to a cloud provider, or even setting up hooks to push all repository 619cloud provider, or even setting up hooks to push all repository info to git
636info to git mirrors on other git hosts. Whatever the method, make sure 620mirrors on other git hosts. Whatever the method, make sure that your data
637that your data doesn't vanish in the event that your drives or servers 621doesn't vanish in the event that your drives or servers fail.
638fail.
content/blog/2022-07-14-gnupg.org +111 −127
@@ -5,33 +5,30 @@
5 5
6* The History of GPG 6* The History of GPG
7 7
8[[https://gnupg.org/][GNU Privacy Guard]], also known as GnuPG and GPG, 8[[https://gnupg.org/][GNU Privacy Guard]], also known as GnuPG and GPG, is a free ("free" as in both
9is a free ("free" as in both speech and beer) software that fully 9speech and beer) software that fully implements the OpenPGP Message Format
10implements the OpenPGP Message Format documented in 10documented in [[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]].
11[[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]]. 11
12 12I won't go in-depth on the full history of the software in this post, but it is
13I won't go in-depth on the full history of the software in this post, 13important to understand that GPG is not the same as PGP (Pretty Good Privacy),
14but it is important to understand that GPG is not the same as PGP 14which is a different implementation of RFC 4880. However, GPG was designed to
15(Pretty Good Privacy), which is a different implementation of RFC 4880. 15interoperate with PGP.
16However, GPG was designed to interoperate with PGP. 16
17 17GPG was originally developed in the late 1990s by [[https://en.wikipedia.org/wiki/Werner_Koch][Werner Koch]] and has
18GPG was originally developed in the late 1990s by
19[[https://en.wikipedia.org/wiki/Werner_Koch][Werner Koch]] and has
20historically been funded generously by the German government. 18historically been funded generously by the German government.
21 19
22Now that we have all the high-level info out of the way, let's dive into 20Now that we have all the high-level info out of the way, let's dive into the
23the different aspects of GPG and its uses. 21different aspects of GPG and its uses.
24 22
25* Encryption Algorithms 23* Encryption Algorithms
26 24
27GPG supports a wide range of different encryption algorithms, including 25GPG supports a wide range of different encryption algorithms, including
28public-key, cipher, hash, and compression algorithms. The support for 26public-key, cipher, hash, and compression algorithms. The support for these
29these algorithms has grown since the adoption of the Libgcrypt library 27algorithms has grown since the adoption of the Libgcrypt library in the 2.x
30in the 2.x versions of GPG. 28versions of GPG.
31 29
32As you will be able to see below in an example of a full key generation 30As you will be able to see below in an example of a full key generation with the
33with the GPG command line tool, GPG recommends the following algorithms 31GPG command line tool, GPG recommends the following algorithms to new users:
34to new users:
35 32
36#+begin_src sh 33#+begin_src sh
37Please select what kind of key you want: 34Please select what kind of key you want:
@@ -43,46 +40,39 @@ Please select what kind of key you want:
43 (10) ECC (sign only) 40 (10) ECC (sign only)
44#+end_src 41#+end_src
45 42
46I am not doing an in-depth explanation here in order to keep the focus 43I am not doing an in-depth explanation here in order to keep the focus on GPG
47on GPG and not encryption algorithms. If you want a deep dive into 44and not encryption algorithms. If you want a deep dive into cryptography or
48cryptography or encryption algorithms, please read my other posts: 45encryption algorithms, please read my other posts:
49 46
50- [[../aes-encryption/][AES Encryption]] (2018) 47- [[https://cleberg.net/blog/aes-encryption.html][How AES Encryption Works]] (2018)
51- [[../cryptography-basics/][Cryptography Basics]] (2020) 48- [[https://cleberg.net/blog/cryptography.html][A Practical Guide to Encryption, Keys, and Secure Communication]] (2020)
52 49
53** Vulnerabilities 50** Vulnerabilities
54 51
55As of 2022-07-14, there are a few different vulnerabilities associated 52As of 2022-07-14, there are a few different vulnerabilities associated with GPG
56with GPG or the libraries it uses: 53or the libraries it uses:
57 54
58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one 55- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one (GPG-generated)
59 (GPG-generated) ElGamal signature of an arbitrary message is released, 56 ElGamal signature of an arbitrary message is released, one can recover the
60 one can recover the signer's private key in less than a second on a 57 signer's private key in less than a second on a PC." ([[https://www.di.ens.fr/~pnguyen/pub_Ng04.htm][Source]])
61 PC." ([[https://www.di.ens.fr/~pnguyen/pub_Ng04.htm][Source]]) 58- GPG versions prior to 1.4.2.1 contain a false positive signature verification
62- GPG versions prior to 1.4.2.1 contain a false positive signature 59 bug. ([[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000211.html][Source]])
63 verification bug. 60- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned data. (
64 ([[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000211.html][Source]])
65- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned
66 data. (
67 [[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html][Source]]) 61 [[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html][Source]])
68- Libgcrypt, a library used by GPG, contained a bug which enabled full 62- Libgcrypt, a library used by GPG, contained a bug which enabled full key
69 key recovery for RSA-1024 and some RSA-2048 keys. This was resolved in 63 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG
70 a GPG update in 2017. ([[https://lwn.net/Articles/727179/][Source]]) 64 update in 2017. ([[https://lwn.net/Articles/727179/][Source]])
71- The [[https://en.wikipedia.org/wiki/ROCA_vulnerability][ROCA 65- The [[https://en.wikipedia.org/wiki/ROCA_vulnerability][ROCA Vulnerability]] affects RSA keys generated by YubiKey 4 tokens.
72 Vulnerability]] affects RSA keys generated by YubiKey 4 tokens.
73 ([[https://crocs.fi.muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf][Source]]) 66 ([[https://crocs.fi.muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf][Source]])
74- The [[https://en.wikipedia.org/wiki/SigSpoof][SigSpoof Attack]] allows 67- The [[https://en.wikipedia.org/wiki/SigSpoof][SigSpoof Attack]] allows an attacker to spoof digital signatures. ([[https://arstechnica.com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/][Source]])
75 an attacker to spoof digital signatures. 68- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow,
76 ([[https://arstechnica.com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/][Source]]) 69 fixed in Libgcrypt 1.9.1 ([[https://web.archive.org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/][Source]])
77- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer
78 overflow, fixed in Libgcrypt 1.9.1
79 ([[https://web.archive.org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/][Source]])
80 70
81*** Platforms 71*** Platforms
82 72
83Originally developed as a command-line program for *nix systems, GPG now 73Originally developed as a command-line program for *nix systems, GPG now has a
84has a wealth of front-end applications and libraries available for 74wealth of front-end applications and libraries available for end-users. However,
85end-users. However, the most recommended programs remain the same: 75the most recommended programs remain the same:
86 76
87- [[https://gnupg.org][GnuPG]] for Linux (depending on distro) 77- [[https://gnupg.org][GnuPG]] for Linux (depending on distro)
88- [[https://gpg4win.org][Gpg4win]] for Windows 78- [[https://gpg4win.org][Gpg4win]] for Windows
@@ -90,27 +80,25 @@ end-users. However, the most recommended programs remain the same:
90 80
91* Creating a Key Pair 81* Creating a Key Pair
92 82
93In order to create a GPG key pair, a user would first need to install 83In order to create a GPG key pair, a user would first need to install GPG on
94GPG on their system. If we're assuming that the user is on Fedora Linux, 84their system. If we're assuming that the user is on Fedora Linux, they would
95they would execute the following: 85execute the following:
96 86
97#+begin_src sh 87#+begin_src sh
98sudo dnf install gpg 88sudo dnf install gpg
99#+end_src 89#+end_src
100 90
101Once installed, a user can create a new key pair with the following 91Once installed, a user can create a new key pair with the following command(s):
102command(s):
103 92
104#+begin_src sh 93#+begin_src sh
105gpg --full-generate-key 94gpg --full-generate-key
106#+end_src 95#+end_src
107 96
108GPG will walk the user through an interactive setup that asks for an 97GPG will walk the user through an interactive setup that asks for an algorithm
109algorithm preference, expiration date, name, and email to associate with 98preference, expiration date, name, and email to associate with this key.
110this key.
111 99
112See the following example key set-up for a default key generation using 100See the following example key set-up for a default key generation using the
113the GnuPG command-line interface: 101GnuPG command-line interface:
114 102
115#+begin_src sh 103#+begin_src sh
116gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc. 104gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc.
@@ -166,12 +154,13 @@ uid John Doe (test key) <johndoe@example.com>
166sub cv25519 2022-07-14 [E] 154sub cv25519 2022-07-14 [E]
167#+end_src 155#+end_src
168 156
169Please note that GUI apps may differ slightly from the GPG command-line 157Please note that graphical apps may differ slightly from the GPG command-line
170interface. 158interface.
171 159
172* Common Usage 160* Common Usage
173 161
174As noted in RFC 4880, the general functions of OpenPGP are as follows: 162As noted in RFC (Request for Comments) 4880, the general functions of OpenPGP
163are as follows:
175 164
176- digital signatures 165- digital signatures
177- encryption 166- encryption
@@ -179,59 +168,57 @@ As noted in RFC 4880, the general functions of OpenPGP are as follows:
179- Radix-64 conversion 168- Radix-64 conversion
180- key management and certificate services 169- key management and certificate services
181 170
182From this, you can probably gather that the main use of GPG is for 171From this, you can probably gather that the main use of GPG is for encrypting
183encrypting data and/or signing the data with a key. The purpose of 172data and/or signing the data with a key. The purpose of encrypting data with GPG
184encrypting data with GPG is to ensure that no one except the intended 173is to ensure that no one except the intended recipient(s) can access the data.
185recipient(s) can access the data.
186 174
187Let's explore some specific GPG use-cases. 175Let's explore some specific GPG use-cases.
188 176
189** Email 177** Email
190 178
191One of the more popular uses of GPG is to sign and/or encrypt emails. 179One of the more popular uses of GPG is to sign and/or encrypt emails. With the
192With the use of a GPG keypair, you can encrypt a message, its subject, 180use of a GPG keypair, you can encrypt a message, its subject, and even the
193and even the attachments within. 181attachments within.
194 182
195The first process, regarding the signing of a message without any 183The first process, regarding the signing of a message without any encryption, is
196encryption, is generally used to provide assurance that an email is 184generally used to provide assurance that an email is truly coming from the
197truly coming from the sender that the message claims. When I send an 185sender that the message claims. When I send an email, and it's signed with my
198email, and it's signed with my public key, the recipient(s) of the 186public key, the recipient(s) of the message can verify that the message was
199message can verify that the message was signed with my personal key. 187signed with my personal key.
200 188
201The second process, regarding the actual encryption of the message and 189The second process, regarding the actual encryption of the message and its
202its contents, works by using a combination of the sender's keys and the 190contents, works by using a combination of the sender's keys and the recipient's
203recipient's keys. This process may vary slightly by implementation, but 191keys. This process may vary slightly by implementation, but it most commonly
204it most commonly uses asymmetric cryptography, also known as public-key 192uses asymmetric cryptography, also known as public-key cryptography. In this
205cryptography. In this version of encryption, the sender's private key to 193version of encryption, the sender's private key to sign the message and a
206sign the message and a combination of the sender's keys and the 194combination of the sender's keys and the recipient's public key to encrypt the
207recipient's public key to encrypt the message. 195message.
208 196
209If two people each have their own private keys and exchange their public 197If two people each have their own private keys and exchange their public keys,
210keys, they can send encrypted messages back and forth with GPG. This is 198they can send encrypted messages back and forth with GPG. This is also possible
211also possible with symmetric cryptography, but the process differs since 199with symmetric cryptography, but the process differs since there are no key
212there are no key pairs. 200pairs.
213 201
214Implementation of email encryption varies greatly between email clients, 202Implementation of email encryption varies greatly between email clients, so you
215so you will need to reference your email client's documentation to 203will need to reference your email client's documentation to ensure you are
216ensure you are setting it up correctly for that specific client. 204setting it up correctly for that specific client.
217 205
218** File Encryption 206** File Encryption
219 207
220As noted in the section above regarding emails, GPG enables users to be 208As noted in the section above regarding emails, GPG enables users to be able to
221able to send a message to each other if they are both set-up with GPG 209send a message to each other if they are both set-up with GPG keys. In this
222keys. In this example, I am going to show how a user could send a file 210example, I am going to show how a user could send a file called
223called =example_file.txt= to another user via the recipient's email. 211=example_file.txt= to another user via the recipient's email.
224 212
225The sender would find the file they want to send and execute the 213The sender would find the file they want to send and execute the following
226following command: 214command:
227 215
228#+begin_src sh 216#+begin_src sh
229gpg --encrypt --output example_file.txt.gpg --recipient \ 217gpg --encrypt --output example_file.txt.gpg --recipient \
230recipient@example.com example_file.txt 218recipient@example.com example_file.txt
231#+end_src 219#+end_src
232 220
233Once received, the recipient can decrypt the file with the following 221Once received, the recipient can decrypt the file with the following command:
234command:
235 222
236#+begin_src sh 223#+begin_src sh
237gpg --decrypt --output example_file.txt example_file.txt.gpg 224gpg --decrypt --output example_file.txt example_file.txt.gpg
@@ -239,29 +226,28 @@ gpg --decrypt --output example_file.txt example_file.txt.gpg
239 226
240** Ownership Signatures 227** Ownership Signatures
241 228
242One important aspect of GPG, especially for developers, is the ability 229One important aspect of GPG, especially for developers, is the ability to sign
243to sign data without encrypting it. For example, developers often sign 230data without encrypting it. For example, developers often sign code changes when
244code changes when they commit the changes back to a central repository, 231they commit the changes back to a central repository, in order to display
245in order to display ownership of who made the changes. This allows other 232ownership of who made the changes. This allows other users to look at a code
246users to look at a code change and determine that the change was valid. 233change and determine that the change was valid.
247 234
248In order to do this using [[https://git-scm.com][Git]], the developer 235In order to do this using [[https://git-scm.com][Git]], the developer simply needs to alter the =git
249simply needs to alter the =git commit= command to include the =-S= flag. 236commit= command to include the =-S= flag. Here's an example:
250Here's an example:
251 237
252#+begin_src sh 238#+begin_src sh
253git commit -S -m "my commit message" 239git commit -S -m "my commit message"
254#+end_src 240#+end_src
255 241
256As an expansion of the example above, Git users can configure their 242As an expansion of the example above, Git users can configure their environment
257environment with a default key to use by adding their GPG signature: 243with a default key to use by adding their GPG signature:
258 244
259#+begin_src sh 245#+begin_src sh
260git config --global user.signingkey XXXXXXXXXXXXXXXX 246git config --global user.signingkey XXXXXXXXXXXXXXXX
261#+end_src 247#+end_src
262 248
263If you're not sure what your signature is, you can find it titled =sig= 249If you're not sure what your signature is, you can find it titled =sig= in the
264in the output of this command: 250output of this command:
265 251
266#+begin_src sh 252#+begin_src sh
267gpg --list-signatures 253gpg --list-signatures
@@ -269,12 +255,11 @@ gpg --list-signatures
269 255
270** File Integrity 256** File Integrity
271 257
272When a person generates a signature for data, they are allowing users 258When a person generates a signature for data, they are allowing users the
273the ability to verify the signature on that data in the future to ensure 259ability to verify the signature on that data in the future to ensure the data
274the data has not been corrupted. This is most common with software 260has not been corrupted. This is most common with software applications hosted on
275applications hosted on the internet - developers provide signatures so 261the internet - developers provide signatures so that users can verify a website
276that users can verify a website was not hijacked and download links 262was not hijacked and download links replaced with dangerous software.
277replaced with dangerous software.
278 263
279In order to verify signed data, a user needs to have: 264In order to verify signed data, a user needs to have:
280 265
@@ -282,9 +267,8 @@ In order to verify signed data, a user needs to have:
2822. A signature file 2672. A signature file
2833. The public GPG key of the signer 2683. The public GPG key of the signer
284 269
285Once the signer's public key is imported on the user's system, and they 270Once the signer's public key is imported on the user's system, and they have the
286have the data and signature, they can verify the data with the following 271data and signature, they can verify the data with the following commands:
287commands:
288 272
289#+begin_src sh 273#+begin_src sh
290# If the signature is attached to the data 274# If the signature is attached to the data
@@ -296,11 +280,11 @@ gpg --verify [signature-file] [original-file]
296 280
297*** Finding Public Keys 281*** Finding Public Keys
298 282
299In order to use GPG with others, a user needs to know the other user(s) 283In order to use GPG with others, a user needs to know the other user(s) keys.
300keys. This is easy to do if the user knows the other user(s) in person, 284This is easy to do if the user knows the other user(s) in person, but may be
301but may be hard if the relationship is strictly digital. Luckily, there 285hard if the relationship is strictly digital. Luckily, there are a few options.
302are a few options. The first option is to look at a user's web page or 286The first option is to look at a user's web page or social pages if they have
303social pages if they have them. 287them.
304 288
305Otherwise, the best option is to use a keyserver, such as: 289Otherwise, the best option is to use a keyserver, such as:
306 290
content/blog/2022-07-25-curseradio.org +24 −28
@@ -6,28 +6,25 @@
6* Overview 6* Overview
7 7
8While exploring some interesting Linux applications, I stumbled across 8While exploring some interesting Linux applications, I stumbled across
9[[https://github.com/chronitis/curseradio][curseradio]], a command-line 9[[https://github.com/chronitis/curseradio][curseradio]], a command-line radio player based on Python.
10radio player based on Python.
11 10
12This application is fantastic and incredibly easy to install, so I 11This application is fantastic and incredibly easy to install, so I wanted to
13wanted to dedicate a post today to this app. Let's look at the features 12dedicate a post today to this app. Let's look at the features within the app and
14within the app and then walk through the installation process I took to 13then walk through the installation process I took to get =curseradio= working.
15get =curseradio= working.
16 14
17* Features 15* Features
18 16
19The radio player itself is quite minimal. As you can see in the 17The radio player itself is quite minimal. As you can see in the screenshot
20screenshot above, it contains a simple plaintext list of all available 18above, it contains a simple plaintext list of all available categories, which
21categories, which can be broken down further and further. In addition, 19can be broken down further and further. In addition, radio shows are available
22radio shows are available for listening, alongside regular radio 20for listening, alongside regular radio stations.
23stations.
24 21
25For example, the =Sports= > =Pro Basketball= > =Shows= category contains 22For example, the =Sports= > =Pro Basketball= > =Shows= category contains a
26a number of specific shows related to Professional Basketball. 23number of specific shows related to Professional Basketball.
27 24
28Aside from being able to play any of the listed stations/shows, you can 25Aside from being able to play any of the listed stations/shows, you can make a
29make a channel your favorite by pressing =f=. It will now show up at the 26channel your favorite by pressing =f=. It will now show up at the top of the
30top of the radio player in the =Favourites= category. 27radio player in the =Favourites= category.
31 28
32** Commands/Shortcuts 29** Commands/Shortcuts
33 30
@@ -45,11 +42,10 @@ top of the radio player in the =Favourites= category.
45 42
46** Dependencies 43** Dependencies
47 44
48Before installing =curseradio=, a handful of system and Python packages 45Before installing =curseradio=, a handful of system and Python packages are
49are required. To get started, install =python3=, =pip3=, and =mpv= on 46required. To get started, install =python3=, =pip3=, and =mpv= on your system.
50your system. In this example, I'm using Fedora Linux, which uses the 47In this example, I'm using Fedora Linux, which uses the =dnf= package manager.
51=dnf= package manager. You may need to adjust this if you're using a 48You may need to adjust this if you're using a different system.
52different system.
53 49
54#+begin_src sh 50#+begin_src sh
55sudo dnf install python3 pip3 mpv 51sudo dnf install python3 pip3 mpv
@@ -63,23 +59,23 @@ pip3 install requests xdg lxml
63 59
64** Repository Source Installation 60** Repository Source Installation
65 61
66Once all the dependencies are installed, we can clone the source code 62Once all the dependencies are installed, we can clone the source code and enter
67and enter that directory: 63that directory:
68 64
69#+begin_src sh 65#+begin_src sh
70git clone https://github.com/chronitis/curseradio && cd curseradio 66git clone https://github.com/chronitis/curseradio && cd curseradio
71#+end_src 67#+end_src
72 68
73Once you're within the =curseradio= directory, you can install the 69Once you're within the =curseradio= directory, you can install the application
74application with the provided =setup.py= script. 70with the provided =setup.py= script.
75 71
76#+begin_src sh 72#+begin_src sh
77sudo python3 setup.py install 73sudo python3 setup.py install
78#+end_src 74#+end_src
79 75
80In my case, I ran into a few errors and needed to create the folders 76In my case, I ran into a few errors and needed to create the folders that
81that curseradio wanted to use for its installation. If you don't get any 77curseradio wanted to use for its installation. If you don't get any errors, you
82errors, you can skip this and run the app. 78can skip this and run the app.
83 79
84#+begin_src sh 80#+begin_src sh
85sudo mkdir /usr/local/lib/python3.10/ 81sudo mkdir /usr/local/lib/python3.10/
content/blog/2022-07-30-flac-to-opus.org +35 −38
@@ -6,17 +6,15 @@
6* Converting FLAC to OPUS 6* Converting FLAC to OPUS
7 7
8I am currently rebuilding my music library from scratch so that I can 8I am currently rebuilding my music library from scratch so that I can
9effectively archive all the music I own in the 9effectively archive all the music I own in [[https://wikipedia.org/wiki/FLAC][FLAC]] (Free Lossless Audio Codec)
10[[https://en.wikipedia.org/wiki/FLAC][FLAC file format]], a lossless 10files.
11audio codec.
12 11
13However, streaming FLAC files outside the home can be difficult due to 12However, streaming FLAC files outside the home can be difficult due to the size
14the size of the files, especially if you're using a weak connection. 13of the files, especially if you're using a weak connection.
15 14
16So, in order to archive the music in a lossless format and still be able 15So, in order to archive the music in a lossless format and still be able to
17to stream it easily, I opted to create a copy of my FLAC files in the 16stream it easily, I opted to create a copy of my FLAC files in the [[https://en.wikipedia.org/wiki/Opus_(audio_format)][Opus audio
18[[https://en.wikipedia.org/wiki/Opus_(audio_format)][Opus audio codec]]. 17codec]]. This allows me to archive a quality, lossless version of the music and
19This allows me to archive a quality, lossless version of the music and
20then point my streaming service to the smaller, stream-ready version. 18then point my streaming service to the smaller, stream-ready version.
21 19
22** Dependencies 20** Dependencies
@@ -28,39 +26,38 @@ proceeding, install the package:
28sudo apt install opus-tools 26sudo apt install opus-tools
29#+end_src 27#+end_src
30 28
31If you want to use a different conversion method, such as =ffmpeg= or 29If you want to use a different conversion method, such as =ffmpeg= or =avconv=,
32=avconv=, simply install that package instead. 30simply install that package instead.
33 31
34** Conversion Process 32** Conversion Process
35 33
36The script I'm using is stored in my home directory, but feel free to 34The script I'm using is stored in my home directory, but feel free to create it
37create it wherever you want. It does not need to be in the same 35wherever you want. It does not need to be in the same directory as your music
38directory as your music files. 36files.
39 37
40#+begin_src sh 38#+begin_src sh
41cd ~ && nano transform.sh 39cd ~ && nano transform.sh
42#+end_src 40#+end_src
43 41
44Once you have your new bash script opened in an editor, go ahead and 42Once you have your new bash script opened in an editor, go ahead and paste the
45paste the following logic into the script. 43following logic into the script.
46 44
47You *MUST* edit the following variables in order for it to work: 45You *MUST* edit the following variables in order for it to work:
48 46
49- =source=: The source directory where your FLAC files are stored. 47- =source=: The source directory where your FLAC files are stored.
50- =dest=: The destination directory where you want the resulting Opus 48- =dest=: The destination directory where you want the resulting Opus files to
51 files to be stored. 49 be stored.
52 50
53You *MAY* want to edit the following variables to suit your needs: 51You *MAY* want to edit the following variables to suit your needs:
54 52
55- =filename=: If you are converting to a file format other than Opus, 53- =filename=: If you are converting to a file format other than Opus, you'll
56 you'll need to edit this so that your resulting files have the correct 54 need to edit this so that your resulting files have the correct filename
57 filename extension. 55 extension.
58- =reldir=: This variable can be edited to strip out more leading 56- =reldir=: This variable can be edited to strip out more leading directories in
59 directories in the file path. As you'll see later, I ignore this for 57 the file path. As you'll see later, I ignore this for now and simply clean it
60 now and simply clean it up afterward. 58 up afterward.
61- =opusenc=: This is the actual conversion process. You may want to edit 59- =opusenc=: This is the actual conversion process. You may want to edit the
62 the bitrate to suit your needs. I set mine at 128 but some prefer 160 60 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher.
63 or higher.
64 61
65#+begin_src sh 62#+begin_src sh
66#!/bin/bash 63#!/bin/bash
@@ -126,8 +123,8 @@ opusenc --vbr --bitrate 128 --date "$DATE" \
126done 123done
127#+end_src 124#+end_src
128 125
129Once you're done, simply save the file and exit your editor. Don't 126Once you're done, simply save the file and exit your editor. Don't forget to
130forget to enable execution of the script: 127enable execution of the script:
131 128
132#+begin_src sh 129#+begin_src sh
133chmod +x transform.sh 130chmod +x transform.sh
@@ -139,16 +136,16 @@ Finally, you may now run the script:
139./transform.sh 136./transform.sh
140#+end_src 137#+end_src
141 138
142If you used =opusenc=, you'll see the conversions happen within the 139If you used =opusenc=, you'll see the conversions happen within the terminal as
143terminal as it progresses. You will also see variables printed if you 140it progresses. You will also see variables printed if you uncommented any of the
144uncommented any of the bash script's comments. 141bash script's comments.
145 142
146** Cleanup 143** Cleanup
147 144
148As I noted above, I didn't customize my =reldir= variable in the script, 145As I noted above, I didn't customize my =reldir= variable in the script, which
149which caused my output directory to be =/mnt/music/library/archives= 146caused my output directory to be =/mnt/music/library/archives= instead of
150instead of =/mnt/music/library=. So, I moved the output up one level and 147=/mnt/music/library=. So, I moved the output up one level and deleted the
151deleted the accidental directory. 148accidental directory.
152 149
153#+begin_src sh 150#+begin_src sh
154cd /mnt/music/library 151cd /mnt/music/library
@@ -158,8 +155,8 @@ rm -rf archives
158 155
159** Check the Resulting Size 156** Check the Resulting Size
160 157
161If you want to see what kind of file size savings you've gained, you can 158If you want to see what kind of file size savings you've gained, you can always
162always use the =du= command to check: 159use the =du= command to check:
163 160
164#+begin_src sh 161#+begin_src sh
165cd /mnt/music 162cd /mnt/music
content/blog/2022-07-31-bash-it.org +57 −66
@@ -5,14 +5,12 @@
5 5
6* Bash 6* Bash
7 7
8For those who are not familiar, 8For those who are not familiar, [[https://en.wikipedia.org/wiki/Bash_(Unix_shell)][Bash]] is a Unix shell that is used as the default
9[[https://en.wikipedia.org/wiki/Bash_(Unix_shell)][Bash]] is a Unix 9login shell for most Linux distributions. This shell and command processor
10shell that is used as the default login shell for most Linux 10should be familiar if you've used Linux (or older version of macOS) before.
11distributions. This shell and command processor should be familiar if
12you've used Linux (or older version of macOS) before.
13 11
14However, bash is not the only option. There are numerous other shells 12However, bash is not the only option. There are numerous other shells that
15that exist. Here are some popular examples: 13exist. Here are some popular examples:
16 14
17- [[https://en.wikipedia.org/wiki/Z_shell][zsh]] 15- [[https://en.wikipedia.org/wiki/Z_shell][zsh]]
18- [[https://en.wikipedia.org/wiki/Fish_(Unix_shell)][fish]] 16- [[https://en.wikipedia.org/wiki/Fish_(Unix_shell)][fish]]
@@ -20,16 +18,15 @@ that exist. Here are some popular examples:
20- [[https://wiki.gentoo.org/wiki/Mksh][mksh]] 18- [[https://wiki.gentoo.org/wiki/Mksh][mksh]]
21- [[https://en.wikipedia.org/wiki/Debian_Almquist_shell][dash]] 19- [[https://en.wikipedia.org/wiki/Debian_Almquist_shell][dash]]
22 20
23While each shell has its differences, bash is POSIX compliant and the 21While each shell has its differences, bash is POSIX compliant and the default
24default for many Linux users. Because of this, I am going to explore a 22for many Linux users. Because of this, I am going to explore a program called
25program called =bash-it= below that helps bash users increase the 23=bash-it= below that helps bash users increase the utility of their shell
26utility of their shell without installing a completely new shell. 24without installing a completely new shell.
27 25
28** Installation 26** Installation
29 27
30First, if bash is not already installed on your system, you can 28First, if bash is not already installed on your system, you can [[https://www.gnu.org/software/bash/][download bash
31[[https://www.gnu.org/software/bash/][download bash from GNU]] or use 29from GNU]] or use your package manager to install it.
32your package manager to install it.
33 30
34For example, this is how you can install bash on Fedora Linux: 31For example, this is how you can install bash on Fedora Linux:
35 32
@@ -37,19 +34,19 @@ For example, this is how you can install bash on Fedora Linux:
37sudo dnf install bash 34sudo dnf install bash
38#+end_src 35#+end_src
39 36
40If you are not using bash as your default shell, use the =chsh= command 37If you are not using bash as your default shell, use the =chsh= command to
41to change your shell: 38change your shell:
42 39
43#+begin_src sh 40#+begin_src sh
44chsh 41chsh
45#+end_src 42#+end_src
46 43
47You should see a prompt like the one below. If the brackets (=[]=) 44You should see a prompt like the one below. If the brackets (=[]=) contain
48contain =bash= already, you're done, and you can simply continue by 45=bash= already, you're done, and you can simply continue by hitting the Enter
49hitting the Enter key. 46key.
50 47
51If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter 48If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter the path
52the path to the bash program on your system (it's most likely located at 49to the bash program on your system (it's most likely located at
53=/usr/bin/bash=). 50=/usr/bin/bash=).
54 51
55#+begin_src sh 52#+begin_src sh
@@ -57,9 +54,9 @@ Changing shell for <user>.
57New shell [/usr/bin/bash]: 54New shell [/usr/bin/bash]:
58#+end_src 55#+end_src
59 56
60You must log out or restart the machine in order for the login shell to 57You must log out or restart the machine in order for the login shell to be
61be refreshed. You can do it now or wait until you're finished 58refreshed. You can do it now or wait until you're finished customizing the
62customizing the shell. 59shell.
63 60
64#+begin_src sh 61#+begin_src sh
65sudo reboot now 62sudo reboot now
@@ -67,31 +64,30 @@ sudo reboot now
67 64
68* Bash-it 65* Bash-it
69 66
70As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]] 67As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]] repository:
71repository:
72 68
73#+begin_quote 69#+begin_quote
74Bash-it is a collection of community Bash commands and scripts for Bash 70Bash-it is a collection of community Bash commands and scripts for Bash
753.2+. (And a shameless ripoff of oh-my-zsh 😃) 713.2+. (And a shameless ripoff of oh-my-zsh 😃)
76#+end_quote 72#+end_quote
77 73
78Bash-it makes it easy to install plugins, set up aliases for common 74Bash-it makes it easy to install plugins, set up aliases for common commands,
79commands, and easily change the visual theme of your shell. 75and easily change the visual theme of your shell.
80 76
81** Installation 77** Installation
82 78
83To install the framework, simply copy the repository files and use the 79To install the framework, simply copy the repository files and use the
84=install.sh= script provided. If you want, you can (and should!) inspect 80=install.sh= script provided. If you want, you can (and should!) inspect the
85the contents of the installation script before you run it. 81contents of the installation script before you run it.
86 82
87#+begin_src sh 83#+begin_src sh
88git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it 84git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it
89~/.bash_it/install.sh 85~/.bash_it/install.sh
90#+end_src 86#+end_src
91 87
92If you didn't restart your session after making bash the default, and 88If you didn't restart your session after making bash the default, and are
93are currently working within another shell, be sure to enter a bash 89currently working within another shell, be sure to enter a bash session before
94session before using =bash-it=: 90using =bash-it=:
95 91
96#+begin_src sh 92#+begin_src sh
97bash 93bash
@@ -100,16 +96,16 @@ bash
100** Aliases 96** Aliases
101 97
102Bash-it contains a number of aliases for common commands to help improve 98Bash-it contains a number of aliases for common commands to help improve
103efficiency in the terminal. To list all available options, use the 99efficiency in the terminal. To list all available options, use the following
104following command: 100command:
105 101
106#+begin_src sh 102#+begin_src sh
107bash-it show aliases 103bash-it show aliases
108#+end_src 104#+end_src
109 105
110This will provide you a list that looks like the following text block. 106This will provide you a list that looks like the following text block. Within
111Within this screen, you will be able to see all available options and 107this screen, you will be able to see all available options and which ones are
112which ones are currently enabled. 108currently enabled.
113 109
114#+begin_src txt 110#+begin_src txt
115Alias Enabled? Description 111Alias Enabled? Description
@@ -140,9 +136,8 @@ bash-it disable alias <alias name> [alias name]... -or- $ bash-it disable alias
140 136
141** Plugins 137** Plugins
142 138
143Similar to aliases, plugins are available with bash-it. You can find a 139Similar to aliases, plugins are available with bash-it. You can find a complete
144complete list of plugins in the same way as aliases. Simply execute the 140list of plugins in the same way as aliases. Simply execute the following:
145following:
146 141
147#+begin_src sh 142#+begin_src sh
148bash-it show plugins 143bash-it show plugins
@@ -177,9 +172,7 @@ bash-it disable plugin <plugin name> [plugin name]... -or- $ bash-it disable plu
177 172
178** Themes 173** Themes
179 174
180There are quite a few pre-defined 175There are quite a few pre-defined [[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]] available with bash-it.
181[[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]]
182available with bash-it.
183 176
184To list all themes: 177To list all themes:
185 178
@@ -187,9 +180,8 @@ To list all themes:
187ls ~/.bash_it/themes/ 180ls ~/.bash_it/themes/
188#+end_src 181#+end_src
189 182
190To use a new theme, you'll need to edit =.bashrc= and alter the 183To use a new theme, you'll need to edit =.bashrc= and alter the =BASH_IT_THEME=
191=BASH_IT_THEME= variable to your desired theme. For example, I am using 184variable to your desired theme. For example, I am using the =zork= theme.
192the =zork= theme.
193 185
194#+begin_src sh 186#+begin_src sh
195nano ~/.bashrc 187nano ~/.bashrc
@@ -199,23 +191,22 @@ nano ~/.bashrc
199export BASH_IT_THEME='zork' 191export BASH_IT_THEME='zork'
200#+end_src 192#+end_src
201 193
202Once you save your changes, you just need to exit your terminal and 194Once you save your changes, you just need to exit your terminal and create a new
203create a new one in order to see your changes to the =.bashrc= file. You 195one in order to see your changes to the =.bashrc= file. You can also =source=
204can also =source= the file to see changes, but I recommend starting a 196the file to see changes, but I recommend starting a completely new shell
205completely new shell instead. 197instead.
206 198
207*** ble.sh 199*** ble.sh
208 200
209One big feature I was missing in Bash that both =zsh= and =fish= have is 201One big feature I was missing in Bash that both =zsh= and =fish= have is an
210an autosuggestion feature. To explain: as you type, an autosuggestion 202autosuggestion feature. To explain: as you type, an autosuggestion feature in
211feature in the shell will offer suggestions in a lighter font color 203the shell will offer suggestions in a lighter font color beyond the characters
212beyond the characters already typed. Once you see the command you want, 204already typed. Once you see the command you want, you can click the right arrow
213you can click the right arrow and have the shell auto-complete that line 205and have the shell auto-complete that line for you.
214for you.
215 206
216Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]] 207Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]] (ble.sh) exists! This program provides a wonderful
217(ble.sh) exists! This program provides a wonderful autosuggestions 208autosuggestions feature perfectly, among other features that I haven't tested
218feature perfectly, among other features that I haven't tested yet. 209yet.
219 210
220In order to install ble.sh, execute the following: 211In order to install ble.sh, execute the following:
221 212
@@ -225,16 +216,16 @@ make -C ble.sh install PREFIX=~/.local
225echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc 216echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
226#+end_src 217#+end_src
227 218
228Again, exit the terminal and open a new one in order to see the 219Again, exit the terminal and open a new one in order to see the newly-configured
229newly-configured shell. 220shell.
230 221
231* Restart the Session 222* Restart the Session
232 223
233Finally, as mentioned above, you'll need to restart the session to 224Finally, as mentioned above, you'll need to restart the session to ensure that
234ensure that your user is using bash by default. 225your user is using bash by default.
235 226
236You will also need to exit and re-open a shell (e.g., terminal or 227You will also need to exit and re-open a shell (e.g., terminal or terminal tab)
237terminal tab) any time you make changes to the =.bashrc= file. 228any time you make changes to the =.bashrc= file.
238 229
239#+begin_src sh 230#+begin_src sh
240sudo reboot now 231sudo reboot now
content/blog/2022-08-31-privacy-com-changes.org +49 −56
@@ -5,50 +5,46 @@
5 5
6* Privacy.com Changes Their Terms 6* Privacy.com Changes Their Terms
7 7
8Recently, Privacy.com reached out to their customers regarding a change 8Recently, Privacy.com reached out to their customers regarding a change in their
9in their terms of use. Further, all customers are required to agree to 9terms of use. Further, all customers are required to agree to the changes in
10the changes in order to continue using their accounts. 10order to continue using their accounts.
11 11
12[[https://privacy.com/commercial-cardholder-agreement][You can view the 12[[https://privacy.com/commercial-cardholder-agreement][You can view the new cardholder agreement here]].
13new cardholder agreement here]].
14 13
15When you log in, you'll be greeted with a pop-up window asking you to 14When you log in, you'll be greeted with a pop-up window asking you to review and
16review and agree to the new terms of use. You will also not be able to 15agree to the new terms of use. You will also not be able to open any new cards
17open any new cards until the terms are agreed to. 16until the terms are agreed to.
18 17
19** Changing from a "Prepaid Debit" Model to a "Charge Card" Model 18** Changing from a "Prepaid Debit" Model to a "Charge Card" Model
20 19
21The actual content of the changes is interesting. While the historical 20The actual content of the changes is interesting. While the historical model of
22model of using Privacy.com was akin to prepaid debit cards, the new 21using Privacy.com was akin to prepaid debit cards, the new model is very similar
23model is very similar to a credit card (they use the term "charge 22to a credit card (they use the term "charge card").
24card").
25 23
26I have used Privacy.com for 1-2 years, and the process was always that 24I have used Privacy.com for 1-2 years, and the process was always that you would
27you would create a single-use or merchant-locked card. This card could 25create a single-use or merchant-locked card. This card could be used for any
28be used for any dollar limit you set and would immediately draw the 26dollar limit you set and would immediately draw the funds from whatever funding
29funds from whatever funding source you connected, e.g. PayPal account or 27source you connected, e.g. PayPal account or a bank account.
30a bank account.
31 28
32The benefit this service provides with a premium account is masking the 29The benefit this service provides with a premium account is masking the merchant
33merchant names from your funding source. If you have a concern that your 30names from your funding source. If you have a concern that your bank account
34bank account uses merchant data from your account, you could direct all 31uses merchant data from your account, you could direct all charges through
35charges through Privacy.com and set the merchant as one of their pre-set 32Privacy.com and set the merchant as one of their pre-set options, such as
36options, such as "Smiley's Corner Store" or "NSA Gift Shop." 33"Smiley's Corner Store" or "NSA Gift Shop."
37 34
38The new model still works with a bank account as a funding source, but 35The new model still works with a bank account as a funding source, but the model
39the model is changed so that you get a "line of credit" set according to 36is changed so that you get a "line of credit" set according to a 14-day billing
40a 14-day billing cycle. It seems that Privacy.com will now allow charges 37cycle. It seems that Privacy.com will now allow charges to be incurred without
41to be incurred without being immediately paid. 38being immediately paid.
42 39
43** Daily Payments and Available Credit 40** Daily Payments and Available Credit
44 41
45Instead of paying as charges are incurred, you must make a "Daily 42Instead of paying as charges are incurred, you must make a "Daily Payment" and
46Payment" and your "Available Credit" will be locked until you make that 43your "Available Credit" will be locked until you make that payment. There are
47payment. There are also "End of Billing Cycle Payments" that are 44also "End of Billing Cycle Payments" that are assigned a due date.
48assigned a due date.
49 45
50Further, Privacy.com will decline charges that would cause you to exceed 46Further, Privacy.com will decline charges that would cause you to exceed your
51your Available Credit or Credit Limit. 47Available Credit or Credit Limit.
52 48
53One particular interesting section states the following: 49One particular interesting section states the following:
54 50
@@ -63,37 +59,34 @@ FOR MORE INFORMATION.
63 59
64** Personal Information 60** Personal Information
65 61
66Now that Privacy.com is more of a financial institution, they are 62Now that Privacy.com is more of a financial institution, they are obligated to
67obligated to comply with the 63comply with the [[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]] guidelines/laws.
68[[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]]
69guidelines/laws.
70 64
71I did not proceed with the change to my Privacy.com account, but I have 65I did not proceed with the change to my Privacy.com account, but I have heard
72heard from some peers that the changes require more personal information 66from some peers that the changes require more personal information to be
73to be submitted, such as SSN. I am not aware of all new personal 67submitted, such as SSN (Social Security Number). I am not aware of all new
74information required or if the funding source is now required to only be 68personal information required or if the funding source is now required to only
75a bank account. 69be a bank account.
76 70
77** Fees 71** Fees
78 72
79Luckily, the fees section did not change much. The subscription fees for 73Luckily, the fees section did not change much. The subscription fees for a
80a premium account are still the only fees. 74premium account are still the only fees.
81 75
82* My Thoughts 76* My Thoughts
83 77
84Personally, I wiped my personal information from my account and then 78Personally, I wiped my personal information from my account and then permanently
85permanently deleted it when I heard about these changes. I have no 79deleted it when I heard about these changes. I have no interest in yet another
86interest in yet another method of credit lending offered by private 80method of credit lending offered by private companies. While I accepted that
87companies. While I accepted that they would have access to my bank 81they would have access to my bank account information for the purposes of paying
88account information for the purposes of paying off my prepaid debit 82off my prepaid debit payments, I have no interest in incurring charges that will
89payments, I have no interest in incurring charges that will need to be 83need to be paid back at a later date. I also have no interest in submitting
90paid back at a later date. I also have no interest in submitting
91personal information to Privacy.com. 84personal information to Privacy.com.
92 85
93This type of change toward a "buy it now, pay us later" model is 86This type of change toward a "buy it now, pay us later" model is concerning, and
94concerning, and I will be watching Privacy.com to see if they further 87I will be watching Privacy.com to see if they further their interests in the
95their interests in the credit model as time goes on. 88credit model as time goes on.
96 89
97Could we see them start charging interest, fees, etc.? I'm not sure, but 90Could we see them start charging interest, fees, etc.? I'm not sure, but this
98this change does not inspire confidence in their mission as a 91change does not inspire confidence in their mission as a privacy-focused
99privacy-focused company. 92company.
content/blog/2022-09-17-serenity-os.org +35 −41
@@ -5,13 +5,13 @@
5 5
6* Overview 6* Overview
7 7
8[[https://serenityos.org][SerenityOS]] is a unique operating system (OS) 8[[https://serenityos.org][SerenityOS]] is a unique operating system (OS) that I have seen pop up in my news
9that I have seen pop up in my news feed a few times over the last few 9feed a few times over the last few years, but I have never had time to test it
10years, but I have never had time to test it out until now. 10out until now.
11 11
12Testing out this system brought back fond memories of yellowed, 12Testing out this system brought back fond memories of yellowed,
13modem-screeching, 100-pound computers that brought so many fond memories 13modem-screeching, 100-pound computers that brought so many fond memories to my
14to my youth. 14youth.
15 15
16Per their website: 16Per their website:
17 17
@@ -31,11 +31,10 @@ This is a system by us, for us, based on the things we like.
31 31
32* Building 32* Building
33 33
34Your first question may be "Where's the iso?" and the answer is... there 34Your first question may be "Where's the iso?" and the answer is... there are
35are none. SerenityOS does not provide pre-built images for testing. You 35none. SerenityOS does not provide pre-built images for testing. You must build
36must build the images yourself. This seems intentionally to limit 36the images yourself. This seems intentionally to limit participation to only
37participation to only those who are truly interested enough to learn how 37those who are truly interested enough to learn how to build the OS.
38to build the OS.
39 38
40** Clone 39** Clone
41 40
@@ -47,25 +46,22 @@ git clone https://github.com/SerenityOS/serenity && cd serenity
47 46
48** Build 47** Build
49 48
50Note that I followed the 49Note that I followed the [[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build Instructions]] in the SerenityOS repository as of
51[[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build 50commit =660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed since
52Instructions]] in the SerenityOS repository as of commit 51my installation, and you should double-check the instructions first.
53=660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed
54since my installation, and you should double-check the instructions
55first.
56 52
57Regardless, I want to repeat my steps here to illustrate any errors or 53Regardless, I want to repeat my steps here to illustrate any errors or differing
58differing commands I needed to run in order to build and run SerenityOS. 54commands I needed to run in order to build and run SerenityOS.
59 55
60Since I am running Fedora, I needed to install these packages in order 56Since I am running Fedora, I needed to install these packages in order to build
61to build the OS images: 57the OS images:
62 58
63#+begin_src sh 59#+begin_src sh
64sudo dnf install texinfo binutils-devel curl cmake mpfr-devel libmpc-devel gmp-devel e2fsprogs ninja-build patch ccache rsync @"C Development Tools and Libraries" @Virtualization 60sudo dnf install texinfo binutils-devel curl cmake mpfr-devel libmpc-devel gmp-devel e2fsprogs ninja-build patch ccache rsync @"C Development Tools and Libraries" @Virtualization
65#+end_src 61#+end_src
66 62
67Next, make sure you're inside the =serenity= directory created earlier 63Next, make sure you're inside the =serenity= directory created earlier during
68during the git cloning process and process to build the toolchain: 64the git cloning process and process to build the toolchain:
69 65
70#+begin_src sh 66#+begin_src sh
71Meta/serenity.sh rebuild-toolchain 67Meta/serenity.sh rebuild-toolchain
@@ -82,29 +78,27 @@ launch.
82 78
83* Issues 79* Issues
84 80
85I played around in SerenityOS for an hour or two in order to see what I 81I played around in SerenityOS for an hour or two in order to see what I could do
86could do and had a lot of fun with it. The only issue I ran into was a 82and had a lot of fun with it. The only issue I ran into was a lack of working
87lack of working internet. I didn't try very hard, but I could tell that 83internet. I didn't try very hard, but I could tell that the main network link
88the main network link wasn't connecting to my Fedora host properly. 84wasn't connecting to my Fedora host properly.
89 85
90* Screenshots 86* Screenshots
91 87
92The initial launch of the image displays the SerenityOS desktop, with a 88The initial launch of the image displays the SerenityOS desktop, with a simple
93simple terminal already launched. 89terminal already launched.
94 90
95There is also a "Fire" application (literally just shows fire burning), 91There is also a "Fire" application (literally just shows fire burning), a
96a browser with the local Serenity Browser page loaded, and a text 92browser with the local Serenity Browser page loaded, and a text editor.
97editor.
98 93
99I also poked around the system utilities and found most tools you'd 94I also poked around the system utilities and found most tools you'd expect to
100expect to find within a standard desktop, such as a system monitoring 95find within a standard desktop, such as a system monitoring tool.
101tool.
102 96
103Lastly, I noted that the default desktop contains numerous pre-defined 97Lastly, I noted that the default desktop contains numerous pre-defined themes to
104themes to choose from. This is a small piece, but it's actually 98choose from. This is a small piece, but it's actually wonderful to see desktop
105wonderful to see desktop developers consider theming directly out of the 99developers consider theming directly out of the box rather than using an
106box rather than using an addon-based mentality. 100addon-based mentality.
107 101
108I didn't take a screenshot of the other pre-installed games, but I did 102I didn't take a screenshot of the other pre-installed games, but I did spend
109spend nearly 30 minutes playing Solitaire before remembering that I was 103nearly 30 minutes playing Solitaire before remembering that I was supposed to be
110supposed to be writing a post about the OS. 104writing a post about the OS.
content/blog/2022-09-21-graphene-os.org +51 −58
@@ -5,26 +5,24 @@
5 5
6* Introduction 6* Introduction
7 7
8After using iOS for a couple of years, I finally took the plunge and 8After using iOS for a couple of years, I finally took the plunge and purchased a
9purchased a Pixel 6 Pro in order to test and use [GrapheneOS] 9Pixel 6 Pro in order to test and use [[https://grapheneos.org][GrapheneOS]].
10([[https://grapheneos.org]]).
11 10
12The installation process was rather quick once you have the tools and 11The installation process was rather quick once you have the tools and files you
13files you need. Overall, it can be done in just a few minutes. 12need. Overall, it can be done in just a few minutes.
14 13
15* Gathering Tools & Files 14* Gathering Tools & Files
16 15
17** Android Tools 16** Android Tools
18 17
19First, in order to interact with the device, we will need the 18First, in order to interact with the device, we will need the [[https://developer.android.com/studio/releases/platform-tools.html][Android platform
20[[https://developer.android.com/studio/releases/platform-tools.html][Android 19tools]]. Find the Linux download and save the ZIP folder to your preferred
21platform tools]]. Find the Linux download and save the ZIP folder to 20location.
22your preferred location.
23 21
24Once we've downloaded the files, we will need to unzip them, enter the 22Once we've downloaded the files, we will need to unzip them, enter the
25directory, and move the necessary executables to a central location, 23directory, and move the necessary executables to a central location, such as
26such as =/usr/bin/=. For this installation, we only need the =fastboot= 24=/usr/bin/=. For this installation, we only need the =fastboot= and =adb=
27and =adb= executables. 25executables.
28 26
29#+begin_src sh 27#+begin_src sh
30cd ~/Downloads 28cd ~/Downloads
@@ -39,9 +37,8 @@ sudo mv adb /usr/bin
39 37
40** GrapheneOS Files 38** GrapheneOS Files
41 39
42Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]] 40Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]] for our device and model. For example, the
43for our device and model. For example, the Pixel 6 Pro is codenamed 41Pixel 6 Pro is codenamed =raven= on the release page.
44=raven= on the release page.
45 42
46Once we have the links, let's download them to our working directory: 43Once we have the links, let's download them to our working directory:
47 44
@@ -53,8 +50,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
53 50
541. Validate Integrity 511. Validate Integrity
55 52
56 In order to validate the integrity of the downloaded files, we will 53 In order to validate the integrity of the downloaded files, we will need the
57 need the =signify= package and Graphene's =factory.pub= file. 54 =signify= package and Graphene's =factory.pub= file.
58 55
59 #+begin_src sh 56 #+begin_src sh
60 sudo dnf install signify 57 sudo dnf install signify
@@ -64,8 +61,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
64 curl -O https://releases.grapheneos.org/factory.pub 61 curl -O https://releases.grapheneos.org/factory.pub
65 #+end_src 62 #+end_src
66 63
67 Then we can validate the files and ensure that no data was corrupted 64 Then we can validate the files and ensure that no data was corrupted or
68 or modified before it was saved to our device. 65 modified before it was saved to our device.
69 66
70 #+begin_src sh 67 #+begin_src sh
71 signify -Cqp factory.pub -x raven-factory-2022091400.zip.sig && echo verified 68 signify -Cqp factory.pub -x raven-factory-2022091400.zip.sig && echo verified
@@ -73,8 +70,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
73 70
742. Unzip Files 712. Unzip Files
75 72
76 Once the files are verified, we can unzip the Graphene image and 73 Once the files are verified, we can unzip the Graphene image and enter the
77 enter the directory: 74 directory:
78 75
79 #+begin_src sh 76 #+begin_src sh
80 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400 77 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400
@@ -84,35 +81,35 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
84 81
85** Enable Developer Debugging & OEM Unlock 82** Enable Developer Debugging & OEM Unlock
86 83
87Before we can actually flash anything to the phone, we will need to 84Before we can actually flash anything to the phone, we will need to enable OEM
88enable OEM Unlocking, as well as either USB Debugging or Wireless 85(Original Equipment Manufacturer) Unlocking, as well as either USB (Universal
89Debugging, depending on which method we will be using. 86Serial Bus) Debugging or Wireless Debugging, depending on which method we will
87be using.
90 88
91To start, enable developer mode by going to =Settings= > =About= and 89To start, enable developer mode by going to =Settings= > =About= and tapping
92tapping =Build Number= seven (7) times. You may need to enter your PIN 90=Build Number= seven (7) times. You may need to enter your personal identified
93to enable this mode. 91number (PIN) to enable this mode.
94 92
95Once developer mode is enabled, go to =Settings= > =System= > 93Once developer mode is enabled, go to =Settings= > =System= > =Devloper Options=
96=Devloper Options= and enable OEM Unlocking, as well as USB or Wireless 94and enable OEM Unlocking, as well as USB or Wireless Debugging. In my case, I
97Debugging. In my case, I chose USB Debugging and performed all actions 95chose USB Debugging and performed all actions via USB cable.
98via USB cable.
99 96
100Once these options are enabled, plug the phone into the computer and 97Once these options are enabled, plug the phone into the computer and execute the
101execute the following command: 98following command:
102 99
103#+begin_src sh 100#+begin_src sh
104adb devices 101adb devices
105#+end_src 102#+end_src
106 103
107If an unauthorized error occurs, make sure the USB mode on the phone is 104If an unauthorized error occurs, make sure the USB mode on the phone is changed
108changed from charging to something like "File Transfer" or "PTP." You 105from charging to something like "File Transfer" or "PTP" (Picture Transfer
109can find the USB mode in the notification tray. 106Protocol). You can find the USB mode in the notification tray.
110 107
111** Reboot Device 108** Reboot Device
112 109
113Once we have found the device via =adb=, we can either boot into the 110Once we have found the device via =adb=, we can either boot into the bootloader
114bootloader interface by holding the volume down button while the phone 111interface by holding the volume down button while the phone reboots or by
115reboots or by executing the following command: 112executing the following command:
116 113
117#+begin_src sh 114#+begin_src sh
118adb reboot bootloader 115adb reboot bootloader
@@ -120,17 +117,14 @@ adb reboot bootloader
120 117
121** Unlock the Bootloader 118** Unlock the Bootloader
122 119
123The phone will reboot and load the bootloader screen upon startup. At 120The phone will reboot and load the bootloader screen upon startup. At this
124this point, we are ready to start the actual flashing of GrapheneOS onto 121point, we are ready to start the actual flashing of GrapheneOS onto the device.
125the device.
126 122
127*NOTE*: In my situation, I needed to use =sudo= with every =fastboot= 123*NOTE*: In my situation, I needed to use =sudo= with every =fastboot= command,
128command, but not with =adb= commands. I am not sure if this is standard 124but not with =adb= commands. I am not sure if this is standard or a Fedora
129or a Fedora quirk, but I'm documenting my commands verbatim in this 125quirk, but I'm documenting my commands verbatim in this post.
130post.
131 126
132First, we start by unlocking the bootloader so that we can load other 127First, we start by unlocking the bootloader so that we can load other ROMs:
133ROMs:
134 128
135#+begin_src sh 129#+begin_src sh
136sudo fastboot flashing unlock 130sudo fastboot flashing unlock
@@ -138,24 +132,23 @@ sudo fastboot flashing unlock
138 132
139** Flashing Factory Images 133** Flashing Factory Images
140 134
141Once the phone is unlocked, we can flash it with the =flash-all.sh= 135Once the phone is unlocked, we can flash it with the =flash-all.sh= script found
142script found inside the =raven-factory-2022091400= folder we entered 136inside the =raven-factory-2022091400= folder we entered earlier:
143earlier:
144 137
145#+begin_src sh 138#+begin_src sh
146sudo ./flash-all.sh 139sudo ./flash-all.sh
147#+end_src 140#+end_src
148 141
149This process should take a few minutes and will print informational 142This process should take a few minutes and will print informational messages as
150messages as things progress. Avoid doing anything on the phone while 143things progress. Avoid doing anything on the phone while this process is
151this process is operating. 144operating.
152 145
153** Lock the Bootloader 146** Lock the Bootloader
154 147
155If everything was successful, the phone should reboot a few times and 148If everything was successful, the phone should reboot a few times and finally
156finally land back on the bootloader screen. At this point, we can 149land back on the bootloader screen. At this point, we can re-lock the bootloader
157re-lock the bootloader to enable full verified boot and protect the 150to enable full verified boot and protect the device from unwanted flashing or
158device from unwanted flashing or erasure of data. 151erasure of data.
159 152
160#+begin_src sh 153#+begin_src sh
161sudo fastboot flashing lock 154sudo fastboot flashing lock
content/blog/2022-10-04-mtp-linux.org +22 −25
@@ -3,31 +3,29 @@
3#+description: Instructions for mounting and accessing Media Transfer Protocol (MTP) compatible mobile devices on Fedora Linux using jmtpfs for file transfer and management. 3#+description: Instructions for mounting and accessing Media Transfer Protocol (MTP) compatible mobile devices on Fedora Linux using jmtpfs for file transfer and management.
4#+slug: mtp-linux 4#+slug: mtp-linux
5 5
6I recently ran into trouble attempting to mount my GrapheneOS phone to 6I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop
7my laptop running Fedora Linux via the 7running Fedora Linux via the [[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer Protocol]] (MTP) and discovered a
8[[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer 8simple and effective solution.
9Protocol]] (MTP) and discovered a simple and effective solution.
10 9
11* Use a USB 3.0 Port 10* Use a Universal Serial Bus (USB) 3.0 Port
12 11
13First, ensure that the device was plugged in to the laptop through a USB 12First, ensure that the device was plugged in to the laptop through a USB 3.0
143.0 port, if possible. From a brief glance online, it seems that USB 2.0 13port, if possible. From a brief glance online, it seems that USB 2.0 ports may
15ports may cause issues with dropped connections over MTP. This is purely 14cause issues with dropped connections over MTP. This is purely anecdotal since I
16anecdotal since I don't have any evidence to link showing that USB 2.0 15don't have any evidence to link showing that USB 2.0 causes issues, but I can
17causes issues, but I can confirm that switching to a USB 3.0 port seemed 16confirm that switching to a USB 3.0 port seemed to cut out most of my issues.
18to cut out most of my issues.
19 17
20* Switch USB Preferences to MTP 18* Switch USB Preferences to MTP
21 19
22Secondly, you need to ensure that the phone's USB preferences/mode is 20Secondly, you need to ensure that the phone's USB preferences/mode is changed to
23changed to MTP or File Transfer once the phone is plugged in. Other 21MTP or File Transfer once the phone is plugged in. Other modes will not allow
24modes will not allow you to access the phone's file system. 22you to access the phone's file system.
25 23
26* Install =jmtpfs= 24* Install =jmtpfs=
27 25
28Next, I used the =jmtpfs= package to mount my phone to my laptop. There 26Next, I used the =jmtpfs= package to mount my phone to my laptop. There are
29are other packages that exist, but this one worked perfectly for me. On 27other packages that exist, but this one worked perfectly for me. On Fedora
30Fedora Linux, you can install it like this: 28Linux, you can install it like this:
31 29
32#+begin_src sh 30#+begin_src sh
33sudo dnf install jmtpfs -y 31sudo dnf install jmtpfs -y
@@ -35,8 +33,8 @@ sudo dnf install jmtpfs -y
35 33
36* Create a Mount Point 34* Create a Mount Point
37 35
38Once you have the package installed, you just need to create a folder 36Once you have the package installed, you just need to create a folder for the
39for the device to use as a mount point. In my case, I used =/mnt/pixel=: 37device to use as a mount point. In my case, I used =/mnt/pixel=:
40 38
41#+begin_src sh 39#+begin_src sh
42sudo mkdir /mnt/pixel 40sudo mkdir /mnt/pixel
@@ -45,8 +43,8 @@ sudo chown -R $USER:$USER /mnt/pixel
45 43
46* Mount & Access the Phone's File System 44* Mount & Access the Phone's File System
47 45
48Finally, plug-in and mount the device, and you should be able to see all 46Finally, plug-in and mount the device, and you should be able to see all storage
49storage (internal and external) inside your new folder! 47(internal and external) inside your new folder!
50 48
51#+begin_src sh 49#+begin_src sh
52jmtpfs /mnt/pixel 50jmtpfs /mnt/pixel
@@ -59,16 +57,15 @@ Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
59Android device detected, assigning default bug flags 57Android device detected, assigning default bug flags
60#+end_src 58#+end_src
61 59
62Now you are mounted and can do anything you'd like with the device's 60Now you are mounted and can do anything you'd like with the device's files:
63files:
64 61
65#+begin_src sh 62#+begin_src sh
66cd /mnt/pixel 63cd /mnt/pixel
67ls -lha 64ls -lha
68#+end_src 65#+end_src
69 66
70From here, you will be able to see any internal or external storage 67From here, you will be able to see any internal or external storage available on
71available on the device: 68the device:
72 69
73#+begin_src sh 70#+begin_src sh
74total 0 71total 0
content/blog/2022-10-04-syncthing.org +78 −93
@@ -5,26 +5,24 @@
5 5
6* An Overview of Syncthing 6* An Overview of Syncthing
7 7
8If you've been looking around the self-hosted cloud storage space for a 8If you've been looking around the self-hosted cloud storage space for a while,
9while, you've undoubtedly run into someone suggesting 9you've undoubtedly run into someone suggesting [[https://syncthing.net][Syncthing]] as an option. However,
10[[https://syncthing.net][Syncthing]] as an option. However, it is an 10it is an unusual alternative for those users out there who are used to having a
11unusual alternative for those users out there who are used to having a
12centralized cloud server that serves as the "controller" of the data and 11centralized cloud server that serves as the "controller" of the data and
13interacts with clients on devices to fetch files. 12interacts with clients on devices to fetch files.
14 13
15This post is a walkthrough of the Syncthing software, how I set up my 14This post is a walkthrough of the Syncthing software, how I set up my personal
16personal storage, and some pros and cons of using the software. 15storage, and some pros and cons of using the software.
17 16
18* Installing Syncthing 17* Installing Syncthing
19 18
20To install Syncthing, visit the 19To install Syncthing, visit the [[https://syncthing.net/downloads/][Downloads]] page or install via your device's
21[[https://syncthing.net/downloads/][Downloads]] page or install via your 20package manager.
22device's package manager.
23 21
24** Server & Desktop 22** Server & Desktop
25 23
26You can install Syncthing on servers and desktops via the Downloads page 24You can install Syncthing on servers and desktops via the Downloads page linked
27linked above or via the command-line. 25above or via the command-line.
28 26
29For Debian-based distros: 27For Debian-based distros:
30 28
@@ -40,19 +38,13 @@ sudo dnf install syncthing
40 38
41** Mobile 39** Mobile
42 40
43Syncthing for Android is available on 41Syncthing for Android is available on [[https://f-droid.org/packages/com.nutomic.syncthingandroid/][F-Droid]] and [[https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid][Google Play]]. Syncthing does
44[[https://f-droid.org/packages/com.nutomic.syncthingandroid/][F-Droid]] 42not have an official iOS client, but there is a third-party client called [[https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216][Möbius
45and
46[[https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid][Google
47Play]]. Syncthing does not have an official iOS client, but there is a
48third-party client called
49[[https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216][Möbius
50Sync]]. 43Sync]].
51 44
52* How Does Syncthing Work? 45* How Does Syncthing Work?
53 46
54To start, I wanted to include the main marketing blurb from their 47To start, I wanted to include the main marketing blurb from their website:
55website:
56 48
57#+begin_quote 49#+begin_quote
58Syncthing is a continuous file synchronization program. It synchronizes 50Syncthing is a continuous file synchronization program. It synchronizes
@@ -62,19 +54,19 @@ where it is stored, whether it is shared with some third party, and how
62it's transmitted over the internet. 54it's transmitted over the internet.
63#+end_quote 55#+end_quote
64 56
65Let's break this apart and add in some other details to help explain 57Let's break this apart and add in some other details to help explain what
66what exactly Syncthing does in order to sync files between devices. 58exactly Syncthing does in order to sync files between devices.
67 59
68** Local Syncthing Server(s) 60** Local Syncthing Server(s)
69 61
70Syncthing syncs files between multiple devices by creating a local 62Syncthing syncs files between multiple devices by creating a local server on
71server on each device. These local servers handle a few different 63each device. These local servers handle a few different things, such as watching
72things, such as watching files and directories for changes, hosting an 64files and directories for changes, hosting an administrative GUI website, and
73administrative GUI website, and authenticating with connected devices. 65authenticating with connected devices.
74 66
75You can also start, stop, and restart the Syncthing server via the 67You can also start, stop, and restart the Syncthing server via the command-line
76command-line or web dashboard. If you're running Syncthing on a device 68or web dashboard. If you're running Syncthing on a device with =systemd=, you
77with =systemd=, you can use the following commands: 69can use the following commands:
78 70
79#+begin_src sh 71#+begin_src sh
80sudo systemctl start syncthing@username.service 72sudo systemctl start syncthing@username.service
@@ -84,13 +76,13 @@ sudo systemctl stop syncthing@username.service
84 76
85** Syncthing Dashboard 77** Syncthing Dashboard
86 78
87This biggest part of Syncthing is the admin GUI website that runs on 79This biggest part of Syncthing is the admin GUI website that runs on each device
88each device (note that mobile devices will use the Syncthing app rather 80(note that mobile devices will use the Syncthing app rather than the web GUI).
89than the web GUI). The admin GUI is available through the web browser on 81The administrative graphical user interface (GUI) is available through the web
90the local device that is running Syncthing - simply go to 82browser on the local device that is running Syncthing - simply go to
91=http://localhost:8384= or =http://127.0.0.1:8384=. This web page is the 83=http://localhost:8384= or =http://127.0.0.1:8384=. This web page is the place
92place where you will change settings, add/modify synced files, and 84where you will change settings, add/modify synced files, and add/modify
93add/modify connected devices. 85connected devices.
94 86
95Here's an example web GUI dashboard: 87Here's an example web GUI dashboard:
96 88
@@ -99,81 +91,74 @@ Here's an example web GUI dashboard:
99 91
100** Remote Devices 92** Remote Devices
101 93
102A cloud storage solution wouldn't be very useful if you aren't able to 94A cloud storage solution wouldn't be very useful if you aren't able to share
103share data among various devices. Syncthing does this by sharing Device 95data among various devices. Syncthing does this by sharing Device IDs to connect
104IDs to connect servers, and then by manually sharing Folders with 96servers, and then by manually sharing Folders with devices that have been
105devices that have been connected. 97connected.
106 98
107For instance, if you have a laptop running Syncthing and then install 99For instance, if you have a laptop running Syncthing and then install the
108the Syncthing mobile app on a phone, you could scan the laptop's QR code 100Syncthing mobile app on a phone, you could scan the laptop's QR (quick-response)
109for Device ID and then accept the authentication on the laptop's 101code for Device ID and then accept the authentication on the laptop's dashboard.
110dashboard. Next, you can use either device to select a folder for 102Next, you can use either device to select a folder for sharing and dictating
111sharing and dictating which device should send, receive, or both. 103which device should send, receive, or both.
112 104
113When you connect devices, you can set one device as an "Introducer," 105When you connect devices, you can set one device as an "Introducer," which can
114which can add devices from the introducer to the device list, for 106add devices from the introducer to the device list, for mutually shared folders.
115mutually shared folders. You can also configure Auto Accept, 107You can also configure Auto Accept, compression, rate limits, and more settings
116compression, rate limits, and more settings per device. 108per device.
117 109
118* My Personal Cloud Storage Set-up 110* My Personal Cloud Storage Set-up
119 111
120Personally, I use a model similar to a traditional cloud storage 112Personally, I use a model similar to a traditional cloud storage service. I have
121service. I have a "centralized" server running 24/7 that acts as an 113a "centralized" server running 24/7 that acts as an Introducer for my Syncthing
122Introducer for my Syncthing network. I think of this as my main storage 114network. I think of this as my main storage and all other devices as tertiary
123and all other devices as tertiary client devices. I will likely add 115client devices. I will likely add additional servers as backups as time goes on
124additional servers as backups as time goes on so that I don't have to 116so that I don't have to rely on my laptop or phone as the only backups.
125rely on my laptop or phone as the only backups.
126 117
127Currently, I have one desktop and one mobile device connected to the 118Currently, I have one desktop and one mobile device connected to the network,
128network, both running intermittently as they are not powered-on 24/7. 119both running intermittently as they are not powered-on 24/7.
129 120
130The initial set-up of the software was easy enough, but data transfer 121The initial set-up of the software was easy enough, but data transfer rates were
131rates were incredibly slow for me due to the Wi-Fi. Instead, I plugged 122incredibly slow for me due to the Wi-Fi. Instead, I plugged my laptop into the
132my laptop into the ethernet network that my server is on and manually 123ethernet network that my server is on and manually copied my folders over to the
133copied my folders over to the server with =scp=. Once complete, 124server with =scp=. Once complete, Syncthing validated that all files were there
134Syncthing validated that all files were there and not missing, and it 125and not missing, and it did not need to transfer any data through the WAN.
135did not need to transfer any data through the WAN.
136 126
137As slow as the transfer was going, this probably saved me a few days of 127As slow as the transfer was going, this probably saved me a few days of waiting
138waiting for my ~100GB sync. 128for my ~100 gigabytes to sync.
139 129
140* Pros & Cons 130* Pros & Cons
141 131
142I've put together a short list of pros and cons for Syncthing. I thought 132I've put together a short list of pros and cons for Syncthing. I thought about
143about my experiences with Nextcloud, WebDAV, proprietary services 133my experiences with Nextcloud, WebDAV, proprietary services (Google Drive,
144(Google Drive, iCloud, etc.), and privacy-focused cloud solutions 134iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.).
145(pCloud, Tresorit, etc.).
146 135
147*Pros:* 136*Pros:*
148 137
149- I've faced no data loss at all through my two-month trial run. 138- I've faced no data loss at all through my two-month trial run.
150- No third-parties store your data on their servers. 139- No third-parties store your data on their servers.
151- You have full control over your data and can take your data and leave 140- You have full control over your data and can take your data and leave at any
152 at any time. 141 time.
153- It's possible to encrypt client-side easily with software like 142- It's possible to encrypt client-side easily with software like Cryptomator.
154 Cryptomator. 143- No proprietary clients or mounted volumes, just plain files and folders.
155- No proprietary clients or mounted volumes, just plain files and
156 folders.
157 144
158*Cons:* 145*Cons:*
159 146
160- The learning curve is steeper than traditional cloud services and is 147- The learning curve is steeper than traditional cloud services and is focused
161 focused on a technical audience. 148 on a technical audience.
162- If a device needs to modify files in a Folder, the devices will need 149- If a device needs to modify files in a Folder, the devices will need to sync
163 to sync ALL files from the folder, which may be large. To avoid size 150 ALL files from the folder, which may be large. To avoid size restraints, split
164 restraints, split large folders into smaller folders for syncing. 151 large folders into smaller folders for syncing.
165- Syncing can be slow due to the clients/servers initially connecting or 152- Syncing can be slow due to the clients/servers initially connecting or
166 re-connecting after sleeping. 153 re-connecting after sleeping.
167- Multiple personal devices are required and require the user to own or 154- Multiple personal devices are required and require the user to own or rent
168 rent them as no third-party servers are involved in the storage of 155 them as no third-party servers are involved in the storage of data.
169 data. 156
170 157Overall, I've had a great experience with Syncthing so far. I've had no data
171Overall, I've had a great experience with Syncthing so far. I've had no 158loss, syncing has been quick and easy when changes are made to files, device
172data loss, syncing has been quick and easy when changes are made to 159connections are reliable, and I love the freedom of controlling the clients and
173files, device connections are reliable, and I love the freedom of 160servers as I choose.
174controlling the clients and servers as I choose. 161
175 162Not to mention that I appreciate that I - or someone else - could pull the
176Not to mention that I appreciate that I - or someone else - could pull 163Syncthing [[https://github.com/syncthing][source code]] and continue development/support if the Syncthing
177the Syncthing [[https://github.com/syncthing][source code]] and continue 164Foundation decides to stop developing the software or sells the business.
178development/support if the Syncthing Foundation decides to stop
179developing the software or sells the business.
content/blog/2022-10-22-alpine-linux.org +91 −103
@@ -5,43 +5,40 @@
5 5
6* Alpine Linux 6* Alpine Linux
7 7
8[[https://alpinelinux.org][Alpine Linux]] is a very small distro, built 8[[https://alpinelinux.org][Alpine Linux]] is a very small distribution, built on musl libc and busybox. It
9on musl libc and busybox. It uses ash as the default shell, OpenRC as 9uses ash as the default shell, OpenRC as the init system, and apk as the package
10the init system, and apk as the package manager. According to their 10manager. According to their website, an Alpine container "requires no more than
11website, an Alpine container "requires no more than 8 MB and a minimal 118 megabytes (MB) and a minimal installation to disk requires around 130 MB of
12installation to disk requires around 130 MB of storage." An actual bare 12storage." An actual bare metal machine is recommended to have 100 MB of RAM and
13metal machine is recommended to have 100 MB of RAM and 0-700 MB of 130-700 MB of storage space.
14storage space. 14
15 15Historically, I've used Ubuntu's minimal installation image as my server OS for
16Historically, I've used Ubuntu's minimal installation image as my server 16the last five years. Ubuntu worked well and helped as my original server
17OS for the last five years. Ubuntu worked well and helped as my original 17contained an nVidia GPU (graphics processing unit) and no onboard graphics, so
18server contained an nVidia GPU and no onboard graphics, so quite a few 18quite a few distributions won't boot or install without a lot of tinkering.
19distros won't boot or install without a lot of tinkering. 19
20 20Alpine has given me a huge increase in performance across my Docker apps and
21Alpine has given me a huge increase in performance across my Docker apps 21Nginx websites. CPU (central processing unit) load for the new server I'm using
22and Nginx websites. CPU load for the new server I'm using to test Alpine 22to test Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100
23hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100 CPU @ 23CPU @ 3.70 Gigahertz (GHz).
243.70GHz. 24
25 25The only services I haven't moved over to Alpine are Plex Media Server and
26The only services I haven't moved over to Alpine are Plex Media Server 26Syncthing, which may increase CPU load quite a bit depending on how many streams
27and Syncthing, which may increase CPU load quite a bit depending on how 27are running.
28many streams are running.
29 28
30** Installation 29** Installation
31 30
32In terms of installation, Alpine has an incredibly useful 31In terms of installation, Alpine has an incredibly useful [[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide a
33[[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide 32user throughout the installation and post-installation processes, as well as
34a user throughout the installation and post-installation processes, as 33various other articles and guides.
35well as various other articles and guides.
36 34
37To install Alpine, find an appropriate 35To install Alpine, find an appropriate [[https://alpinelinux.org/downloads/][image to download]] and flash it to a USB
38[[https://alpinelinux.org/downloads/][image to download]] and flash it 36(Universal Serial Bus) using software such as Rufus or Etcher. I opted to use
39to a USB using software such as Rufus or Etcher. I opted to use the 37the Standard image for my x86_{64} architecture.
40Standard image for my x86_{64} architecture.
41 38
42Once the USB is ready, plug it into the machine and reboot. Note that 39Once the USB is ready, plug it into the machine and reboot. Note that you may
43you may have to use a key such as =Esc= or =F1-12= to access the boot 40have to use a key such as =Esc= or =F1-12= to access the boot menu. The Alpine
44menu. The Alpine Linux terminal will load quickly and for a login. 41Linux terminal will load quickly and for a login.
45 42
46To log in to the installation image, use the =root= account; there is no 43To log in to the installation image, use the =root= account; there is no
47password. Once logged-in, execute the setup command: 44password. Once logged-in, execute the setup command:
@@ -50,34 +47,32 @@ password. Once logged-in, execute the setup command:
50setup-alpine 47setup-alpine
51#+end_src 48#+end_src
52 49
53The setup script will ask a series of questions to configure the system. 50The setup script will ask a series of questions to configure the system. Be sure
54Be sure to answer carefully or else you may have to re-configure the 51to answer carefully or else you may have to re-configure the system after boot.
55system after boot.
56 52
57- Keyboard Layout (Local keyboard language and usage mode, e.g., us and 53- *Keyboard Layout*: Local keyboard language and usage mode, e.g., us and variant
58 variant of us-nodeadkeys.) 54 of us-nodeadkeys.
59- Hostname (The name for the computer.) 55- *Hostname*: The name for the computer.
60- Network (For example, automatic IP address discovery with the "DHCP" 56- *Network*: For example, automatic internet protocol (IP) address discovery
61 protocol.) 57 with the Dynamic Host Configuration Protocol (DHCP) protocol.
62- DNS Servers (Domain Name Servers to query. For privacy reasons, it is 58- *DNS (Domain Name System)*: DNS servers to query. For privacy reasons, it is
63 NOT recommended to route every local request to servers like Google's 59 NOT recommended to route every local request to servers like Google's
64 8.8.8.8.) 60 8.8.8.8.
65- Timezone 61- *Timezone
66- Proxy (Proxy server to use for accessing the web. Use "none" for 62- *Proxy*: Proxy server to use for accessing the web. Use =none= for direct
67 direct connections to the internet.) 63 connections to the internet.
68- Mirror (From where to download packages. Choose the organization you 64- *Mirror*: From where to download packages. Choose the organization you trust
69 trust giving your usage patterns to.) 65 giving your usage patterns to.
70- SSH (Secure SHell remote access server. "Openssh" is part of the 66- *SSH (Secure Shell Protocol)*: Remote access server. =Openssh= is part of the
71 default install image. Use "none" to disable remote login, e.g. on 67 default install image. Use =none= to disable remote login, e.g. on laptops.
72 laptops.) 68- *NTP (Network Time Protocol)*: Client used for keeping the system clock in
73- NTP (Network Time Protocol client used for keeping the system clock in 69 sync with a time-server. Package =chrony= is part of the default install
74 sync with a time-server. Package "chrony" is part of the default 70 image.
75 install image.) 71- *Disk Mode*: Select between diskless (=none=), =data= or =sys=, as described
76- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as 72 above.
77 described above.) 73
78 74Once the setup script is finished, be sure to reboot the machine and remove the
79Once the setup script is finished, be sure to reboot the machine and 75USB device.
80remove the USB device.
81 76
82#+begin_src sh 77#+begin_src sh
83reboot 78reboot
@@ -86,9 +81,8 @@ reboot
86** Post-Installation 81** Post-Installation
87 82
88There are many things you can do once your Alpine Linux system is up and 83There are many things you can do once your Alpine Linux system is up and
89running, and it largely depends on what you'll use the machine for. I'm 84running, and it largely depends on what you'll use the machine for. I'm going to
90going to walk through my personal post-installation setup for my web 85walk through my personal post-installation setup for my web server.
91server.
92 86
931. Upgrade the System 871. Upgrade the System
94 88
@@ -100,9 +94,9 @@ server.
100 94
1012. Adding a User 952. Adding a User
102 96
103 I needed to add a user so that I don't need to log in as root. Note 97 I needed to add a user so that I don't need to log in as root. Note that if
104 that if you're used to using the =sudo= command, you will now need to 98 you're used to using the =sudo= command, you will now need to use the =doas=
105 use the =doas= command on Alpine Linux. 99 command on Alpine Linux.
106 100
107 #+begin_src sh 101 #+begin_src sh
108 apk add doas 102 apk add doas
@@ -118,16 +112,14 @@ server.
118 112
1193. Enable Community Packages 1133. Enable Community Packages
120 114
121 In order to install more common packages that aren't found in the 115 In order to install more common packages that aren't found in the =main=
122 =main= repository, you will need to enable the =community= 116 repository, you will need to enable the =community= repository:
123 repository:
124 117
125 #+begin_src sh 118 #+begin_src sh
126 doas nano /etc/apk/repositories 119 doas nano /etc/apk/repositories
127 #+end_src 120 #+end_src
128 121
129 Uncomment the community line for whichever version of Alpine you're 122 Uncomment the community line for whichever version of Alpine you're running:
130 running:
131 123
132 #+begin_src sh 124 #+begin_src sh
133 /media/usb/apks 125 /media/usb/apks
@@ -140,9 +132,9 @@ server.
140 132
1414. Install Required Packages 1334. Install Required Packages
142 134
143 Now that the community packages are available, you can install any 135 Now that the community packages are available, you can install any packages
144 packages you need. In my case, I installed the web server packages I 136 you need. In my case, I installed the web server packages I need for my
145 need for my services: 137 services:
146 138
147 #+begin_src sh 139 #+begin_src sh
148 doas apk add nano nginx docker docker-compose ufw 140 doas apk add nano nginx docker docker-compose ufw
@@ -150,15 +142,14 @@ server.
150 142
1515. SSH 1435. SSH
152 144
153 If you didn't install OpenSSH as part of the installation, you can do 145 If you didn't install OpenSSH as part of the installation, you can do so now:
154 so now:
155 146
156 #+begin_src sh 147 #+begin_src sh
157 doas apk add openssh 148 doas apk add openssh
158 #+end_src 149 #+end_src
159 150
160 Next, either create a new key or copy your SSH key to the server from 151 Next, either create a new key or copy your SSH key to the server from your
161 your current machines: 152 current machines:
162 153
163 #+begin_src sh 154 #+begin_src sh
164 # Create a new key 155 # Create a new key
@@ -174,9 +165,9 @@ server.
174 165
1756. Firewall 1666. Firewall
176 167
177 Lastly, I installed =ufw= above as my firewall. To set up, default to 168 Lastly, I installed =ufw= above as my firewall. To set up, default to deny
178 deny incoming and allow outgoing connections. Then selectively allow 169 incoming and allow outgoing connections. Then selectively allow other ports
179 other ports or apps as needed. 170 or apps as needed.
180 171
181 #+begin_src sh 172 #+begin_src sh
182 doas ufw default deny incoming 173 doas ufw default deny incoming
@@ -188,8 +179,8 @@ server.
188 179
1897. Change Hostname 1807. Change Hostname
190 181
191 If you don't like the hostname set during installation, you just need 182 If you don't like the hostname set during installation, you just need to edit
192 to edit two files. First, edit the simple hostname file: 183 two files. First, edit the simple hostname file:
193 184
194 #+begin_src sh 185 #+begin_src sh
195 doas nano /etc/hostname 186 doas nano /etc/hostname
@@ -223,17 +214,17 @@ doas chown -R www:www /var/lib/nginx/
223doas chown -R www:www /www 214doas chown -R www:www /www
224#+end_src 215#+end_src
225 216
226If you're running a simple webroot, you can alter the main =nginx.conf= 217If you're running a simple webroot, you can alter the main =nginx.conf= file.
227file. Otherwise, you can drop configuration files in the following 218Otherwise, you can drop configuration files in the following directory. You
228directory. You don't need to enable or symlink the configuration file 219don't need to enable or symlink the configuration file like you do in other
229like you do in other systems. 220systems.
230 221
231#+begin_src sh 222#+begin_src sh
232doas nano /etc/nginx/http.d/example_website.conf 223doas nano /etc/nginx/http.d/example_website.conf
233#+end_src 224#+end_src
234 225
235Once the configuration is set and pointed at the =/www= directory to 226Once the configuration is set and pointed at the =/www= directory to serve
236serve files, enable the Nginx service: 227files, enable the Nginx service:
237 228
238#+begin_src sh 229#+begin_src sh
239# Note that 'default' must be included or Nginx will not start on boot 230# Note that 'default' must be included or Nginx will not start on boot
@@ -242,18 +233,16 @@ doas rc-update add nginx default
242 233
243* Docker Containers 234* Docker Containers
244 235
245Docker works exactly the same as other systems. Either execute a 236Docker works exactly the same as other systems. Either execute a =docker run=
246=docker run= command or create a =docker-compose.yml= file and do 237command or create a =docker-compose.yml= file and do =docker-compose up -d=.
247=docker-compose up -d=.
248 238
249* Git Server 239* Git Server
250 240
251I went in-depth on how to self-host a git server in another post: 241I went in-depth on how to self-host a git server in another post: [[https://cleberg.net/blog/git-server.html][Self-Hosting
252[[../git-server/][Self-Hosting a Personal Git Server]]. 242Guide: Git & cGit]].
253 243
254However, there are a few differences with Alpine. First note that in 244However, there are a few differences with Alpine. First note that in order to
255order to change the =git= user's shell, you must do a few things a 245change the =git= user's shell, you must do a few things a little different:
256little different:
257 246
258#+begin_src sh 247#+begin_src sh
259doas apk add libuser 248doas apk add libuser
@@ -265,12 +254,11 @@ doas lchsh git
265 254
266* Thoughts on Alpine 255* Thoughts on Alpine
267 256
268So far, I love Alpine Linux. I have no complaints about anything at this 257So far, I love Alpine Linux. I have no complaints about anything at this point,
269point, but I'm not completely finished with the migration yet. Once I'm 258but I'm not completely finished with the migration yet. Once I'm able to upgrade
270able to upgrade my hardware to a rack-mounted server, I will migrate 259my hardware to a rack-mounted server, I will migrate Plex and Syncthing over to
271Plex and Syncthing over to Alpine as well - possibly putting Plex into a 260Alpine as well - possibly putting Plex into a container or VM.
272container or VM.
273 261
274The performance is stellar, the =apk= package manager is seamless, and 262The performance is stellar, the =apk= package manager is seamless, and system
275system administration tasks are effortless. My only regret is that I 263administration tasks are effortless. My only regret is that I didn't install
276didn't install Alpine sooner. 264Alpine sooner.
content/blog/2022-10-30-linux-display-manager.org +21 −24
@@ -5,18 +5,16 @@
5 5
6* Display Manager Services 6* Display Manager Services
7 7
8In order to change the 8In order to change the [[https://en.wikipedia.org/wiki/Display_manager][display manager]] on Void Linux - or any other Linux
9[[https://en.wikipedia.org/wiki/Display_manager][display manager]] on 9distribution - you need to identify the currently enabled display manager.
10Void Linux - or any other Linux distro - you need to identify the
11currently enabled display manager.
12 10
13** Disabling the Current Display Manager 11** Disabling the Current Display Manager
14 12
15Void Linux only has one ISO available for download with a pre-built 13Void Linux only has one optical disc image (ISO) available for download with a
16display manager at the time of this post: the XFCE ISO. If you've 14pre-built display manager at the time of this post: the XFCE ISO. If you've
17installed this version, the pre-assigned display manager is =lxdm=. If 15installed this version, the pre-assigned display manager is =lxdm=. If you
18you installed another display manager, replace =lxdm= in the following 16installed another display manager, replace =lxdm= in the following command with
19command with the display manager you have installed. 17the display manager you have installed.
20 18
21To disable =lxdm=, simply remove the service symlink: 19To disable =lxdm=, simply remove the service symlink:
22 20
@@ -26,9 +24,9 @@ sudo rm /var/service/lxdm
26 24
27** Enabling a New Display Manager 25** Enabling a New Display Manager
28 26
29If you want to enable a new display manager, you can do so after =lxdm= 27If you want to enable a new display manager, you can do so after =lxdm= is
30is disabled. Make sure to replace =<new_display_manager>= with your new 28disabled. Make sure to replace =<new_display_manager>= with your new DM, such as
31DM, such as =gdm=, =xdm=, etc. 29=gdm=, =xdm=, etc.
32 30
33#+begin_src sh 31#+begin_src sh
34sudo ln -s /etc/sv/<new_display_manager> /var/service 32sudo ln -s /etc/sv/<new_display_manager> /var/service
@@ -37,8 +35,8 @@ sudo ln -s /etc/sv/<new_display_manager> /var/service
37* Set Up =.xinitrc= 35* Set Up =.xinitrc=
38 36
39Depending on your setup, you may need to create a few X files, such as 37Depending on your setup, you may need to create a few X files, such as
40=~/.xinitrc=. For my personal set-up, I created this file to launch the 38=~/.xinitrc=. For my personal set-up, I created this file to launch the i3wm as
41i3wm as my desktop. 39my desktop.
42 40
43#+begin_src sh 41#+begin_src sh
44nano ~/.xinitrc 42nano ~/.xinitrc
@@ -50,21 +48,20 @@ nano ~/.xinitrc
50exec i3 48exec i3
51#+end_src 49#+end_src
52 50
53If you run a desktop other than i3, simply replace =i3= with the shell 51If you run a desktop other than i3, simply replace =i3= with the shell command
54command that launches that desktop. 52that launches that desktop.
55 53
56* Set Up Your Shell Profile 54* Set Up Your Shell Profile
57 55
58Finally, in order to automatically launch an X session upon login, you 56Finally, in order to automatically launch an X session upon login, you will need
59will need to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files 57to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files for your shell:
60for your shell:
61 58
62#+begin_src sh 59#+begin_src sh
63nano ~/.zprofile 60nano ~/.zprofile
64#+end_src 61#+end_src
65 62
66Add the following snippet to the end of the shell profile file. This 63Add the following snippet to the end of the shell profile file. This will
67will execute the =startx= command upon login. 64execute the =startx= command upon login.
68 65
69#+begin_src sh 66#+begin_src sh
70if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then 67if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
@@ -72,6 +69,6 @@ if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
72fi 69fi
73#+end_src 70#+end_src
74 71
75Alternatively, you can ignore this step and simply choose to manually 72Alternatively, you can ignore this step and simply choose to manually execute
76execute =startx= upon login. This can be useful if you have issues with 73=startx= upon login. This can be useful if you have issues with your desktop or
77your desktop or like to manually launch different desktops by choice. 74like to manually launch different desktops by choice.
content/blog/2022-11-07-self-hosting-matrix.org +41 −48
@@ -5,21 +5,19 @@
5 5
6* Synapse 6* Synapse
7 7
8If you're reading this, you likely know that 8If you're reading this, you likely know that [[https://github.com/matrix-org/synapse/][Synapse]] is a popular [[https://matrix.org/][Matrix]] home
9[[https://github.com/matrix-org/synapse/][Synapse]] is a popular 9server software that allows users to run their own Matrix home server.
10[[https://matrix.org/][Matrix]] home server software that allows users
11to run their own Matrix home server.
12 10
13This post is a short guide describing how I was able to get Synapse 11This post is a short guide describing how I was able to get Synapse working in a
14working in a minimally-usable state on Alpine Linux. 12minimally-usable state on Alpine Linux.
15 13
16* Installation Process 14* Installation Process
17 15
18** Dependencies 16** Dependencies
19 17
20First, since there is no Alpine-specific package for Synapse, we need to 18First, since there is no Alpine-specific package for Synapse, we need to ensure
21ensure that Alpine has the required dependencies for the Python-based 19that Alpine has the required dependencies for the Python-based installation
22installation method. 20method.
23 21
24#+begin_src sh 22#+begin_src sh
25doas apk -U update 23doas apk -U update
@@ -39,10 +37,9 @@ pip install matrix-synapse
39 37
40** Running Synapse 38** Running Synapse
41 39
42Once installed, running Synapse is easy. Simply execute the following 40Once installed, running Synapse is easy. Simply execute the following command,
43command, replacing =example.com= with the domain name that will be used 41replacing =example.com= with the domain name that will be used with this home
44with this home server. This will generate the configuration files needed 42server. This will generate the configuration files needed to run the server.
45to run the server.
46 43
47#+begin_src sh 44#+begin_src sh
48python -m synapse.app.homeserver \ 45python -m synapse.app.homeserver \
@@ -60,17 +57,15 @@ synctl start
60 57
61** Configuring Synapse 58** Configuring Synapse
62 59
63To make any change to Synapse, we need to edit the =YAML= configuration 60To make any change to Synapse, we need to edit the =YAML= configuration file:
64file:
65 61
66#+begin_src sh 62#+begin_src sh
67nano ~/synapse/homeserver.yaml 63nano ~/synapse/homeserver.yaml
68#+end_src 64#+end_src
69 65
70For now, we just need to ensure the =server_name= is accurate. However, 66For now, we just need to ensure the =server_name= is accurate. However, there
71there are a lot of other configuration options found in the 67are a lot of other configuration options found in the [[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring Synapse]]
72[[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring 68documentation that can be enabled/disabled at any point.
73Synapse]] documentation that can be enabled/disabled at any point.
74 69
75#+begin_src yaml 70#+begin_src yaml
76server_name: "example.com" 71server_name: "example.com"
@@ -84,9 +79,9 @@ synctl restart
84 79
85** Nginx Reverse-Proxy 80** Nginx Reverse-Proxy
86 81
87To ensure that Synapse is reachable from the public, we need to connect 82To ensure that Synapse is reachable from the public, we need to connect our
88our domain to the Synapse server. In my case, I use a Nginx 83domain to the Synapse server. In my case, I use a Nginx reverse-proxy for this
89reverse-proxy for this purpose. 84purpose.
90 85
91To use Nginx, we need to create a reverse-proxy configuration file: 86To use Nginx, we need to create a reverse-proxy configuration file:
92 87
@@ -94,9 +89,9 @@ To use Nginx, we need to create a reverse-proxy configuration file:
94doas nano /etc/nginx/http.d/example.com.conf 89doas nano /etc/nginx/http.d/example.com.conf
95#+end_src 90#+end_src
96 91
97If you already have TLS certificates for this domain (=example.com=), 92If you already have TLS (Transport Layer Security) certificates for this domain
98you can simply use the SSL configuration and point toward your TLS 93(=example.com=), you can simply use the SSL (Secure Socket Layer) configuration
99certificates. 94and point toward your TLS certificates.
100 95
101#+begin_src conf 96#+begin_src conf
102server { 97server {
@@ -139,10 +134,9 @@ server {
139} 134}
140#+end_src 135#+end_src
141 136
142If you need to generate TLS certificates (I recommend 137If you need to generate TLS certificates (I recommend [[https://certbot.eff.org/][Certbot]]), you'll need a
143[[https://certbot.eff.org/][Certbot]]), you'll need a more minimal Nginx 138more minimal Nginx conf file before you can use the TLS-enabled example above.
144conf file before you can use the TLS-enabled example above. Instead, use 139Instead, use this configuration file during the Certbot certificate generation
145this configuration file during the Certbot certificate generation
146process: 140process:
147 141
148#+begin_src conf 142#+begin_src conf
@@ -161,13 +155,13 @@ Once you're done editing the Nginx conf file, restart Nginx:
161doas rc-service nginx restart 155doas rc-service nginx restart
162#+end_src 156#+end_src
163 157
164If you still need to generate TLS certificates, run =certbot= now and 158If you still need to generate TLS certificates, run =certbot= now and obtain the
165obtain the certificates. Certbot will ask if you want to use a webroot 159certificates. Certbot will ask if you want to use a webroot or spin up a
166or spin up a temporary web server. I *highly* recommend using the 160temporary web server. I *highly* recommend using the temporary web server due to
167temporary web server due to the many issues with using a webroot. 161the many issues with using a webroot.
168 162
169You will need to stop Nginx in order to user the temporary web server 163You will need to stop Nginx in order to user the temporary web server option
170option with Certbot: 164with Certbot:
171 165
172#+begin_src sh 166#+begin_src sh
173# Stop Nginx so certbot can spin up a temp webserver for cert generation 167# Stop Nginx so certbot can spin up a temp webserver for cert generation
@@ -178,11 +172,11 @@ doas rc-service nginx start
178 172
179** Open Firewall & Router Ports 173** Open Firewall & Router Ports
180 174
181If you use a firewall on the server, open the =8448= port for discovery 175If you use a firewall on the server, open the =8448= port for discovery and
182and federation, as well as the normal web server ports if you're using a 176federation, as well as the normal web server ports if you're using a reverse
183reverse proxy. If you want additional services, such as voice calls, you 177proxy. If you want additional services, such as voice calls, you will need to
184will need to read the Synapse documentation to see which ports need to 178read the Synapse documentation to see which ports need to be opened for those
185be opened for those features. 179features.
186 180
187Here's an example of the Universal Firewall (UFW) software: 181Here's an example of the Universal Firewall (UFW) software:
188 182
@@ -193,14 +187,13 @@ doas ufw allow 8448
193doas ufw allow "Nginx Full" 187doas ufw allow "Nginx Full"
194#+end_src 188#+end_src
195 189
196Remember to forward any Synapse ports, such as =8448=, =80=, and =443=, 190Remember to forward any Synapse ports, such as =8448=, =80=, and =443=, in your
197in your Router from the internet to your server's IP address. 191Router from the internet to your server's internet protocol (IP) address.
198 192
199** Adding Matrix Users 193** Adding Matrix Users
200 194
201Finally, if you didn't enable public registration in the 195Finally, if you didn't enable public registration in the =homeserver.yaml= file,
202=homeserver.yaml= file, you can manually create users via the 196you can manually create users via the command-line:
203command-line:
204 197
205#+begin_src sh 198#+begin_src sh
206cd ~/synapse 199cd ~/synapse
@@ -210,6 +203,6 @@ register_new_matrix_user -c homeserver.yaml
210Remember that the format for federated Matrix usernames is 203Remember that the format for federated Matrix usernames is
211=@username:example.com= when logging in to client applications. 204=@username:example.com= when logging in to client applications.
212 205
213Once Synapse is running, and you have a username, you are ready to log 206Once Synapse is running, and you have a username, you are ready to log in to a
214in to a Matrix client and start sending messages, joining rooms, and 207Matrix client and start sending messages, joining rooms, and utilizing your very
215utilizing your very own Matrix server. 208own Matrix server.
content/blog/2022-11-11-nginx-tmp-errors.org +16 −17
@@ -8,10 +8,10 @@ has occurred multiple times for me./
8 8
9* The Problem 9* The Problem
10 10
11After migrating to a new server OS, I started receiving quite a few 11After migrating to a new server operating system (OS), I started receiving quite
12permission errors like the one below. These popped up for various 12a few permission errors like the one below. These popped up for various
13different websites I'm serving via Nginx on this server, but did not 13different websites I'm serving via Nginx on this server, but did not prevent the
14prevent the website from loading. 14website from loading.
15 15
16I found the errors in the standard log file: 16I found the errors in the standard log file:
17 17
@@ -23,19 +23,18 @@ cat /var/log/nginx/error.log
232022/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/" 232022/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/"
24#+end_src 24#+end_src
25 25
26You can see that the error is =13: Permission denied= and it occurs in 26You can see that the error is =13: Permission denied= and it occurs in the
27the =/var/lib/nginx/tmp/= directory. In my case, I had thousands of 27=/var/lib/nginx/tmp/= directory. In my case, I had thousands of errors where
28errors where Nginx was denied permission to read/write files in this 28Nginx was denied permission to read/write files in this directory.
29directory.
30 29
31So how do I fix it? 30So how do I fix it?
32 31
33* The Solution 32* The Solution
34 33
35In order to resolve the issue, I had to ensure the =/var/lib/nginx= 34In order to resolve the issue, I had to ensure the =/var/lib/nginx= directory is
36directory is owned by Nginx. Mine was owned by the =www= user and Nginx 35owned by Nginx. Mine was owned by the =www= user and Nginx was not able to read
37was not able to read or write files within that directory. This 36or write files within that directory. This prevented Nginx from caching
38prevented Nginx from caching temporary files. 37temporary files.
39 38
40#+begin_src sh 39#+begin_src sh
41# Alpine Linux 40# Alpine Linux
@@ -45,9 +44,9 @@ doas chown -R nginx:nginx /var/lib/nginx
45sudo chown -R nginx:nginx /var/lib/nginx 44sudo chown -R nginx:nginx /var/lib/nginx
46#+end_src 45#+end_src
47 46
48You /may/ also be able to change the =proxy_temp_path= in your Nginx 47You /may/ also be able to change the =proxy_temp_path= in your Nginx config, but
49config, but I did not try this. Here's a suggestion I found online that 48I did not try this. Here's a suggestion I found online that may work if the
50may work if the above solution does not: 49above solution does not:
51 50
52#+begin_src sh 51#+begin_src sh
53nano /etc/nginx/http.d/example.com.conf 52nano /etc/nginx/http.d/example.com.conf
@@ -65,8 +64,8 @@ server {
65} 64}
66#+end_src 65#+end_src
67 66
68Finally, restart Nginx and your server should be able to cache temporary 67Finally, restart Nginx and your server should be able to cache temporary files
69files again. 68again.
70 69
71#+begin_src sh 70#+begin_src sh
72# Alpine Linux (OpenRC) 71# Alpine Linux (OpenRC)
content/blog/2022-11-27-server-build.org +60 −67
@@ -5,39 +5,37 @@
5 5
6* The Dilemma 6* The Dilemma
7 7
8For years, I have been using desktops and a Raspberry Pi as the backbone 8For years, I have been using desktops and a Raspberry Pi as the backbone of my
9of my homelab. I have always wanted to move toward a single dedicated 9homelab. I have always wanted to move toward a single dedicated server that
10server that could handle all of my tasks, but was often put off by the 10could handle all of my tasks, but was often put off by the complexity of the
11complexity of the choices (and financial roadblocks at some times). 11choices (and financial roadblocks at some times).
12 12
13However, after purchasing a small server rack this past year, I have 13However, after purchasing a small server rack this past year, I have been
14been researching to see what kind of rack-mounted server I could buy. I 14researching to see what kind of rack-mounted server I could buy. I initially
15initially bought a Dell R720XD loaded up with everything I could ever 15bought a Dell R720XD loaded up with everything I could ever want in a server -
16want in a server - but I did not care for it. It was far too loud, and 16but I did not care for it. It was far too loud, and the age of the CPU/RAM was
17the age of the CPU/RAM was something I wanted to improve upon. 17something I wanted to improve upon.
18 18
19After returning the R720XD, I decided that I wanted to build my own 19After returning the R720XD, I decided that I wanted to build my own server with
20server with modern, consumer-grade PC components. This time, I am very 20modern, consumer-grade PC components. This time, I am very happy with the
21happy with the results of my server. 21results of my server.
22 22
23* Components 23* Components
24 24
25I'll start by listing all the components I used for this server build: 25I'll start by listing all the components I used for this server build:
26 26
27- *Case*: 27- *Case*: [[https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825][Rosewill RSV-R4100U 4U Server Chassis Rackmount Case]]
28 [[https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825][Rosewill
29 RSV-R4100U 4U Server Chassis Rackmount Case]]
30- *Motherboard*: [[https://nzxt.com/product/n7-b550][NZXT B550]] 28- *Motherboard*: [[https://nzxt.com/product/n7-b550][NZXT B550]]
31- *CPU*: AMD Ryzen 7 5700G with Radeon Graphics 29- *CPU*: AMD Ryzen 7 5700G with Radeon Graphics
32- *GPU*: N/A - I specifically chose one of the few AMD CPUs that support 30- *GPU*: N/A - I specifically chose one of the few AMD CPUs that support onboard
33 onboard graphics. 31 graphics.
34- *RAM*: 64GB RAM (2x32GB) /Max of 128GB RAM on this motherboard/ 32- *RAM*: 64GB RAM (2x32GB) /Max of 128GB RAM on this motherboard/
35- *Boot Drive*: Western Digital 500GB M.2 NVME SSD 33- *Boot Drive*: Western Digital 500GB M.2 NVME SSD
36- *HDD Bay*: 34- *HDD Bay*:
37 - 10TB WD White /(shucked, moved from previous server)/ 35 - 10TB WD White /(shucked, moved from previous server)/
38 - 8TB WD White /(shucked, moved from previous server)/ 36 - 8TB WD White /(shucked, moved from previous server)/
39 - 2 x 8TB WD Red Plus /(Black Friday lined up perfectly with this 37 - 2 x 8TB WD Red Plus /(Black Friday lined up perfectly with this build, so I
40 build, so I grabbed two of these)/ 38 grabbed two of these)/
41- *PSU*: Corsair RM850 PSU 39- *PSU*: Corsair RM850 PSU
42- *Extras*: 40- *Extras*:
43 - Corsair TM3Q Thermal Paste 41 - Corsair TM3Q Thermal Paste
@@ -47,54 +45,52 @@ I'll start by listing all the components I used for this server build:
47 45
48* Building the Server 46* Building the Server
49 47
50This took quite a while for me to build (in my opinion of time), 48This took quite a while for me to build (in my opinion of time), totaling around
51totaling around 3 hours from start to finish. The case has some peculiar 493 hours from start to finish. The case has some peculiar construction, so you
52construction, so you have to completely remove the ODD & HDD cages to 50have to completely remove the ODD & HDD cages to install the motherboard and
53install the motherboard and other components first. 51other components first.
54 52
55Now, I've never built a computer of any kind before, so I was quite 53Now, I've never built a computer of any kind before, so I was quite nervous.
56nervous. Personally, the only challenging part was getting the CPU 54Personally, the only challenging part was getting the CPU cooler to screw into
57cooler to screw into the motherboard without sliding the thermal paste 55the motherboard without sliding the thermal paste around too much underneath.
58around too much underneath. I'm still not entirely sure if I did a great 56I'm still not entirely sure if I did a great job of it, but nothing's broken
59job of it, but nothing's broken yet. 57yet.
60 58
61The main components were all fine and simple. However, installing the 59The main components were all fine and simple. However, installing the hard
62hard drives is slightly tedious as I need to power off the server and 60drives is slightly tedious as I need to power off the server and completely
63completely unscrew the HDD cage to install or remove any drives. 61unscrew the HDD cage to install or remove any drives. Additionally, the drives
64Additionally, the drives are screwed directly into the metal cage with 62are screwed directly into the metal cage with small screws, which are quite a
65small screws, which are quite a bit different from the HDD trays I'm 63bit different from the HDD trays I'm used to in other machines.
66used to in other machines.
67 64
68Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay 65Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay dealing
69dealing with the tedium of removing the cage to install new drives. 66with the tedium of removing the cage to install new drives.
70 67
71* Software 68* Software
72 69
73I'm not going to dive into the software as I have done so in other 70I'm not going to dive into the software as I have done so in other recent posts.
74recent posts. However, I wanted to note that I am using Alpine Linux on 71However, I wanted to note that I am using Alpine Linux on this server and
75this server and hosting most services inside Docker. No virtual machines 72hosting most services inside Docker. No virtual machines (VMs) and very few
76(VMs) and very few bare-metal services. 73bare-metal services.
77 74
78* The Results 75* The Results
79 76
80How did my build turn out? Well, after migrating my other servers and 77How did my build turn out? Well, after migrating my other servers and their
81their services over, I found that my server is blazing fast. The 78services over, I found that my server is blazing fast. The heaviest of my
82heaviest of my applications, Plex, is handled with ease. Even 4k 79applications, Plex, is handled with ease. Even 4k streaming seems to be
83streaming seems to be effortless. 80effortless.
84 81
85I am very happy with the results and will likely continue to improve on 82I am very happy with the results and will likely continue to improve on this
86this server as the years go by rather than buying another used server 83server as the years go by rather than buying another used server online.
87online.
88 84
89** Mistakes I Made 85** Mistakes I Made
90 86
91This post wouldn't be complete unless I wrote about the mistakes I made 87This post wouldn't be complete unless I wrote about the mistakes I made while
92while building. The only real mistake I made beyond a "whoops I dropped 88building. The only real mistake I made beyond a "whoops I dropped a screw"
93a screw" related to airflow and fan direction. 89related to airflow and fan direction.
94 90
95While installing the two new hard drives that showed up on 2022-11-30 91While installing the two new hard drives that showed up on 2022-11-30 and
96and getting ready to install the case in my rack, I noticed that the 92getting ready to install the case in my rack, I noticed that the hard drive
97hard drive temperatures were quite high. 93temperatures were quite high.
98 94
99I used the =smartctl= command for each of my drives (=/dev/sda= through 95I used the =smartctl= command for each of my drives (=/dev/sda= through
100=/dev/sdd=): 96=/dev/sdd=):
@@ -104,9 +100,8 @@ doas smartctl -a /dev/sda | grep Temperature_Celsius
104#+end_src 100#+end_src
105 101
106The results were unusual - all four drives were idling at ~44-46 degrees 102The results were unusual - all four drives were idling at ~44-46 degrees
107Celsius. The only drive that was cooler was my 10TB drive, which was at 103Celsius. The only drive that was cooler was my 10TB drive, which was at 38
10838 degrees Celsius. I noted that this 10TB drive was also closest to the 104degrees Celsius. I noted that this 10TB drive was also closest to the case fan.
109case fan.
110 105
111#+begin_src sh 106#+begin_src sh
112ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 107ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
@@ -120,15 +115,14 @@ ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_
120194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56) 115194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56)
121#+end_src 116#+end_src
122 117
123After looking to see if I could fit more fans into the case, I noticed 118After looking to see if I could fit more fans into the case, I noticed that the
124that the 120mm fan used for intake from the front of the case was 119120mm fan used for intake from the front of the case was actually pushing air
125actually pushing air out of the case by mistake. This fan sits right in 120out of the case by mistake. This fan sits right in front of the hard drive bay.
126front of the hard drive bay.
127 121
128Once I flipped the fan around to act as an intake fan, the temperatures 122Once I flipped the fan around to act as an intake fan, the temperatures dropped
129dropped immediately! They are now idling at ~31-33 degrees Celsius. A 123immediately! They are now idling at ~31-33 degrees Celsius. A single fan
130single fan spinning the wrong way caused my drives to idle 10-15 degrees 124spinning the wrong way caused my drives to idle 10-15 degrees higher than they
131higher than they should have. 125should have.
132 126
133#+begin_src sh 127#+begin_src sh
134ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 128ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
@@ -142,6 +136,5 @@ ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_
142194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46) 136194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46)
143#+end_src 137#+end_src
144 138
145This was a silly error to make, but I'm glad I found it today before I 139This was a silly error to make, but I'm glad I found it today before I screwed
146screwed the case into the rack and made things a lot more tedious to 140the case into the rack and made things a lot more tedious to fix.
147fix.
content/blog/2022-11-29-nginx-referrer-ban-list.org +23 −24
@@ -5,9 +5,9 @@
5 5
6* Creating the Ban List 6* Creating the Ban List
7 7
8In order to ban list referral domains or websites with Nginx, you need 8In order to ban list referral domains or websites with Nginx, you need to create
9to create a ban list file. The file below will accept regexes for 9a ban list file. The file below will accept regexes for different domains or
10different domains or websites you wish to block. 10websites you wish to block.
11 11
12First, create the file in your nginx directory: 12First, create the file in your nginx directory:
13 13
@@ -15,8 +15,8 @@ First, create the file in your nginx directory:
15doas nano /etc/nginx/banlist.conf 15doas nano /etc/nginx/banlist.conf
16#+end_src 16#+end_src
17 17
18Next, paste the following contents in and fill out the regexes with 18Next, paste the following contents in and fill out the regexes with whichever
19whichever domains you're blocking. 19domains you're blocking.
20 20
21#+begin_src conf 21#+begin_src conf
22# /etc/nginx/banlist.conf 22# /etc/nginx/banlist.conf
@@ -33,15 +33,15 @@ map $http_referer $bad_referer {
33 33
34* Configuring Nginx 34* Configuring Nginx
35 35
36In order for the ban list to work, Nginx needs to know it exists and how 36In order for the ban list to work, Nginx needs to know it exists and how to
37to handle it. For this, edit the =nginx.conf= file. 37handle it. For this, edit the =nginx.conf= file.
38 38
39#+begin_src sh 39#+begin_src sh
40doas nano /etc/nginx/nginx.conf 40doas nano /etc/nginx/nginx.conf
41#+end_src 41#+end_src
42 42
43Within this file, find the =http= block and add your ban list file 43Within this file, find the =http= block and add your ban list file location to
44location to the end of the block. 44the end of the block.
45 45
46#+begin_src conf 46#+begin_src conf
47# /etc/nginx/nginx.conf 47# /etc/nginx/nginx.conf
@@ -56,23 +56,22 @@ http {
56 56
57* Enabling the Ban List 57* Enabling the Ban List
58 58
59Finally, we need to take action when a bad referral site is found. To do 59Finally, we need to take action when a bad referral site is found. To do so,
60so, edit the configuration file for your website. For example, I have 60edit the configuration file for your website. For example, I have all website
61all website configuration files in the =http.d= directory. You may have 61configuration files in the =http.d= directory. You may have them in the
62them in the =sites-available= directory on some distributions. 62=sites-available= directory on some distributions.
63 63
64#+begin_src sh 64#+begin_src sh
65doas nano /etc/nginx/http.d/example.com.conf 65doas nano /etc/nginx/http.d/example.com.conf
66#+end_src 66#+end_src
67 67
68Within each website's configuration file, edit the =server= blocks that 68Within each website's configuration file, edit the =server= blocks that are
69are listening to ports 80 and 443 and create a check for the 69listening to ports 80 and 443 and create a check for the =$bad_referrer=
70=$bad_referrer= variable we created in the ban list file. 70variable we created in the ban list file.
71 71
72If a matching site is found, you can return any 72If a matching site is found, you can return any [[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes][HTTP Status Code]] you want. Code
73[[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes][HTTP Status 73403 (Forbidden) is logical in this case since you are preventing a client
74Code]] you want. Code 403 (Forbidden) is logical in this case since you 74connection due to a banned domain.
75are preventing a client connection due to a banned domain.
76 75
77#+begin_src conf 76#+begin_src conf
78server { 77server {
@@ -97,8 +96,8 @@ doas rc-service nginx restart
97 96
98* Testing Results 97* Testing Results
99 98
100In order to test the results, let's curl the contents of our site. To 99In order to test the results, let's curl the contents of our site. To start,
101start, I'll curl the site normally: 100I'll curl the site normally:
102 101
103#+begin_src sh 102#+begin_src sh
104curl https://cleberg.net 103curl https://cleberg.net
@@ -117,8 +116,8 @@ curl --referer https://news.ycombinator.com https://cleberg.net
117#+end_src 116#+end_src
118 117
119This time, I'm met with a 403 Forbidden response page. That means we are 118This time, I'm met with a 403 Forbidden response page. That means we are
120successful and any clients being referred from a banned domain will be 119successful and any clients being referred from a banned domain will be met with
121met with this same response code. 120this same response code.
122 121
123#+begin_src html 122#+begin_src html
124<html> 123<html>
content/blog/2022-12-01-nginx-compression.org +31 −36
@@ -5,24 +5,23 @@
5 5
6* Text Compression 6* Text Compression
7 7
8Text compression allows a web server to serve text-based resources 8Text compression allows a web server to serve text-based resources faster than
9faster than uncompressed data. This can speed up things like First 9uncompressed data. This can speed up things like First Contentful Paint, Tie to
10Contentful Paint, Tie to Interactive, and Speed Index. 10Interactive, and Speed Index.
11 11
12* Enable Nginx Compression with gzip 12* Enable Nginx Compression with gzip
13 13
14In order to enable text compression on Nginx, we need to enable it 14In order to enable text compression on Nginx, we need to enable it within the
15within the configuration file: 15configuration file:
16 16
17#+begin_src sh 17#+begin_src sh
18nano /etc/nginx/nginx.conf 18nano /etc/nginx/nginx.conf
19#+end_src 19#+end_src
20 20
21Within the =http= block, find the section that shows something like the 21Within the =http= block, find the section that shows something like the block
22block below. This is the default gzip configuration I found in my 22below. This is the default gzip configuration I found in my =nginx.conf= file on
23=nginx.conf= file on Alpine Linux 3.17. Yours may look slightly 23Alpine Linux 3.17. Yours may look slightly different, just make sure that you're
24different, just make sure that you're not creating any duplicate gzip 24not creating any duplicate gzip options.
25options.
26 25
27#+begin_src conf 26#+begin_src conf
28# Enable gzipping of responses. 27# Enable gzipping of responses.
@@ -46,31 +45,27 @@ gzip_disable "MSIE [1-6]";
46 45
47* Explanations of ngx_{httpgzipmodule} Options 46* Explanations of ngx_{httpgzipmodule} Options
48 47
49Each of the lines above enables a different aspect of the gzip response 48Each of the lines above enables a different aspect of the gzip response for
50for Nginx. Here are the full explanations: 49Nginx. Here are the full explanations:
51 50
52- =gzip= -- Enables or disables gzipping of responses. 51- =gzip=: Enables or disables gzipping of responses.
53- =gzip_vary= -- Enables or disables inserting the "Vary: 52- =gzip_vary=: Enables or disables inserting the "Vary: Accept-Encoding"
54 Accept-Encoding" response header field if the directives gzip, 53 response header field if the directives gzip, gzip_{static}, or gunzip are
55 gzip_{static}, or gunzip are active. 54 active.
56- =gzip_min_length= -- Sets the minimum length of a response that will 55- =gzip_min_length=: Sets the minimum length of a response that will be
57 be gzipped. The length is determined only from the "Content-Length" 56 gzipped. The length is determined only from the "Content-Length" response
58 response header field. 57 header field.
59- =gzip_proxied= -- Enables or disables gzipping of responses for 58- =gzip_proxied=: Enables or disables gzipping of responses for proxied
60 proxied requests depending on the request and response. The fact that 59 requests depending on the request and response. The fact that the request is
61 the request is proxied is determined by the presence of the "Via" 60 proxied is determined by the presence of the "Via" request header field.
62 request header field. 61- =gzip_types=: Enables gzipping of responses for the specified MIME types in
63- =gzip_types= -- Enables gzipping of responses for the specified MIME 62 addition to "text/html". The special value "*" matches any MIME type (0.8.29).
64 types in addition to "text/html". The special value "*" matches any 63 Responses with the "text/html" type are always compressed.
65 MIME type (0.8.29). Responses with the "text/html" type are always 64- =gzip_disable=: Disables gzipping of responses for requests with
66 compressed. 65 "User-Agent" header fields matching any of the specified regular expressions.
67- =gzip_disable= -- Disables gzipping of responses for requests with 66 - The special mask "msie6" (0.7.12) corresponds to the regular expression
68 "User-Agent" header fields matching any of the specified regular 67 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE 6.0;
69 expressions. 68 ... SV1" is excluded from this mask.
70 - The special mask "msie6" (0.7.12) corresponds to the regular
71 expression "MSIE [4-6].", but works faster. Starting from version
72 0.8.11, "MSIE 6.0; ... SV1" is excluded from this mask.
73 69
74More information on these directives and their options can be found on 70More information on these directives and their options can be found on the
75the [[https://nginx.org/en/docs/http/ngx_http_gzip_module.html][Module 71[[https://nginx.org/en/docs/http/ngx_http_gzip_module.html][Module ngx_{httpgzipmodule}]] page in Nginx's documentation.
76ngx_{httpgzipmodule}]] page in Nginx's documentation.
content/blog/2022-12-07-nginx-wildcard-redirect.org +29 −31
@@ -5,18 +5,18 @@
5 5
6* Problem 6* Problem
7 7
8I recently migrated domains and replaced the old webpage with a simple 8I recently migrated domains and replaced the old webpage with a simple info page
9info page with instructions to users on how to edit their bookmarks and 9with instructions to users on how to edit their bookmarks and URLs to get to the
10URLs to get to the page they were seeking. 10page they were seeking.
11 11
12This was not ideal as it left the work up to the user and may have 12This was not ideal as it left the work up to the user and may have caused
13caused friction for users who accessed my RSS feed. 13friction for users who accessed my RSS (Really Simple Syndication) feed.
14 14
15* Solution 15* Solution
16 16
17Instead, I finally found a solution that allows me to redirect both 17Instead, I finally found a solution that allows me to redirect both subdomains
18subdomains AND trailing content. For example, both of these URLs now 18AND trailing content. For example, both of these URLs now redirect properly
19redirect properly using the logic I'll explain below: 19using the logic I'll explain below:
20 20
21#+begin_src txt 21#+begin_src txt
22# Example 1 - Simple base domain redirect with trailing content 22# Example 1 - Simple base domain redirect with trailing content
@@ -28,19 +28,19 @@ https://libreddit.domain1.com/r/history/comments/7z8cbg/new_discovery_mode_turns
28https://libreddit.domain2.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/ 28https://libreddit.domain2.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/
29#+end_src 29#+end_src
30 30
31Go ahead, try the URLs if you want to test them. 31Go ahead, try the URLs (uniform resource locators) if you want to test them.
32 32
33** Nginx Config 33** Nginx Config
34 34
35To make this possible. I needed to configure a proper redirect scheme in 35To make this possible. I needed to configure a proper redirect scheme in my
36my Nginx configuration. 36Nginx configuration.
37 37
38#+begin_src sh 38#+begin_src sh
39doas nano /etc/nginx/http.d/domain1.conf 39doas nano /etc/nginx/http.d/domain1.conf
40#+end_src 40#+end_src
41 41
42Within this file, I had one block configured to redirect HTTP requests 42Within this file, I had one block configured to redirect HTTP requests to HTTPS
43to HTTPS for the base domain and all subdomains. 43for the base domain and all subdomains.
44 44
45#+begin_src conf 45#+begin_src conf
46server { 46server {
@@ -60,10 +60,9 @@ server {
60} 60}
61#+end_src 61#+end_src
62 62
63For the base domain, I have another =server= block dedicated to 63For the base domain, I have another =server= block dedicated to redirecting all
64redirecting all base domain requests. You can see that the =rewrite= 64base domain requests. You can see that the =rewrite= line is instructing Nginx
65line is instructing Nginx to gather all trailing content and append it 65to gather all trailing content and append it to the new =domain2.com= URL.
66to the new =domain2.com= URL.
67 66
68#+begin_src conf 67#+begin_src conf
69server { 68server {
@@ -79,17 +78,16 @@ server {
79} 78}
80#+end_src 79#+end_src
81 80
82Finally, the tricky part is figuring out how to tell Nginx to redirect 81Finally, the tricky part is figuring out how to tell Nginx to redirect while
83while keeping both a subdomain and trailing content intact. I found that 82keeping both a subdomain and trailing content intact. I found that the easiest
84the easiest way to do this is to give it a =server= block of its own. 83way to do this is to give it a =server= block of its own.
85 84
86Within this block, we need to do some regex on the =server_name= line 85Within this block, we need to do some regex on the =server_name= line before we
87before we can rewrite anything. This creates a variable called 86can rewrite anything. This creates a variable called =subdomain=.
88=subdomain=.
89 87
90Once the server gets to the =rewrite= line, it pulls the =subdomain= 88Once the server gets to the =rewrite= line, it pulls the =subdomain= variable
91variable from above and uses it on the new =domain2.com= domain before 89from above and uses it on the new =domain2.com= domain before appending the
92appending the trailing content (=$request_uri=). 90trailing content (=$request_uri=).
93 91
94#+begin_src conf 92#+begin_src conf
95server { 93server {
@@ -105,15 +103,15 @@ server {
105} 103}
106#+end_src 104#+end_src
107 105
108That's all there is to it. With this, I simply restarted Nginx and 106That's all there is to it. With this, I simply restarted Nginx and watched the
109watched the redirections work in-action. 107redirections work in-action.
110 108
111#+begin_src sh 109#+begin_src sh
112doas rc-service nginx restart 110doas rc-service nginx restart
113#+end_src 111#+end_src
114 112
115Looking back on it, I wish I had done this sooner. Who knows how many 113Looking back on it, I wish I had done this sooner. Who knows how many people
116people went looking for my sites or bookmarks and gave up when they saw 114went looking for my sites or bookmarks and gave up when they saw the redirect
117the redirect instructions page. 115instructions page.
118 116
119Oh well, it's done now. Live and learn. 117Oh well, it's done now. Live and learn.
content/blog/2022-12-17-st.org +20 −26
@@ -5,12 +5,11 @@
5 5
6* st 6* st
7 7
8[[https://st.suckless.org][st]] standards for Simple Terminal, a simple 8[[https://st.suckless.org][st]] standards for Simple Terminal, a simple terminal implementation for X made by
9terminal implementation for X made by the 9the [[https://suckless.org][suckless]] team.
10[[https://suckless.org][suckless]] team.
11 10
12This post walks through the dependencies needed and process to build and 11This post walks through the dependencies needed and process to build and install
13install =st= on Fedora Workstation. 12=st= on Fedora Workstation.
14 13
15** Obtain Files 14** Obtain Files
16 15
@@ -23,8 +22,8 @@ git clone https://git.suckless.org/st && cd st
23 22
24** Dependencies 23** Dependencies
25 24
26Once you have the files and are in the =st= directory, ensure the 25Once you have the files and are in the =st= directory, ensure the following
27following packages are installed. 26packages are installed.
28 27
29#+begin_src sh 28#+begin_src sh
30sudo dnf update && sudo dnf upgrade 29sudo dnf update && sudo dnf upgrade
@@ -39,13 +38,12 @@ Before building, ensure that you read the README file.
39cat README 38cat README
40#+end_src 39#+end_src
41 40
42Once you've read the instructions, open the =config.mk= file and ensure 41Once you've read the instructions, open the =config.mk= file and ensure it
43it matches your setup. If you're not sure, leave the default options 42matches your setup. If you're not sure, leave the default options within the
44within the file. 43file.
45 44
46Finally, you can build =st= with the following command. Ensure you run 45Finally, you can build =st= with the following command. Ensure you run as root
47as root (e.g., =sudo=) or else you may not end up with a usable 46(e.g., =sudo=) or else you may not end up with a usable application file.
48application file.
49 47
50#+begin_src sh 48#+begin_src sh
51sudo make clean install 49sudo make clean install
@@ -54,38 +52,34 @@ sudo make clean install
54** Customization (Patches) 52** Customization (Patches)
55 53
56Note that customizing =st= requires you to modify the source files or to 54Note that customizing =st= requires you to modify the source files or to
57download one of the [[https://st.suckless.org/patches/][available 55download one of the [[https://st.suckless.org/patches/][available patches]] for suckless.org.
58patches]] for suckless.org.
59 56
60If you've already installed =st= and want to customize or install a 57If you've already installed =st= and want to customize or install a patch, start
61patch, start by uninstalling the current program. 58by uninstalling the current program.
62 59
63#+begin_src sh 60#+begin_src sh
64cd ~/suckless/st 61cd ~/suckless/st
65sudo make uninstall 62sudo make uninstall
66#+end_src 63#+end_src
67 64
68Next, grab the =<path>.diff= file from the page of the patch you chose. 65Next, grab the =<path>.diff= file from the page of the patch you chose. For
69For example, I will be using the 66example, I will be using the [[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]] patch in the below example.
70[[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]]
71patch in the below example.
72 67
73#+begin_src sh 68#+begin_src sh
74wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff 69wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff
75#+end_src 70#+end_src
76 71
77Once the file is downloaded inside the =st= folder, apply the patch and 72Once 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 73re-install the program. You may need to install the =patch= command if you don't
79you don't have it installed already (you should have installed it 74have it installed already (you should have installed it above).
80above).
81 75
82#+begin_src sh 76#+begin_src sh
83patch -i st-defaultfontsize-20210225-4ef0cbd.diff 77patch -i st-defaultfontsize-20210225-4ef0cbd.diff
84sudo make clean install 78sudo make clean install
85#+end_src 79#+end_src
86 80
87Once installed, you can use the default font size patch to launch =st= 81Once installed, you can use the default font size patch to launch =st= with any
88with any font size you wish: 82font size you wish:
89 83
90#+begin_src sh 84#+begin_src sh
91st -z 16 85st -z 16
content/blog/2022-12-23-alpine-desktop.org +43 −45
@@ -5,30 +5,31 @@
5 5
6* Isn't Alpine Linux for Servers? 6* Isn't Alpine Linux for Servers?
7 7
8This is a question I see a lot when people are presented with an example 8This is a question I see a lot when people are presented with an example of
9of Alpine Linux running as a desktop OS. 9Alpine Linux running as a desktop operating system (OS).
10 10
11While Alpine is small, fast, and minimal, that doesn't stop it from 11While Alpine is small, fast, and minimal, that doesn't stop it from functioning
12functioning at a productive level for desktop users. 12at a productive level for desktop users.
13 13
14This post is documentation of how I installed and modified Alpine Linux 14This post is documentation of how I installed and modified Alpine Linux to
15to become my daily desktop OS. 15become my daily desktop OS.
16 16
17* Installation 17* Installation
18 18
19Note that I cover the installation of Alpine Linux in my other post, so 19Note that I cover the installation of Alpine Linux in my other post, so I won't
20I won't repeat it here: [[../alpine-linux/][Alpine Linux: My New Server 20repeat it here: [[https://cleberg.net/blog/alpine-linux.html][Alpine Linux Essentials: Installing and Setting Up a Secure
21OS]]. 21Minimal Server]].
22 22
23Basically, get a bootable USB or whatever you prefer with Alpine on it, 23Basically, get a bootable USB (Universal Serial Bus) device or whatever you
24boot the ISO, and run the setup script. 24prefer with Alpine on it, boot the optical disc image (ISO), and run the setup
25script.
25 26
26#+begin_src sh 27#+begin_src sh
27setup-alpine 28setup-alpine
28#+end_src 29#+end_src
29 30
30Once you have gone through all the options and installer finishes 31Once you have gone through all the options and installer finishes without
31without errors, reboot. 32errors, reboot.
32 33
33#+begin_src sh 34#+begin_src sh
34reboot 35reboot
@@ -37,9 +38,9 @@ reboot
37* Initial Setup 38* Initial Setup
38 39
39Once Alpine is installed and the machine has rebooted, login is as root 40Once Alpine is installed and the machine has rebooted, login is as root
40initially or =su= to root once you log in as your user. From here, you 41initially or =su= to root once you log in as your user. From here, you should
41should start by updating and upgrading the system in case the ISO was 42start by updating and upgrading the system in case the ISO was not fully
42not fully up-to-date. 43up-to-date.
43 44
44#+begin_src sh 45#+begin_src sh
45# Update and upgrade system 46# Update and upgrade system
@@ -49,8 +50,8 @@ apk -U update && apk -U upgrade
49apk add nano 50apk add nano
50#+end_src 51#+end_src
51 52
52You need to uncomment the =community= repository for your version of 53You need to uncomment the =community= repository for your version of Alpine
53Alpine Linux. 54Linux.
54 55
55For v3.17, the =repositories= file should look like this: 56For v3.17, the =repositories= file should look like this:
56 57
@@ -77,11 +78,11 @@ adduser $USER wheel
77 78
78* Window Manager (Desktop) 79* Window Manager (Desktop)
79 80
80The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]] 81The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]] has everything you need to get Sway working on
81has everything you need to get Sway working on Alpine. 82Alpine.
82 83
83However, I'll include a brief list of the commands I ran and their 84However, I'll include a brief list of the commands I ran and their purpose for
84purpose for posterity here. 85posterity here.
85 86
86#+begin_src sh 87#+begin_src sh
87# Add eudev and set it up 88# Add eudev and set it up
@@ -125,8 +126,8 @@ apk add \ # Install optional dependencies:
125Once you have the packages installed and set-up, you need to export the 126Once you have the packages installed and set-up, you need to export the
126=XDG_RUNTIME_DIR= upon login. To do this, edit your =.profile= file. 127=XDG_RUNTIME_DIR= upon login. To do this, edit your =.profile= file.
127 128
128If you use another shell, such as =zsh=, you need to edit that shell's 129If you use another shell, such as =zsh=, you need to edit that shell's profile
129profile (e.g., =~/.zprofile=)! 130(e.g., =~/.zprofile=)!
130 131
131#+begin_src sh 132#+begin_src sh
132nano ~/.profile 133nano ~/.profile
@@ -152,8 +153,7 @@ dbus-run-session -- sway
152 153
153** Personal Touches 154** Personal Touches
154 155
155I also added the following packages, per my personal preferences and 156I also added the following packages, per my personal preferences and situation.
156situation.
157 157
158#+begin_src sh 158#+begin_src sh
159doas apk add brightnessctl \ # Brightness controller 159doas apk add brightnessctl \ # Brightness controller
@@ -174,8 +174,8 @@ stored from prior desktops, such as my [[https://git.cleberg.net/dotfiles.git][d
174 174
175** WiFi Issues 175** WiFi Issues
176 176
177I initially tried to set up my Wi-Fi the standard way with =iwd=, but it 177I initially tried to set up my Wi-Fi the standard way with =iwd=, but it didn't
178didn't work. 178work.
179 179
180Here is what I initially tried (I did all of this as =root=): 180Here is what I initially tried (I did all of this as =root=):
181 181
@@ -186,8 +186,7 @@ iwctl station wlan0 connect <SSID> # This will prompt for the password
186rc-update add iwd boot && rc-update add dbus boot 186rc-update add iwd boot && rc-update add dbus boot
187#+end_src 187#+end_src
188 188
189Then, I added the Wi-Fi entry to the bottom of the networking interface 189Then, I added the Wi-Fi entry to the bottom of the networking interface file:
190file:
191 190
192#+begin_src sh 191#+begin_src sh
193nano /etc/network/interfaces 192nano /etc/network/interfaces
@@ -204,13 +203,13 @@ Finally, restart the networking service:
204rc-service networking restart 203rc-service networking restart
205#+end_src 204#+end_src
206 205
207My Wi-Fi interface would receive an IP address from the router, but it 206My Wi-Fi interface would receive an internet protocol (IP) address from the
208could not ping anything in the network. To solve the Wi-Fi issues, I 207router, but it could not ping anything in the network. To solve the Wi-Fi
209originally upgraded to Alpine's =edge= repositories, which was 208issues, I originally upgraded to Alpine's =edge= repositories, which was
210unnecessary. 209unnecessary.
211 210
212Really, the solution was to enable the =NameResolvingService=resolvconf= 211Really, the solution was to enable the =NameResolvingService=resolvconf= in
213in =/etc/iwd/main.conf=. 212=/etc/iwd/main.conf=.
214 213
215#+begin_src sh 214#+begin_src sh
216doas nano /etc/iwd/main.conf 215doas nano /etc/iwd/main.conf
@@ -226,11 +225,10 @@ Once I finished this process, my Wi-Fi is working flawlessly.
226 225
227** Sound Issues 226** Sound Issues
228 227
229Same as with the Wi-Fi, I had no sound and could not control the 228Same as with the Wi-Fi, I had no sound and could not control the mute/unmute or
230mute/unmute or volume buttons on my laptop. 229volume buttons on my laptop.
231 230
232To resolve this, I installed 231To resolve this, I installed [[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]].
233[[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]].
234 232
235#+begin_src sh 233#+begin_src sh
236# Add your user to the following groups 234# Add your user to the following groups
@@ -242,8 +240,8 @@ apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa
242#+end_src 240#+end_src
243 241
244Finally, I needed to add =/usr/libexec/pipewire-launcher= to my 242Finally, I needed to add =/usr/libexec/pipewire-launcher= to my
245=.config/sway/config= file so that Pipewire would run every time I 243=.config/sway/config= file so that Pipewire would run every time I launched
246launched sway. 244sway.
247 245
248#+begin_src sh 246#+begin_src sh
249nano ~/.config/sway/config 247nano ~/.config/sway/config
@@ -260,8 +258,8 @@ bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ to
260bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle 258bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle
261#+end_src 259#+end_src
262 260
263Note that I do not use bluetooth or screen sharing, so I won't cover 261Note that I do not use bluetooth or screen sharing, so I won't cover those
264those options in this post. 262options in this post.
265 263
266Other than these issues, I have a working Alpine desktop. No other 264Other than these issues, I have a working Alpine desktop. No other complaints
267complaints thus far! 265thus far!