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 @@
55
66* The Working World is Changing
77
8There has been a trend for the past few years of companies slowly
9realizing that the pandemic is not just a temporary state that will go
10away eventually and let everything return to the way it was before. In
11terms of business and employment, this means that more and more jobs are
12being offered as permanently remote roles.
8There has been a trend for the past few years of companies slowly realizing that
9the pandemic is not just a temporary state that will go away eventually and let
10everything return to the way it was before. In terms of business and employment,
11this means that more and more jobs are being offered as permanently remote
12roles.
1313
1414I 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
16development field. However, I have found that almost all roles being
17sent to me via recruiters are permanently remote (although most are
18limited to US citizens or even region-locked for companies who only
19operate in select states).
15especially since I did not want to move over into the software development
16field. However, I have found that almost all roles being sent to me via
17recruiters are permanently remote (although most are limited to US citizens or
18even region-locked for companies who only operate in select states).
2019
21I decided to take a look back at my relatively short career so far and
22compare the positive and negative effects of the different work
23environments I've been in.
20I decided to take a look back at my relatively short career so far and compare
21the positive and negative effects of the different work environments I've been
22in.
2423
2524* In-Person Offices
2625
2726** Retail Internship
2827
29I started my first job as a management intern at a busy retail pharmacy,
30working my 40-hour weeks on my feet. As these retail stores don't
31believe in resting or sitting down, you can guarantee that you will
32spend entire shifts standing, walking, or running around the store.
33Unfortunately, I worked at a time when our store didn't have enough
34managers, so I spent the majority of my tenure at the store running and
35breaking a sweat.
36
37Now, things aren't all bad in retail stores like this. It is definitely
38tiring and inefficient to force employees to work constantly, or pretend
39to work if there's nothing to do, and not allow anyone to sit down.
40However, if you are able to operate a retail store with a limited crew
41and provide enough comfort and support, I believe these jobs could be
42both comfortable and efficient.
28I started my first job as a management intern at a busy retail pharmacy, working
29my 40-hour weeks on my feet. As these retail stores don't believe in resting or
30sitting down, you can guarantee that you will spend entire shifts standing,
31walking, or running around the store. Unfortunately, I worked at a time when our
32store didn't have enough managers, so I spent the majority of my tenure at the
33store running and breaking a sweat.
34
35Now, things aren't all bad in retail stores like this. It is definitely tiring
36and inefficient to force employees to work constantly, or pretend to work if
37there's nothing to do, and not allow anyone to sit down. However, if you are
38able to operate a retail store with a limited crew and provide enough comfort
39and support, I believe these jobs could be both comfortable and efficient.
4340
4441** Semi-Private Cubicles
4542
46After about a year, I was able to find another internship - this time,
47it was in my field of interest: internal auditing. This was for a life
48insurance company that was well over 100 years old. The age of the
49company shows if you work there, as most people in management are well
50into their 40s-60s with little to no youthful leadership in the company.
51Likewise, they owned a large headquarters in a nice area of town with
52plenty of space, parking, etc.
53
54One upside is that each person gets their own large L-shaped desk,
55formed into cubicles that house 4 desks/employees. These "pods" of
564-person cubicles are linked throughout each floor of the headquarters
57(except the sales people, who had that open-floor concept going on). The
58walls of the cubicle were tall and provided a lot of privacy and
59sound-proofing, except when I used the standing desk feature (I'm over 6
60feet tall, so probably not an issue for most people).
43After about a year, I was able to find another internship - this time, it was in
44my field of interest: internal auditing. This was for a life insurance company
45that was well over 100 years old. The age of the company shows if you work
46there, as most people in management are well into their 40s-60s with little to
47no youthful leadership in the company. Likewise, they owned a large headquarters
48in a nice area of town with plenty of space, parking, etc.
49
50One upside is that each person gets their own large L-shaped desk, formed into
51cubicles that house 4 desks/employees. These "pods" of 4-person cubicles are
52linked throughout each floor of the headquarters (except the sales people, who
53had that open-floor concept going on). The walls of the cubicle were tall and
54provided a lot of privacy and sound-proofing, except when I used the standing
55desk feature (I'm over 6 feet tall, so probably not an issue for most people).
6156
6257I 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
64chair and chat with my friends without leaving my chair. This is the
65closest I've been to a home office environment (which is my personal
66favorite, as I'll get to later in this post).
58distractions, but also allowed easy access, so I could spin around in my chair
59and chat with my friends without leaving my chair. This is the closest I've been
60to a home office environment (which is my personal favorite, as I'll get to
61later in this post).
6762
6863** Semi-Open Floor Concept
6964
70When I shifted to my first full-time internal audit job out of college,
71I was working at a company that was headquartered on a floor in a
72downtown high-rise building. The company was only about 20 years old
73when I worked there and were trying a lot of new things to attract young
74talent, one of which was a semi-open floor concept for the office. My
75department worked just around the hallway corner from the executive
76offices and used that "modern" layout young tech companies started using
77in the 2000s/2010s.
78
79Each desk was brief, and you could look most coworkers in the face
80without moving from your chair, I hated this so much. Directly to my
81left was the Chief Audit Executive (our department's leading boss), and
82his desk was pointed so that his face would stare straight at my desk
83all day. I spent more time thinking about who was looking at me or
84checking on me than actually working.
85
86The other annoying part of the open concept they used was that the
87kitchen area and pathways were too close to everyone's desks (since the
88desks were spread out, to provide space or something), so noise and
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.
65When I shifted to my first full-time internal audit job out of college, I was
66working at a company that was headquartered on a floor in a downtown high-rise
67building. The company was only about 20 years old when I worked there and were
68trying a lot of new things to attract young talent, one of which was a semi-open
69floor concept for the office. My department worked just around the hallway
70corner from the executive offices and used that "modern" layout young tech
71companies started using in the 2000s/2010s.
72
73Each desk was brief, and you could look most coworkers in the face without
74moving from your chair, I hated this so much. Directly to my left was the Chief
75Audit Executive (our department's leading boss), and his desk was pointed so
76that his face would stare straight at my desk all day. I spent more time
77thinking about who was looking at me or checking on me than actually working.
78
79The other annoying part of the open concept they used was that the kitchen area
80and pathways were too close to everyone's desks (since the desks were spread
81out, to provide space or something), so noise and conversation would be constant
82throughout the day while you try to work. For someone like me, who needs silence
83to get work done, that was a non-starter.
9284
9385** Hotel Office Concept
9486
95I currently work for a company remotely (for now) and travel to the
96office every once in a while for events and to help coach the staff
97underneath me. The office I visit uses the hotel desk concept, where you
98need to check in at a touch screen when you enter the office and "rent"
99a desk for the day. The same goes for offices and meeting rooms.
87I currently work for a company remotely (for now) and travel to the office every
88once in a while for events and to help coach the staff underneath me. The office
89I visit uses the hotel desk concept, where you need to check in at a touch
90screen when you enter the office and "rent" a desk for the day. The same goes
91for offices and meeting rooms.
10092
101These desks are flat-top only and do not have any walls at all. In
102addition, they're stacked with one row of 4 desks facing another row of
1034 desks. These pairs of desk rows are repeated through the office.
93These desks are flat-top only and do not have any walls at all. In addition,
94they're stacked with one row of 4 desks facing another row of 4 desks. These
95pairs of desk rows are repeated through the office.
10496
105This means that when I go, I need to rent a random desk or try to
106remember the unique ID numbers on desks I like. Once I rent it, I have
107to make sure no one sat down in that desk without renting it. Then, I
108can sit down and work, but will probably need to adjust the monitors so
109that I'm not staring in the face of the person across from me all day.
110Finally, I need to wear headphones as this environment does nothing to
111provide you with peace or quiet.
97This means that when I go, I need to rent a random desk or try to remember the
98unique identification (ID) numbers on desks I like. Once I rent it, I have to
99make sure no one sat down in that desk without renting it. Then, I can sit down
100and work, but will probably need to adjust the monitors so that I'm not staring
101in the face of the person across from me all day. Finally, I need to wear
102headphones as this environment does nothing to provide you with peace or quiet.
112103
113Luckily, you can rent offices with doors that offer quiet and privacy,
114which can be very nice if you have a lot of meetings or webinars on a
115certain day.
104Luckily, you can rent offices with doors that offer quiet and privacy, which can
105be very nice if you have a lot of meetings or webinars on a certain day.
116106
117107* Home Office
118108
119Okay, now let's finally get to the home office concept. I have worked
120from home for a little over two years at this point, across three
121different jobs/employers. Over this time, I have experimented with a
122plethora of different organizational ideas, desks, and room layouts to
123find what works best for me.
109Okay, now let's finally get to the home office concept. I have worked from home
110for a little over two years at this point, across three different
111jobs/employers. Over this time, I have experimented with a plethora of different
112organizational ideas, desks, and room layouts to find what works best for me.
124113
125These things might not apply to you, and that's fine. Everyone has a
126different situation, and I really don't think you'll know what works
127until you try.
114These things might not apply to you, and that's fine. Everyone has a different
115situation, and I really don't think you'll know what works until you try.
128116
129117** Tip #1
130118
@@ -134,16 +122,15 @@ Let's start with my top rule for a home office:
134122If you live with others, working in a shared space is not effective.
135123#+end_quote
136124
137It just does not work. If you have another person sleeping in your
138bedroom, it is difficult to manage your work schedule with their
139sleeping/work/school schedule. If they wake up after you need to start
140work, you might wake them up or have to suffer the agony of staring at
141bright screens in a dark room.
125It just does not work. If you have another person sleeping in your bedroom, it
126is difficult to manage your work schedule with their sleeping/work/school
127schedule. If they wake up after you need to start work, you might wake them up
128or have to suffer the agony of staring at bright screens in a dark room.
142129
143In a similar vein, working from a location such as the living room
144likely won't work either. Distractions will come far more frequently:
145televisions, cooking, cleaning, deliveries, etc. If you're like me,
146you'll end up playing a game instead of actually doing any work.
130In a similar vein, working from a location such as the living room likely won't
131work either. Distractions will come far more frequently: televisions, cooking,
132cleaning, deliveries, etc. If you're like me, you'll end up playing a game
133instead of actually doing any work.
147134
148135** Tip #2
149136
@@ -154,39 +141,38 @@ Use the pomodoro method (or something similar) to balance work tasks
154141with personal tasks.
155142#+end_quote
156143
157I use a very casual version of the pomodoro method where I will work for
1581-2 hours (usually set in strict intervals like 1, 1.5, 2 hours) and
159then will allow myself 30-60 minutes for personal tasks. This schedule
160works for me, since my work schedule really only comes to 3-6 hours of
161work per day.
144I use a very casual version of the pomodoro method where I will work for 1-2
145hours (usually set in strict intervals like 1, 1.5, 2 hours) and then will allow
146myself 30-60 minutes for personal tasks. This schedule works for me, since my
147work schedule really only comes to 3-6 hours of work per day.
162148
163In this case, I'll work through my list of tasks for an hour or two and
164then give myself personal time to get drinks and food, wash dishes, put
165clothes in the washer, get the mail, etc. If you're in a convenient
166location, this usually gives time for things like getting groceries (as
167long as you're not a slow shopper).
149In this case, I'll work through my list of tasks for an hour or two and then
150give myself personal time to get drinks and food, wash dishes, put clothes in
151the washer, get the mail, etc. If you're in a convenient location, this usually
152gives time for things like getting groceries (as long as you're not a slow
153shopper).
168154
169155** Tip #3
170156
171While I listed this one as number three, I don't think I'd accomplish
172anything without it:
157While I listed this one as number three, I don't think I'd accomplish anything
158without it:
173159
174160#+begin_quote
175161Document everything: even things you didn't before - such as task lists
176162and notes from casual calls or meetings.
177163#+end_quote
178164
179I've noticed that staying in an office gave me more constant reminders
180of outstanding tasks or facts I had learned in a conversation.
181Translating everything to a digital world has made me lose a bit of that
182focus (perhaps since I don't have visual reminders?).
165I've noticed that staying in an office gave me more constant reminders of
166outstanding tasks or facts I had learned in a conversation. Translating
167everything to a digital world has made me lose a bit of that focus (perhaps
168since I don't have visual reminders?).
183169
184Keeping a running task list of all things I have to do - even potential
185tasks! - has helped me keep up without missing anything small. Likewise,
186keeping notes for ALL meetings and calls, no matter how casual/quick,
187has improved my retention immensely. Beyond helping my mental
188recollection, it has saved me numerous times when I need to do a keyword
189search for some topic that was discussed 6+ months ago.
170Keeping a running task list of all things I have to do - even potential tasks! -
171has helped me keep up without missing anything small. Likewise, keeping notes
172for ALL meetings and calls, no matter how casual/quick, has improved my
173retention immensely. Beyond helping my mental recollection, it has saved me
174numerous times when I need to do a keyword search for some topic that was
175discussed 6+ months ago.
190176
191177** Tip #4
192178
@@ -196,36 +182,32 @@ Okay, last one for now.
196182Keep your work area clean.
197183#+end_quote
198184
199This one is straightforward, but I know some people struggle with
200cleanliness or may not believe it makes a difference. Trust me, keeping
201your desk area clean and organized makes a huge difference, both
202mentally and emotionally.
185This one is straightforward, but I know some people struggle with cleanliness or
186may not believe it makes a difference. Trust me, keeping your desk area clean
187and organized makes a huge difference, both mentally and emotionally.
203188
204Just think about it, you walk into your home office and see a clean desk
205with a laptop, dock, monitors, keyboard, mouse, and a notepad with a pen
206on top.
189Just think about it, you walk into your home office and see a clean desk with a
190laptop, dock, monitors, keyboard, mouse, and a notepad with a pen on top.
207191
208Now imagine the opposite, there's an office with the same equipment, but
209there are clothes hanging on the chair, empty drink bottles, candy
210wrappers and dirty plates. This can take both a mental and emotional
211toll by bringing constant disarray and stress into your working
212environment.
192Now imagine the opposite, there's an office with the same equipment, but there
193are clothes hanging on the chair, empty drink bottles, candy wrappers and dirty
194plates. This can take both a mental and emotional toll by bringing constant
195disarray and stress into your working environment.
213196
214Just keep things clean each day, and you won't need to do any big
215cleaning days to recover.
197Just keep things clean each day, and you won't need to do any big cleaning days
198to recover.
216199
217200* My Preferences
218201
219I've talked about the different environments I've worked in and
220expressed some honest thoughts on pros or cons to each, but what do I
221prefer? Well, if you're reading along, you should be able to tell that I
222much prefer a home office above all else.
202I've talked about the different environments I've worked in and expressed some
203honest thoughts on pros or cons to each, but what do I prefer? Well, if you're
204reading along, you should be able to tell that I much prefer a home office above
205all else.
223206
224Being able to control my own day and allot my time as needed has brought
225a calmness to my life and has allowed me to maximize each day. I feel
226far more effective and efficient in a home office than any other office,
227especially open-office layouts.
207Being able to control my own day and allot my time as needed has brought a
208calmness to my life and has allowed me to maximize each day. I feel far more
209effective and efficient in a home office than any other office, especially
210open-office layouts.
228211
229If I do need to return to an office part-time in the future, I really
230hope the office will have privacy and quietness in order for me to get
231my work done.
212If I do need to return to an office part-time in the future, I really hope the
213office will have privacy and quietness in order for me to get my work done.
content/blog/2022-02-10-njalla-dns-api.org +45 −51
@@ -5,47 +5,43 @@
55
66* Njalla's API
77
8As noted in my recent post about
9[[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from
10Cloudflare]], I was searching for a way to replace my very easy-to-use
11bash script to [[https://cleberg.net/blog/cloudflare-dns-api/][update Cloudflare's
12DNS via their API]].
8As noted in my recent post about [[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from Cloudflare]], I was
9searching for a way to replace my [[https://cleberg.net/blog/cloudflare-dns-api.html][bash script]] to update my domain's =A= record
10with my home's internet protocol (IP) address dynamically.
1311
14To reiterate what I said in those posts, this is a common necessity for
15those of us who have non-static IP addresses that can change at any
16moment due to ISP policy.
12To reiterate what I said in those posts, this is a common necessity for those of
13us who have non-static IP addresses that can change at any moment due to
14internet service provider (ISP) policy.
1715
18In order to keep a home server running smoothly, the server admin needs
19to have a process to constantly monitor their public IP address and
20update their domain's DNS records if it changes.
16In order to keep a home server running smoothly, the server admin needs to have
17a process to constantly monitor their public IP address and update their
18domain's DNS records if it changes.
2119
22This post explains how to use Python to update Njalla's DNS records
23whenever a machine's public IP address changes.
20This post explains how to use Python to update Njalla's DNS (domain name system)
21records whenever a machine's public IP address changes.
2422
2523** Creating a Token
2624
27To use Njalla's API, you will first need to create a token that will be
28used to authenticate you every time you call the API. Luckily, this is
29very easy to do if you have an account with Njalla.
25To use Njalla's API, you will first need to create a token that will be used to
26authenticate you every time you call the API (application programming
27interface). Luckily, this is very easy to do if you have an account with Njalla.
3028
31Simply go the [[https://njal.la/settings/api/][API Settings]] page and
32click the =Add Token= button. Next, enter a name for the token and click
33=Add=.
29Simply go the [[https://njal.la/settings/api/][API Settings]] page and click the =Add Token= button. Next, enter a
30name for the token and click =Add=.
3431
35Finally, click the =Manage= button next to your newly created token and
36copy the =API Token= field.
32Finally, click the =Manage= button next to your newly created token and copy the
33=API Token= field.
3734
3835** Finding the Correct API Request
3936
40Once you have a token, you're ready to call the Njalla API for any
41number of requests. For a full listing of available requests, see the
42[[https://njal.la/api/][Njalla API Documentation]].
37Once you have a token, you're ready to call the Njalla API for any number of
38requests. For a full listing of available requests, see the [[https://njal.la/api/][Njalla API
39Documentation]].
4340
44For this demo, we are using the =list-records= and =edit-record=
45requests.
41For this demo, we are using the =list-records= and =edit-record= requests.
4642
47The =list-records= request requires the following payload to be sent
48when calling the API:
43The =list-records= request requires the following payload to be sent when
44calling the API:
4945
5046#+begin_src txt
5147params: {
@@ -53,8 +49,8 @@ params: {
5349}
5450#+end_src
5551
56The =edit-record= request requires the following payload to be sent when
57calling the API:
52The =edit-record= request requires the following payload to be sent when calling
53the API:
5854
5955#+begin_src txt
6056params: {
@@ -66,14 +62,14 @@ params: {
6662
6763* Server Set-Up
6864
69To create this script, we will be using Python. By default, I use Python
703 on my servers, so please note that I did not test this in Python 2,
71and I do not know if Python 2 will work for this.
65To create this script, we will be using Python. By default, I use Python 3 on my
66servers, so please note that I did not test this in Python 2, and I do not know
67if Python 2 will work for this.
7268
7369** Creating the Script
7470
75First, find a suitable place to create your script. Personally, I just
76create a directory called =ddns= in my home directory:
71First, find a suitable place to create your script. Personally, I just create a
72directory called =ddns= in my home directory:
7773
7874#+begin_src sh
7975mkdir ~/ddns
@@ -85,20 +81,18 @@ Next, create a Python script file:
8581nano ~/ddns/ddns.py
8682#+end_src
8783
88The following code snippet is quite long, so I won't go into depth on
89each part. However, I suggest you read through the entire script before
90running it; it is quite simple and contains comments to help explain
91each code block.
84The following code snippet is quite long, so I won't go into depth on each part.
85However, I suggest you read through the entire script before running it; it is
86quite simple and contains comments to help explain each code block.
9287
93:warning: *Note*: You will need to update the following variables for
94this to work:
88*Note*: You will need to update the following variables for this to work:
9589
9690- =token=: This is the Njalla API token you created earlier.
9791- =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
99 subdomains found under the TLD.
100- =subdomains=: If =include_subdomains= = =True=, you can include your
101 list of subdomains to be modified here.
92- =include_subdomains=: Set this to =True= if you also want to modify subdomains
93 found under the TLD (top-level domain).
94- =subdomains=: If =include_subdomains= = =True=, you can include your list of
95 subdomains to be modified here.
10296
10397#+begin_src python
10498#!/usr/bin/python
@@ -183,8 +177,8 @@ for record in data['records']:
183177
184178** Running the Script
185179
186Once you've created the script and are ready to test it, run the
187following command:
180Once you've created the script and are ready to test it, run the following
181command:
188182
189183#+begin_src sh
190184python3 ~/ddns/ddns.py
@@ -192,15 +186,15 @@ python3 ~/ddns/ddns.py
192186
193187** Setting the Script to Run Automatically
194188
195To make sure the scripts run automatically, add it to the =cron= file so
196that it will run on a schedule. To do this, open the =cron= file:
189To make sure the scripts run automatically, add it to the =cron= file so that it
190will run on a schedule. To do this, open the =cron= file:
197191
198192#+begin_src sh
199193crontab -e
200194#+end_src
201195
202In the cron file, paste the following at the bottom of the editor in
203order to check the IP every five minutes:
196In the cron file, paste the following at the bottom of the editor in order to
197check the IP every five minutes:
204198
205199#+begin_src sh
206200*/5 * * * * python3 /home/<your_username>/ddns/ddns.py
content/blog/2022-02-16-debian-and-nginx.org +57 −64
@@ -3,34 +3,31 @@
33#+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.
44#+slug: debian-and-nginx
55
6* Server OS: Debian
6* Server Operating System (OS): Debian
77
8I've used various Linux distributions throughout the years, but I've
9never used anything except Ubuntu for my servers. Why? I really have no
10idea, mostly just comfort around the commands and software availability.
8I've used various Linux distributions throughout the years, but I've never used
9anything except Ubuntu for my servers. Why? I really have no idea, mostly just
10comfort around the commands and software availability.
1111
12However, I have always wanted to try Debian as a server OS after testing
13it out in a VM a few years ago (side-note: I'd love to try Alpine too,
14but I always struggle with compatibility). So, I decided to launch a new
15VPS and use [[https://www.debian.org][Debian]] 11 as the OS. Spoiler
16alert: it feels identical to Ubuntu for my purposes.
12However, I have always wanted to try Debian as a server OS after testing it out
13in a VM a few years ago (side-note: I'd love to try Alpine too, but I always
14struggle with compatibility). So, I decided to launch a new VPS and use [[https://www.debian.org][Debian]]
1511 as the operating system (OS). Spoiler alert: it feels identical to Ubuntu for my purposes.
1716
18I did the normal things when first launching the VPS, such as adding a
19new user, locking down SSH, etc. If you want to see that level of
20detail, read my other post about
21[[https://cleberg.net/blog/how-to-set-up-a-vps-web-server/][How to Set
22Up a VPS Web Server]].
17I did the normal things when first launching the VPS (virtual private server),
18such as adding a new user, locking down SSH (secure shell protocol), etc. If you
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
20Web Server]].
2321
24All of this has been similar, apart from small things such as the
25location of users' home folders. No complaints at all from me - Debian
26seems great.
22All of this has been similar, apart from small things such as the location of
23users' home folders. No complaints at all from me - Debian seems great.
2724
2825* Web Server: Nginx
2926
30Once I had the baseline server configuration set-up for Debian, I moved
31on to trying out [[https://nginx.org][Nginx]] as my web server software.
32This required me to install the =nginx= and =ufw= packages, as well as
33setting up the initial UFW config:
27Once I had the baseline server configuration set-up for Debian, I moved on to
28trying out [[https://nginx.org][Nginx]] as my web server software. This required me to install the
29=nginx= and =ufw= packages, as well as setting up the initial UFW (Uncomplicated
30Firewall) config:
3431
3532#+begin_src sh
3633sudo apt install nginx ufw
@@ -41,9 +38,9 @@ sudo ufw status
4138sudo systemctl status nginx
4239#+end_src
4340
44Once I had the firewall set, I moved on to creating the directories and
45files for my website. This is very easy and is basically the same as
46setting up an Apache server, so no struggles here.
41Once I had the firewall set, I moved on to creating the directories and files
42for my website. This is very easy and is basically the same as setting up an
43Apache server, so no struggles here.
4744
4845#+begin_src sh
4946sudo mkdir -p /var/www/your_domain/html
@@ -52,17 +49,17 @@ sudo chmod -R 755 /var/www/your_domain
5249nano /var/www/your_domain/html/index.html
5350#+end_src
5451
55The next part, creating the Nginx configuration files, is quite a bit
56different from Apache. First, you need to create the files in the
57=sites-available= folder and symlink it the =sites-enabled= folder.
52The next part, creating the Nginx configuration files, is quite a bit different
53from Apache. First, you need to create the files in the =sites-available= folder
54and symlink it the =sites-enabled= folder.
5855
59Creating the config file for your domain:
56Creating the configuration file for your domain:
6057
6158#+begin_src sh
6259sudo nano /etc/nginx/sites-available/your_domain
6360#+end_src
6461
65Default content for an Nginx config file:
62Default content for an Nginx configuration file:
6663
6764#+begin_src sh
6865server {
@@ -87,9 +84,9 @@ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
8784#+end_src
8885
8986This 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)!
9188
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)
9390certificate for my domains using the following commands:
9491
9592#+begin_src sh
@@ -99,16 +96,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
9996sudo certbot --nginx
10097#+end_src
10198
102Now that certbot ran successfully and updated my Nginx config files to
99Now that =certbot= ran successfully and updated my Nginx configuration files to
103100include 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
105is recommended for security purposes; you can even test a website's HTTP
106header security at [[https://securityheaders.com/][Security Headers]].
101configuration file to include security HTTP headers. This part is optional, but
102is recommended for security purposes; you can even test a website's HTTP header
103security at [[https://securityheaders.com/][Security Headers]].
107104
108The configuration below shows a set-up where you only want your website
109to serve content from its own domain, except for images and scripts,
110which may come from =nullitics.com=. All other content would be blocked
111from loading in a browser.
105The configuration below shows a set-up where you only want your website to serve
106content from its own domain, except for images and scripts, which may come from
107=nullitics.com=. All other content would be blocked from loading in a browser.
112108
113109#+begin_src sh
114110sudo nano /etc/nginx/sites-available/your_domain
@@ -133,35 +129,32 @@ sudo systemctl restart nginx
133129
134130** Nginx vs. Apache
135131
136As I stated at the beginning, my historical hesitation with trying Nginx
137was that the differences in configuration formats scared me away from
138leaving Apache. However, I prefer Nginx to Apache for a few reasons:
132As I stated at the beginning, my historical hesitation with trying Nginx was
133that the differences in configuration formats scared me away from leaving
134Apache. However, I prefer Nginx to Apache for a few reasons:
139135
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
141137 approach for HTTP vs. HTTPS (=your_domain.conf= and
142138 =your_domain-le-ssl.conf=).
1432. Symlinking new configurations files and reloading Nginx are way
144 easier than Apache's process of having to enable headers with
145 =a2enmod mod_headers=, enable PHP with =a2enmod php= (plus any other
146 mods you need), and then enabling sites with =a2ensite=, and THEN
147 reloading Apache.
1483. The contents of the Nginx config files seem more organized and
149 logical with the curly-bracket approach. This is a minor reason, but
150 everything just felt cleaner while I was installing my sites and that
151 had a big quality of life impact on the installation for me.
152
153They're both great software packages, but Nginx just seems more
154organized and easier to use these days. I will certainly be exploring
155the Nginx docs to see what other fun things I can do with all of this.
1392. Symlinking new configurations files and reloading Nginx are way easier than
140 Apache's process of having to enable headers with =a2enmod mod_headers=,
141 enable PHP with =a2enmod php= (plus any other mods you need), and then
142 enabling sites with =a2ensite=, and THEN reloading Apache.
1433. The contents of the Nginx configuration files seem more organized and logical
144 with the curly-bracket approach. This is a minor reason, but everything just
145 felt cleaner while I was installing my sites and that had a big quality of
146 life impact on the installation for me.
147
148They're both great software packages, but Nginx just seems more organized and
149easier to use these days. I will certainly be exploring the Nginx docs to see
150what other fun things I can do with all of this.
156151
157152* Gemini Server: Agate
158153
159Finally, I set up the Agate software on this server again to host my
160Gemini server content, using Rust as I have before. You can read my
161other post for more information on installing Agate:
162[[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini
163Server]].
154Finally, I set up the Agate software on this server again to host my Gemini
155server content, using Rust as I have before. You can read my other post for more
156information on installing Agate: [[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini Server]].
164157
165All in all, Debian + Nginx is very slick and I prefer it over my old
166combination of Ubuntu + Apache (although it's really just Nginx > Apache
167for me, since Debian seems mostly the same as Ubuntu is so far).
158All in all, Debian + Nginx is very slick and I prefer it over my old combination
159of Ubuntu + Apache (although it's really just Nginx > Apache for me, since
160Debian seems mostly the same as Ubuntu is so far).
content/blog/2022-02-17-exiftool.org +18 −20
@@ -5,14 +5,14 @@
55
66** Why Strip Metadata?
77
8Okay, so you want to strip metadata from your photos. Perhaps you take
9pictures of very rare birds, and the location metadata is a gold mine
10for poachers, or perhaps you're just privacy-oriented like me and prefer
11to strip metadata from publicly-available images.
8Okay, so you want to strip metadata from your photos. Perhaps you take pictures
9of very rare birds, and the location metadata is a gold mine for poachers, or
10perhaps you're just privacy-oriented like me and prefer to strip metadata from
11publicly-available images.
1212
13There are various components of image metadata that you may want to
14delete before releasing a photo to the public. Here's an incomplete list
15of things I could easily see just by inspecting a photo on my laptop:
13There are various components of image metadata that you may want to delete
14before releasing a photo to the public. Here's an incomplete list of things I
15could easily see just by inspecting a photo on my laptop:
1616
1717- Location (Latitude & Longitude)
1818- Dimensions
@@ -25,15 +25,14 @@ of things I could easily see just by inspecting a photo on my laptop:
2525- Metering Mode
2626- F Number
2727
28Regardless of your reasoning, I'm going to explain how I used the
29=exiftool= package in Linux to automatically strip metadata from all
30images in a directory (+ subdirectories).
28Regardless of your reasoning, I'm going to explain how I used the =exiftool=
29package in Linux to automatically strip metadata from all images in a directory
30(+ subdirectories).
3131
3232** Installing =exiftool=
3333
34First things first: we need to install the tool. I'm running Debian 11
35on my server (Ubuntu will work the same), so the command is as simple
36as:
34First things first: we need to install the tool. I'm running Debian 11 on my
35server (Ubuntu will work the same), so the command is as simple as:
3736
3837#+begin_src sh
3938sudo apt install exiftool
@@ -44,16 +43,15 @@ distributions, but I really only care to test out this one package.
4443
4544** Recursively Strip Data
4645
47I actually use this tool extensively to strip any photos uploaded to the
48website that serves all the images for my blog (=img.cleberg.net=).
46I actually use this tool extensively to strip any photos uploaded to the website
47that serves all the images for my blog (=img.cleberg.net=).
4948
50The following command is incredibly useful and can be modified to
51include any image extensions that =exiftool= supports:
49The following command is incredibly useful and can be modified to include any
50image extensions that =exiftool= supports:
5251
5352#+begin_src sh
5453exiftool -r -all= -ext jpg -ext png /path/to/directory/
5554#+end_src
5655
57The output of the command will let you know how many directories were
58scanned, how many images were updated, and how many images were
59unchanged.
56The output of the command will let you know how many directories were scanned,
57how many images were updated, and how many images were unchanged.
content/blog/2022-02-20-nginx-caching.org +31 −37
@@ -5,16 +5,15 @@
55
66* Update Your Nginx Config to Cache Static Files
77
8If you run a website on Nginx that serves static content (i.e., content
9that is not dynamic and changing with interactions from the user), you
10would likely benefit from caching that content on the client-side. If
11you're used to Apache and looking for the Nginx equivalent, this post
12should help.
8If you run a website on Nginx that serves static content (i.e., content that is
9not dynamic and changing with interactions from the user), you would likely
10benefit from caching that content on the client-side. If you're used to Apache
11and looking for the Nginx equivalent, this post should help.
1312
14Luckily, setting up the cache is as easy as identifying the file types
15you want to cache and determining the expiration length. To include more
16file types, simply use the bar separator (=|=) and type the new file
17extension you want to include.
13Luckily, setting up the cache is as easy as identifying the file types you want
14to cache and determining the expiration length. To include more file types,
15simply use the bar separator (=|=) and type the new file extension you want to
16include.
1817
1918#+begin_src config
2019server {
@@ -28,41 +27,36 @@ server {
2827}
2928#+end_src
3029
31I have seen some people who prefer to set =expires= as =365d= or even
32=max=, but that is only for stable, infrequently changing websites. As
33my site often changes (i.e., I'm never content with my website), I need
34to know that my readers are seeing the new content without waiting too
35long.
30I have seen some people who prefer to set =expires= as =365d= or even =max=, but
31that is only for stable, infrequently changing websites. As my site often
32changes (i.e., I'm never content with my website), I need to know that my
33readers are seeing the new content without waiting too long.
3634
37So, I went ahead and set the expiration date at =30d=, which is short
38enough to refresh for readers but long enough that clients/browsers
39won't be re-requesting the static files too often, hopefully resulting
40in faster loading times, as images should be the only thing slowing down
41my site.
35So, I went ahead and set the expiration date at =30d=, which is short enough to
36refresh for readers but long enough that clients/browsers won't be re-requesting
37the static files too often, hopefully resulting in faster loading times, as
38images should be the only thing slowing down my site.
4239
4340* Testing Results
4441
45To test my changes to the Nginx configuration, I used the
46[[https://addons.mozilla.org/en-US/firefox/addon/http-header-live/][HTTP
47Header Live]] extension on my Gecko browser and used the sidebar to
48inspect the headers of a recent image from my blog.
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]]
43extension on my Gecko browser and used the sidebar to inspect the headers of a
44recent image from my blog.
4945
50In the image below, you can see that the =Cache-Control= header is now
51present and set to 2592000, which is 30 days represented in seconds (30
52days _ 24 hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000
53seconds).
46In the image below, you can see that the =Cache-Control= header is now present
47and set to 2592000, which is 30 days represented in seconds (30 days _ 24
48hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds).
5449
55The =Expires= field is now showing 22 March 2022, which is 30 days from
56the day of this post, 20 February 2022.
50The =Expires= field is now showing 22 March 2022, which is 30 days from the day
51of this post, 20 February 2022.
5752
5853* Caveats
5954
60Remember that this caching system is *client-side*, which means that
61content is only cached for as long as a client allows it. For example,
62my browser purges all caches, data, etc. upon exit, so this caching
63policy will only work as long as my browser remains open and running.
55Remember that this caching system is *client-side*, which means that content is
56only cached for as long as a client allows it. For example, my browser purges
57all caches, data, etc. upon exit, so this caching policy will only work as long
58as my browser remains open and running.
6459
65If you need to test updates to your site, you'll need to clear the cache
66to see updates for any file extension you configured. This can often be
67done with the =Shift + F5= or =Ctrl + F5= key combinations in most
68browsers.
60If you need to test updates to your site, you'll need to clear the cache to see
61updates for any file extension you configured. This can often be done with the
62=Shift + F5= or =Ctrl + F5= key combinations in most browsers.
content/blog/2022-02-22-tuesday.org +20 −27
@@ -5,34 +5,27 @@
55
66* Tuesday, Twosday
77
8I'm taking a break from my usual technology-related posts and writing
9about something a little more enjoyable today.
8I'm taking a break from my usual technology-related posts and writing about
9something a little more enjoyable today.
1010
11Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is
12Twosday.
11Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is Twosday.
1312
1413Let's look at everything that fell in place today:
1514
161. Written in the =m-dd-yy= or =dd-m-yy= formats, today is 2-22-22 or
17 22-2-22, which is a neat little palindrome in either format. (The
18 last ubiquitous six-digit palindrome was 1-11-11.)
192. Today is Tuesday, which is why everyone is using the nickname Twosday
20 to call out these similarities.
213. Falling on Tuesday means today is the 2nd day of the week (for most
22 cultures. For the US, it's the 3rd day of the week since we start on
23 Sunday).
244. The only culture I could find with a connection to a =2= is that some
25 Slavic languages derived their version of Tuesday from the Old Church
26 Slavonic word =въторъ=, meaning "the second."
275. Written in the classic monospaced, digital font (think of digital
28 clocks from the 80s/90s), there is nice symmetry to the numbers
29 ([[https://img.cleberg.net/blog/20220222-tuesday/digital_font.webp][view
30 the image here]]!).
316. This one isn't naturally-occurring, but it seems people around the
32 world are celebrating the day. For example, a group is putting
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.
151. Written in the =m-dd-yy= or =dd-m-yy= formats, today is 2-22-22 or 22-2-22,
16 which is a neat little palindrome in either format. (The last ubiquitous
17 six-digit palindrome was 1-11-11.)
182. Today is Tuesday, which is why everyone is using the nickname Twosday to call
19 out these similarities.
203. Falling on Tuesday means today is the 2nd day of the week (for most cultures.
21 For the US, it's the 3rd day of the week since we start on Sunday).
224. The only culture I could find with a connection to a =2= is that some Slavic
23 languages derived their version of Tuesday from the Old Church Slavonic word
24 =въторъ=, meaning "the second."
255. Written in the classic monospaced, digital font (think of digital clocks from
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]]!).
276. This one isn't naturally-occurring, but it seems people around the world are
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
29 222 couples at the California State Capitol in Sacramento]], concluding at
30 exactly 2:22 PM. These couples will record their marriage dates as 2-22-22
31 2:22 PM. Tickets were on sale for $222.22.
content/blog/2022-03-02-reliable-notes.org +80 −105
@@ -4,154 +4,129 @@
44#+slug: reliable-notes
55
66* Choosing Durable File Formats
7:PROPERTIES:
8:CUSTOM_ID: choosing-durable-file-formats
9:END:
107
118#+begin_quote
12TL;DR: Write in a format that can be easily rendered and read in
13plain-text mode (e.g., =.txt=, =.md=, etc.).
9TL;DR (Too Long; Didn't Read): Write in a format that can be easily rendered and
10read in plain-text mode (e.g., =.txt=, =.md=, etc.).
1411#+end_quote
1512
1613As 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
18can be written down in a note and saved digitally, with no cost to
19myself. Unlike paper copies that need physical storage space, digital
20files simply need space on your local disk or cloud storage, which is
21fairly abundant these days.
22
23However, I had a historical struggle with migration of notes between
24different apps that require different formats and applied proprietary
25styling. This meant that I had to go through each note during migration
26and edit the file to look presentable again.
27
28For the last year or two, I have written everything exclusively in
29[[https://en.wikipedia.org/wiki/Markdown][Markdown]] format. Small
30notes, long-form writings, and even these blog posts are all written in
31Markdown.
32
33Why Markdown? While I do appreciate the simplicity of plain-text files
34without any formatting, I often need visual cues such as heading and
35code blocks to keep my thoughts straight. Markdown provides a minimal
36set of styling indicators for me to style my notes without adding any
37proprietary, embedded data into the files. If I want a top-level
38heading, I simply add a hash (=#=) before the line. An added bonus is
39that even if a system doesn't understand Markdown, it will render it as
40plain-text and I can read it just as easily.
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:
14note-taking is always growing. Everything I learn or need to remember can be
15written down in a note and saved digitally, with no cost to myself. Unlike paper
16copies that need physical storage space, digital files simply need space on your
17local disk or cloud storage, which is fairly abundant these days.
18
19However, I had a historical struggle with migration of notes between different
20apps that require different formats and applied proprietary styling. This meant
21that I had to go through each note during migration and edit the file to look
22presentable again.
23
24For the last year or two, I have written everything exclusively in [[https://en.wikipedia.org/wiki/Markdown][Markdown]]
25format. Small notes, long-form writings, and even these blog posts are all
26written in Markdown.
27
28Why Markdown? While I do appreciate the simplicity of plain-text files without
29any formatting, I often need visual cues such as heading and code blocks to keep
30my thoughts straight. Markdown provides a minimal set of styling indicators for
31me to style my notes without adding any proprietary, embedded data into the
32files. If I want a top-level heading, I simply add a hash (=#=) before the line.
33An added bonus is that even if a system doesn't understand Markdown, it will
34render it as plain-text and I can read it just as easily.
35
36For example, here's how TextEdit on macOS will open and display a Markdown file
37in plain-text, since it does contain any features to preview Markdown as HTML:
4538
4639#+caption: Plain Text Markdown
4740[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.webp]]
4841
4942** 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).
5843
59You can use whatever sync software you want - syncing plain-text or
60markdown files is incredibly easy and fast, since the files are
61generally tiny.
44In order to read and edit my notes across platforms, I use my personal cloud
45storage through Tresorit due to its native integration with macOS and iOS file
46managers. In addition, Tresorit works well on Debian-based Linux distributions,
47which I used before macOS (and will likely switch back to in a few years).
6248
63Since the cloud storage syncs files automatically, there is no need for
64me to sync anything manually or kick-off a sync job to update my files.
65This means that I can edit on mobile, and it takes about 5-10 seconds to
66see the changes on desktop.
49You can use whatever sync software you want - syncing plain-text or markdown
50files is incredibly easy and fast, since the files are generally tiny.
51
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.
6756
6857*** Version Control with Git
6958:PROPERTIES:
7059:CUSTOM_ID: version-control-with-git
7160:END:
72A different approach I've contemplated is storing my notes and
73attachments is using a hosted Git repository to track changes to the
74files. However, I don't want to rely on an external service that could
75potentially see into my data, even if the repository is private.
61A different approach I've contemplated is storing my notes and attachments is
62using a hosted Git repository to track changes to the files. However, I don't
63want to rely on an external service that could potentially see into my data,
64even if the repository is private.
7665
77I might just do =git init= locally and then commit my changes each time
78I write or update a note, but that seems to be a lot of work just for
79tracking changes - which I don't necessarily care to know.
66I might just do =git init= locally and then commit my changes each time I write
67or update a note, but that seems to be a lot of work just for tracking changes -
68which I don't necessarily care to know.
8069
8170*** Backups!
8271:PROPERTIES:
8372:CUSTOM_ID: backups
8473:END:
85One small addition to the storage/sync conversation is the idea of
86backups. Personally, I manually create periodic backups of my entire
87cloud storage, compress it into an archive, and store it on my home
88server.
74One small addition to the storage/sync conversation is the idea of backups.
75Personally, I manually create periodic backups of my entire cloud storage,
76compress it into an archive, and store it on my home server.
8977
90To improve my workflow, I am going to be exploring options to
91automatically compress the mounted cloud directory and send it over to
92my server on a set schedule.
78To improve my workflow, I am going to be exploring options to automatically
79compress the mounted cloud directory and send it over to my server on a set
80schedule.
9381
9482** Writing on Desktop
95:PROPERTIES:
96:CUSTOM_ID: writing-on-desktop
97:END:
9883
9984#+begin_quote
100*Update (06.14.22)*: Since writing this post, I have reverted to simply
101keeping my =notes= folder open and opening notes individually in
102TextEdit for a more minimal and relaxing writing experience on the
103desktop.
85*Update (06.14.22)*: Since writing this post, I have reverted to simply keeping
86my =notes= folder open and opening notes individually in TextEdit for a more
87minimal and relaxing writing experience on the desktop.
10488#+end_quote
10589
106The bulk of my writing occurs in a desktop environment, with a full
107keyboard layout and wide screen. I don't illustrate with a smart pen, I
108rarely use embedded images, and I love being able to see all of my
109notes/directories in a sidebar.
90The bulk of my writing occurs in a desktop environment, with a full keyboard
91layout and wide screen. I don't illustrate with a smart pen, I rarely use
92embedded images, and I love being able to see all of my notes/directories in a
93sidebar.
11094
111With this simple set of requirements, I chose
112[[https://obsidian.md][Obsidian]] as my desktop text editor. Obsidian
113has some in-depth tools like a graph view, command palette, mentions,
114etc., but I've found that using it as a simple Markdown editor is
95With this simple set of requirements, I chose [[https://obsidian.md][Obsidian]] as my desktop text
96editor. Obsidian has some in-depth tools like a graph view, command palette,
97mentions, etc., but I've found that using it as a simple Markdown editor is
11598incredibly easy and straightforward.
11699
117Here's an example of how my Markdown notes look when opened in
118plain-text mode:
100Here's an example of how my Markdown notes look when opened in plain-text mode:
119101
120102#+caption: Obsidian Markdown Source Mode
121103[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.webp]]
122104
123Here's the "live preview" version, where the Markdown is rendered into
124its HTML format:
105Here's the "live preview" version, where the Markdown is rendered into its HTML
106format:
125107
126108#+caption: Obsidian Markdown Live Preview
127109[[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.webp]]
128110
129111*** Programming on Desktop
130:PROPERTIES:
131:CUSTOM_ID: programming-on-desktop
132:END:
133While I was writing this, I realized I should specify that I don't use
134the same editor for writing notes and for writing code. For programming
135purposes, I use [[https://vscodium.com][VSCodium]] as my development
136IDE.
112
113While I was writing this, I realized I should specify that I don't use the same
114editor for writing notes and for writing code. For programming purposes, I use
115[[https://vscodium.com][VSCodium]] as my development IDE.
137116
138117** Writing on Mobile
139:PROPERTIES:
140:CUSTOM_ID: writing-on-mobile
141:END:
142Personally, I write very little on mobile, except when needing to take
143important notes on-the-go. Any long-form writing, journals, etc. are
144done at home, where I always have my laptop available.
145
146I wanted a simple and foolproof editor for iOS, preferably open-source.
147After a long journey of testing the few (& terrible) open-source iOS
148note-taking apps, I finally found a phenomenal one:
149[[https://github.com/simonbs/runestone][Runestone]]. This app is
150fantastic for note-taking, has plenty of optional features, and
151integrates natively with the iOS file manager.
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.
118
119Personally, I write very little on mobile, except when needing to take important
120notes on-the-go. Any long-form writing, journals, etc. are done at home, where I
121always have my laptop available.
122
123I wanted a simple and foolproof editor for iOS, preferably open-source. After a
124long journey of testing the few (& terrible) open-source iOS note-taking apps, I
125finally found a phenomenal one: [[https://github.com/simonbs/runestone][Runestone]]. This app is fantastic for
126note-taking, has plenty of optional features, and integrates natively with the
127iOS file manager.
128
129This app opens the iOS file manager and allows you to click any file you want,
130opens it up in an editor, and lets me save and close out of that note.
156131
157132Quite simple but effective.
content/blog/2022-03-03-financial-database.org +69 −90
@@ -4,60 +4,49 @@
44#+slug: financial-database
55
66* Personal Financial Tracking
7:PROPERTIES:
8:CUSTOM_ID: personal-financial-tracking
9:END:
10For the last 6-ish years, I've tracked my finances in a spreadsheet.
11This is common practice in the business world, but any good dev will
12cringe at the thought of storing long-term data in a spreadsheet. A
13spreadsheet is not for long-term storage or as a source of data to pull
14data/reports.
15
16As I wanted to expand the functionality of my financial data (e.g.,
17adding more reports), I decided to migrate the data into a database. To
18run reports, I would query the database and use a language like Python
19or Javascript to process the data, perform calculations, and visualize
20the data.
7
8For the last 6-ish years, I've tracked my finances in a spreadsheet. This is
9common practice in the business world, but any good dev will cringe at the
10thought of storing long-term data in a spreadsheet. A spreadsheet is not for
11long-term storage or as a source of data to pull data/reports.
12
13As I wanted to expand the functionality of my financial data (e.g., adding more
14reports), I decided to migrate the data into a database. To run reports, I would
15query the database and use a language like Python or Javascript to process the
16data, perform calculations, and visualize the data.
2117
2218* SQLite
23:PROPERTIES:
24:CUSTOM_ID: sqlite
25:END:
26When choosing the type of database I wanted to use for this project, I
27was split between three options:
28
291. MySQL: The database I have the most experience with and have used for
30 years.
19
20When choosing the type of database I wanted to use for this project, I was split
21between three options:
22
231. MySQL: The database I have the most experience with and have used for years.
31242. 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
33 moderate experience.
34
35I ended up choosing SQLite since it can be maintained within a single
36=.sqlite= file, which allows me more flexibility for storage and backup.
37I keep this file in my cloud storage and pull it up whenever needed.
38
39** GUI Editing
40:PROPERTIES:
41:CUSTOM_ID: gui-editing
42:END:
43Since I didn't want to try and import 1000--1500 records into my new
44database via the command line, I opted to use
45[[https://sqlitebrowser.org/][DB Browser for SQLite (DB4S)]] as a GUI
46tool. This application is excellent, and I don't see myself going back
47to the CLI when working in this database.
253. SQLite: A database that I've used for a couple projects and have moderate
26 experience.
27
28I ended up choosing SQLite since it can be maintained within a single =.sqlite=
29file, which allows me more flexibility for storage and backup. I keep this file
30in my cloud storage and pull it up whenever needed.
31
32** Visual Editing
33
34Since I didn't want to try and import 1000--1500 records into my new database
35via the command line, I opted to use [[https://sqlitebrowser.org/][DB Browser for SQLite (DB4S)]] as a GUI
36(graphical user interface) tool. This application is excellent, and I don't see
37myself going back to the CLI (command line interface) when working in this
38database.
4839
4940DB4S 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,
511290 account statements, and 126 pay statements. Overall, I'm guessing
52this took anywhere between 4--8 hours. In comparison, it probably took
53me 2-3 days to initially create the spreadsheet.
41straight into the SQL table. I used this process for all 36 accounts, 1290
42account statements, and 126 pay statements. Overall, I'm guessing this took
43anywhere between 4--8 hours. In comparison, it probably took me 2-3 days to
44initially create the spreadsheet.
5445
5546** Schema
56:PROPERTIES:
57:CUSTOM_ID: schema
58:END:
59The schema for this database is actually extremely simple and involves
60only three tables (for now):
47
48The schema for this database is actually extremely simple and involves only
49three tables (for now):
6150
62511. Accounts
63522. Statements
@@ -65,9 +54,9 @@ only three tables (for now):
6554
6655*Accounts*
6756
68The Accounts table contains summary information about an account, such
69as a car loan or a credit card. By viewing this table, you can find
70high-level data, such as interest rate, credit line, or owner.
57The Accounts table contains summary information about an account, such as a car
58loan or a credit card. By viewing this table, you can find high-level data, such
59as interest rate, credit line, or owner.
7160
7261#+begin_src sql
7362CREATE TABLE "Accounts" (
@@ -85,10 +74,10 @@ CREATE TABLE "Accounts" (
8574
8675*Statements*
8776
88The Statements table uses the same unique identifier as the Accounts
89table, meaning you can join the tables to find a monthly statement for
90any of the accounts listed in the Accounts table. Each statement has an
91account ID, statement date, and total balance.
77The Statements table uses the same unique identifier as the Accounts table,
78meaning you can join the tables to find a monthly statement for any of the
79accounts listed in the Accounts table. Each statement has an account identified
80(ID), statement date, and total balance.
9281
9382#+begin_src sql
9483CREATE TABLE "Statements" (
@@ -103,10 +92,10 @@ CREATE TABLE "Statements" (
10392
10493*Payroll*
10594
106The Payroll table is a separate entity, unrelated to the Accounts or
107Statements tables. This table contains all information you would find on
108a pay statement from an employer. As you change employers or obtain new
109perks/benefits, just add new columns to adapt to the new data.
95The Payroll table is a separate entity, unrelated to the Accounts or Statements
96tables. This table contains all information you would find on a pay statement
97from an employer. As you change employers or obtain new perks/benefits, just add
98new columns to adapt to the new data.
11099
111100#+begin_src sql
112101CREATE TABLE "Payroll" (
@@ -141,23 +130,18 @@ CREATE TABLE "Payroll" (
141130#+end_src
142131
143132** 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.
150133
151In order to explore and create the reports I'm interested in, I utilized
152a two-part process involving Jupyter Notebooks and Python scripts.
134Once I created the database tables and imported all my data, the only step left
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.
153139
154140*** Step 1: Jupyter Notebooks
155:PROPERTIES:
156:CUSTOM_ID: step-1-jupyter-notebooks
157:END:
141
158142When 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
160=Accounts= table until I found the following useful information:
143cell-by-cell, I use Jupyter Notebooks. For example, I explored the =Accounts=
144table until I found the following useful information:
161145
162146#+begin_src python
163147import sqlite3
@@ -182,12 +166,9 @@ df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type',
182166#+end_src
183167
184168*** Step 2: Python Scripts
185:PROPERTIES:
186:CUSTOM_ID: step-2-python-scripts
187:END:
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:
169
170Once I explored enough through the notebooks and had a list of reports I wanted,
171I moved on to create a Python project with the following structure:
191172
192173#+begin_src txt
193174finance/
@@ -212,16 +193,15 @@ This structure allows me to:
212193
2131941. Compile all required python packages into =requirements.txt= for easy
214195 installation if I move to a new machine.
2152. Activate a virtual environment in =venv/= so I don't need to maintain
216 a system-wide Python environment just for this project.
2173. Keep my =notebooks/= folder to continuously explore the data as I see
218 fit.
1962. Activate a virtual environment in =venv/= so I don't need to maintain a
197 system-wide Python environment just for this project.
1983. Keep my =notebooks/= folder to continuously explore the data as I see fit.
2191994. Maintain a local copy of the database in =src/= for easy access.
2202005. Export reports, images, HTML files, etc. to =public/=.
221201
222Now, onto the differences between the code in a Jupyter Notebook and the
223actual Python files. To create the report in the Notebook snippet above,
224I created the following function inside =process.py=:
202Now, onto the differences between the code in a Jupyter Notebook and the actual
203Python files. To create the report in the Notebook snippet above, I created the
204following function inside =process.py=:
225205
226206#+begin_src python
227207# Create summary pie chart
@@ -258,11 +238,10 @@ Other charts generated by this project include:
258238
259239- Charts of account balances over time.
260240- Line chart of effective tax rate (taxes divided by taxable income).
261- Salary projections and error limits using past income and inflation
262 rates.
241- Salary projections and error limits using past income and inflation rates.
263242- Multi-line chart of gross income, taxable income, and net income.
264243
265The best thing about this project? I can improve it at any given time,
266shaping it into whatever helps me the most for that time. I imagine that
267I will be introducing an asset tracking table soon to track the
268depreciating value of cars, houses, etc. Who knows what's next?
244The best thing about this project? I can improve it at any given time, shaping
245it into whatever helps me the most for that time. I imagine that I will be
246introducing an asset tracking table soon to track the depreciating value of
247cars, houses, etc. Who knows what's next?
content/blog/2022-03-08-plex-migration.org +101 −137
@@ -4,18 +4,15 @@
44#+slug: plex-migration
55
66* Migration Phases
7:PROPERTIES:
8:CUSTOM_ID: migration-phases
9:END:
10I recently decided to migrate my server from an old OptiPlex desktop
11machine to a custom-built tower with better hardware in every category.
12In order to do this, I would need to properly migrate a full Plex
13installation.
14
15The second part of this migration is that the new server uses an Nvidia
16GPU and does not have any integrated graphics, which requires extra work
17for installation, but provides much better hardware transcoding options
18for Plex.
7
8I recently decided to migrate my server from an old OptiPlex desktop machine to
9a custom-built tower with better hardware in every category. In order to do
10this, I would need to properly migrate a full Plex installation.
11
12The second part of this migration is that the new server uses an Nvidia GPU
13(graphics processing unit) and does not have any integrated graphics, which
14requires extra work for installation, but provides much better hardware
15transcoding options for Plex.
1916
2017Therefore, I have broken this migration down into three phases:
2118
@@ -24,50 +21,41 @@ Therefore, I have broken this migration down into three phases:
24213. Configure GPU Transcoding
2522
2623* Phase 1: Configure the New Server
27:PROPERTIES:
28:CUSTOM_ID: phase-1-configure-the-new-server
29:END:
30** Choosing an OS
31:PROPERTIES:
32:CUSTOM_ID: choosing-an-os
33:END:
24
25** Choosing an Operating System (OS)
26
3427In 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
36that I have encountered numerous issues installing other Linux
37distributions properly with Nvidia graphics, I chose
38[[https://ubuntu.com/download/server][Ubuntu Server]].
28appropriate OS and install it on the machine. Given that I have encountered
29numerous issues installing other Linux distributions properly with Nvidia
30graphics, I chose [[https://ubuntu.com/download/server][Ubuntu Server]].
3931
40The first step is to create a bootable USB with Ubuntu Server. This is
41easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on
42many different platforms. Just download the Ubuntu Server =.iso= image,
43launch Etcher, and install the =.iso= on the USB.
32The first step is to create a bootable USB (universal serial bus) with Ubuntu
33Server. This is easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on many different platforms.
34Just download the Ubuntu Server =.iso= image, launch Etcher, and install the
35=.iso= on the USB.
4436
45Once the USB is created, insert it into my server, reboot, and click
46=Esc= (or any of the =F1-12= keys) until the BIOS menu appears. Finally,
47launch the USB boot drive.
37Once the USB is created, insert it into my server, reboot, and click =Esc= (or
38any of the =F1-12= keys) until the BIOS (Basic Input/Output System) menu
39appears. Finally, launch the USB boot drive.
4840
4941** Booting with Nvidia
50:PROPERTIES:
51:CUSTOM_ID: booting-with-nvidia
52:END:
42
5343In order to install Ubuntu Server with an Nvidia Graphics card (and no
54integrated graphics on this device for some reason), you'll have to
55configure the boot menu to allow different graphics drivers to be
56loaded.
44integrated graphics on this device for some reason), you'll have to configure
45the boot menu to allow different graphics drivers to be loaded.
5746
58When booting from the USB, the machine will launch the initial
59installation menu. From this menu, type =e= to view the default command
60options that come with the device - it's a good idea to take a photo of
61this screen, so you can enter these commands on the next screen (along
62with adding support for Nvidia).
47When booting from the USB, the machine will launch the initial installation
48menu. From this menu, type =e= to view the default command options that come
49with the device - it's a good idea to take a photo of this screen, so you can
50enter these commands on the next screen (along with adding support for Nvidia).
6351
64Finally, type =Ctrl + C= to enter the command line. From this command
65line, enter the commands found on the =e= screen. /Remember to add
66=nomodeset= to the =linux ...= line so that your Nvidia device will
67display the installation screens properly!/
52Finally, type =Ctrl + C= to enter the command line. From this command line,
53enter the commands found on the =e= screen. Remember to add =nomodeset= to the
54=linux ...= line so that your Nvidia device will display the installation
55screens properly!
6856
69Here's an example of the commands I pulled from the =e= screen and
70entered on the command line.
57Here's an example of the commands I pulled from the =e= screen and entered on
58the command line.
7159
7260#+begin_src sh
7361setparams 'Install Ubuntu Server'
@@ -77,12 +65,11 @@ initrd /casper/initrd
7765boot
7866#+end_src
7967
80Once the machine is rebooted, enter the =e= screen again and add
81=nomodeset= to the =linux ...= line again and press =Ctrl + X= to save
82the boot options.
68Once the machine is rebooted, enter the =e= screen again and add =nomodeset= to
69the =linux ...= line again and press =Ctrl + X= to save the boot options.
8370
84The machine is now fully installed and can properly display on an
85external display using the Nvidia GPU.
71The machine is now fully installed and can properly display on an external
72display using the Nvidia GPU.
8673
8774Always remember to update and upgrade on a new installation:
8875
@@ -91,40 +78,29 @@ sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
9178#+end_src
9279
9380* Phase 2: Migrate Plex Data & Devices
94:PROPERTIES:
95:CUSTOM_ID: phase-2-migrate-plex-data-devices
96:END:
97This phase uses the great Plex article on migrations
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.
81
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
83Another System]]) and adds a bit more information to help with commands and
84context.
10185
10286** Terminology
103:PROPERTIES:
104:CUSTOM_ID: terminology
105:END:
106*Source:* The original server that is being replaced.\\
107*Destination:* The new server.\\
108*Client:* Any application that can be used to modify settings for both
109source/destination.
87
88- *Source:* The original server that is being replaced.
89- *Destination:* The new server.
90- *Client:* Any application that can be used to modify settings for both
91 source/destination.
11092
11193** Step 01: [Client] Update Settings
112:PROPERTIES:
113:CUSTOM_ID: step-01-client-update-settings
114:END:
115Open up a Plex app and /disable/ the =Account= > =Library= >
116=Empty trash automatically after every scan= preference for the source
117server.
94
95Open up a Plex app and /disable/ the =Account= > =Library= > =Empty trash
96automatically after every scan= preference for the source server.
11897
11998** 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.
12599
126Execute the following commands on the destination server to install
127Plex:
100Open up the [[https://www.plex.tv/media-server-downloads/][Plex Media Server download page]] and copy the link for the
101appropriate platform.
102
103Execute the following commands on the destination server to install Plex:
128104
129105#+begin_src sh
130106wget <url>
@@ -133,50 +109,44 @@ sudo systemctl stop plexmediaserver.service
133109#+end_src
134110
135111** Step 03: [Source] Stop Plex & Migrate Data
136:PROPERTIES:
137:CUSTOM_ID: step-03-source-stop-plex-migrate-data
138:END:
139First, stop the Plex service so that no data is created or modified
140during the migration.
112
113First, stop the Plex service so that no data is created or modified during the
114migration.
141115
142116#+begin_src sh
143117sudo systemctl stop plexmediaserver.service
144118#+end_src
145119
146Next, copy the data to the new server. To find where the Plex data
147directory is located, Plex has another excellent article available:
148[[https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/][Where
149is the Plex Media Server data directory located?]].
120Next, copy the data to the new server. To find where the Plex data directory is
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
122Server data directory located?]].
150123
151There are many ways to copy the data to the new server and will largely
152depend on the size of the folder being copied. Personally, my data
153folder was ~23GB and I opted to simply use the =scp= command to copy the
154files over SSH.
124There are many ways to copy the data to the new server and will largely depend
125on the size of the folder being copied. Personally, my data folder was ~23GB and
126I opted to simply use the =scp= command to copy the files over SSH (Secure Shell
127Protocol).
155128
156This process was throttled by the old server's slow HDD and ports and
157took approximately 90 minutes to complete. In comparison, moving the
158data from the new server's =home/user/= directory to the
159=/var/.../Plex Media Server= directory took 2-3 minutes.
129This process was throttled by the old server's slow hard disk and ports and took
130approximately 90 minutes to complete. In comparison, moving the data from the
131new server's =home/user/= directory to the =/var/.../Plex Media Server=
132directory took 2-3 minutes.
160133
161134#+begin_src sh
162135scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'"
163136#+end_src
164137
165138** Step 04: [Destination] Update File Permissions
166:PROPERTIES:
167:CUSTOM_ID: step-04-destination-update-file-permissions
168:END:
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:
139
140In case you move the data directory to a common area on the new server, it will
141have to be moved to the proper location before Plex can function properly:
172142
173143#+begin_src sh
174144mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/
175145#+end_src
176146
177To ensure permissions were retained properly, the server will need to
178show that all files and folders in the data directory are owned by
179=plex:plex= (or whichever user is running the Plex application).
147To ensure permissions were retained properly, the server will need to show that
148all files and folders in the data directory are owned by =plex:plex= (or
149whichever user is running the Plex application).
180150
181151#+begin_src sh
182152sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"
@@ -190,43 +160,37 @@ sudo systemctl status plexmediaserver.service
190160#+end_src
191161
192162** Step 05: [Client] Update Libraries & Metadata
193:PROPERTIES:
194:CUSTOM_ID: step-05-client-update-libraries-metadata
195:END:
196The first step - now that the new server is up and running - is to sign
197out of the client and sign back in. Once this is done, update any
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.
163
164The first step - now that the new server is up and running - is to sign out of
165the client and sign back in. Once this is done, update any library locations, if
166necessary. This was unnecessary in my case since I simply moved my storage
167drives from the source server to the destination server.
201168
202169Next, perform the following actions in the client:
203170
2041. On the left sidebar, click =More= > Three-Dot Menu >
205 =Scan Library Files=
2062. /Enable/ the =Account= > =Library= >
207 =Empty trash automatically after every scan= preference for the
208 source server.
2093. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server=
210 > =Empty Trash=
2114. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server=
212 > =Clean Bundles=
2135. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server=
214 > =Optimize Database=
1711. On the left sidebar, click =More= > Three-Dot Menu > =Scan Library Files=
1722. /Enable/ the =Account= > =Library= > =Empty trash automatically after every
173 scan= preference for the source server.
1743. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Empty
175 Trash=
1764. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Clean
177 Bundles=
1785. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= >
179 =Optimize Database=
215180
216Finally, double-check the Remote Access settings to make sure no changes
217have caused issues with accessing the server from outside the network.
181Finally, double-check the Remote Access settings to make sure no changes have
182caused issues with accessing the server from outside the network.
218183
219In my case, I use a single port forwarding rule in my router and needed
220to update the Local LAN IP Address to the new server IP address.
184In my case, I use a single port forwarding rule in my router and needed to
185update the Local LAN (local area network) IP (internet protocol) Address to the
186new server IP address.
221187
222188* Phase 3: Configure GPU Transcoding
223:PROPERTIES:
224:CUSTOM_ID: phase-3-configure-gpu-transcoding
225:END:
226The final piece to the migration is enabling hardware transcoding so
227that Plex can fully utilize the new Nvidia GPU available in the server.
228The first step is to install Nvidia graphics drivers. This process may
229take a few minutes, but the commands are pretty simple:
189
190The final piece to the migration is enabling hardware transcoding so that Plex
191can fully utilize the new Nvidia GPU available in the server. The first step is
192to install Nvidia graphics drivers. This process may take a few minutes, but the
193commands are pretty simple:
230194
231195#+begin_src sh
232196sudo add-apt-repository ppa:graphics-drivers/ppa
@@ -248,5 +212,5 @@ following command to view the available GPUs, statistics, and processes:
248212sudo nvidia-smi
249213#+end_src
250214
251Finally, enable hardware transcoding settings in the Plex application to
252finish the process.
215Finally, enable hardware transcoding settings in the Plex application to finish
216the process.
content/blog/2022-03-23-cloudflare-dns-api.org +20 −22
@@ -7,15 +7,15 @@
77:PROPERTIES:
88:CUSTOM_ID: ddns-dynamic-dns
99:END:
10If you're hosting a service from a location with dynamic DNS (where your
11IP may change at any time), you must have a solution to update the DNS
12so that you can access your service even when the IP of the server
13changes.
10If you're hosting a service from a location with DDNS (Dynamic Domain Name
11System), where your internet protocol (IP)address may change at any time, you
12must have a solution to update the DNS (Domain Name System) so that you can
13access your service even when the IP of the server changes.
1414
15The process below uses the [[https://api.cloudflare.com/][Cloudflare
16API]] to update DNS =A= and =AAAA= records with the server's current IP.
17If you use another DNS provider, you will have to find a way to update
18your DNS (or find a way to get a static IP).
15The process below uses the [[https://api.cloudflare.com/][Cloudflare API]] (application programming interface) to
16update DNS =A= and =AAAA= records with the server's current IP. If you use
17another DNS provider, you will have to find a way to update your DNS (or find a
18way to get a static IP).
1919
2020First, install =jq= since we will use it in the next script:
2121
@@ -23,18 +23,16 @@ First, install =jq= since we will use it in the next script:
2323sudo apt install jq
2424#+end_src
2525
26Next, create a location for your DDNS update scripts and open the first
27script:
26Next, create a location for your DDNS update scripts and open the first script:
2827
2928#+begin_src sh
3029mkdir ~/ddns
3130nano ~/ddns/update.sh
3231#+end_src
3332
34The following =update.sh= script will take all of your domains and
35subdomains and check Cloudflare to see if the current =A= and =AAAA=
36records match your server's IP address. If not, it will update the
37records.
33The following =update.sh= script will take all of your domains and subdomains
34and check Cloudflare to see if the current =A= and =AAAA= records match your
35server's IP address. If not, it will update the records.
3836
3937#+begin_src sh
4038# file: update.sh
@@ -60,16 +58,16 @@ do
6058done
6159#+end_src
6260
63Next, open up the =ddns.sh= script. Paste the following into the script
64and update the =api_token= and =email= variables.
61Next, open up the =ddns.sh= script. Paste the following into the script and
62update the =api_token= and =email= variables.
6563
6664#+begin_src sh
6765nano ~/ddns/ddns.sh
6866#+end_src
6967
70*Note*: If you want your DNS records to be proxied through Cloudflare,
71find and update the following snippet: ="proxied":false}"= to say =true=
72instead of =false=.
68*Note*: If you want your DNS records to be proxied through Cloudflare, find and
69update the following snippet: ="proxied":false}"= to say =true= instead of
70=false=.
7371
7472#+begin_src sh
7573# file: ddns.sh
@@ -179,14 +177,14 @@ You can test the script by running it manually:
179177./update.sh
180178#+end_src
181179
182To make sure the scripts run automatically, add it to the =cron= file so
183that it will run on a schedule. To do this, open the cron file:
180To make sure the scripts run automatically, add it to the =cron= file so that it
181will run on a schedule. To do this, open the cron file:
184182
185183#+begin_src sh
186184crontab -e
187185#+end_src
188186
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:
190188
191189#+begin_src sh
192190,*/5 ** ** ** ** bash /home/<your_username>/ddns/update.sh
content/blog/2022-03-23-nextcloud-on-ubuntu.org +28 −33
@@ -7,8 +7,8 @@
77:PROPERTIES:
88:CUSTOM_ID: what-is-nextcloud
99:END:
10[[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for
11storage, communications, editing, calendar, contacts, and more.
10[[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for storage, communications, editing,
11calendar, contacts, and more.
1212
1313This tutorial assumes that you have an Ubuntu server and a domain name
1414configured 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
2929:PROPERTIES:
3030:CUSTOM_ID: set-up-mysql
3131:END:
32Next, you will need to log in to MySQL as the =root= user of the
33machine.
32Next, you will need to log in to MySQL as the =root= user of the machine.
3433
3534#+begin_src sh
3635sudo mysql -uroot -p
3736#+end_src
3837
39Once you've logged in, you must create a new user so that Nextcloud can
40manage the database. You will also create a =nextcloud= database and
41assign privileges:
38Once you've logged in, you must create a new user so that Nextcloud can manage
39the database. You will also create a =nextcloud= database and assign privileges:
4240
4341#+begin_src sql
4442CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
@@ -52,15 +50,12 @@ quit;
5250:PROPERTIES:
5351:CUSTOM_ID: download-install-nextcloud
5452:END:
55To download Nextcloud, go the
56[[https://nextcloud.com/install/#instructions-server][Nextcloud
57downloads page]], click on =Archive File= and right-click the big blue
58button to copy the link.
53To download Nextcloud, go the [[https://nextcloud.com/install/#instructions-server][Nextcloud downloads page]], click on =Archive File=
54and right-click the big blue button to copy the link.
5955
60Then, go to your server and enter the following commands to download,
61unzip, and move the files to your destination directory. This example
62uses =example.com= as the destination, but you can put it wherever you
63want to server your files from.
56Then, go to your server and enter the following commands to download, unzip, and
57move the files to your destination directory. This example uses =example.com= as
58the destination, but you can put it wherever you want to server your files from.
6459
6560#+begin_src sh
6661wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip
@@ -73,9 +68,9 @@ sudo cp -r nextcloud /var/www/example.com
7368:PROPERTIES:
7469:CUSTOM_ID: configure-the-apache-web-server
7570:END:
76Now that the database is set up and Nextcloud is installed, you need to
77set up the Apache configuration files to tell the server how to handle
78requests for =example.com/nextcloud=.
71Now that the database is set up and Nextcloud is installed, you need to set up
72the Apache configuration files to tell the server how to handle requests for
73=example.com/nextcloud=.
7974
8075First, open the following file in the editor:
8176
@@ -83,8 +78,8 @@ First, open the following file in the editor:
8378sudo nano /etc/apache2/sites-available/nextcloud.conf
8479#+end_src
8580
86Once the editor is open, paste the following information in. Then, save
87and close the file.
81Once the editor is open, paste the following information in. Then, save and
82close the file.
8883
8984#+begin_src config
9085<VirtualHost *:80>
@@ -113,14 +108,14 @@ Once the file is saved, enable it with Apache:
113108sudo a2ensite nextcloud.conf
114109#+end_src
115110
116Next, enable the Apache mods required by Nextcloud:
111Next, enable the Apache modules required by Nextcloud:
117112
118113#+begin_src sh
119114sudo a2enmod rewrite headers env dir mime
120115#+end_src
121116
122Finally, restart Apache. If any errors arise, you must solve those
123before continuing.
117Finally, restart Apache. If any errors arise, you must solve those before
118continuing.
124119
125120#+begin_src sh
126121sudo systemctl restart apache2
@@ -137,20 +132,20 @@ sudo chown -R www-data:www-data /var/www/example.com/nextcloud/
137132:PROPERTIES:
138133:CUSTOM_ID: dns
139134:END:
140If you do not have a static IP address, you will need to update your DNS
141settings (at your DNS provider) whenever your dynamic IP address
142changes.
135If you do not have a static internet protocol (IP) address, you will need to
136update your DNS (Domain Name System) settings (at your DNS provider) whenever
137your dynamic IP address changes.
143138
144For an example on how I do that with Cloudflare, see my other post:
145[[../updating-dynamic-dns-with-cloudflare-api/][Updating Dynamic DNS
146with Cloudflare API]]
139For an example on how I do that with Cloudflare, see my other post: [[https://cleberg.net/blog/cloudflare-dns-api.html][Dynamic DNS
140Record Updates via Cloudflare API]].
147141
148142* Certbot
149143:PROPERTIES:
150144:CUSTOM_ID: certbot
151145:END:
152If you want to serve Nextcloud from HTTPS rather than plain HTTP, use
153the following commands to issue Let's Encrypt SSL certificates:
146If you want to serve Nextcloud from HTTPS (Hypertext Transfer Protocol Secure)
147rather than plain HTTP (Hypertext Transfer Protocol), use the following commands
148to issue Let's Encrypt SSL (Secure Socket Layer) certificates:
154149
155150#+begin_src sh
156151sudo apt install snapd
@@ -165,5 +160,5 @@ sudo certbot --apache
165160:PROPERTIES:
166161:CUSTOM_ID: results
167162:END:
168Voilà! You're all done and should be able to access Nextcloud from your
169domain or IP address.
163Voilà! You're all done and should be able to access Nextcloud from your domain
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=.
2727Let's start with the actual server itself. Think about the following:
2828
2929- Do I have a firewall enabled? Do I need to update this to allow new ports or
30 IPs?
31- Do I have an IPS/IDS that may prevent outside traffic?
30 internet protocol (IP) addresses?
31- Do I have an intrusion prevention system (IPS) or intrusion detection system
32 (IDS) that may prevent outside traffic?
3233- Do I have any other security software installed?
3334- Are the services hosted inside Docker containers, behind a reverse proxy, or
3435 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
3738managed switch. In this case, I asked the following:
3839
3940- What configurations is the switch using?
40- Am I using VLANs?
41- Am I using VLANs (virtual local area networks)?
4142 - Yes, I am using 802.1Q VLANs.
4243- Are the VLANs configured properly?
4344 - 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:
4748At this point, the data has been processed through the switch. Where does it go
4849next? In my case, it's pretty simple: it goes to the router/modem device.
4950
50- Does my ISP block any ports that I need?
51- Does my internet service provider (ISP) block any ports that I need?
5152 - This is an important step that a lot of people run into when self-hosting at
5253 home. Use an online port-checker tool for your IP or call your ISP if you
5354 think ports are blocked.
@@ -59,9 +60,9 @@ next? In my case, it's pretty simple: it goes to the router/modem device.
5960- Are there any other settings affecting inbound/outbound traffic?
6061 - Schedules or access blocks
6162 - Static Routing
62 - QoS
63 - QoS (Quality of Service)
6364 - Port Forwarding
64 - DMZ Hosting
65 - DMZ (demilitarized zone) hosting
6566 - Remote Management (this can sometimes mess with services that also require
6667 the use of ports 80 and 443)
6768
@@ -70,27 +71,31 @@ publicly.
7071
7172*** Server
7273
73The services I run on my server are installed straight into the OS, without any
74use of Docker or VMs, so I don't need any extra application configuration to
75make them accessible to the outside world.+
74The services I run on my server are installed straight into the operating system
75(OS), without any use of Docker or virtual machines (VMs), so I don't need any
76extra application configuration to make them accessible to the outside world.
7677
78#+BEGIN_QUOTE
7779As of 2022-10-04, the paragraph above is no longer true as I now run a reverse
7880proxy with Nginx and host many services inside Docker. However, it doesn't
7981change anything regarding this post as I still just need to open ports 80 & 443
8082and create the necessary website configuration files.
83#+END_QUOTE
8184
8285When creating new services - either installed directly on bare metal or within
8386something like Docker - I ensure that I read through the documentation
84thoroughly to understand a few key things: - What network activities should this
85app perform (if any)? Using which ports and protocols? - Does this app require
86any commands/services to be run as =root=? - Does this app log errors,
87authentication failures/successes, or anything else that would be useful for an
88investigation?
87thoroughly to understand a few key things:
88
89- What network activities should this app perform (if any)? Using which ports
90 and protocols?
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?
8994
9095For extra security, I use limit all incoming connections to SSH connections
91through my server firewall (=ufw=) and disable common SSH settings. After all of
92that, I use =fail2ban= as a preventative measure against brute-force login
93attempts.
96through my server firewall [=ufw= (Uncomplicated Firewall)] and disable common
97SSH (Secure Shell Protocol) settings. After all of that, I use =fail2ban= as a
98preventative measure against brute-force login attempts.
9499
95100As another piece of security, you can randomize your SSH port to ensure that
96101random scanners or attackers can't easily try to force their way into your
@@ -101,8 +106,8 @@ via your randomized port.
101106
102107** =ufw=
103108
104To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your
105Network with the Uncomplicated Firewall]].
109To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your Network with the
110Uncomplicated Firewall]].
106111
107112The general notion with an on-device firewall is that you want to deny all
108113incoming connections by default and then selectively open certain ports for
@@ -178,7 +183,7 @@ sudo ufw enable
178183 lock yourself out at some point and will need to use a recovery method (e.g.,
179184 hooking monitor up to home server) to get yourself back in.
180185
1813. Enable MFA for =ssh=
1863. Enable Multi-Factor Authentication (MFA) for =ssh=
182187
183188 This part is optional, but I highly recommend it. So far, we've ensured that
184189 no one can log into our user on the server without using our secret key, and
@@ -187,8 +192,7 @@ sudo ufw enable
187192
188193 This process involves editing a couple files and installing an MFA package,
189194 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
191 SSH]].
195 MFA for =ssh=, see my other post: [[https://cleberg.net/blog/ssh-mfa.html][Enabling MFA for SSH]].
192196
193197** =fail2ban=
194198
@@ -224,8 +228,8 @@ the server to manage it.
224228
225229| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports |
226230|---------+-----------+--------------+--------------+----------------|
227| 1 | Default | 1-24 | 1-24 | |
228| 2 | Server | 1,8,23 | 1,8,23 | |
231| 1 | Default | 1-24 | 1-24 | |
232| 2 | Server | 1,8,23 | 1,8,23 | |
229233
230234** 802.1Q VLAN PVID Setting
231235
@@ -235,30 +239,30 @@ any related ports (in this case, see that ports =8= and =23= have a PVID of
235239
236240| Port | PVID |
237241|------+------|
238| 1 | 1 |
239| 2 | 1 |
240| 3 | 1 |
241| 4 | 1 |
242| 5 | 1 |
243| 6 | 1 |
244| 7 | 1 |
245| 8 | 2 |
246| 9 | 1 |
247| 10 | 1 |
248| 11 | 1 |
249| 12 | 1 |
250| 13 | 1 |
251| 14 | 1 |
252| 15 | 1 |
253| 16 | 1 |
254| 17 | 1 |
255| 18 | 1 |
256| 19 | 1 |
257| 20 | 1 |
258| 21 | 1 |
259| 22 | 1 |
260| 23 | 2 |
261| 24 | 1 |
242| 1 | 1 |
243| 2 | 1 |
244| 3 | 1 |
245| 4 | 1 |
246| 5 | 1 |
247| 6 | 1 |
248| 7 | 1 |
249| 8 | 2 |
250| 9 | 1 |
251| 10 | 1 |
252| 11 | 1 |
253| 12 | 1 |
254| 13 | 1 |
255| 14 | 1 |
256| 15 | 1 |
257| 16 | 1 |
258| 17 | 1 |
259| 18 | 1 |
260| 19 | 1 |
261| 20 | 1 |
262| 21 | 1 |
263| 22 | 1 |
264| 23 | 2 |
265| 24 | 1 |
262266
263267* Router
264268
@@ -266,9 +270,9 @@ On my router, the configuration was as easy as opening the firewall settings and
266270unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL,
267271etc.).
268272
269Since I'm relying on an ISP-provided modem/router combo for now (not by
270choice), I do not use any other advanced settings on my router that would
271inhibit any valid traffic to these services.
273Since I'm relying on an ISP-provided modem/router combo for now (not by choice),
274I do not use any other advanced settings on my router that would inhibit any
275valid traffic to these services.
272276
273277The paragraph above regarding the ISP-owned router is no longer accurate as I
274278now 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
287291hosts a server like this. Exactly /how/ important it is depends on the server
288292use/purpose.
289293
290If you self-host customer applications that hold protected data (HIPAA, GDPR,
291COPPA, etc.), then physical security is extremely important and cannot be
292ignored. If you simply host a blog and some hobby sites, then it's a relatively
293minor consideration, but one you still need to think about.
294If you self-host customer applications that hold protected data, then physical
295security is extremely important and cannot be ignored. If you simply host a blog
296and some hobby sites, then it's a relatively minor consideration, but one you
297still need to think about.
294298
295299** Location
296300
@@ -312,8 +316,9 @@ Secondly, consider the hardware itself:
312316- Are any other users able to access the server, even if your data/space is
313317 segregated?
314318- 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,
316 internal security/safety documentation.
319 responsibility? This could be a Service Organization Controls (SOC) 1/2/3
320 report, International Organization for Standardization (ISO) compliance
321 report, internal security/safety documentation.
317322
318323** Physical Controls
319324
content/blog/2022-03-26-ssh-mfa.org +34 −35
@@ -3,31 +3,29 @@
33#+description: Step-by-step deployment guide for enabling TOTP multi-factor authentication on SSH services using Google Authenticator and Pluggable Authentication Module (PAM) integration.
44#+slug: ssh-mfa
55
6* Why Do I Need MFA for SSH?
6* Why Do I Need Multi-Factor Authentication (MFA) for SSH (Secure Shell Protocol)?
77
8If you are a sysadmin of a server anywhere (that includes at home!), you
9may want an added layer of protection against intruders. This is not a
10replacement for other security measures, such as:
8If you are a sysadmin of a server anywhere (that includes at home!), you may
9want an added layer of protection against intruders. This is not a replacement
10for other security measures, such as:
1111
1212- Disable root SSH
1313- Disable SSH password authentication
1414- 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
1616
17However, MFA can be added as an additional security measure to ensure
18that your server is protected. This is especially important if you need
19to allow password authentication for SSH.
17However, MFA can be added as an additional security measure to ensure that your
18server is protected. This is especially important if you need to allow password
19authentication for SSH.
2020
21For more guidance on server security measures, see my other post:
22[[../hardening-a-public-facing-home-server/][Hardening a Public-Facing
23Home Server]].
21For more guidance on server security measures, see my other post: [[https://cleberg.net/blog/server-hardening.html][Step-by-Step
22Guide to Securing Your Home Server with Firewalls, SSH, and VLANs]].
2423
2524* Install MFA PAM Module
2625
27PAM, which stands for Pluggable Authentication Module, is an
28authentication infrastructure used on Linux systems to authenticate a
29user. In order to use this technology, let's install the
30=libpam-google-authenticator= package:
26PAM (Pluggable Authentication Module) is an authentication infrastructure used
27on Linux systems to authenticate a user. In order to use this technology, let's
28install the =libpam-google-authenticator= package:
3129
3230#+begin_src sh
3331sudo apt-get update
@@ -41,16 +39,17 @@ sudo apt-get install libpam-google-authenticator
4139
4240** Interactive Method
4341
44Once the package is installed, initialize it and following the
45interactive prompts to generate your OTP or TOTP:
42Once the package is installed, initialize it and following the interactive
43prompts to generate your OTP (One-Time Password) or TOTP (Time-based One-Time
44Password):
4645
4746#+begin_src sh
4847google-authenticator
4948#+end_src
5049
51If you are not sure how to answer, read the prompts carefully and think
52about having to how each situation would affect your normal login
53attempts. If you are still not sure, use my default responses below.
50If you are not sure how to answer, read the prompts carefully and think about
51having to how each situation would affect your normal login attempts. If you are
52still not sure, use my default responses below.
5453
5554#+begin_src txt
5655OUTPUT
@@ -58,8 +57,8 @@ OUTPUT
5857Do you want authentication tokens to be time-based (y/n) y
5958#+end_src
6059
61At this point, use an authenticator app somewhere one of your devices to
62scan the QR code. Any future login attempts after our upcoming
60At this point, use an authenticator app somewhere one of your devices to scan
61the QR (quick-response) code. Any future login attempts after our upcoming
6362configuration changes will require that TOTP.
6463
6564#+begin_src txt
@@ -134,23 +133,23 @@ google-authenticator [<options>]
134133 -e, --emergency-codes=N Number of emergency codes to generate
135134#+end_src
136135
137This fully configures the authenticator, saves it to a file, and then
138outputs the secret key, QR code, and recovery codes. (If you add the
139flag =-q=, then there won't be any output). If you use this command in
140an automated fashion, make sure your script captures the secret key
141and/or recovery codes and makes them available to the user.
136This fully configures the authenticator, saves it to a file, and then outputs
137the secret key, QR code, and recovery codes. (If you add the flag =-q=, then
138there won't be any output). If you use this command in an automated fashion,
139make sure your script captures the secret key and/or recovery codes and makes
140them available to the user.
142141
143142* PAM Configuration Settings
144143
145Once you've enabled the T/OTP and have it saved to an MFA app on your
146phone or other device, open the PAM =sshd= file:
144Once you've enabled MFA and have it saved to an MFA app on your phone or other
145device, open the PAM =sshd= file:
147146
148147#+begin_src sh
149148sudo nano /etc/pam.d/sshd
150149#+end_src
151150
152You need to do two things in this file. First, add the following lines
153to the bottom of the file:
151You need to do two things in this file. First, add the following lines to the
152bottom of the file:
154153
155154#+begin_src config
156155auth required pam_google_authenticator.so nullok
@@ -159,8 +158,8 @@ auth required pam_permit.so
159158
160159Second, comment-out the following line near the top of the file.
161160
162If you leave this line uncommented, every SSH login attempt will ask for
163the following three authentication factors:
161If you leave this line uncommented, every SSH login attempt will ask for the
162following three authentication factors:
164163
1651641. Publickey
1661652. Password
@@ -178,8 +177,8 @@ Finally, edit the =sshd_config= file again:
178177sudo nano /etc/ssh/sshd_config
179178#+end_src
180179
181You'll need to change =ChallengeResponseAuthentication= to yes and add
182the =AuthenticationMethods= line to the bottom of the file.
180You'll need to change =ChallengeResponseAuthentication= to yes and add the
181=AuthenticationMethods= line to the bottom of the file.
183182
184183#+begin_src config
185184ChallengeResponseAuthentication yes
content/blog/2022-04-02-nginx-reverse-proxy.org +64 −71
@@ -5,10 +5,10 @@
55
66* What is a Reverse Proxy?
77
8A reverse proxy is a server that is placed between local servers or
9services and clients/users (e.g., the internet). The reverse proxy
10intercepts all requests from clients at the network edge and uses its
11configuration files to determine where each request should be sent.
8A reverse proxy is a server that is placed between local servers or services and
9clients/users (e.g., the internet). The reverse proxy intercepts all requests
10from clients at the network edge and uses its configuration files to determine
11where each request should be sent.
1212
1313** A Brief Example
1414
@@ -18,23 +18,21 @@ For example, let's say that I run three servers in my home:
1818- Server02 (=service01.example.com=)
1919- Server03 (=service02.example.com=)
2020
21I also run a reverse proxy in my home that intercepts all public
22traffic:
21I also run a reverse proxy in my home that intercepts all public traffic:
2322
2423- Reverse Proxy
2524
26Assume that I have a domain name (=example.com=) that allows clients to
27request websites or services from my home servers.
25Assume that I have a domain name (=example.com=) that allows clients to request
26websites or services from my home servers.
2827
29In this case, the reverse proxy will intercept all traffic from
30=example.com= that enters my network and determine if the client is
31requesting valid data, based on my configuration.
28In this case, the reverse proxy will intercept all traffic from =example.com=
29that enters my network and determine if the client is requesting valid data,
30based on my configuration.
3231
33If the user is requesting =example.com= and my configuration files say
34that Server_{01} holds that data, Nginx will send the user to
35Server_{01}. If I were to change the configuration so that =example.com=
36is routed to Server_{02}, that same user would be sent to Server_{02}
37instead.
32If the user is requesting =example.com= and my configuration files say that
33Server_{01} holds that data, Nginx will send the user to Server_{01}. If I were
34to change the configuration so that =example.com= is routed to Server_{02}, that
35same user would be sent to Server_{02} instead.
3836
3937#+begin_src txt
4038┌──────┐ ┌───────────┐
@@ -50,9 +48,9 @@ instead.
5048
5149* Reverse Proxy Options
5250
53There are a lot of options when it comes to reverse proxy servers, so
54I'm just going to list a few of the options I've heard recommended over
55the last few years:
51There are a lot of options when it comes to reverse proxy servers, so I'm just
52going to list a few of the options I've heard recommended over the last few
53years:
5654
5755- [[https://nginx.com][Nginx]]
5856- [[https://caddyserver.com][Caddy]]
@@ -60,42 +58,41 @@ the last few years:
6058- [[https://www.haproxy.org/][HAProxy]]
6159- [[https://ubuntu.com/server/docs/proxy-servers-squid][Squid]]
6260
63In this post, we will be using Nginx as our reverse proxy, running on
64Ubuntu Server 20.04.4 LTS.
61In this post, we will be using Nginx as our reverse proxy, running on Ubuntu
62Server 20.04.4 LTS.
6563
6664* Nginx Reverse Proxy Example
6765
6866** Local Applications
6967
70You may be like me and have a lot of applications running on your local
71network that you'd like to expose publicly with a domain.
68You may be like me and have a lot of applications running on your local network
69that you'd like to expose publicly with a domain.
7270
73In my case, I have services running in multiple Docker containers within
74a single server and want a way to visit those services from anywhere
75with a URL. For example, on my local network,
76[[https://dashy.to][Dashy]] runs through port 4000 (=localhost:4000=)
77and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs
78through port 3001 (=localhost:3001=).
71In my case, I have services running in multiple Docker containers within a
72single server and want a way to visit those services from anywhere with a URL.
73For example, on my local network, [[https://dashy.to][Dashy]] runs through port 4000
74(=localhost:4000=) and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs through port 3001 (=localhost:3001=).
7975
8076In order to expose these services to the public, I will need to do the
8177following:
8278
831. Set up DNS records for a domain or subdomain (one per service) to
84 point toward the IP address of the server.
852. Open up the server network's HTTP and HTTPS ports (80 & 443) so that
86 the reverse proxy can accept traffic and determine where to send it.
791. Set up DNS (Domain Name System) records for a domain or subdomain (one per
80 service) to point toward the internet protocol (IP) address of the server.
812. Open up the server network's HTTP (Hypertext Transfer Protocol) and HTTPS
82 (Hypertext Transfer Protocol Secure) ports (80 & 443) so that the reverse
83 proxy can accept traffic and determine where to send it.
87843. Install the reverse proxy software.
884. Configure the reverse proxy to recognize which service should get
89 traffic from any of the domains or subdomains.
854. Configure the reverse proxy to recognize which service should get traffic
86 from any of the domains or subdomains.
9087
9188** Step 1: DNS Configuration
9289
93To start, update your DNS configuration so that you have an =A= record
94for each domain or subdomain.
90To start, update your DNS configuration so that you have an =A= record for each
91domain or subdomain.
9592
96The =A= records should point toward the public IP address of the server.
97If you don't know the public IP address, log in to the server and run
98the following command:
93The =A= records should point toward the public IP address of the server. If you
94don't know the public IP address, log in to the server and run the following
95command:
9996
10097#+begin_src sh
10198curl ifconfig.co
@@ -111,34 +108,30 @@ dashy.example.com A xxx.xxx.xxx.xxx
111108www CNAME example.com
112109#+end_src
113110
114Finally, ensure the DNS has propagated correctly with
115[[https://dnschecker.org][DNS Checker]] by entering your domains or
116subdomains in the search box and ensuring the results are showing the
117correct IP address.
111Finally, ensure the DNS has propagated correctly with [[https://dnschecker.org][DNS Checker]] by entering
112your domains or subdomains in the search box and ensuring the results are
113showing the correct IP address.
118114
119115** Step 2: Open Network Ports
120116
121This step will be different depending on which router you have in your
122home. If you're not sure, try to visit
123[[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials
124are usually written on a sticker somewhere on your modem/router.
117This step will be different depending on which router you have in your home. If
118you're not sure, try to visit [[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials are
119usually written on a sticker somewhere on your modem/router.
125120
126Once you're able to log in to your router, find the Port Forwarding
127settings. You will need to forward ports =80= and =443= to whichever
128machine is running the reverse proxy.
121Once you're able to log in to your router, find the Port Forwarding settings.
122You will need to forward ports =80= and =443= to whichever machine is running
123the reverse proxy.
129124
130In my case, the table below shows the port-forwarding rules I've
131created. In this table, =xxx.xxx.xxx.xxx= is the local device IP of the
132reverse proxy server, it will probably be an IP between =192.168.1.1=
133and =192.168.1.255=.
125In my case, the table below shows the port-forwarding rules I've created. In
126this table, =xxx.xxx.xxx.xxx= is the local device IP of the reverse proxy
127server, it will probably be an IP between =192.168.1.1= and =192.168.1.255=.
134128
135129| NAME | FROM PORT | DEST PORT/IP | ENABLED |
136130|-------+-----------+-----------------+---------|
137131| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE |
138132| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE |
139133
140Once configured, these rules will direct all web traffic to your reverse
141proxy.
134Once configured, these rules will direct all web traffic to your reverse proxy.
142135
143136** Step 3: Nginx Installation
144137
@@ -148,11 +141,11 @@ To install Nginx, simply run the following command:
148141sudo apt install nginx
149142#+end_src
150143
151If you have a firewall enabled, open up ports =80= and =443= on your
152server so that Nginx can accept web traffic from the router.
144If you have a firewall enabled, open up ports =80= and =443= on your server so
145that Nginx can accept web traffic from the router.
153146
154For example, if you want to use =ufw= for web traffic and SSH, run the
155following commands:
147For example, if you want to use =ufw= for web traffic and SSH, run the following
148commands:
156149
157150#+begin_src sh
158151sudo ufw allow 'Nginx Full'
@@ -162,9 +155,8 @@ sudo ufw enable
162155
163156** Step 4: Nginx Configuration
164157
165Now that we have domains pointing toward the server, the only step left
166is to configure the reverse proxy to direct traffic from domains to
167local services.
158Now that we have domains pointing toward the server, the only step left is to
159configure the reverse proxy to direct traffic from domains to local services.
168160
169161To start, you'll need to create a configuration file for each domain in
170162=/etc/nginx/sites-available/=. They will look identical except for the
@@ -204,22 +196,23 @@ server {
204196}
205197#+end_src
206198
207Once the configuration files are created, you will need to enable them
208with the =symlink= command:
199Once the configuration files are created, you will need to enable them with the
200=symlink= command:
209201
210202#+begin_src sh
211203sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/
212204#+end_src
213205
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).
215208
216209* HTTPS with Certbot
217210
218If you've followed along, you'll notice that your services are only
219available via HTTP (not HTTPS).
211If you've followed along, you'll notice that your services are only available
212via HTTP (not HTTPS).
220213
221If you want to enable HTTPS for your new domains, you will need to
222generate SSL/TLS certificates for them. The easiest way to generate
214If you want to enable HTTPS for your new domains, you will need to generate TLS
215(Transport Layer Security) certificates for them. The easiest way to generate
223216certificates on Nginx is [[https://certbot.eff.org][Certbot]]:
224217
225218#+begin_src sh
content/blog/2022-04-09-pinetime.org +57 −65
@@ -7,17 +7,15 @@
77
88** Overview
99
10The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source
11smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally
12announced in September 2019, this ARM-based watch is a fantastic option
13for users who want the benefits of a modern smartwatch with the backing
14of open-source components and software.
10The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally
11announced in September 2019, this ARM-based watch is a fantastic option for
12users who want the benefits of a modern smartwatch with the backing of
13open-source components and software.
1514
1615** Product Specifications
1716
18I won't dive into too many details that you can find on
19[[https://www.pine64.org/pinetime/][the product page]], but I wanted to
20point out the prices for each watch and the primary functions:
17I won't dive into too many details that you can find on [[https://www.pine64.org/pinetime/][the product page]], but I
18wanted to point out the prices for each watch and the primary functions:
2119
22201. Price:
2321
@@ -38,52 +36,48 @@ point out the prices for each watch and the primary functions:
3836
3937* Unboxing
4038
41Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and
42was delivered on 2022-03-23. With the current delays on shipping times
43around the world (and the semiconductor shortage), a month for delivery
44from China seems reasonable to me.
39Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and was
40delivered on 2022-03-23. With the current delays on shipping times around the
41world (and the semiconductor shortage), a month for delivery from China seems
42reasonable to me.
4543
46The packaging is simple, and the watch comes with instructions,
47technical information, the watch, and a charger (it does not include a
48USB wall adapter).
44The packaging is simple, and the watch comes with instructions, technical
45information, the watch, and a charger (it does not include a USB wall adapter).
4946
50The watch itself was able to turn on immediately when I pulled it out of
51the box, but the battery was depleted and required charging right away.
47The watch itself was able to turn on immediately when I pulled it out of the
48box, but the battery was depleted and required charging right away.
5249
5350* Software
5451
55** Watch OS: InfiniTime
52** Watch Operating System (OS): InfiniTime
5653
57While turning on the watch for the first time, some of the main design
58choices you can see in the watch OS,
59[[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are:
54While turning on the watch for the first time, some of the main design choices
55you can see in the watch OS, [[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are:
6056
6157- A square bezel, not too thin against the sides of the watch.
6258- A simple, rubber band.
6359- Basic font and screen pixel design.
6460- Swipe gestures to access other screens.
6561
66The OS itself is fantastic in terms of functionality for me. It does
67exactly what a smartwatch should do - track time, steps, heart rates,
68and connect to another smart device, without being overly burdensome to
69the user.
62The OS itself is fantastic in terms of functionality for me. It does exactly
63what a smartwatch should do - track time, steps, heart rates, and connect to
64another smart device, without being overly burdensome to the user.
7065
71My only gripe so far is that it's /really/ difficult to swipe to
72different screens, such as pulling down the notification tray. I'm not
73sure if this is an OS or hardware issue, but it makes it quite hard to
74quickly move around the screens.
66My only gripe so far is that it's /really/ difficult to swipe to different
67screens, such as pulling down the notification tray. I'm not sure if this is an
68OS or hardware issue, but it makes it quite hard to quickly move around the
69screens.
7570
76However, my absolute favorite design choice is that the button the side
77turns the screen on and off and tilting/waving my wrist doesn't
78accidentally turn on the screen. With other watches, I absolutely hated
79not being able to turn off the raise-to-wake or wave features (i.e.,
80blinding myself while wearing a watch at night because I moved my arm).
71However, my absolute favorite design choice is that the button the side turns
72the screen on and off and tilting/waving my wrist doesn't accidentally turn on
73the screen. With other watches, I absolutely hated not being able to turn off
74the raise-to-wake or wave features (i.e., blinding myself while wearing a watch
75at night because I moved my arm).
8176
8277** iOS App: InfiniLink
8378
84Since I am using iOS as my primary mobile device OS, I am using the
85[[https://github.com/xan-m/InfiniLink][InfiniLink]] app to connect my
86watch.
79Since I am using iOS as my primary mobile device OS, I am using the [[https://github.com/xan-m/InfiniLink][InfiniLink]]
80app to connect my watch.
8781
8882This app provides the following for PineTime owners:
8983
@@ -92,47 +86,45 @@ This app provides the following for PineTime owners:
9286- Charts
9387- Notifications
9488
95Another big feature of InfiniLink is the ability to track pedometer
96steps in a collection of beautiful graphs, with the option to change
97your step goal and add in manual steps.
89Another big feature of InfiniLink is the ability to track pedometer steps in a
90collection of beautiful graphs, with the option to change your step goal and add
91in manual steps.
9892
99Finally, there are charts to display the battery percentage and heart
100rates over time. This area also comes with an option to clear data.
93Finally, there are charts to display the battery percentage and heart rates over
94time. This area also comes with an option to clear data.
10195
10296* Final Thoughts
10397
10498** Pros
10599
106After wearing my watch for a few weeks, I have mostly positive thoughts
107about the watch so far. In the past, I have owned smartwatches by
108FitBit, Fossil, Apple, etc. - *but I prefer the PineTime over all of
109those watches*.
100After wearing my watch for a few weeks, I have mostly positive thoughts about
101the watch so far. In the past, I have owned smartwatches by FitBit, Fossil,
102Apple, etc. - *but I prefer the PineTime over all of those watches*.
110103
111The PineTime strips out all the unnecessary features and performs the
112functions that it provides effectively and efficiently.
104The PineTime strips out all the unnecessary features and performs the functions
105that it provides effectively and efficiently.
113106
114The battery life is amazing on this device. By default, the watch seems
115to last anywhere from a few days to a week before dying.
107The battery life is amazing on this device. By default, the watch seems to last
108anywhere from a few days to a week before dying.
116109
117110And of course, it's open source and backed by some of the most dedicated
118enthusiasts and developers I've seen. Watching the Matrix channel,
119forums, and website have been exciting to see.
111enthusiasts and developers I've seen. Watching the Matrix channel, forums, and
112website have been exciting to see.
120113
121114** Cons
122115
123If I had to complain about anything, it would simply be the small bugs
124in some features that can be contributed to the companion apps more than
125the watch itself.
116If I had to complain about anything, it would simply be the small bugs in some
117features that can be contributed to the companion apps more than the watch
118itself.
126119
127A regular user would want native notification support out-of-the-box,
128which is the biggest item not working for me at the moment.
120A regular user would want native notification support out-of-the-box, which is
121the biggest item not working for me at the moment.
129122
130My only other complaint is that the battery indicator on the watch
131doesn't seem accurate when it's nearing depletion - it seems that
132there's a bit of battery life left and then my watch is dead very
133suddenly after. This could just be me misinterpreting the battery level
134icons, but it has fooled me a few times into thinking I had more battery
135left than I actually did.
123My only other complaint is that the battery indicator on the watch doesn't seem
124accurate when it's nearing depletion - it seems that there's a bit of battery
125life left and then my watch is dead very suddenly after. This could just be me
126misinterpreting the battery level icons, but it has fooled me a few times into
127thinking I had more battery left than I actually did.
136128
137Other than those small items, I really do love this watch and am glad I
138replaced my Apple Watch with the PineTime.
129Other than those small items, I really do love this watch and am glad I replaced
130my Apple Watch with the PineTime.
content/blog/2022-06-01-ditching-cloudflare.org +49 −56
@@ -5,91 +5,84 @@
55
66* Registrar
77
8After spending a year or so using Cloudflare for DNS only - no proxying
9or applications - I spent the last few months using Cloudflare Tunnels
10and Cloudflare Access to protect my self-hosted websites and
8After spending a year or so using Cloudflare for DNS (Domain Name System) only -
9no proxying or applications - I spent the last few months using Cloudflare
10Tunnels and Cloudflare Access to protect my self-hosted websites and
1111applications via their proxy traffic model.
1212
13However, I have never liked using Cloudflare due to their increasingly
14large share of control over web traffic, as well as their business model
15of being a MITM for all of your traffic.
13However, I have never liked using Cloudflare due to their increasingly large
14share of control over web traffic, as well as their business model of being a
15MITM (man-in-the-middle) for all of your traffic.
1616
17So, as of today, I have switched over to [[https://njal.la][Njalla]] as
18my registrar and DNS manager. I was able to easily transfer my domains
19over rapidly, with only one domain taking more than 15-30 minutes to
20propagate.
17So, as of today, I have switched over to [[https://njal.la][Njalla]] as my registrar and DNS manager.
18I was able to easily transfer my domains over rapidly, with only one domain
19taking more than 15-30 minutes to propagate.
2120
22+I do still have two domains sitting at Cloudflare for the moment while
23I decide if they're worth the higher rates (one domain is 30€ and the
24other is 45€).+
21+I do still have two domains sitting at Cloudflare for the moment while I decide
22if they're worth the higher rates (one domain is 30€ and the other is 45€).+
2523
2624#+begin_quote
27*Update (2022.06.03)*: I ended up transferring my final two domains over
28to Njalla, clearing my Cloudflare account of personal data, and deleting
29the Cloudflare account entirely. /I actually feel relieved to have moved
30on to a provider I trust./
25*Update (2022.06.03)*: I ended up transferring my final two domains over to
26Njalla, clearing my Cloudflare account of personal data, and deleting the
27Cloudflare account entirely. /I actually feel relieved to have moved on to a
28provider I trust./
3129#+end_quote
3230
3331* DNS
3432
35As noted above, I'm using Njalla exclusively for DNS configurations on
36my domains.
33As noted above, I'm using Njalla exclusively for DNS configurations on my
34domains.
3735
38However, the transfer process was not ideal. As soon as the domains
39transferred over, I switched the nameservers from Cloudflare to Njalla
40and lost most of the associated DNS records. So, the majority of the
41time spent during the migration was simply re-typing all the DNS records
42back in one-by-one.
36However, the transfer process was not ideal. As soon as the domains transferred
37over, I switched the nameservers from Cloudflare to Njalla and lost most of the
38associated DNS records. So, the majority of the time spent during the migration
39was simply re-typing all the DNS records back in one-by-one.
4340
44This would be much simpler if I were able to edit the plain-text format
45of the DNS configuration. I was able to do that at a past registrar
46(perhaps it was [[https://gandi.net/][Gandi.net]]?) and it made life a
47lot easier.
41This would be much simpler if I were able to edit the plain-text format of the
42DNS configuration. I was able to do that at a past registrar (perhaps it was
43[[https://gandi.net/][Gandi.net]]?) and it made life a lot easier.
4844
4945** Dynamic DNS Updates
5046
5147I 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
53Njalla, and update the DNS records if they don't match. You can see the
54full script and process in my other post: [[../njalla-dns-api/][Updating
55Dynamic DNS with Njalla API]].
48automatically) that will check my server's IPv4 (Internet Protocol version 4)and
49IPv6 (Internet Protocol version 6), compare it to Njalla, and update the DNS
50records if they don't match. You can see the full script and process in my other
51post: [[https://cleberg.net/blog/njalla-dns-api.html][Automating Dynamic DNS Record Updates via Njalla API]].
5652
57I haven't used this other method, but I do know that you can create
58=Dynamic= DNS records with Njalla that
59[[https://njal.la/docs/ddns/][work for updating dynamic subdomains]].
53I haven't used this other method, but I do know that you can create =Dynamic=
54DNS records with Njalla that [[https://njal.la/docs/ddns/][work for updating dynamic subdomains]].
6055
6156** Njalla's DNS Tool
6257
63One neat upside to Njalla is that they have a
64[[https://check.njal.la/dns/][DNS lookup tool]] that provides a lot of
65great information for those of you (AKA: me) who hate using the =dig=
58One neat upside to Njalla is that they have a [[https://check.njal.la/dns/][DNS lookup tool]] that provides a
59lot of great information for those of you (AKA: me) who hate using the =dig=
6660command.
6761
68This was very useful for monitoring a couple of my transferred domains
69to see when the changes in nameservers, records, and DNSSEC went into
70effect.
62This was very useful for monitoring a couple of my transferred domains to see
63when the changes in nameservers, records, and DNSSEC (Domain Name System
64Security Extensions) went into effect.
7165
7266* Tunnel
7367
7468Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on
75Cloudflare's servers) and allowed me to mask the private IP address of
76the server hosting my various websites and apps.
77
78However, as I was moving away from Cloudflare, I was not able to find a
79suitable replacement that was both inexpensive and simple. So, I simply
80went back to hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own
81reverse proxy with Nginx]]. With the recent additions of Unifi hardware
82in my server/network rack, I am much more protected against spam and
69Cloudflare's servers) and allowed me to mask the private internet protocol (IP)
70address of the server hosting my various websites and apps.
71
72However, as I was moving away from Cloudflare, I was not able to find a suitable
73replacement that was both inexpensive and simple. So, I simply went back to
74hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own reverse proxy with Nginx]]. With the recent additions of Unifi
75hardware in my server/network rack, I am much more protected against spam and
8376malicious attacks at the network edge than I was before I switched to
8477Cloudflare.
8578
8679* Access
8780
88Cloudflare Access, another app I used in combination with Cloudflare
89Tunnel, provided an authentication screen that required you to enter
90valid credentials before Cloudflare would forward you to the actual
91website or app (if the website/app has their own authentication, you'd
92then have to authenticate a second time).
81Cloudflare Access, another app I used in combination with Cloudflare Tunnel,
82provided an authentication screen that required you to enter valid credentials
83before Cloudflare would forward you to the actual website or app (if the
84website/app has their own authentication, you'd then have to authenticate a
85second time).
9386
94I did not replace this service with anything since I only host a handful
95of non-sensitive apps that don't require duplicate authentication.
87I did not replace this service with anything since I only host a handful of
88non-sensitive apps that don't require duplicate authentication.
content/blog/2022-06-07-self-hosting-freshrss.org +71 −81
@@ -3,47 +3,43 @@
33#+description: Stepwise instructions for installing FreshRSS using Docker and configuring Nginx as a reverse proxy to enable secure and synchronized RSS feed access.
44#+slug: self-hosting-freshrss
55
6* Why RSS?
6* Why Use Really Simple Syndication (RSS)?
77
8After noticing that I have collected 50+ blogs as bookmarks, I decided
9to migrate back to using RSS feeds to stay up-to-date with my favorite
10websites. Using RSS allows me to read all of these posts in a single app
11(on both mobile & desktop) and allows me to be notified when new posts
12are available.
8After noticing that I have collected 50+ blogs as bookmarks, I decided to
9migrate back to using RSS feeds to stay up-to-date with my favorite websites.
10Using RSS allows me to read all of these posts in a single app (on both mobile &
11desktop) and allows me to be notified when new posts are available.
1312
14However, I ran into one issue: syncing subscriptions and read/unread
15posts across devices. Since I want to be able to easily read on both
16mobile and desktop, I decided to look for a self-hosted RSS solution.
13However, I ran into one issue: syncing subscriptions and read/unread posts
14across devices. Since I want to be able to easily read on both mobile and
15desktop, I decided to look for a self-hosted RSS solution.
1716
18Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to
19successfully install it on my server in about 30 minutes.
17Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to successfully install it on my server in
18about 30 minutes.
2019
2120* Documentation
2221
23While it's certainly not robust, the
24[[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is
25helpful for figuring out basic information about the service.
22While it's certainly not robust, the [[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is helpful for
23figuring out basic information about the service.
2624
27However, I wanted to install this service as a Docker container and
28stumbled across the
29[[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]]
30within the GitHub repository.
25However, I wanted to install this service as a Docker container and stumbled
26across the [[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]] within the GitHub repository.
3127
32This README was the documentation I actually needed. However, as you'll
33see below, I still had to manually edit one file (=config.php=) to
34access the API externally via my RSS apps.
28This README was the documentation I actually needed. However, as you'll see
29below, I still had to manually edit one file (=config.php=) to access the API
30externally via my RSS apps.
3531
3632* Installation
3733
3834** DNS
3935
40The first step, as required by any external web service, was assigning a
41domain name to use. I chose to use a subdomain, like =rss.example.com=.
36The first step, as required by any external web service, was assigning a domain
37name to use. I chose to use a subdomain, like =rss.example.com=.
4238
4339To 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
45server. Note: assigning an IPv6 (=AAAA=) record is optional, but I like
46to enable IPV6 for my services.
40(Internet Protocol version 4) address of the server and an =AAAA= record with
41the IPv6 (Internet Protocol version 6) address of the server. Note: assigning an
42IPv6 (=AAAA=) record is optional, but I like to enable IPV6 for my services.
4743
4844#+begin_src config
4945rss.example.com A xxx.xxx.xxx.xxx
@@ -52,11 +48,10 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx
5248
5349** Docker
5450
55I initially tried to set up a =docker-compose.yml= file with a =.env=
56file because I prefer to have a file I can look back at later to see how
57I initially started the container, but it simply wouldn't work for me.
58I'm not sure why, but I assume I wasn't telling =docker-compose= where
59the =.env= file was.
51I initially tried to set up a =docker-compose.yml= file with a =.env= file
52because I prefer to have a file I can look back at later to see how I initially
53started the container, but it simply wouldn't work for me. I'm not sure why, but
54I assume I wasn't telling =docker-compose= where the =.env= file was.
6055
6156Regardless, I chose to simply run the service with =docker run=. See the
6257following command for my =docker run= configuration:
@@ -72,25 +67,24 @@ sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
7267 freshrss/freshrss
7368#+end_src
7469
75This started the container successfully and allowed me to visit the
76FreshRSS instance at =localhost:8080=.
70This started the container successfully and allowed me to visit the FreshRSS
71instance at =localhost:8080=.
7772
7873** Fresh RSS Set-Up
7974
80I *HIGHLY* suggest that you set up your user account prior to exposing
81this service to the public. It's unlikely that someone is trying to
82access the exact domain or IP/port you're assigning here, but as soon as
83you expose this service, the first person to open the URL will be able
84to create the admin user.
75I *HIGHLY* suggest that you set up your user account prior to exposing this
76service to the public. It's unlikely that someone is trying to access the exact
77domain or IP/port you're assigning here, but as soon as you expose this service,
78the first person to open the URL will be able to create the administrative user.
8579
86In order to set up your FreshRSS service, open the =localhost:8080= URL
87in your browser (you may need to use a local IP instead of =localhost=
88if you're accessing the page from a different machine on the network -
89e.g., =192.168.1.20:8080=).
80In order to set up your FreshRSS service, open the =localhost:8080= URL in your
81browser (you may need to use a local internet protocol (IP) instead of
82=localhost= if you're accessing the page from a different machine on the
83network - e.g., =192.168.1.20:8080=).
9084
9185Once the page loads, set up your default user with a strong username and
92password. You may also choose to configure other settings prior to
93exposing this service.
86password. You may also choose to configure other settings prior to exposing this
87service.
9488
9589** Nginx Reverse-Proxy
9690
@@ -103,7 +97,7 @@ First, I created a new Nginx configuration file:
10397sudo nano /etc/nginx/sites-available/rss.example.com
10498#+end_src
10599
106Within the config file, I pasted the following code:
100Within the configuration file, I pasted the following code:
107101
108102#+begin_src config
109103upstream freshrss {
@@ -136,8 +130,7 @@ server {
136130}
137131#+end_src
138132
139Finally, restart Nginx and you will be able to access your service via
140HTTP:
133Finally, restart Nginx and you will be able to access your service via HTTP (Hypertext Transfer Protocol):
141134
142135#+begin_src sh
143136sudo systemctl restart nginx.service
@@ -145,49 +138,46 @@ sudo systemctl restart nginx.service
145138
146139** HTTPS
147140
148However, I don't want to access my RSS feeds via HTTP. I want it
149available only via HTTPS. In order to do this, I ran the
150[[https://certbot.eff.org/][certbot]] program to generate SSL
151certificates for me:
141However, I don't want to access my RSS feeds via HTTP. I want it available only
142via HTTPS (Hypertext Transfer Protocol Secure). In order to do this, I ran the
143[[https://certbot.eff.org/][certbot]] program to generate SSL (Secure Socket Layer) certificates for me:
152144
153145#+begin_src sh
154146sudo certbot --nginx
155147#+end_src
156148
157This process will automatically generate an SSL certificate for you and
158modify the Nginx configuration file to include a redirect from HTTP to
159HTTPS.
149This process will automatically generate an SSL certificate for you and modify
150the Nginx configuration file to include a redirect from HTTP to HTTPS.
160151
161152* Post-Installation Fixes
162153
163At this point, we have a functional FreshRSS website, available from
164anywhere and secured with HTTPS. However, attempting to connect this
165service to an RSS app resulted in many errors regarding unavailable URLs
166and incorrect credentials.
154At this point, we have a functional FreshRSS website, available from anywhere
155and secured with HTTPS. However, attempting to connect this service to an RSS
156app resulted in many errors regarding unavailable URLs and incorrect
157credentials.
167158
168159** API Set-Up
169160
170First, you need to open your user profile in FreshRSS (=Settings= >
171=Profile=) and set an API password in the field at the bottom. This is
172the password you will need to provide to your RSS apps.
161First, you need to open your user profile in FreshRSS (=Settings= > =Profile=)
162and set an API password in the field at the bottom. This is the password you
163will need to provide to your RSS apps.
173164
174Once that is set and saved, click the link below the API password field
175to open the API check tool. It should look something like
176=https://localhost:8080/api/= or =https://rss.example.com/api/=.
165Once that is set and saved, click the link below the API password field to open
166the API (application programming interface) check tool. It should look something
167like =https://localhost:8080/api/= or =https://rss.example.com/api/=.
177168
178Within this page, you /should/ see your correct external URL and "PASS"
179at the bottom of each API type. This would mean everything is set up
180correctly, and you can now move on and login to any RSS apps that
181support self-hosted options.
169Within this page, you /should/ see your correct external URL and "PASS" at the
170bottom of each API type. This would mean everything is set up correctly, and you
171can now move on and login to any RSS apps that support self-hosted options.
182172
183173In 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
185next section for a fix.
174=base_url= variable may be misconfigured. If this is the case, see the next
175section for a fix.
186176
187177** Base URL Fix
188178
189In order to fix the =base_url= for the API, I opened up my docker
190container with the following command:
179In order to fix the =base_url= for the API, I opened up my docker container with
180the following command:
191181
192182#+begin_src sh
193183sudo docker exec -it freshrss bash
@@ -206,9 +196,10 @@ Finally, open up =config.php= in the =data= directory:
206196nano data/config.php
207197#+end_src
208198
209Within =config.php=, you will need to update the =base_url= variable and
210update it to match your external URL. In my case, I simply commented-out
211the incorrect URL with =//= and added the correct one on a new line:
199Within =config.php=, you will need to update the =base_url= variable and update
200it to match your external URL (uniform resource locator). In my case, I simply
201commented-out the incorrect URL with =//= and added the correct one on a new
202line:
212203
213204#+begin_src php
214205<?php
@@ -221,8 +212,8 @@ the incorrect URL with =//= and added the correct one on a new line:
221212>
222213#+end_src
223214
224You can now exit the file with =Ctrl + x=, press =y= to save the file,
225and then click =Enter= to keep the same file name.
215You can now exit the file with =Ctrl + x=, press =y= to save the file, and then
216click =Enter= to keep the same file name.
226217
227218Finally, just exit out of the docker container:
228219
@@ -236,8 +227,7 @@ Next, just restart the container:
236227sudo docker restart freshrss
237228#+end_src
238229
239Voilà! Your API check should now "PASS" and you should be able to use
240one of the API URLs in your RSS apps.
230Voilà! Your API check should now "PASS" and you should be able to use one of the
231API URLs in your RSS apps.
241232
242In my case, I use [[https://netnewswire.com][NetNewsWire]] on my desktop
243and phone.
233In my case, I use [[https://netnewswire.com][NetNewsWire]] on my desktop and phone.
content/blog/2022-06-16-terminal-lifestyle.org +97 −115
@@ -5,29 +5,27 @@
55
66* Text-Based Simplicity
77
8I've detailed my views on web-based minimalism and related topics in
9other posts throughout the years; e.g., JavaScript/CSS bloat slowing
10down websites that are essentially a text document. However, I have
11never really expanded beyond talking about the web and describing how I
12focus on minimizing distractions in other digital environments.
13
14This post is going to set the baseline for how I /try/ to live my
15digital life. It does not necessarily get into my physical life, which
16is often harder to control and contain all the noise in our modern
17world.
18
19While there are new things to do every day in our digital world, I find
20that keeping a core set of values and interests can ground you and keep
21you mindful of /why/ you are participating in the digital world. For
22example, if - at your core - you have no interest in what strangers
23think about random topics, it would be unwise to start participating in
24social media. However, I am someone who has been dragged in by effective
25advertising to participate in communities that I realize I do not care
26for.
27
28I won't dive much further into explaining the philosophy of all this,
29but I will link a few helpful articles that may pique your interest if
30you're in search of more meaningful experiences:
8I've detailed my views on web-based minimalism and related topics in other posts
9throughout the years; e.g., JavaScript/CSS (Cascading Style Sheets) bloat
10slowing down websites that are essentially a text document. However, I have
11never really expanded beyond talking about the web and describing how I focus on
12minimizing distractions in other digital environments.
13
14This post is going to set the baseline for how I /try/ to live my digital life.
15It does not necessarily get into my physical life, which is often harder to
16control and contain all the noise in our modern world.
17
18While there are new things to do every day in our digital world, I find that
19keeping a core set of values and interests can ground you and keep you mindful
20of /why/ you are participating in the digital world. For example, if - at your
21core - you have no interest in what strangers think about random topics, it
22would be unwise to start participating in social media. However, I am someone
23who has been dragged in by effective advertising to participate in communities
24that I realize I do not care for.
25
26I won't dive much further into explaining the philosophy of all this, but I will
27link a few helpful articles that may pique your interest if you're in search of
28more meaningful experiences:
3129
3230- [[https://en.wikipedia.org/wiki/Mindfulness][Mindfulness]]
3331- [[https://en.wikipedia.org/wiki/Minimalism][Minimalism]]
@@ -35,125 +33,111 @@ you're in search of more meaningful experiences:
3533
3634* Living Life in the Terminal
3735
38My personal approach to reducing digital distractions and increasing my
39focus on the task at hand is to use a terminal for as much as I possibly
40can.
36My personal approach to reducing digital distractions and increasing my focus on
37the task at hand is to use a terminal for as much as I possibly can.
4138
42Most days, this means that I have a few tabs open constantly in my
43terminal:
39Most days, this means that I have a few tabs open constantly in my terminal:
4440
45411. A web browser
46422. A chat client
47433. An email client
484. An RSS feed reader
444. An RSS (Really Simple Syndication) feed reader
49455. A local shell for navigating my computer's files
50466. A remote shell for managing servers and other machines
5147
52Beyond this, I rarely open other tabs or GUI applications, unless
53absolutely necessary. If you look, you may be surprised what can be
54accomplished in the terminal.
48Beyond this, I rarely open other tabs or graphical applications, unless
49absolutely necessary. If you look, you may be surprised what can be accomplished
50in the terminal.
5551
56For example, I have moved my music and entertainment downloads to the
57terminal, along with my device VPN connections. I am exploring options
58for moving my RSS subscriptions to something like
59[[https://newsboat.org/][Newsboat]], so that I can read my daily
60articles without all the fuss.
52For example, I have moved my music and entertainment downloads to the terminal,
53along with my device virtual private network (VPN) connections. I am exploring
54options for moving my RSS subscriptions to something like [[https://newsboat.org/][Newsboat]], so that I
55can read my daily articles without all the fuss.
6156
62Now that we have some examples out of the way, let's dive into the
63specifics.
57Now that we have some examples out of the way, let's dive into the specifics.
6458
6559** Browsing the Web
6660
67I'm going to start off with a hard topic for those who prefer to live in
68the terminal: web browsing. This task is made hard mostly by websites
69and web apps that require JavaScript to run. The other difficult part is
70that if you're using a text-based browser, that means images won't load
71(hopefully that's obvious).
61I'm going to start off with a hard topic for those who prefer to live in the
62terminal: web browsing. This task is made hard mostly by websites and web apps
63that require JavaScript to run. The other difficult part is that if you're using
64a text-based browser, that means images won't load (hopefully that's obvious).
7265
73I am using [[https://lynx.invisible-island.net][Lynx]], a text-based
74browser that runs quickly and easily in the terminal. Lynx allows me to
75browser most websites by simply typing =g= and then typing in the URL I
76want.
66I am using [[https://lynx.invisible-island.net][Lynx]], a text-based browser that runs quickly and easily in the
67terminal. Lynx allows me to browser most websites by simply typing =g= and then
68typing in the URL I want.
7769
78If you need a search engine while in Lynx, I recommend
79[[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which allows
80you to search the web using their text-only interface.
70If you need a search engine while in Lynx, I recommend [[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which
71allows you to search the web using their text-only interface.
8172
82Eventually, you will run into websites that don't work (or are just too
83ugly and messy) in a text-only mode, and you'll be forced to switch over
84to a GUI browser to look at that site. Personally, I don't mind this as
85it doesn't happen as often as I thought it would.
73Eventually, you will run into websites that don't work (or are just too ugly and
74messy) in a text-only mode, and you'll be forced to switch over to a GUI browser
75to look at that site. Personally, I don't mind this as it doesn't happen as
76often as I thought it would.
8677
87The only time I need to do this is when I want to browse an
88image/video-focused webpage or if I need to log in to a site, and it
89doesn't support a text-only login page. For example, I am able to easily
90log in to [[https://sr.ht][Sourcehut]] in lynx.
78The only time I need to do this is when I want to browse an image/video-focused
79webpage or if I need to log in to a site, and it doesn't support a text-only
80login page. For example, I am able to easily log in to [[https://sr.ht][Sourcehut]] in lynx.
9181
9282** Chatting with Friends
9383
94After web browsing activities, my main form of terminal communication is
95Matrix. I use the [[https://docs.mau.fi/gomuks/][gomuks]] client
96currently.
84After web browsing activities, my main form of terminal communication is Matrix.
85I use the [[https://docs.mau.fi/gomuks/][gomuks]] client currently.
9786
98This was incredibly easy to install on macOS (but I will need to see if
99it'll be just as easy on Linux when my new laptop arrives):
87This was incredibly easy to install on macOS (but I will need to see if it'll be
88just as easy on Linux when my new laptop arrives):
10089
10190#+begin_src sh
10291brew install gomuks
10392#+end_src
10493
105Once you launch gomuks, it will sync and require your username and
106password to login. After doing so, the only problem I ran into was
107verifying my gomuks client so that I could participate in rooms with
108E2EE.
94Once you launch gomuks, it will sync and require your username and password to
95login. After doing so, the only problem I ran into was verifying my gomuks
96client so that I could participate in rooms with E2EE (end-to-end encryption).
10997
110Finally, I was able to verify the session by opening the Element desktop
111app (I assume you can do this in the browser and mobile app too, but I'm
112not sure) and manually verifying myself with this process:
98Finally, I was able to verify the session by opening the Element desktop app (I
99assume you can do this in the browser and mobile app too, but I'm not sure) and
100manually verifying myself with this process:
113101
1141021. Open the Element desktop app
1151032. Open a room I was a member of
1161043. Open the =Room Info= pane
1171054. Open the =People= menu and search for myself
1181065. Click on my profile name
1196. Click on the session link under the =Security= section and follow the
120 prompts to manually verify the session
1076. Click on the session link under the =Security= section and follow the prompts
108 to manually verify the session
121109
122Overall, I like gomuks and am able to enjoy all the features I was using
123in Element. The only hiccup I have occurred is manually downloading
124images to view them, which can be annoying.
110Overall, I like gomuks and am able to enjoy all the features I was using in
111Element. The only hiccup I have occurred is manually downloading images to view
112them, which can be annoying.
125113
126114** Email
127115
128Moving email to the terminal has been the hardest of the tasks for me.
129Unlike web browsing, where I can simply decide to not look at a website
130that does not work in the terminal, I cannot simply ignore emails sent
131to me.
116Moving email to the terminal has been the hardest of the tasks for me. Unlike
117web browsing, where I can simply decide to not look at a website that does not
118work in the terminal, I cannot simply ignore emails sent to me.
132119
133Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as
134a potential email client.
120Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as a potential email client.
135121
136However, this requires a *TON* of configuration and tweaking to get
137right. Even when I was able to set up neomutt, configure my email
138account, and customize a few personal preferences, a lot of emails still
139do not display correctly (mostly due to HTML and images).
122However, this requires a *TON* of configuration and tweaking to get right. Even
123when I was able to set up neomutt, configure my email account, and customize a
124few personal preferences, a lot of emails still do not display correctly (mostly
125due to HTML (Hypertext Markup Language) and images).
140126
141I won't get into the details of configuring =neomutt=; I mostly followed
142this blog post:
143[[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the
144Terminal: Configuring Neomutt]].
127I won't get into the details of configuring =neomutt=; I mostly followed this
128blog post: [[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the Terminal: Configuring Neomutt]].
145129
146Finally, I have yet to figure out how to connect my GPG keys to
147=neomutt=, but that's a problem for another day.
130Finally, I have yet to figure out how to connect my PGP (Pretty Good Privacy)
131keys to =neomutt=, but that's a problem for another day.
148132
149133** RSS Feed Reader
150134
151I have just started using [[https://newsboat.org/][Newsboat]] to read
152articles in my terminal and have found quick success with it.
135I have just started using [[https://newsboat.org/][Newsboat]] to read articles in my terminal and have
136found quick success with it.
153137
154The configuration was super easy for this app; I simply installed the
155app, created a file for URLs, and imported my OPML subscriptions that I
156had exported out of my old feed reader:
138The configuration was super easy for this app; I simply installed the app,
139created a file for URLs, and imported my OPML (Outline Processor Markup
140Language) subscriptions that I had exported out of my old feed reader:
157141
158142#+begin_src sh
159143brew install newsboat
@@ -169,13 +153,12 @@ newsboat -i=my_subscriptions.opml
169153
170154** Writing & Programming
171155
172Unfortunately, the weak link in my terminal-based environment right now
173is my grasp of the possibilities of editing files within a shell.
156Unfortunately, the weak link in my terminal-based environment right now is my
157grasp of the possibilities of editing files within a shell.
174158
175I am used to the easy extensions found in VSCodium and Kate, so I am
176slowly learning how to mold the default editing tools to my needs.
177Currently, this means I am using =nano= with the following
178configuration:
159I am used to the easy extensions found in VSCodium and Kate, so I am slowly
160learning how to mold the default editing tools to my needs. Currently, this
161means I am using =nano= with the following configuration:
179162
180163#+begin_src config
181164set breaklonglines
@@ -187,15 +170,14 @@ set fill 80
187170#+end_src
188171
189172This configuration allows nano to automatically hard-wrap lines at 80
190characters, autoindent the wrapped lines (if the previous line was
191indented), use 2 spaces per tab, and display line numbers within each
192file I open.
193
194I am currently looking to see if =vim= or =emacs= would be more useful
195for my current needs, but I'm not in any rush, so I don't expect to find
196an answer anytime soon.
197
198With my current life demands, I am not programming at the moment and
199have not explored the best terminal set-up for programming. However, I
200have seen many peers find success configuring =vim= and =emacs=, so
201that's where I will start when I pick my projects back up.
173characters, autoindent the wrapped lines (if the previous line was indented),
174use 2 spaces per tab, and display line numbers within each file I open.
175
176I am currently looking to see if =vim= or =emacs= would be more useful for my
177current needs, but I'm not in any rush, so I don't expect to find an answer
178anytime soon.
179
180With my current life demands, I am not programming at the moment and have not
181explored the best terminal set-up for programming. However, I have seen many
182peers find success configuring =vim= and =emacs=, so that's where I will start
183when 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:
1414Most of my programming projects are small, random projects that are made
1515strictly to fix some small problem I have or enhance my quality of life.
1616
17In this case, I was looking for a simply and easy way to get a daily
18dose of literature or poetry to read in the mornings.
17In this case, I was looking for a simply and easy way to get a daily dose of
18literature or poetry to read in the mornings.
1919
2020However, I don't want to sign up for a random mailing list on just any
2121website. 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.
2929This solution uses Python and email, so the following process requires
3030the following to be installed:
3131
321. An SMTP server, which can be as easy as installing =mailutils= if
33 you're on a Debian-based distro.
321. A Simple Mail Transfer Protocol (SMTP) server, which can be as easy as
33 installing =mailutils= if you're on a Debian-based distribution.
34342. Python (& pip!)
353. The following Python packages: =email=, =smtplib=, =json=, and
36 =requests=
353. The following Python packages: =email=, =smtplib=, =json=, and =requests=
3736
3837* Breaking Down the Logic
3938
40I want to break down the logic for this program, as it's quite simple
41and informational.
39I want to break down the logic for this program, as it's quite simple and
40informational.
4241
4342** Required Packages
4443
45This program starts with a simple import of the required packages, so I
46wanted to explain why each package is used:
44This program starts with a simple import of the required packages, so I wanted
45to explain why each package is used:
4746
4847#+begin_src python
4948from email.mime.text import MIMEText # Required for translating MIMEText
@@ -54,15 +53,15 @@ import requests # Required to send out a request to the API
5453
5554** Sending the API Request
5655
57Next, we need to actually send the API request. In my case, I'm calling
58a random poem from the entire API. If you want, you can call specific
59poems or authors from this API.
56Next, we need to actually send the application programming interface (API)
57request. In my case, I'm calling a random poem from the entire API. If you want,
58you can call specific poems or authors from this API.
6059
6160#+begin_src python
6261json_data = requests.get('https://poetrydb.org/random').json()
6362#+end_src
6463
65This gives us the following result in JSON:
64This gives us the following result in JSON (JavaScript Object Notation):
6665
6766#+begin_src json
6867[
@@ -94,12 +93,12 @@ This gives us the following result in JSON:
9493
9594** Parsing the API Results
9695
97In order to parse this into a readable format, we need to use the =json=
98package and extract the fields we want. In the example below, I am
99grabbing every field presented by the API.
96In order to parse this into a readable format, we need to use the =json= package
97and extract the fields we want. In the example below, I am grabbing every field
98presented by the API.
10099
101For the actual poem content, we need to loop over each line in the
102=lines= variable since each line is a separate string by default.
100For the actual poem content, we need to loop over each line in the =lines=
101variable since each line is a separate string by default.
103102
104103#+begin_quote
105104You /could/ also extract the title or author and make another call out
@@ -125,21 +124,20 @@ for line in json_data[0]['lines']:
125124
126125** Composing the Email
127126
128Now that I have all the data I need, I just need to compose it into a
129message and prepare the message metadata.
127Now that I have all the data I need, I just need to compose it into a message
128and prepare the message metadata.
130129
131For my daily email, I want to see the title of the poem first, followed
132by the author, then a blank line, and finally the full poem. This code
133snippet combines that data and packages it into a MIMEText container,
134ready to be emailed.
130For my daily email, I want to see the title of the poem first, followed by the
131author, then a blank line, and finally the full poem. This code snippet combines
132that data and packages it into a MIMEText container, ready to be emailed.
135133
136134#+begin_src python
137135msg_body = title + "\n" + author + "\n\n" + lines
138136msg = MIMEText(msg_body)
139137#+end_src
140138
141Before we send the email, we need to prepare the metadata (subject,
142from, to, etc.):
139Before we send the email, we need to prepare the metadata (subject, from, to,
140etc.):
143141
144142#+begin_src python
145143sender_email = 'example@server.local'
@@ -151,10 +149,9 @@ msg['To'] = recipient_email
151149
152150** Sending the Email
153151
154Now that I have everything ready to be emailed, the last step is to
155simply connect to an SMTP server and send the email out to the
156recipients. In my case, I installed =mailutils= on Ubuntu and let my
157SMTP server be =localhost=.
152Now that I have everything ready to be emailed, the last step is to simply
153connect to an SMTP server and send the email out to the recipients. In my case,
154I installed =mailutils= on Ubuntu and let my SMTP server be =localhost=.
158155
159156#+begin_src python
160157smtp_server = 'localhost'
@@ -165,9 +162,8 @@ s.quit()
165162
166163* The Result!
167164
168Instead of including a screenshot, I've copied the contents of the email
169that was delivered to my inbox below since I set this process up in
170plaintext format.
165Instead of including a screenshot, I've copied the contents of the email that
166was delivered to my inbox below since I set this process up in plaintext format.
171167
172168#+begin_src txt
173169Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
@@ -200,16 +196,16 @@ Some, wise in show, more fools indeed than they.
200196* Scheduling the Daily Email
201197
202198Last, 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
204do this, open =crontab= in editing mode:
199schedule a script to run daily, you can add it to the =crontab= file. To do
200this, open =crontab= in editing mode:
205201
206202#+begin_src sh
207203crontab -e
208204#+end_src
209205
210In the file, simply paste the following snippet at the bottom of the
211file and ensure that the file path is correctly pointing to wherever you
212saved your Python script:
206In the file, simply paste the following snippet at the bottom of the file and
207ensure that the file path is correctly pointing to wherever you saved your
208Python script:
213209
214210#+begin_src config
2152110 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py
content/blog/2022-06-24-fedora-i3.org +53 −57
@@ -5,61 +5,57 @@
55
66* Leaving macOS
77
8As I noted [[../foss-macos-apps][in a recent post]], I have been
9planning on migrating from macOS back to a Linux-based OS. I am happy to
10say that I have finally completed my migration and am now stuck in the
11wonderful world of Linux again.
8As I noted in a recent post, I have been planning on migrating from macOS back
9to a Linux-based operating system (OS). I am happy to say that I have finally
10completed my migration and am now stuck in the wonderful world of Linux again.
1211
1312My decision to leave macOS really came down to just a few important
1413things:
1514
16- Apple Security (Gatekeeper) restricting me from running any software I
17 want. Even if you disable Gatekeeper and allow software to bypass the
18 rest of the device installation security, you still have to repeat
19 that process every time the allowed software is updated.
20- macOS sends out nearly constant connections, pings, telemetry, etc. to
21 a myriad of mysterious Apple services. I'm not even going to dive into
22 how many macOS apps have constant telemetry on, as well.
23- Lastly, I just /really/ missed the customization and freedom that
24 comes with Linux. Being able to switch to entirely new kernel, OS, or
25 desktop within minutes is a freedom I took for granted when I switched
26 to macOS.
27
28Now that I've covered macOS, I'm going to move on to more exciting
29topics: my personal choice of OS, DE, and various customizations I'm
15- Apple Security (Gatekeeper) restricting me from running any software I want.
16 Even if you disable Gatekeeper and allow software to bypass the rest of the
17 device installation security, you still have to repeat that process every time
18 the allowed software is updated.
19- macOS sends out nearly constant connections, pings, telemetry, etc. to a
20 myriad of mysterious Apple services. I'm not even going to dive into how many
21 macOS apps have constant telemetry on, as well.
22- Lastly, I just /really/ missed the customization and freedom that comes with
23 Linux. Being able to switch to entirely new kernel, OS, or desktop within
24 minutes is a freedom I took for granted when I switched to macOS.
25
26Now that I've covered macOS, I'm going to move on to more exciting topics: my
27personal choice of OS, desktop environment (DE), and various customizations I'm
3028using.
3129
3230* Fedora
3331
34After trying a ton of distros (I think I booted and tested around 20-25
35distros), I finally landed on [[https://getfedora.org/][Fedora Linux]].
36I have quite a bit of experience with Fedora and enjoy the =dnf= package
37manager. Fedora allows me to keep up-to-date with recent software (I'm
38looking at you, Debian), but still provides a level of stability you
39don't find in every distro.
40
41In a very close second place was Arch Linux, as well as its spin-off:
42Garuda Linux (Garuda w/ sway is /beautiful/). Arch is great for
43compatibility and the massive community it has, but I have just never
44had the time to properly sit down and learn the methodology behind their
45packaging systems.
46
47Basically, everything else I tested was unacceptable in at least one way
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
32After trying a ton of distributions (I think I booted and tested around 20-25
33distributions), I finally landed on [[https://getfedora.org/][Fedora Linux]]. I have quite a bit of experience
34with Fedora and enjoy the =dnf= package manager. Fedora allows me to keep
35up-to-date with recent software (I'm looking at you, Debian), but still provides
36a level of stability you don't find in every distribution.
37
38In a very close second place was Arch Linux, as well as its spin-off: Garuda
39Linux (Garuda w/ sway is /beautiful/). Arch is great for compatibility and the
40massive community it has, but I have just never had the time to properly sit
41down and learn the methodology behind their packaging systems.
42
43Basically, everything else I tested was unacceptable in at least one way or
44another. Void (=glibc=) was great, but doesn't support all the software I need.
45Slackware worked well as a text-based user interface (TUI), but I wasn't skilled
5046enough to get a tiling window manager (WM) working on it.
5147
5248** i3
5349
54One of the reasons I settled on Fedora is that it comes with an official
55i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of
56the biggest things I wanted to do as soon as I adopted Linux again.
50One of the reasons I settled on Fedora is that it comes with an official i3
51spin. Being able to use a tiling WM, such as i3 or sway, is one of the biggest
52things I wanted to do as soon as I adopted Linux again.
5753
58I will probably set up a dotfile repository soon, so that I don't lose
59any of my configurations, but nothing big has been configured thus far.
54I will probably set up a dotfile repository soon, so that I don't lose any of my
55configurations, but nothing big has been configured thus far.
6056
61The two main things I have updated in i3wm are natural scrolling and
62binding my brightness keys to the =brightnessctl= program.
57The two main things I have updated in i3wm are natural scrolling and binding my
58brightness keys to the =brightnessctl= program.
6359
64601. Natural Scrolling
6561
@@ -69,8 +65,8 @@ binding my brightness keys to the =brightnessctl= program.
6965 sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf
7066 #+end_src
7167
72 Within the =40-libinput.conf= file, find the following input sections
73 and enable the natural scrolling option.
68 Within the =40-libinput.conf= file, find the following input sections and
69 enable the natural scrolling option.
7470
7571 This is the =pointer= section:
7672
@@ -98,10 +94,10 @@ binding my brightness keys to the =brightnessctl= program.
9894
99952. Enabling Brightness Keys
10096
101 Likewise, enabling brightness key functionality is as simple as
102 binding the keys to the =brightnessctl= program.
97 Likewise, enabling brightness key functionality is as simple as binding the
98 keys to the =brightnessctl= program.
10399
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:
105101
106102 #+begin_src sh
107103 nano /home/<my-user>/.config/i3/config
@@ -115,24 +111,24 @@ binding my brightness keys to the =brightnessctl= program.
115111
1161123. =polybar=
117113
118 Instead of using the default =i3status= bar, I have opted to use
119 =polybar= instead (as you can also see in the screenshot above).
114 Instead of using the default =i3status= bar, I have opted to use =polybar=
115 instead (as you can also see in the screenshot above).
120116
121 My config for this menu bar is basically just the default settings
122 with modified colors and an added battery block to quickly show me
123 the machine's battery info.
117 My configuration for this menu bar is basically just the default settings
118 with modified colors and an added battery block to quickly show me the
119 machine's battery info.
124120
1251214. =alacritty=
126122
127 Not much to say on this part yet, as I haven't configured it much,
128 but I installed =alacritty= as my default terminal, and I am using
129 =zsh= and the shell.
123 Not much to say on this part yet, as I haven't configured it much, but I
124 installed =alacritty= as my default terminal, and I am using =zsh= and the
125 shell.
130126
131127* Software Choices
132128
133Again, I'm not going to say much that I haven't said yet in other blog
134posts, so I'll just do a quick rundown of the apps I installed
135immediately after I set up the environment.
129Again, I'm not going to say much that I haven't said yet in other blog posts, so
130I'll just do a quick rundown of the apps I installed immediately after I set up
131the environment.
136132
137133Flatpak Apps:
138134
content/blog/2022-07-01-git-server.org +139 −156
@@ -5,56 +5,55 @@
55
66* My Approach to Self-Hosting Git
77
8I have often tried to self-host my Git repositories, but have always
9fallen short when I tried to find a suitable web interface to show on
10the front-end.
8I have often tried to self-host my Git repositories, but have always fallen
9short when I tried to find a suitable web interface to show on the front-end.
1110
12After a few years, I have finally found a combination of methods that
13allow me to easily self-host my projects, view them on the web, and
14access them from anywhere.
11After a few years, I have finally found a combination of methods that allow me
12to easily self-host my projects, view them on the web, and access them from
13anywhere.
1514
16Before I dive into the details, I want to state a high-level summary of
17my self-hosted Git approach:
15Before I dive into the details, I want to state a high-level summary of my
16self-hosted Git approach:
1817
1918- This method uses the =ssh://= (read & write) and =git://= (read-only)
2019 protocols for push and pull access.
21 - For the =git://= protocol, I create a =git-daemon-export-ok= file in
22 any repository that I want to be cloneable by anyone.
23 - The web interface I am using (=cgit=) allows simple HTTP cloning by
24 default. I do not disable this setting as I want beginners to be
25 able to clone one of my repositories even if they don't know the
26 proper method.
27- I am not enabling Smart HTTPS for any repositories. Updates to
28 repositories must be pushed via SSH.
29- Beyond the actual repository management, I am using =cgit= for the
30 front-end web interface.
20 - For the =git://= protocol, I create a =git-daemon-export-ok= file in any
21 repository that I want to be cloneable by anyone.
22 - The web interface I am using (=cgit=) allows simple HTTP cloning by default.
23 I do not disable this setting as I want beginners to be able to clone one of
24 my repositories even if they don't know the proper method.
25- I am not enabling Smart HTTPS (Hypertext Transfer Protocol Secure) for any
26 repositories. Updates to repositories must be pushed via SSH (Secure Shell
27 Protocol).
28- Beyond the actual repository management, I am using =cgit= for the front-end
29 web interface.
3130 - If you use the =scan-path=<path>= configuration in the =cgitrc=
32 configuration file to automatically find repositories, you can't
33 exclude a repository from =cgit= if it's stored within the path that
34 =cgit= reads. To host private repositories, you'd need to set up
35 another directory that =cgit= can't read.
31 configuration file to automatically find repositories, you can't exclude a
32 repository from =cgit= if it's stored within the path that =cgit= reads. To
33 host private repositories, you'd need to set up another directory that
34 =cgit= can't read.
3635
3736* Assumptions
3837
3938For 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
41server that you will be using to host your git repositories.
39(=git.example.com=) or internet protocol (IP) address (=207.84.26.991=)
40addressed to the server that you will be using to host your git repositories.
4241
4342* Adding a Git User
4443
45In order to use the SSH method associated with git, we will need to add
46a user named =git=. If you have used the SSH method for other git
47hosting sites, you are probably used to the following syntax:
44In order to use the SSH method associated with Git, we will need to add a user
45named =git=. If you have used the SSH method for other git hosting sites, you
46are probably used to the following syntax:
4847
4948#+begin_src sh
5049git clone [user@]server:project.git
5150#+end_src
5251
53The syntax above is an =scp=-like syntax for using SSH on the =git= user
54on the server to access your repository.
52The syntax above is an =scp=-like syntax for using SSH on the =git= user on the
53server to access your repository.
5554
56Let's delete any remnants of an old =git= user, if any, and create the
57new user account:
55Let's delete any remnants of an old =git= user, if any, and create the new user
56account:
5857
5958#+begin_src sh
6059sudo deluser --remove-home git
@@ -63,8 +62,8 @@ sudo adduser git
6362
6463** Import Your SSH Keys to the Git User
6564
66Once the =git= user is created, you will need to copy your public SSH
67key on your local development machine to the =git= user on the server.
65Once the =git= user is created, you will need to copy your public SSH key on
66your local development machine to the =git= user on the server.
6867
6968If you don't have an SSH key yet, create one with this command:
7069
@@ -72,11 +71,10 @@ If you don't have an SSH key yet, create one with this command:
7271ssh-keygen
7372#+end_src
7473
75Once you create the key pair, the public should be saved to
76=~/.ssh/id_rsa.pub=.
74Once you create the key pair, the public should be saved to =~/.ssh/id_rsa.pub=.
7775
78If your server still has password-based authentication available, you
79can copy it over to your user's home directory like this:
76If your server still has password-based authentication available, you can copy
77it over to your user's home directory like this:
8078
8179#+begin_src sh
8280ssh-copy-id git@server
@@ -88,8 +86,8 @@ Otherwise, copy it over to any user that you can access.
8886scp ~/.ssh/id_rsa.pub your_user@your_server:
8987#+end_src
9088
91Once on the server, you will need to copy the contents into the =git=
92user's =authorized_keys= file:
89Once on the server, you will need to copy the contents into the =git= user's
90=authorized_keys= file:
9391
9492#+begin_src sh
9593cat id_rsa.pub > /home/git/.ssh/authorized_keys
@@ -97,16 +95,15 @@ cat id_rsa.pub > /home/git/.ssh/authorized_keys
9795
9896** (Optional) Disable Password-Based SSH
9997
100If you want to lock down your server and ensure that no one can
101authenticate in via SSH with a password, you will need to edit your SSH
102configuration.
98If you want to lock down your server and ensure that no one can authenticate in
99via SSH with a password, you will need to edit your SSH configuration.
103100
104101#+begin_src sh
105102sudo nano /etc/ssh/sshd_config
106103#+end_src
107104
108Within this file, find the following settings and set them to the values
109I am showing below:
105Within this file, find the following settings and set them to the values I am
106showing below:
110107
111108#+begin_src conf
112109PermitRootLogin no
@@ -114,18 +111,17 @@ PasswordAuthentication no
114111AuthenticationMethods publickey
115112#+end_src
116113
117You may have other Authentication Methods required in your personal
118set-up, so the key here is just to ensure that =AuthenticationMethods=
119does not allow passwords.
114You may have other Authentication Methods required in your personal set-up, so
115the key here is just to ensure that =AuthenticationMethods= does not allow
116passwords.
120117
121118*** Setting up the Base Directory
122119
123Now that we have set up a =git= user to handle all transport methods, we
124need to set up the directory that we will be using as our base of all
125repositories.
120Now that we have set up a =git= user to handle all transport methods, we need to
121set up the directory that we will be using as our base of all repositories.
126122
127In my case, I am using =/git= as my source folder. To create this folder
128and assign it to the user we created, execute the following commands:
123In my case, I am using =/git= as my source folder. To create this folder and
124assign it to the user we created, execute the following commands:
129125
130126#+begin_src sh
131127sudo mkdir /git
@@ -134,15 +130,15 @@ sudo chown -R git:git /git
134130
135131*** Creating a Test Repository
136132
137On your server, switch over to the =git= user in order to start managing
138git files.
133On your server, switch over to the =git= user in order to start managing git
134files.
139135
140136#+begin_src sh
141137su git
142138#+end_src
143139
144Once logged-in as the =git= user, go to your base directory and create a
145test repository.
140Once logged-in as the =git= user, go to your base directory and create a test
141repository.
146142
147143#+begin_src sh
148144cd /git
@@ -150,9 +146,9 @@ mkdir test.git && cd test.git
150146git init --bare
151147#+end_src
152148
153If you want to make this repo viewable/cloneable to the public via the
154=git://= protocol, you need to create a =git-daemon-export-ok= file
155inside the repository.
149If you want to make this repo viewable/cloneable to the public via the =git://=
150protocol, you need to create a =git-daemon-export-ok= file inside the
151repository.
156152
157153#+begin_src sh
158154touch git-daemon-export-ok
@@ -160,34 +156,33 @@ touch git-daemon-export-ok
160156
161157* Change the Login Shell for =git=
162158
163To make sure that the =git= user is only used for git operations and
164nothing else, you need to change the user's login shell. To do this,
165simply use the =chsh= command:
159To make sure that the =git= user is only used for git operations and nothing
160else, you need to change the user's login shell. To do this, simply use the
161=chsh= command:
166162
167163#+begin_src sh
168164sudo chsh git
169165#+end_src
170166
171The interactive prompt will ask which shell you want the =git= user to
172use. You must use the following value:
167The interactive prompt will ask which shell you want the =git= user to use. You
168must use the following value:
173169
174170#+begin_src sh
175171/usr/bin/git-shell
176172#+end_src
177173
178Once done, no one will be able to SSH to the =git= user or execute
179commands other than the standard git commands.
174Once done, no one will be able to SSH to the =git= user or execute commands
175other than the standard git commands.
180176
181177* Opening the Firewall
182178
183Don't forget to open up ports on the device firewall and network
184firewall if you want to access these repositories publicly. If you're
185using default ports, forward ports =22= (ssh) and =9418= (git) from your
186router to your server's IP address.
179Don't forget to open up ports on the device firewall and network firewall if you
180want to access these repositories publicly. If you're using default ports,
181forward ports =22= (ssh) and =9418= (git) from your router to your server's IP
182address.
187183
188If your server also has a firewall, ensure that the firewall allows the
189same ports that are forwarded from the router. For example, if you use
190=ufw=:
184If your server also has a firewall, ensure that the firewall allows the same
185ports that are forwarded from the router. For example, if you use =ufw=:
191186
192187#+begin_src sh
193188sudo ufw allow 22
@@ -196,12 +191,12 @@ sudo ufw allow 9418
196191
197192** Non-Standard SSH Ports
198193
199If you use a non-standard port for SSH, such as =9876=, you will need to
200create an SSH configuration file on your local development machine in
201order to connect to your server's git repositories.
194If you use a non-standard port for SSH, such as =9876=, you will need to create
195an SSH configuration file on your local development machine in order to connect
196to your server's git repositories.
202197
203To do this, you'll need to define your custom port on your client
204machine in your =~/.ssh/config= file:
198To do this, you'll need to define your custom port on your client machine in
199your =~/.ssh/config= file:
205200
206201#+begin_src sh
207202nano ~/.ssh/config
@@ -222,8 +217,8 @@ There are two main syntaxes you can use to manage git over SSH:
222217- =git clone [user@]server:project.git=
223218- =git clone ssh://[user@]server/project.git=
224219
225I prefer the first, which is an =scp=-like syntax. To test it, try to
226clone the test repository you set up on the server:
220I prefer the first, which is an =scp=-like syntax. To test it, try to clone the
221test repository you set up on the server:
227222
228223#+begin_src sh
229224git clone git@git.example.com:/git/test.git
@@ -231,9 +226,8 @@ git clone git@git.example.com:/git/test.git
231226
232227* Enabling Read-Only Access
233228
234If you want people to be able to clone any repository where you've
235placed a =git-daemon-export-ok= file, you will need to start the git
236daemon.
229If you want people to be able to clone any repository where you've placed a
230=git-daemon-export-ok= file, you will need to start the git daemon.
237231
238232To do this on a system with =systemd=, create a service file:
239233
@@ -271,8 +265,7 @@ sudo systemctl enable git-daemon.service
271265sudo systemctl start git-daemon.service
272266#+end_src
273267
274To clone read-only via the =git://= protocol, you can use the following
275syntax:
268To clone read-only via the =git://= protocol, you can use the following syntax:
276269
277270#+begin_src sh
278271git clone git://git.example.com/test.git
@@ -283,9 +276,9 @@ git clone git://git.example.com/test.git
283276At this point, we have a working git server that works with both SSH and
284277read-only access.
285278
286For each of the repositories I had hosted a different provider, I
287executed the following commands in order to place a copy on my server as
288my new source of truth:
279For each of the repositories I had hosted a different provider, I executed the
280following commands in order to place a copy on my server as my new source of
281truth:
289282
290283Server:
291284
@@ -308,20 +301,20 @@ git push
308301
309302* Optional Web View: =cgit=
310303
311If you want a web viewer for your repositories, you can use various
312tools, such as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its
313simple interface and fairly easy set-up (compared to others). Not to
314mention that the [[https://git.kernel.org/][Linux kernel uses =cgit=]].
304If you want a web viewer for your repositories, you can use various tools, such
305as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its simple interface and
306fairly easy set-up (compared to others). Not to mention that the [[https://git.kernel.org/][Linux kernel
307uses =cgit=]].
315308
316309** Docker Compose
317310
318Instead of using my previous method of using a =docker run= command,
319I've updated this section to use =docker-compose= instead for an easier
320installation and simpler management and configuration.
311Instead of using my previous method of using a =docker run= command, I've
312updated this section to use =docker-compose= instead for an easier installation
313and simpler management and configuration.
321314
322In order to use Docker Compose, you will set up a =docker-compose.yml=
323file to automatically connect resources like the repositories, =cgitrc=,
324and various files or folders to the =cgit= container you're creating:
315In order to use Docker Compose, you will set up a =docker-compose.yml= file to
316automatically connect resources like the repositories, =cgitrc=, and various
317files or folders to the =cgit= container you're creating:
325318
326319#+begin_src sh
327320mkdir ~/cgit && cd ~/cgit
@@ -352,16 +345,16 @@ Then, just start the container:
352345sudo docker-compose up -d
353346#+end_src
354347
355Once it's finished installing, you can access the site at
356=<SERVER_IP>:8763= or use a reverse-proxy service to forward =cgit= to a
357URL, such as =git.example.com=. See the next section for more details on
358reverse proxying a URL to a local port.
348Once it's finished installing, you can access the site at =<SERVER_IP>:8763= or
349use a reverse-proxy service to forward =cgit= to a URL, such as
350=git.example.com=. See the next section for more details on reverse proxying a
351URL to a local port.
359352
360353** Nginx Reverse Proxy
361354
362I am using Nginx as my reverse proxy so that the =cgit= Docker container
363can use =git.example.com= as its URL. To do so, I simply created the
364following configuration file:
355I am using Nginx as my reverse proxy so that the =cgit= Docker container can use
356=git.example.com= as its uniform resource locator (URL). To do so, I simply
357created the following configuration file:
365358
366359#+begin_src sh
367360sudo 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/
410403sudo systemctl restart nginx.service
411404#+end_src
412405
413As we can see below, my site at =git.example.com= is available and
414running:
406As we can see below, my site at =git.example.com= is available and running:
415407
416408** Settings Up Git Details
417409
418Once you have =cgit= running, you can add some small details, such as
419repository owners and descriptions by editing the following files within
420each repository.
410Once you have =cgit= running, you can add some small details, such as repository
411owners and descriptions by editing the following files within each repository.
421412
422Alternatively, you can use the =cgitrc= file to edit these details if
423you only care to edit them for the purpose of seeing them on your
424website.
413Alternatively, you can use the =cgitrc= file to edit these details if you only
414care to edit them for the purpose of seeing them on your website.
425415
426The =description= file within the repository on your server will display
427the description online.
416The =description= file within the repository on your server will display the
417description online.
428418
429419#+begin_src sh
430420cd /git/example.git
431421nano description
432422#+end_src
433423
434You can add a =[gitweb]= block to the =config= file in order to display
435the owner of the repository.
424You can add a =[gitweb]= block to the =config= file in order to display the
425owner of the repository.
436426
437427#+begin_src sh
438428cd /git/example.git
@@ -444,22 +434,20 @@ nano config
444434 owner = "YourName"
445435#+end_src
446436
447Note that you can ignore the configuration within each repository and
448simply set up this information in the =cgitrc= file, if you want to do
449it that way.
437Note that you can ignore the configuration within each repository and simply set
438up this information in the =cgitrc= file, if you want to do it that way.
450439
451440** Editing =cgit=
452441
453In order to edit certain items within =cgit=, you need to edit the
454=cgitrc= file.
442In order to edit certain items within =cgit=, you need to edit the =cgitrc=
443file.
455444
456445#+begin_src sh
457446nano ~/cgit/cgitrc
458447#+end_src
459448
460449Below is an example configuration for =cgitrc=. You can find all the
461configuration options within the [configuration manual]
462([[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt]]).
450configuration options within the [[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt][configuration manual]].
463451
464452#+begin_src conf
465453css=/cgit.css
@@ -537,15 +525,14 @@ repo.desc=An example repository!
537525
538526** Final Fixes: Syntax Highlighting & README Rendering
539527
540After completing my initial install and playing around with it for a few
541days, I noticed two issues:
528After completing my initial install and playing around with it for a few days, I
529noticed two issues:
542530
5431. Syntax highlighting did not work when viewing the source code within
544 a file.
5311. Syntax highlighting did not work when viewing the source code within a file.
5455322. The =about= tab within a repository was not rendered to HTML.
546533
547The following process fixes these issues. To start, let's go to the
548=cgit= directory where we were editing our configuration file earlier.
534The following process fixes these issues. To start, let's go to the =cgit=
535directory where we were editing our configuration file earlier.
549536
550537#+begin_src sh
551538cd ~/cgit
@@ -575,14 +562,12 @@ curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html
575562chmod 755 md2html
576563#+end_src
577564
578If you need other filters or html-converters found within
579[[https://git.zx2c4.com/cgit/tree/filters][the cgit project files]],
580repeat the =curl= and =chmod= process above for whichever files you
581need.
565If you need other filters or html-converters found within [[https://git.zx2c4.com/cgit/tree/filters][the cgit project
566files]], repeat the =curl= and =chmod= process above for whichever files you need.
582567
583However, formatting will not work quite yet since the Docker cgit
584container we're using doesn't have the formatting package installed. You
585can install this easily by install Python 3+ and the =pygments= package:
568However, formatting will not work quite yet since the Docker cgit container
569we're using doesn't have the formatting package installed. You can install this
570easily by install Python 3+ and the =pygments= package:
586571
587572#+begin_src sh
588573# Enter the container's command line
@@ -601,8 +586,8 @@ exit
601586*You will need to enter the cgit docker container and re-run these =yum=
602587commands every time you kill and restart the container!*
603588
604If not done already, we need to add the following variables to our
605=cgitrc= file in order for =cgit= to know where our filtering files are:
589If not done already, we need to add the following variables to our =cgitrc= file
590in order for =cgit= to know where our filtering files are:
606591
607592#+begin_src conf
608593# Highlight source code with python pygments-based highlighter
@@ -613,26 +598,24 @@ source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
613598about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
614599#+end_src
615600
616Now you should see that syntax highlighting and README rendering to the
617=about= tab is fixed.
601Now you should see that syntax highlighting and README rendering to the =about=
602tab is fixed.
618603
619604** Theming
620605
621I won't go into much detail in this section, but you can fully theme
622your installation of =cgit= since you have access to the =cgit.css= file
623in your web root. This is another file you can add as a volume to the
624=docker-compose.yml= file if you want to edit this without entering the
625container's command line.
606I won't go into much detail in this section, but you can fully theme your
607installation of =cgit= since you have access to the =cgit.css= file in your web
608root. This is another file you can add as a volume to the =docker-compose.yml=
609file if you want to edit this without entering the container's command line.
626610
627*** :warning: Remember to Back Up Your Data!
611*** Remember to Back Up Your Data!
628612
629The last thing to note is that running services on your own equipment
630means that you're assuming a level of risk that exists regarding data
631loss, catastrophes, etc. In order to reduce the impact of any such
632occurrence, I suggest backing up your data regularly.
613The last thing to note is that running services on your own equipment means that
614you're assuming a level of risk that exists regarding data loss, catastrophes,
615etc. In order to reduce the impact of any such occurrence, I suggest backing up
616your data regularly.
633617
634Backups can be automated via =cron=, by hooking your base directory up
635to a cloud provider, or even setting up hooks to push all repository
636info to git mirrors on other git hosts. Whatever the method, make sure
637that your data doesn't vanish in the event that your drives or servers
638fail.
618Backups can be automated via =cron=, by hooking your base directory up to a
619cloud provider, or even setting up hooks to push all repository info to git
620mirrors on other git hosts. Whatever the method, make sure that your data
621doesn't vanish in the event that your drives or servers fail.
content/blog/2022-07-14-gnupg.org +111 −127
@@ -5,33 +5,30 @@
55
66* The History of GPG
77
8[[https://gnupg.org/][GNU Privacy Guard]], also known as GnuPG and GPG,
9is a free ("free" as in both speech and beer) software that fully
10implements the OpenPGP Message Format documented in
11[[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]].
12
13I won't go in-depth on the full history of the software in this post,
14but it is important to understand that GPG is not the same as PGP
15(Pretty Good Privacy), which is a different implementation of RFC 4880.
16However, GPG was designed to interoperate with PGP.
17
18GPG was originally developed in the late 1990s by
19[[https://en.wikipedia.org/wiki/Werner_Koch][Werner Koch]] and has
8[[https://gnupg.org/][GNU Privacy Guard]], also known as GnuPG and GPG, is a free ("free" as in both
9speech and beer) software that fully implements the OpenPGP Message Format
10documented in [[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]].
11
12I won't go in-depth on the full history of the software in this post, but it is
13important to understand that GPG is not the same as PGP (Pretty Good Privacy),
14which is a different implementation of RFC 4880. However, GPG was designed to
15interoperate with PGP.
16
17GPG was originally developed in the late 1990s by [[https://en.wikipedia.org/wiki/Werner_Koch][Werner Koch]] and has
2018historically been funded generously by the German government.
2119
22Now that we have all the high-level info out of the way, let's dive into
23the different aspects of GPG and its uses.
20Now that we have all the high-level info out of the way, let's dive into the
21different aspects of GPG and its uses.
2422
2523* Encryption Algorithms
2624
2725GPG supports a wide range of different encryption algorithms, including
28public-key, cipher, hash, and compression algorithms. The support for
29these algorithms has grown since the adoption of the Libgcrypt library
30in the 2.x versions of GPG.
26public-key, cipher, hash, and compression algorithms. The support for these
27algorithms has grown since the adoption of the Libgcrypt library in the 2.x
28versions of GPG.
3129
32As you will be able to see below in an example of a full key generation
33with the GPG command line tool, GPG recommends the following algorithms
34to new users:
30As you will be able to see below in an example of a full key generation with the
31GPG command line tool, GPG recommends the following algorithms to new users:
3532
3633#+begin_src sh
3734Please select what kind of key you want:
@@ -43,46 +40,39 @@ Please select what kind of key you want:
4340 (10) ECC (sign only)
4441#+end_src
4542
46I am not doing an in-depth explanation here in order to keep the focus
47on GPG and not encryption algorithms. If you want a deep dive into
48cryptography or encryption algorithms, please read my other posts:
43I am not doing an in-depth explanation here in order to keep the focus on GPG
44and not encryption algorithms. If you want a deep dive into cryptography or
45encryption algorithms, please read my other posts:
4946
50- [[../aes-encryption/][AES Encryption]] (2018)
51- [[../cryptography-basics/][Cryptography Basics]] (2020)
47- [[https://cleberg.net/blog/aes-encryption.html][How AES Encryption Works]] (2018)
48- [[https://cleberg.net/blog/cryptography.html][A Practical Guide to Encryption, Keys, and Secure Communication]] (2020)
5249
5350** Vulnerabilities
5451
55As of 2022-07-14, there are a few different vulnerabilities associated
56with GPG or the libraries it uses:
57
58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one
59 (GPG-generated) ElGamal signature of an arbitrary message is released,
60 one can recover the signer's private key in less than a second on a
61 PC." ([[https://www.di.ens.fr/~pnguyen/pub_Ng04.htm][Source]])
62- GPG versions prior to 1.4.2.1 contain a false positive signature
63 verification bug.
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. (
52As of 2022-07-14, there are a few different vulnerabilities associated with GPG
53or the libraries it uses:
54
55- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one (GPG-generated)
56 ElGamal signature of an arbitrary message is released, one can recover the
57 signer's private key in less than a second on a 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
59 bug. ([[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000211.html][Source]])
60- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned data. (
6761 [[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html][Source]])
68- Libgcrypt, a library used by GPG, contained a bug which enabled full
69 key recovery for RSA-1024 and some RSA-2048 keys. This was resolved in
70 a GPG update in 2017. ([[https://lwn.net/Articles/727179/][Source]])
71- The [[https://en.wikipedia.org/wiki/ROCA_vulnerability][ROCA
72 Vulnerability]] affects RSA keys generated by YubiKey 4 tokens.
62- Libgcrypt, a library used by GPG, contained a bug which enabled full key
63 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG
64 update in 2017. ([[https://lwn.net/Articles/727179/][Source]])
65- The [[https://en.wikipedia.org/wiki/ROCA_vulnerability][ROCA Vulnerability]] affects RSA keys generated by YubiKey 4 tokens.
7366 ([[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
75 an attacker to spoof digital signatures.
76 ([[https://arstechnica.com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/][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]])
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]])
68- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow,
69 fixed in Libgcrypt 1.9.1 ([[https://web.archive.org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/][Source]])
8070
8171*** Platforms
8272
83Originally developed as a command-line program for *nix systems, GPG now
84has a wealth of front-end applications and libraries available for
85end-users. However, the most recommended programs remain the same:
73Originally developed as a command-line program for *nix systems, GPG now has a
74wealth of front-end applications and libraries available for end-users. However,
75the most recommended programs remain the same:
8676
8777- [[https://gnupg.org][GnuPG]] for Linux (depending on distro)
8878- [[https://gpg4win.org][Gpg4win]] for Windows
@@ -90,27 +80,25 @@ end-users. However, the most recommended programs remain the same:
9080
9181* Creating a Key Pair
9282
93In order to create a GPG key pair, a user would first need to install
94GPG on their system. If we're assuming that the user is on Fedora Linux,
95they would execute the following:
83In order to create a GPG key pair, a user would first need to install GPG on
84their system. If we're assuming that the user is on Fedora Linux, they would
85execute the following:
9686
9787#+begin_src sh
9888sudo dnf install gpg
9989#+end_src
10090
101Once installed, a user can create a new key pair with the following
102command(s):
91Once installed, a user can create a new key pair with the following command(s):
10392
10493#+begin_src sh
10594gpg --full-generate-key
10695#+end_src
10796
108GPG will walk the user through an interactive setup that asks for an
109algorithm preference, expiration date, name, and email to associate with
110this key.
97GPG will walk the user through an interactive setup that asks for an algorithm
98preference, expiration date, name, and email to associate with this key.
11199
112See the following example key set-up for a default key generation using
113the GnuPG command-line interface:
100See the following example key set-up for a default key generation using the
101GnuPG command-line interface:
114102
115103#+begin_src sh
116104gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc.
@@ -166,12 +154,13 @@ uid John Doe (test key) <johndoe@example.com>
166154sub cv25519 2022-07-14 [E]
167155#+end_src
168156
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
170158interface.
171159
172160* Common Usage
173161
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:
175164
176165- digital signatures
177166- encryption
@@ -179,59 +168,57 @@ As noted in RFC 4880, the general functions of OpenPGP are as follows:
179168- Radix-64 conversion
180169- key management and certificate services
181170
182From this, you can probably gather that the main use of GPG is for
183encrypting data and/or signing the data with a key. The purpose of
184encrypting data with GPG is to ensure that no one except the intended
185recipient(s) can access the data.
171From this, you can probably gather that the main use of GPG is for encrypting
172data and/or signing the data with a key. The purpose of encrypting data with GPG
173is to ensure that no one except the intended recipient(s) can access the data.
186174
187175Let's explore some specific GPG use-cases.
188176
189177** Email
190178
191One of the more popular uses of GPG is to sign and/or encrypt emails.
192With the use of a GPG keypair, you can encrypt a message, its subject,
193and even the attachments within.
194
195The first process, regarding the signing of a message without any
196encryption, is generally used to provide assurance that an email is
197truly coming from the sender that the message claims. When I send an
198email, and it's signed with my public key, the recipient(s) of the
199message can verify that the message was signed with my personal key.
200
201The second process, regarding the actual encryption of the message and
202its contents, works by using a combination of the sender's keys and the
203recipient's keys. This process may vary slightly by implementation, but
204it most commonly uses asymmetric cryptography, also known as public-key
205cryptography. In this version of encryption, the sender's private key to
206sign the message and a combination of the sender's keys and the
207recipient's public key to encrypt the message.
208
209If two people each have their own private keys and exchange their public
210keys, they can send encrypted messages back and forth with GPG. This is
211also possible with symmetric cryptography, but the process differs since
212there are no key pairs.
213
214Implementation of email encryption varies greatly between email clients,
215so you will need to reference your email client's documentation to
216ensure you are setting it up correctly for that specific client.
179One of the more popular uses of GPG is to sign and/or encrypt emails. With the
180use of a GPG keypair, you can encrypt a message, its subject, and even the
181attachments within.
182
183The first process, regarding the signing of a message without any encryption, is
184generally used to provide assurance that an email is truly coming from the
185sender that the message claims. When I send an email, and it's signed with my
186public key, the recipient(s) of the message can verify that the message was
187signed with my personal key.
188
189The second process, regarding the actual encryption of the message and its
190contents, works by using a combination of the sender's keys and the recipient's
191keys. This process may vary slightly by implementation, but it most commonly
192uses asymmetric cryptography, also known as public-key cryptography. In this
193version of encryption, the sender's private key to sign the message and a
194combination of the sender's keys and the recipient's public key to encrypt the
195message.
196
197If two people each have their own private keys and exchange their public keys,
198they can send encrypted messages back and forth with GPG. This is also possible
199with symmetric cryptography, but the process differs since there are no key
200pairs.
201
202Implementation of email encryption varies greatly between email clients, so you
203will need to reference your email client's documentation to ensure you are
204setting it up correctly for that specific client.
217205
218206** File Encryption
219207
220As noted in the section above regarding emails, GPG enables users to be
221able to send a message to each other if they are both set-up with GPG
222keys. In this example, I am going to show how a user could send a file
223called =example_file.txt= to another user via the recipient's email.
208As noted in the section above regarding emails, GPG enables users to be able to
209send a message to each other if they are both set-up with GPG keys. In this
210example, I am going to show how a user could send a file called
211=example_file.txt= to another user via the recipient's email.
224212
225The sender would find the file they want to send and execute the
226following command:
213The sender would find the file they want to send and execute the following
214command:
227215
228216#+begin_src sh
229217gpg --encrypt --output example_file.txt.gpg --recipient \
230218recipient@example.com example_file.txt
231219#+end_src
232220
233Once received, the recipient can decrypt the file with the following
234command:
221Once received, the recipient can decrypt the file with the following command:
235222
236223#+begin_src sh
237224gpg --decrypt --output example_file.txt example_file.txt.gpg
@@ -239,29 +226,28 @@ gpg --decrypt --output example_file.txt example_file.txt.gpg
239226
240227** Ownership Signatures
241228
242One important aspect of GPG, especially for developers, is the ability
243to sign data without encrypting it. For example, developers often sign
244code changes when they commit the changes back to a central repository,
245in order to display ownership of who made the changes. This allows other
246users to look at a code change and determine that the change was valid.
229One important aspect of GPG, especially for developers, is the ability to sign
230data without encrypting it. For example, developers often sign code changes when
231they commit the changes back to a central repository, in order to display
232ownership of who made the changes. This allows other users to look at a code
233change and determine that the change was valid.
247234
248In order to do this using [[https://git-scm.com][Git]], the developer
249simply needs to alter the =git commit= command to include the =-S= flag.
250Here's an example:
235In order to do this using [[https://git-scm.com][Git]], the developer simply needs to alter the =git
236commit= command to include the =-S= flag. Here's an example:
251237
252238#+begin_src sh
253239git commit -S -m "my commit message"
254240#+end_src
255241
256As an expansion of the example above, Git users can configure their
257environment with a default key to use by adding their GPG signature:
242As an expansion of the example above, Git users can configure their environment
243with a default key to use by adding their GPG signature:
258244
259245#+begin_src sh
260246git config --global user.signingkey XXXXXXXXXXXXXXXX
261247#+end_src
262248
263If you're not sure what your signature is, you can find it titled =sig=
264in the output of this command:
249If you're not sure what your signature is, you can find it titled =sig= in the
250output of this command:
265251
266252#+begin_src sh
267253gpg --list-signatures
@@ -269,12 +255,11 @@ gpg --list-signatures
269255
270256** File Integrity
271257
272When a person generates a signature for data, they are allowing users
273the ability to verify the signature on that data in the future to ensure
274the data has not been corrupted. This is most common with software
275applications hosted on the internet - developers provide signatures so
276that users can verify a website was not hijacked and download links
277replaced with dangerous software.
258When a person generates a signature for data, they are allowing users the
259ability to verify the signature on that data in the future to ensure the data
260has not been corrupted. This is most common with software applications hosted on
261the internet - developers provide signatures so that users can verify a website
262was not hijacked and download links replaced with dangerous software.
278263
279264In order to verify signed data, a user needs to have:
280265
@@ -282,9 +267,8 @@ In order to verify signed data, a user needs to have:
2822672. A signature file
2832683. The public GPG key of the signer
284269
285Once the signer's public key is imported on the user's system, and they
286have the data and signature, they can verify the data with the following
287commands:
270Once the signer's public key is imported on the user's system, and they have the
271data and signature, they can verify the data with the following commands:
288272
289273#+begin_src sh
290274# If the signature is attached to the data
@@ -296,11 +280,11 @@ gpg --verify [signature-file] [original-file]
296280
297281*** Finding Public Keys
298282
299In order to use GPG with others, a user needs to know the other user(s)
300keys. This is easy to do if the user knows the other user(s) in person,
301but may be hard if the relationship is strictly digital. Luckily, there
302are a few options. The first option is to look at a user's web page or
303social pages if they have them.
283In order to use GPG with others, a user needs to know the other user(s) keys.
284This is easy to do if the user knows the other user(s) in person, but may be
285hard if the relationship is strictly digital. Luckily, there are a few options.
286The first option is to look at a user's web page or social pages if they have
287them.
304288
305289Otherwise, the best option is to use a keyserver, such as:
306290
content/blog/2022-07-25-curseradio.org +24 −28
@@ -6,28 +6,25 @@
66* Overview
77
88While exploring some interesting Linux applications, I stumbled across
9[[https://github.com/chronitis/curseradio][curseradio]], a command-line
10radio player based on Python.
9[[https://github.com/chronitis/curseradio][curseradio]], a command-line radio player based on Python.
1110
12This application is fantastic and incredibly easy to install, so I
13wanted to dedicate a post today to this app. Let's look at the features
14within the app and then walk through the installation process I took to
15get =curseradio= working.
11This application is fantastic and incredibly easy to install, so I wanted to
12dedicate a post today to this app. Let's look at the features within the app and
13then walk through the installation process I took to get =curseradio= working.
1614
1715* Features
1816
19The radio player itself is quite minimal. As you can see in the
20screenshot above, it contains a simple plaintext list of all available
21categories, which can be broken down further and further. In addition,
22radio shows are available for listening, alongside regular radio
23stations.
17The radio player itself is quite minimal. As you can see in the screenshot
18above, it contains a simple plaintext list of all available categories, which
19can be broken down further and further. In addition, radio shows are available
20for listening, alongside regular radio stations.
2421
25For example, the =Sports= > =Pro Basketball= > =Shows= category contains
26a number of specific shows related to Professional Basketball.
22For example, the =Sports= > =Pro Basketball= > =Shows= category contains a
23number of specific shows related to Professional Basketball.
2724
28Aside from being able to play any of the listed stations/shows, you can
29make a channel your favorite by pressing =f=. It will now show up at the
30top of the radio player in the =Favourites= category.
25Aside from being able to play any of the listed stations/shows, you can make a
26channel your favorite by pressing =f=. It will now show up at the top of the
27radio player in the =Favourites= category.
3128
3229** Commands/Shortcuts
3330
@@ -45,11 +42,10 @@ top of the radio player in the =Favourites= category.
4542
4643** Dependencies
4744
48Before installing =curseradio=, a handful of system and Python packages
49are required. To get started, install =python3=, =pip3=, and =mpv= on
50your system. In this example, I'm using Fedora Linux, which uses the
51=dnf= package manager. You may need to adjust this if you're using a
52different system.
45Before installing =curseradio=, a handful of system and Python packages are
46required. To get started, install =python3=, =pip3=, and =mpv= on your system.
47In this example, I'm using Fedora Linux, which uses the =dnf= package manager.
48You may need to adjust this if you're using a different system.
5349
5450#+begin_src sh
5551sudo dnf install python3 pip3 mpv
@@ -63,23 +59,23 @@ pip3 install requests xdg lxml
6359
6460** Repository Source Installation
6561
66Once all the dependencies are installed, we can clone the source code
67and enter that directory:
62Once all the dependencies are installed, we can clone the source code and enter
63that directory:
6864
6965#+begin_src sh
7066git clone https://github.com/chronitis/curseradio && cd curseradio
7167#+end_src
7268
73Once you're within the =curseradio= directory, you can install the
74application with the provided =setup.py= script.
69Once you're within the =curseradio= directory, you can install the application
70with the provided =setup.py= script.
7571
7672#+begin_src sh
7773sudo python3 setup.py install
7874#+end_src
7975
80In my case, I ran into a few errors and needed to create the folders
81that curseradio wanted to use for its installation. If you don't get any
82errors, you can skip this and run the app.
76In my case, I ran into a few errors and needed to create the folders that
77curseradio wanted to use for its installation. If you don't get any errors, you
78can skip this and run the app.
8379
8480#+begin_src sh
8581sudo mkdir /usr/local/lib/python3.10/
content/blog/2022-07-30-flac-to-opus.org +35 −38
@@ -6,17 +6,15 @@
66* Converting FLAC to OPUS
77
88I am currently rebuilding my music library from scratch so that I can
9effectively archive all the music I own in the
10[[https://en.wikipedia.org/wiki/FLAC][FLAC file format]], a lossless
11audio codec.
9effectively archive all the music I own in [[https://wikipedia.org/wiki/FLAC][FLAC]] (Free Lossless Audio Codec)
10files.
1211
13However, streaming FLAC files outside the home can be difficult due to
14the size of the files, especially if you're using a weak connection.
12However, streaming FLAC files outside the home can be difficult due to the size
13of the files, especially if you're using a weak connection.
1514
16So, in order to archive the music in a lossless format and still be able
17to stream it easily, I opted to create a copy of my FLAC files in the
18[[https://en.wikipedia.org/wiki/Opus_(audio_format)][Opus audio codec]].
19This allows me to archive a quality, lossless version of the music and
15So, in order to archive the music in a lossless format and still be able to
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
17codec]]. This allows me to archive a quality, lossless version of the music and
2018then point my streaming service to the smaller, stream-ready version.
2119
2220** Dependencies
@@ -28,39 +26,38 @@ proceeding, install the package:
2826sudo apt install opus-tools
2927#+end_src
3028
31If you want to use a different conversion method, such as =ffmpeg= or
32=avconv=, simply install that package instead.
29If you want to use a different conversion method, such as =ffmpeg= or =avconv=,
30simply install that package instead.
3331
3432** Conversion Process
3533
36The script I'm using is stored in my home directory, but feel free to
37create it wherever you want. It does not need to be in the same
38directory as your music files.
34The script I'm using is stored in my home directory, but feel free to create it
35wherever you want. It does not need to be in the same directory as your music
36files.
3937
4038#+begin_src sh
4139cd ~ && nano transform.sh
4240#+end_src
4341
44Once you have your new bash script opened in an editor, go ahead and
45paste the following logic into the script.
42Once you have your new bash script opened in an editor, go ahead and paste the
43following logic into the script.
4644
4745You *MUST* edit the following variables in order for it to work:
4846
4947- =source=: The source directory where your FLAC files are stored.
50- =dest=: The destination directory where you want the resulting Opus
51 files to be stored.
48- =dest=: The destination directory where you want the resulting Opus files to
49 be stored.
5250
5351You *MAY* want to edit the following variables to suit your needs:
5452
55- =filename=: If you are converting to a file format other than Opus,
56 you'll need to edit this so that your resulting files have the correct
57 filename extension.
58- =reldir=: This variable can be edited to strip out more leading
59 directories in the file path. As you'll see later, I ignore this for
60 now and simply clean it up afterward.
61- =opusenc=: This is the actual conversion process. You may want to edit
62 the bitrate to suit your needs. I set mine at 128 but some prefer 160
63 or higher.
53- =filename=: If you are converting to a file format other than Opus, you'll
54 need to edit this so that your resulting files have the correct filename
55 extension.
56- =reldir=: This variable can be edited to strip out more leading directories in
57 the file path. As you'll see later, I ignore this for now and simply clean it
58 up afterward.
59- =opusenc=: This is the actual conversion process. You may want to edit the
60 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher.
6461
6562#+begin_src sh
6663#!/bin/bash
@@ -126,8 +123,8 @@ opusenc --vbr --bitrate 128 --date "$DATE" \
126123done
127124#+end_src
128125
129Once you're done, simply save the file and exit your editor. Don't
130forget to enable execution of the script:
126Once you're done, simply save the file and exit your editor. Don't forget to
127enable execution of the script:
131128
132129#+begin_src sh
133130chmod +x transform.sh
@@ -139,16 +136,16 @@ Finally, you may now run the script:
139136./transform.sh
140137#+end_src
141138
142If you used =opusenc=, you'll see the conversions happen within the
143terminal as it progresses. You will also see variables printed if you
144uncommented any of the bash script's comments.
139If you used =opusenc=, you'll see the conversions happen within the terminal as
140it progresses. You will also see variables printed if you uncommented any of the
141bash script's comments.
145142
146143** Cleanup
147144
148As I noted above, I didn't customize my =reldir= variable in the script,
149which caused my output directory to be =/mnt/music/library/archives=
150instead of =/mnt/music/library=. So, I moved the output up one level and
151deleted the accidental directory.
145As I noted above, I didn't customize my =reldir= variable in the script, which
146caused my output directory to be =/mnt/music/library/archives= instead of
147=/mnt/music/library=. So, I moved the output up one level and deleted the
148accidental directory.
152149
153150#+begin_src sh
154151cd /mnt/music/library
@@ -158,8 +155,8 @@ rm -rf archives
158155
159156** Check the Resulting Size
160157
161If you want to see what kind of file size savings you've gained, you can
162always use the =du= command to check:
158If you want to see what kind of file size savings you've gained, you can always
159use the =du= command to check:
163160
164161#+begin_src sh
165162cd /mnt/music
content/blog/2022-07-31-bash-it.org +57 −66
@@ -5,14 +5,12 @@
55
66* Bash
77
8For those who are not familiar,
9[[https://en.wikipedia.org/wiki/Bash_(Unix_shell)][Bash]] is a Unix
10shell that is used as the default login shell for most Linux
11distributions. This shell and command processor should be familiar if
12you've used Linux (or older version of macOS) before.
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
9login shell for most Linux distributions. This shell and command processor
10should be familiar if you've used Linux (or older version of macOS) before.
1311
14However, bash is not the only option. There are numerous other shells
15that exist. Here are some popular examples:
12However, bash is not the only option. There are numerous other shells that
13exist. Here are some popular examples:
1614
1715- [[https://en.wikipedia.org/wiki/Z_shell][zsh]]
1816- [[https://en.wikipedia.org/wiki/Fish_(Unix_shell)][fish]]
@@ -20,16 +18,15 @@ that exist. Here are some popular examples:
2018- [[https://wiki.gentoo.org/wiki/Mksh][mksh]]
2119- [[https://en.wikipedia.org/wiki/Debian_Almquist_shell][dash]]
2220
23While each shell has its differences, bash is POSIX compliant and the
24default for many Linux users. Because of this, I am going to explore a
25program called =bash-it= below that helps bash users increase the
26utility of their shell without installing a completely new shell.
21While each shell has its differences, bash is POSIX compliant and the default
22for many Linux users. Because of this, I am going to explore a program called
23=bash-it= below that helps bash users increase the utility of their shell
24without installing a completely new shell.
2725
2826** Installation
2927
30First, if bash is not already installed on your system, you can
31[[https://www.gnu.org/software/bash/][download bash from GNU]] or use
32your package manager to install it.
28First, if bash is not already installed on your system, you can [[https://www.gnu.org/software/bash/][download bash
29from GNU]] or use your package manager to install it.
3330
3431For example, this is how you can install bash on Fedora Linux:
3532
@@ -37,19 +34,19 @@ For example, this is how you can install bash on Fedora Linux:
3734sudo dnf install bash
3835#+end_src
3936
40If you are not using bash as your default shell, use the =chsh= command
41to change your shell:
37If you are not using bash as your default shell, use the =chsh= command to
38change your shell:
4239
4340#+begin_src sh
4441chsh
4542#+end_src
4643
47You should see a prompt like the one below. If the brackets (=[]=)
48contain =bash= already, you're done, and you can simply continue by
49hitting the Enter key.
44You should see a prompt like the one below. If the brackets (=[]=) contain
45=bash= already, you're done, and you can simply continue by hitting the Enter
46key.
5047
51If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter
52the path to the bash program on your system (it's most likely located at
48If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter the path
49to the bash program on your system (it's most likely located at
5350=/usr/bin/bash=).
5451
5552#+begin_src sh
@@ -57,9 +54,9 @@ Changing shell for <user>.
5754New shell [/usr/bin/bash]:
5855#+end_src
5956
60You must log out or restart the machine in order for the login shell to
61be refreshed. You can do it now or wait until you're finished
62customizing the shell.
57You must log out or restart the machine in order for the login shell to be
58refreshed. You can do it now or wait until you're finished customizing the
59shell.
6360
6461#+begin_src sh
6562sudo reboot now
@@ -67,31 +64,30 @@ sudo reboot now
6764
6865* Bash-it
6966
70As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]]
71repository:
67As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]] repository:
7268
7369#+begin_quote
7470Bash-it is a collection of community Bash commands and scripts for Bash
75713.2+. (And a shameless ripoff of oh-my-zsh 😃)
7672#+end_quote
7773
78Bash-it makes it easy to install plugins, set up aliases for common
79commands, and easily change the visual theme of your shell.
74Bash-it makes it easy to install plugins, set up aliases for common commands,
75and easily change the visual theme of your shell.
8076
8177** Installation
8278
8379To install the framework, simply copy the repository files and use the
84=install.sh= script provided. If you want, you can (and should!) inspect
85the contents of the installation script before you run it.
80=install.sh= script provided. If you want, you can (and should!) inspect the
81contents of the installation script before you run it.
8682
8783#+begin_src sh
8884git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it
8985~/.bash_it/install.sh
9086#+end_src
9187
92If you didn't restart your session after making bash the default, and
93are currently working within another shell, be sure to enter a bash
94session before using =bash-it=:
88If you didn't restart your session after making bash the default, and are
89currently working within another shell, be sure to enter a bash session before
90using =bash-it=:
9591
9692#+begin_src sh
9793bash
@@ -100,16 +96,16 @@ bash
10096** Aliases
10197
10298Bash-it contains a number of aliases for common commands to help improve
103efficiency in the terminal. To list all available options, use the
104following command:
99efficiency in the terminal. To list all available options, use the following
100command:
105101
106102#+begin_src sh
107103bash-it show aliases
108104#+end_src
109105
110This will provide you a list that looks like the following text block.
111Within this screen, you will be able to see all available options and
112which ones are currently enabled.
106This will provide you a list that looks like the following text block. Within
107this screen, you will be able to see all available options and which ones are
108currently enabled.
113109
114110#+begin_src txt
115111Alias Enabled? Description
@@ -140,9 +136,8 @@ bash-it disable alias <alias name> [alias name]... -or- $ bash-it disable alias
140136
141137** Plugins
142138
143Similar to aliases, plugins are available with bash-it. You can find a
144complete list of plugins in the same way as aliases. Simply execute the
145following:
139Similar to aliases, plugins are available with bash-it. You can find a complete
140list of plugins in the same way as aliases. Simply execute the following:
146141
147142#+begin_src sh
148143bash-it show plugins
@@ -177,9 +172,7 @@ bash-it disable plugin <plugin name> [plugin name]... -or- $ bash-it disable plu
177172
178173** Themes
179174
180There are quite a few pre-defined
181[[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]]
182available with bash-it.
175There are quite a few pre-defined [[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]] available with bash-it.
183176
184177To list all themes:
185178
@@ -187,9 +180,8 @@ To list all themes:
187180ls ~/.bash_it/themes/
188181#+end_src
189182
190To use a new theme, you'll need to edit =.bashrc= and alter the
191=BASH_IT_THEME= variable to your desired theme. For example, I am using
192the =zork= theme.
183To use a new theme, you'll need to edit =.bashrc= and alter the =BASH_IT_THEME=
184variable to your desired theme. For example, I am using the =zork= theme.
193185
194186#+begin_src sh
195187nano ~/.bashrc
@@ -199,23 +191,22 @@ nano ~/.bashrc
199191export BASH_IT_THEME='zork'
200192#+end_src
201193
202Once you save your changes, you just need to exit your terminal and
203create a new one in order to see your changes to the =.bashrc= file. You
204can also =source= the file to see changes, but I recommend starting a
205completely new shell instead.
194Once you save your changes, you just need to exit your terminal and create a new
195one in order to see your changes to the =.bashrc= file. You can also =source=
196the file to see changes, but I recommend starting a completely new shell
197instead.
206198
207199*** ble.sh
208200
209One big feature I was missing in Bash that both =zsh= and =fish= have is
210an autosuggestion feature. To explain: as you type, an autosuggestion
211feature in the shell will offer suggestions in a lighter font color
212beyond the characters already typed. Once you see the command you want,
213you can click the right arrow and have the shell auto-complete that line
214for you.
201One big feature I was missing in Bash that both =zsh= and =fish= have is an
202autosuggestion feature. To explain: as you type, an autosuggestion feature in
203the shell will offer suggestions in a lighter font color beyond the characters
204already typed. Once you see the command you want, you can click the right arrow
205and have the shell auto-complete that line for you.
215206
216Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]]
217(ble.sh) exists! This program provides a wonderful autosuggestions
218feature perfectly, among other features that I haven't tested yet.
207Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]] (ble.sh) exists! This program provides a wonderful
208autosuggestions feature perfectly, among other features that I haven't tested
209yet.
219210
220211In order to install ble.sh, execute the following:
221212
@@ -225,16 +216,16 @@ make -C ble.sh install PREFIX=~/.local
225216echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
226217#+end_src
227218
228Again, exit the terminal and open a new one in order to see the
229newly-configured shell.
219Again, exit the terminal and open a new one in order to see the newly-configured
220shell.
230221
231222* Restart the Session
232223
233Finally, as mentioned above, you'll need to restart the session to
234ensure that your user is using bash by default.
224Finally, as mentioned above, you'll need to restart the session to ensure that
225your user is using bash by default.
235226
236You will also need to exit and re-open a shell (e.g., terminal or
237terminal tab) any time you make changes to the =.bashrc= file.
227You will also need to exit and re-open a shell (e.g., terminal or terminal tab)
228any time you make changes to the =.bashrc= file.
238229
239230#+begin_src sh
240231sudo reboot now
content/blog/2022-08-31-privacy-com-changes.org +49 −56
@@ -5,50 +5,46 @@
55
66* Privacy.com Changes Their Terms
77
8Recently, Privacy.com reached out to their customers regarding a change
9in their terms of use. Further, all customers are required to agree to
10the changes in order to continue using their accounts.
8Recently, Privacy.com reached out to their customers regarding a change in their
9terms of use. Further, all customers are required to agree to the changes in
10order to continue using their accounts.
1111
12[[https://privacy.com/commercial-cardholder-agreement][You can view the
13new cardholder agreement here]].
12[[https://privacy.com/commercial-cardholder-agreement][You can view the new cardholder agreement here]].
1413
15When you log in, you'll be greeted with a pop-up window asking you to
16review and agree to the new terms of use. You will also not be able to
17open any new cards until the terms are agreed to.
14When you log in, you'll be greeted with a pop-up window asking you to review and
15agree to the new terms of use. You will also not be able to open any new cards
16until the terms are agreed to.
1817
1918** Changing from a "Prepaid Debit" Model to a "Charge Card" Model
2019
21The actual content of the changes is interesting. While the historical
22model of using Privacy.com was akin to prepaid debit cards, the new
23model is very similar to a credit card (they use the term "charge
24card").
20The actual content of the changes is interesting. While the historical model of
21using Privacy.com was akin to prepaid debit cards, the new model is very similar
22to a credit card (they use the term "charge card").
2523
26I have used Privacy.com for 1-2 years, and the process was always that
27you would create a single-use or merchant-locked card. This card could
28be used for any dollar limit you set and would immediately draw the
29funds from whatever funding source you connected, e.g. PayPal account or
30a bank account.
24I have used Privacy.com for 1-2 years, and the process was always that you would
25create a single-use or merchant-locked card. This card could be used for any
26dollar limit you set and would immediately draw the funds from whatever funding
27source you connected, e.g. PayPal account or a bank account.
3128
32The benefit this service provides with a premium account is masking the
33merchant names from your funding source. If you have a concern that your
34bank account uses merchant data from your account, you could direct all
35charges through Privacy.com and set the merchant as one of their pre-set
36options, such as "Smiley's Corner Store" or "NSA Gift Shop."
29The benefit this service provides with a premium account is masking the merchant
30names from your funding source. If you have a concern that your bank account
31uses merchant data from your account, you could direct all charges through
32Privacy.com and set the merchant as one of their pre-set options, such as
33"Smiley's Corner Store" or "NSA Gift Shop."
3734
38The new model still works with a bank account as a funding source, but
39the model is changed so that you get a "line of credit" set according to
40a 14-day billing cycle. It seems that Privacy.com will now allow charges
41to be incurred without being immediately paid.
35The new model still works with a bank account as a funding source, but the model
36is changed so that you get a "line of credit" set according to a 14-day billing
37cycle. It seems that Privacy.com will now allow charges to be incurred without
38being immediately paid.
4239
4340** Daily Payments and Available Credit
4441
45Instead of paying as charges are incurred, you must make a "Daily
46Payment" and your "Available Credit" will be locked until you make that
47payment. There are also "End of Billing Cycle Payments" that are
48assigned a due date.
42Instead of paying as charges are incurred, you must make a "Daily Payment" and
43your "Available Credit" will be locked until you make that payment. There are
44also "End of Billing Cycle Payments" that are assigned a due date.
4945
50Further, Privacy.com will decline charges that would cause you to exceed
51your Available Credit or Credit Limit.
46Further, Privacy.com will decline charges that would cause you to exceed your
47Available Credit or Credit Limit.
5248
5349One particular interesting section states the following:
5450
@@ -63,37 +59,34 @@ FOR MORE INFORMATION.
6359
6460** Personal Information
6561
66Now that Privacy.com is more of a financial institution, they are
67obligated to comply with the
68[[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]]
69guidelines/laws.
62Now that Privacy.com is more of a financial institution, they are obligated to
63comply with the [[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]] guidelines/laws.
7064
71I did not proceed with the change to my Privacy.com account, but I have
72heard from some peers that the changes require more personal information
73to be submitted, such as SSN. I am not aware of all new personal
74information required or if the funding source is now required to only be
75a bank account.
65I did not proceed with the change to my Privacy.com account, but I have heard
66from some peers that the changes require more personal information to be
67submitted, such as SSN (Social Security Number). I am not aware of all new
68personal information required or if the funding source is now required to only
69be a bank account.
7670
7771** Fees
7872
79Luckily, the fees section did not change much. The subscription fees for
80a premium account are still the only fees.
73Luckily, the fees section did not change much. The subscription fees for a
74premium account are still the only fees.
8175
8276* My Thoughts
8377
84Personally, I wiped my personal information from my account and then
85permanently deleted it when I heard about these changes. I have no
86interest in yet another method of credit lending offered by private
87companies. While I accepted that they would have access to my bank
88account information for the purposes of paying off my prepaid debit
89payments, I have no interest in incurring charges that will need to be
90paid back at a later date. I also have no interest in submitting
78Personally, I wiped my personal information from my account and then permanently
79deleted it when I heard about these changes. I have no interest in yet another
80method of credit lending offered by private companies. While I accepted that
81they would have access to my bank account information for the purposes of paying
82off my prepaid debit payments, I have no interest in incurring charges that will
83need to be paid back at a later date. I also have no interest in submitting
9184personal information to Privacy.com.
9285
93This type of change toward a "buy it now, pay us later" model is
94concerning, and I will be watching Privacy.com to see if they further
95their interests in the credit model as time goes on.
86This type of change toward a "buy it now, pay us later" model is concerning, and
87I will be watching Privacy.com to see if they further their interests in the
88credit model as time goes on.
9689
97Could we see them start charging interest, fees, etc.? I'm not sure, but
98this change does not inspire confidence in their mission as a
99privacy-focused company.
90Could we see them start charging interest, fees, etc.? I'm not sure, but this
91change does not inspire confidence in their mission as a privacy-focused
92company.
content/blog/2022-09-17-serenity-os.org +35 −41
@@ -5,13 +5,13 @@
55
66* Overview
77
8[[https://serenityos.org][SerenityOS]] is a unique operating system (OS)
9that I have seen pop up in my news feed a few times over the last few
10years, but I have never had time to test it out until now.
8[[https://serenityos.org][SerenityOS]] is a unique operating system (OS) that I have seen pop up in my news
9feed a few times over the last few years, but I have never had time to test it
10out until now.
1111
1212Testing out this system brought back fond memories of yellowed,
13modem-screeching, 100-pound computers that brought so many fond memories
14to my youth.
13modem-screeching, 100-pound computers that brought so many fond memories to my
14youth.
1515
1616Per their website:
1717
@@ -31,11 +31,10 @@ This is a system by us, for us, based on the things we like.
3131
3232* Building
3333
34Your first question may be "Where's the iso?" and the answer is... there
35are none. SerenityOS does not provide pre-built images for testing. You
36must build the images yourself. This seems intentionally to limit
37participation to only those who are truly interested enough to learn how
38to build the OS.
34Your first question may be "Where's the iso?" and the answer is... there are
35none. SerenityOS does not provide pre-built images for testing. You must build
36the images yourself. This seems intentionally to limit participation to only
37those who are truly interested enough to learn how to build the OS.
3938
4039** Clone
4140
@@ -47,25 +46,22 @@ git clone https://github.com/SerenityOS/serenity && cd serenity
4746
4847** Build
4948
50Note that I followed the
51[[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build
52Instructions]] in the SerenityOS repository as of commit
53=660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed
54since my installation, and you should double-check the instructions
55first.
49Note that I followed the [[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build Instructions]] in the SerenityOS repository as of
50commit =660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed since
51my installation, and you should double-check the instructions first.
5652
57Regardless, I want to repeat my steps here to illustrate any errors or
58differing commands I needed to run in order to build and run SerenityOS.
53Regardless, I want to repeat my steps here to illustrate any errors or differing
54commands I needed to run in order to build and run SerenityOS.
5955
60Since I am running Fedora, I needed to install these packages in order
61to build the OS images:
56Since I am running Fedora, I needed to install these packages in order to build
57the OS images:
6258
6359#+begin_src sh
6460sudo 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
6561#+end_src
6662
67Next, make sure you're inside the =serenity= directory created earlier
68during the git cloning process and process to build the toolchain:
63Next, make sure you're inside the =serenity= directory created earlier during
64the git cloning process and process to build the toolchain:
6965
7066#+begin_src sh
7167Meta/serenity.sh rebuild-toolchain
@@ -82,29 +78,27 @@ launch.
8278
8379* Issues
8480
85I played around in SerenityOS for an hour or two in order to see what I
86could do and had a lot of fun with it. The only issue I ran into was a
87lack of working internet. I didn't try very hard, but I could tell that
88the main network link wasn't connecting to my Fedora host properly.
81I played around in SerenityOS for an hour or two in order to see what I could do
82and had a lot of fun with it. The only issue I ran into was a lack of working
83internet. I didn't try very hard, but I could tell that the main network link
84wasn't connecting to my Fedora host properly.
8985
9086* Screenshots
9187
92The initial launch of the image displays the SerenityOS desktop, with a
93simple terminal already launched.
88The initial launch of the image displays the SerenityOS desktop, with a simple
89terminal already launched.
9490
95There is also a "Fire" application (literally just shows fire burning),
96a browser with the local Serenity Browser page loaded, and a text
97editor.
91There is also a "Fire" application (literally just shows fire burning), a
92browser with the local Serenity Browser page loaded, and a text editor.
9893
99I also poked around the system utilities and found most tools you'd
100expect to find within a standard desktop, such as a system monitoring
101tool.
94I also poked around the system utilities and found most tools you'd expect to
95find within a standard desktop, such as a system monitoring tool.
10296
103Lastly, I noted that the default desktop contains numerous pre-defined
104themes to choose from. This is a small piece, but it's actually
105wonderful to see desktop developers consider theming directly out of the
106box rather than using an addon-based mentality.
97Lastly, I noted that the default desktop contains numerous pre-defined themes to
98choose from. This is a small piece, but it's actually wonderful to see desktop
99developers consider theming directly out of the box rather than using an
100addon-based mentality.
107101
108I didn't take a screenshot of the other pre-installed games, but I did
109spend nearly 30 minutes playing Solitaire before remembering that I was
110supposed to be writing a post about the OS.
102I didn't take a screenshot of the other pre-installed games, but I did spend
103nearly 30 minutes playing Solitaire before remembering that I was supposed to be
104writing a post about the OS.
content/blog/2022-09-21-graphene-os.org +51 −58
@@ -5,26 +5,24 @@
55
66* Introduction
77
8After using iOS for a couple of years, I finally took the plunge and
9purchased a Pixel 6 Pro in order to test and use [GrapheneOS]
10([[https://grapheneos.org]]).
8After using iOS for a couple of years, I finally took the plunge and purchased a
9Pixel 6 Pro in order to test and use [[https://grapheneos.org][GrapheneOS]].
1110
12The installation process was rather quick once you have the tools and
13files you need. Overall, it can be done in just a few minutes.
11The installation process was rather quick once you have the tools and files you
12need. Overall, it can be done in just a few minutes.
1413
1514* Gathering Tools & Files
1615
1716** Android Tools
1817
19First, in order to interact with the device, we will need the
20[[https://developer.android.com/studio/releases/platform-tools.html][Android
21platform tools]]. Find the Linux download and save the ZIP folder to
22your preferred location.
18First, in order to interact with the device, we will need the [[https://developer.android.com/studio/releases/platform-tools.html][Android platform
19tools]]. Find the Linux download and save the ZIP folder to your preferred
20location.
2321
2422Once we've downloaded the files, we will need to unzip them, enter the
25directory, and move the necessary executables to a central location,
26such as =/usr/bin/=. For this installation, we only need the =fastboot=
27and =adb= executables.
23directory, and move the necessary executables to a central location, such as
24=/usr/bin/=. For this installation, we only need the =fastboot= and =adb=
25executables.
2826
2927#+begin_src sh
3028cd ~/Downloads
@@ -39,9 +37,8 @@ sudo mv adb /usr/bin
3937
4038** GrapheneOS Files
4139
42Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]]
43for our device and model. For example, the Pixel 6 Pro is codenamed
44=raven= on the release page.
40Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]] for our device and model. For example, the
41Pixel 6 Pro is codenamed =raven= on the release page.
4542
4643Once we have the links, let's download them to our working directory:
4744
@@ -53,8 +50,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
5350
54511. Validate Integrity
5552
56 In order to validate the integrity of the downloaded files, we will
57 need the =signify= package and Graphene's =factory.pub= file.
53 In order to validate the integrity of the downloaded files, we will need the
54 =signify= package and Graphene's =factory.pub= file.
5855
5956 #+begin_src sh
6057 sudo dnf install signify
@@ -64,8 +61,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
6461 curl -O https://releases.grapheneos.org/factory.pub
6562 #+end_src
6663
67 Then we can validate the files and ensure that no data was corrupted
68 or modified before it was saved to our device.
64 Then we can validate the files and ensure that no data was corrupted or
65 modified before it was saved to our device.
6966
7067 #+begin_src sh
7168 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
7370
74712. Unzip Files
7572
76 Once the files are verified, we can unzip the Graphene image and
77 enter the directory:
73 Once the files are verified, we can unzip the Graphene image and enter the
74 directory:
7875
7976 #+begin_src sh
8077 unzip raven-factory-2022091400.zip && cd raven-factory-2022091400
@@ -84,35 +81,35 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig
8481
8582** Enable Developer Debugging & OEM Unlock
8683
87Before we can actually flash anything to the phone, we will need to
88enable OEM Unlocking, as well as either USB Debugging or Wireless
89Debugging, depending on which method we will be using.
84Before we can actually flash anything to the phone, we will need to enable OEM
85(Original Equipment Manufacturer) Unlocking, as well as either USB (Universal
86Serial Bus) Debugging or Wireless Debugging, depending on which method we will
87be using.
9088
91To start, enable developer mode by going to =Settings= > =About= and
92tapping =Build Number= seven (7) times. You may need to enter your PIN
93to enable this mode.
89To start, enable developer mode by going to =Settings= > =About= and tapping
90=Build Number= seven (7) times. You may need to enter your personal identified
91number (PIN) to enable this mode.
9492
95Once developer mode is enabled, go to =Settings= > =System= >
96=Devloper Options= and enable OEM Unlocking, as well as USB or Wireless
97Debugging. In my case, I chose USB Debugging and performed all actions
98via USB cable.
93Once developer mode is enabled, go to =Settings= > =System= > =Devloper Options=
94and enable OEM Unlocking, as well as USB or Wireless Debugging. In my case, I
95chose USB Debugging and performed all actions via USB cable.
9996
100Once these options are enabled, plug the phone into the computer and
101execute the following command:
97Once these options are enabled, plug the phone into the computer and execute the
98following command:
10299
103100#+begin_src sh
104101adb devices
105102#+end_src
106103
107If an unauthorized error occurs, make sure the USB mode on the phone is
108changed from charging to something like "File Transfer" or "PTP." You
109can find the USB mode in the notification tray.
104If an unauthorized error occurs, make sure the USB mode on the phone is changed
105from charging to something like "File Transfer" or "PTP" (Picture Transfer
106Protocol). You can find the USB mode in the notification tray.
110107
111108** Reboot Device
112109
113Once we have found the device via =adb=, we can either boot into the
114bootloader interface by holding the volume down button while the phone
115reboots or by executing the following command:
110Once we have found the device via =adb=, we can either boot into the bootloader
111interface by holding the volume down button while the phone reboots or by
112executing the following command:
116113
117114#+begin_src sh
118115adb reboot bootloader
@@ -120,17 +117,14 @@ adb reboot bootloader
120117
121118** Unlock the Bootloader
122119
123The phone will reboot and load the bootloader screen upon startup. At
124this point, we are ready to start the actual flashing of GrapheneOS onto
125the device.
120The phone will reboot and load the bootloader screen upon startup. At this
121point, we are ready to start the actual flashing of GrapheneOS onto the device.
126122
127*NOTE*: In my situation, I needed to use =sudo= with every =fastboot=
128command, but not with =adb= commands. I am not sure if this is standard
129or a Fedora quirk, but I'm documenting my commands verbatim in this
130post.
123*NOTE*: In my situation, I needed to use =sudo= with every =fastboot= command,
124but not with =adb= commands. I am not sure if this is standard or a Fedora
125quirk, but I'm documenting my commands verbatim in this post.
131126
132First, we start by unlocking the bootloader so that we can load other
133ROMs:
127First, we start by unlocking the bootloader so that we can load other ROMs:
134128
135129#+begin_src sh
136130sudo fastboot flashing unlock
@@ -138,24 +132,23 @@ sudo fastboot flashing unlock
138132
139133** Flashing Factory Images
140134
141Once the phone is unlocked, we can flash it with the =flash-all.sh=
142script found inside the =raven-factory-2022091400= folder we entered
143earlier:
135Once the phone is unlocked, we can flash it with the =flash-all.sh= script found
136inside the =raven-factory-2022091400= folder we entered earlier:
144137
145138#+begin_src sh
146139sudo ./flash-all.sh
147140#+end_src
148141
149This process should take a few minutes and will print informational
150messages as things progress. Avoid doing anything on the phone while
151this process is operating.
142This process should take a few minutes and will print informational messages as
143things progress. Avoid doing anything on the phone while this process is
144operating.
152145
153146** Lock the Bootloader
154147
155If everything was successful, the phone should reboot a few times and
156finally land back on the bootloader screen. At this point, we can
157re-lock the bootloader to enable full verified boot and protect the
158device from unwanted flashing or erasure of data.
148If everything was successful, the phone should reboot a few times and finally
149land back on the bootloader screen. At this point, we can re-lock the bootloader
150to enable full verified boot and protect the device from unwanted flashing or
151erasure of data.
159152
160153#+begin_src sh
161154sudo fastboot flashing lock
content/blog/2022-10-04-mtp-linux.org +22 −25
@@ -3,31 +3,29 @@
33#+description: Instructions for mounting and accessing Media Transfer Protocol (MTP) compatible mobile devices on Fedora Linux using jmtpfs for file transfer and management.
44#+slug: mtp-linux
55
6I recently ran into trouble attempting to mount my GrapheneOS phone to
7my laptop running Fedora Linux via the
8[[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer
9Protocol]] (MTP) and discovered a simple and effective solution.
6I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop
7running Fedora Linux via the [[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer Protocol]] (MTP) and discovered a
8simple and effective solution.
109
11* Use a USB 3.0 Port
10* Use a Universal Serial Bus (USB) 3.0 Port
1211
13First, ensure that the device was plugged in to the laptop through a USB
143.0 port, if possible. From a brief glance online, it seems that USB 2.0
15ports may cause issues with dropped connections over MTP. This is purely
16anecdotal since I don't have any evidence to link showing that USB 2.0
17causes issues, but I can confirm that switching to a USB 3.0 port seemed
18to cut out most of my issues.
12First, ensure that the device was plugged in to the laptop through a USB 3.0
13port, if possible. From a brief glance online, it seems that USB 2.0 ports may
14cause issues with dropped connections over MTP. This is purely anecdotal since I
15don't have any evidence to link showing that USB 2.0 causes issues, but I can
16confirm that switching to a USB 3.0 port seemed to cut out most of my issues.
1917
2018* Switch USB Preferences to MTP
2119
22Secondly, you need to ensure that the phone's USB preferences/mode is
23changed to MTP or File Transfer once the phone is plugged in. Other
24modes will not allow you to access the phone's file system.
20Secondly, you need to ensure that the phone's USB preferences/mode is changed to
21MTP or File Transfer once the phone is plugged in. Other modes will not allow
22you to access the phone's file system.
2523
2624* Install =jmtpfs=
2725
28Next, I used the =jmtpfs= package to mount my phone to my laptop. There
29are other packages that exist, but this one worked perfectly for me. On
30Fedora Linux, you can install it like this:
26Next, I used the =jmtpfs= package to mount my phone to my laptop. There are
27other packages that exist, but this one worked perfectly for me. On Fedora
28Linux, you can install it like this:
3129
3230#+begin_src sh
3331sudo dnf install jmtpfs -y
@@ -35,8 +33,8 @@ sudo dnf install jmtpfs -y
3533
3634* Create a Mount Point
3735
38Once you have the package installed, you just need to create a folder
39for the device to use as a mount point. In my case, I used =/mnt/pixel=:
36Once you have the package installed, you just need to create a folder for the
37device to use as a mount point. In my case, I used =/mnt/pixel=:
4038
4139#+begin_src sh
4240sudo mkdir /mnt/pixel
@@ -45,8 +43,8 @@ sudo chown -R $USER:$USER /mnt/pixel
4543
4644* Mount & Access the Phone's File System
4745
48Finally, plug-in and mount the device, and you should be able to see all
49storage (internal and external) inside your new folder!
46Finally, plug-in and mount the device, and you should be able to see all storage
47(internal and external) inside your new folder!
5048
5149#+begin_src sh
5250jmtpfs /mnt/pixel
@@ -59,16 +57,15 @@ Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
5957Android device detected, assigning default bug flags
6058#+end_src
6159
62Now you are mounted and can do anything you'd like with the device's
63files:
60Now you are mounted and can do anything you'd like with the device's files:
6461
6562#+begin_src sh
6663cd /mnt/pixel
6764ls -lha
6865#+end_src
6966
70From here, you will be able to see any internal or external storage
71available on the device:
67From here, you will be able to see any internal or external storage available on
68the device:
7269
7370#+begin_src sh
7471total 0
content/blog/2022-10-04-syncthing.org +78 −93
@@ -5,26 +5,24 @@
55
66* An Overview of Syncthing
77
8If you've been looking around the self-hosted cloud storage space for a
9while, you've undoubtedly run into someone suggesting
10[[https://syncthing.net][Syncthing]] as an option. However, it is an
11unusual alternative for those users out there who are used to having a
8If you've been looking around the self-hosted cloud storage space for a while,
9you've undoubtedly run into someone suggesting [[https://syncthing.net][Syncthing]] as an option. However,
10it is an unusual alternative for those users out there who are used to having a
1211centralized cloud server that serves as the "controller" of the data and
1312interacts with clients on devices to fetch files.
1413
15This post is a walkthrough of the Syncthing software, how I set up my
16personal storage, and some pros and cons of using the software.
14This post is a walkthrough of the Syncthing software, how I set up my personal
15storage, and some pros and cons of using the software.
1716
1817* Installing Syncthing
1918
20To install Syncthing, visit the
21[[https://syncthing.net/downloads/][Downloads]] page or install via your
22device's package manager.
19To install Syncthing, visit the [[https://syncthing.net/downloads/][Downloads]] page or install via your device's
20package manager.
2321
2422** Server & Desktop
2523
26You can install Syncthing on servers and desktops via the Downloads page
27linked above or via the command-line.
24You can install Syncthing on servers and desktops via the Downloads page linked
25above or via the command-line.
2826
2927For Debian-based distros:
3028
@@ -40,19 +38,13 @@ sudo dnf install syncthing
4038
4139** Mobile
4240
43Syncthing for Android is available on
44[[https://f-droid.org/packages/com.nutomic.syncthingandroid/][F-Droid]]
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
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
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
5043Sync]].
5144
5245* How Does Syncthing Work?
5346
54To start, I wanted to include the main marketing blurb from their
55website:
47To start, I wanted to include the main marketing blurb from their website:
5648
5749#+begin_quote
5850Syncthing 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
6254it's transmitted over the internet.
6355#+end_quote
6456
65Let's break this apart and add in some other details to help explain
66what exactly Syncthing does in order to sync files between devices.
57Let's break this apart and add in some other details to help explain what
58exactly Syncthing does in order to sync files between devices.
6759
6860** Local Syncthing Server(s)
6961
70Syncthing syncs files between multiple devices by creating a local
71server on each device. These local servers handle a few different
72things, such as watching files and directories for changes, hosting an
73administrative GUI website, and authenticating with connected devices.
62Syncthing syncs files between multiple devices by creating a local server on
63each device. These local servers handle a few different things, such as watching
64files and directories for changes, hosting an administrative GUI website, and
65authenticating with connected devices.
7466
75You can also start, stop, and restart the Syncthing server via the
76command-line or web dashboard. If you're running Syncthing on a device
77with =systemd=, you can use the following commands:
67You can also start, stop, and restart the Syncthing server via the command-line
68or web dashboard. If you're running Syncthing on a device with =systemd=, you
69can use the following commands:
7870
7971#+begin_src sh
8072sudo systemctl start syncthing@username.service
@@ -84,13 +76,13 @@ sudo systemctl stop syncthing@username.service
8476
8577** Syncthing Dashboard
8678
87This biggest part of Syncthing is the admin GUI website that runs on
88each device (note that mobile devices will use the Syncthing app rather
89than the web GUI). The admin GUI is available through the web browser on
90the 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
92place where you will change settings, add/modify synced files, and
93add/modify connected devices.
79This biggest part of Syncthing is the admin GUI website that runs on each device
80(note that mobile devices will use the Syncthing app rather than the web GUI).
81The administrative graphical user interface (GUI) is available through the web
82browser on the local device that is running Syncthing - simply go to
83=http://localhost:8384= or =http://127.0.0.1:8384=. This web page is the place
84where you will change settings, add/modify synced files, and add/modify
85connected devices.
9486
9587Here's an example web GUI dashboard:
9688
@@ -99,81 +91,74 @@ Here's an example web GUI dashboard:
9991
10092** Remote Devices
10193
102A cloud storage solution wouldn't be very useful if you aren't able to
103share data among various devices. Syncthing does this by sharing Device
104IDs to connect servers, and then by manually sharing Folders with
105devices that have been connected.
94A cloud storage solution wouldn't be very useful if you aren't able to share
95data among various devices. Syncthing does this by sharing Device IDs to connect
96servers, and then by manually sharing Folders with devices that have been
97connected.
10698
107For instance, if you have a laptop running Syncthing and then install
108the Syncthing mobile app on a phone, you could scan the laptop's QR code
109for Device ID and then accept the authentication on the laptop's
110dashboard. Next, you can use either device to select a folder for
111sharing and dictating which device should send, receive, or both.
99For instance, if you have a laptop running Syncthing and then install the
100Syncthing mobile app on a phone, you could scan the laptop's QR (quick-response)
101code for Device ID and then accept the authentication on the laptop's dashboard.
102Next, you can use either device to select a folder for sharing and dictating
103which device should send, receive, or both.
112104
113When you connect devices, you can set one device as an "Introducer,"
114which can add devices from the introducer to the device list, for
115mutually shared folders. You can also configure Auto Accept,
116compression, rate limits, and more settings per device.
105When you connect devices, you can set one device as an "Introducer," which can
106add devices from the introducer to the device list, for mutually shared folders.
107You can also configure Auto Accept, compression, rate limits, and more settings
108per device.
117109
118110* My Personal Cloud Storage Set-up
119111
120Personally, I use a model similar to a traditional cloud storage
121service. I have a "centralized" server running 24/7 that acts as an
122Introducer for my Syncthing network. I think of this as my main storage
123and all other devices as tertiary client devices. I will likely add
124additional servers as backups as time goes on so that I don't have to
125rely on my laptop or phone as the only backups.
112Personally, I use a model similar to a traditional cloud storage service. I have
113a "centralized" server running 24/7 that acts as an Introducer for my Syncthing
114network. I think of this as my main storage and all other devices as tertiary
115client devices. I will likely add additional servers as backups as time goes on
116so that I don't have to rely on my laptop or phone as the only backups.
126117
127Currently, I have one desktop and one mobile device connected to the
128network, both running intermittently as they are not powered-on 24/7.
118Currently, I have one desktop and one mobile device connected to the network,
119both running intermittently as they are not powered-on 24/7.
129120
130The initial set-up of the software was easy enough, but data transfer
131rates were incredibly slow for me due to the Wi-Fi. Instead, I plugged
132my laptop into the ethernet network that my server is on and manually
133copied my folders over to the server with =scp=. Once complete,
134Syncthing validated that all files were there and not missing, and it
135did not need to transfer any data through the WAN.
121The initial set-up of the software was easy enough, but data transfer rates were
122incredibly slow for me due to the Wi-Fi. Instead, I plugged my laptop into the
123ethernet network that my server is on and manually copied my folders over to the
124server with =scp=. Once complete, Syncthing validated that all files were there
125and not missing, and it did not need to transfer any data through the WAN.
136126
137As slow as the transfer was going, this probably saved me a few days of
138waiting for my ~100GB sync.
127As slow as the transfer was going, this probably saved me a few days of waiting
128for my ~100 gigabytes to sync.
139129
140130* Pros & Cons
141131
142I've put together a short list of pros and cons for Syncthing. I thought
143about my experiences with Nextcloud, WebDAV, proprietary services
144(Google Drive, iCloud, etc.), and privacy-focused cloud solutions
145(pCloud, Tresorit, etc.).
132I've put together a short list of pros and cons for Syncthing. I thought about
133my experiences with Nextcloud, WebDAV, proprietary services (Google Drive,
134iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.).
146135
147136*Pros:*
148137
149138- I've faced no data loss at all through my two-month trial run.
150139- No third-parties store your data on their servers.
151- You have full control over your data and can take your data and leave
152 at any time.
153- It's possible to encrypt client-side easily with software like
154 Cryptomator.
155- No proprietary clients or mounted volumes, just plain files and
156 folders.
140- You have full control over your data and can take your data and leave at any
141 time.
142- It's possible to encrypt client-side easily with software like Cryptomator.
143- No proprietary clients or mounted volumes, just plain files and folders.
157144
158145*Cons:*
159146
160- The learning curve is steeper than traditional cloud services and is
161 focused on a technical audience.
162- If a device needs to modify files in a Folder, the devices will need
163 to sync ALL files from the folder, which may be large. To avoid size
164 restraints, split large folders into smaller folders for syncing.
147- The learning curve is steeper than traditional cloud services and is focused
148 on a technical audience.
149- If a device needs to modify files in a Folder, the devices will need to sync
150 ALL files from the folder, which may be large. To avoid size restraints, split
151 large folders into smaller folders for syncing.
165152- Syncing can be slow due to the clients/servers initially connecting or
166153 re-connecting after sleeping.
167- Multiple personal devices are required and require the user to own or
168 rent them as no third-party servers are involved in the storage of
169 data.
170
171Overall, I've had a great experience with Syncthing so far. I've had no
172data loss, syncing has been quick and easy when changes are made to
173files, device connections are reliable, and I love the freedom of
174controlling the clients and servers as I choose.
175
176Not to mention that I appreciate that I - or someone else - could pull
177the Syncthing [[https://github.com/syncthing][source code]] and continue
178development/support if the Syncthing Foundation decides to stop
179developing the software or sells the business.
154- Multiple personal devices are required and require the user to own or rent
155 them as no third-party servers are involved in the storage of data.
156
157Overall, I've had a great experience with Syncthing so far. I've had no data
158loss, syncing has been quick and easy when changes are made to files, device
159connections are reliable, and I love the freedom of controlling the clients and
160servers as I choose.
161
162Not to mention that I appreciate that I - or someone else - could pull the
163Syncthing [[https://github.com/syncthing][source code]] and continue development/support if the Syncthing
164Foundation decides to stop developing the software or sells the business.
content/blog/2022-10-22-alpine-linux.org +91 −103
@@ -5,43 +5,40 @@
55
66* Alpine Linux
77
8[[https://alpinelinux.org][Alpine Linux]] is a very small distro, built
9on musl libc and busybox. It uses ash as the default shell, OpenRC as
10the init system, and apk as the package manager. According to their
11website, an Alpine container "requires no more than 8 MB and a minimal
12installation to disk requires around 130 MB of storage." An actual bare
13metal machine is recommended to have 100 MB of RAM and 0-700 MB of
14storage space.
15
16Historically, I've used Ubuntu's minimal installation image as my server
17OS for the last five years. Ubuntu worked well and helped as my original
18server contained an nVidia GPU and no onboard graphics, so quite a few
19distros won't boot or install without a lot of tinkering.
20
21Alpine has given me a huge increase in performance across my Docker apps
22and Nginx websites. CPU load for the new server I'm using to test Alpine
23hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100 CPU @
243.70GHz.
25
26The only services I haven't moved over to Alpine are Plex Media Server
27and Syncthing, which may increase CPU load quite a bit depending on how
28many streams are running.
8[[https://alpinelinux.org][Alpine Linux]] is a very small distribution, built on musl libc and busybox. It
9uses ash as the default shell, OpenRC as the init system, and apk as the package
10manager. According to their website, an Alpine container "requires no more than
118 megabytes (MB) and a minimal installation to disk requires around 130 MB of
12storage." An actual bare metal machine is recommended to have 100 MB of RAM and
130-700 MB of storage space.
14
15Historically, I've used Ubuntu's minimal installation image as my server OS for
16the last five years. Ubuntu worked well and helped as my original server
17contained an nVidia GPU (graphics processing unit) and no onboard graphics, so
18quite a few distributions won't boot or install without a lot of tinkering.
19
20Alpine has given me a huge increase in performance across my Docker apps and
21Nginx websites. CPU (central processing unit) load for the new server I'm using
22to test Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100
23CPU @ 3.70 Gigahertz (GHz).
24
25The only services I haven't moved over to Alpine are Plex Media Server and
26Syncthing, which may increase CPU load quite a bit depending on how many streams
27are running.
2928
3029** Installation
3130
32In terms of installation, Alpine has an incredibly useful
33[[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide
34a user throughout the installation and post-installation processes, as
35well as various other articles and guides.
31In terms of installation, Alpine has an incredibly useful [[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide a
32user throughout the installation and post-installation processes, as well as
33various other articles and guides.
3634
37To install Alpine, find an appropriate
38[[https://alpinelinux.org/downloads/][image to download]] and flash it
39to a USB using software such as Rufus or Etcher. I opted to use the
40Standard image for my x86_{64} architecture.
35To install Alpine, find an appropriate [[https://alpinelinux.org/downloads/][image to download]] and flash it to a USB
36(Universal Serial Bus) using software such as Rufus or Etcher. I opted to use
37the Standard image for my x86_{64} architecture.
4138
42Once the USB is ready, plug it into the machine and reboot. Note that
43you may have to use a key such as =Esc= or =F1-12= to access the boot
44menu. The Alpine Linux terminal will load quickly and for a login.
39Once the USB is ready, plug it into the machine and reboot. Note that you may
40have to use a key such as =Esc= or =F1-12= to access the boot menu. The Alpine
41Linux terminal will load quickly and for a login.
4542
4643To log in to the installation image, use the =root= account; there is no
4744password. Once logged-in, execute the setup command:
@@ -50,34 +47,32 @@ password. Once logged-in, execute the setup command:
5047setup-alpine
5148#+end_src
5249
53The setup script will ask a series of questions to configure the system.
54Be sure to answer carefully or else you may have to re-configure the
55system after boot.
50The setup script will ask a series of questions to configure the system. Be sure
51to answer carefully or else you may have to re-configure the system after boot.
5652
57- Keyboard Layout (Local keyboard language and usage mode, e.g., us and
58 variant of us-nodeadkeys.)
59- Hostname (The name for the computer.)
60- Network (For example, automatic IP address discovery with the "DHCP"
61 protocol.)
62- DNS Servers (Domain Name Servers to query. For privacy reasons, it is
53- *Keyboard Layout*: Local keyboard language and usage mode, e.g., us and variant
54 of us-nodeadkeys.
55- *Hostname*: The name for the computer.
56- *Network*: For example, automatic internet protocol (IP) address discovery
57 with the Dynamic Host Configuration Protocol (DHCP) protocol.
58- *DNS (Domain Name System)*: DNS servers to query. For privacy reasons, it is
6359 NOT recommended to route every local request to servers like Google's
64 8.8.8.8.)
65- Timezone
66- Proxy (Proxy server to use for accessing the web. Use "none" for
67 direct connections to the internet.)
68- Mirror (From where to download packages. Choose the organization you
69 trust giving your usage patterns to.)
70- SSH (Secure SHell remote access server. "Openssh" is part of the
71 default install image. Use "none" to disable remote login, e.g. on
72 laptops.)
73- NTP (Network Time Protocol client used for keeping the system clock in
74 sync with a time-server. Package "chrony" is part of the default
75 install image.)
76- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as
77 described above.)
78
79Once the setup script is finished, be sure to reboot the machine and
80remove the USB device.
60 8.8.8.8.
61- *Timezone
62- *Proxy*: Proxy server to use for accessing the web. Use =none= for direct
63 connections to the internet.
64- *Mirror*: From where to download packages. Choose the organization you trust
65 giving your usage patterns to.
66- *SSH (Secure Shell Protocol)*: Remote access server. =Openssh= is part of the
67 default install image. Use =none= to disable remote login, e.g. on laptops.
68- *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
70 image.
71- *Disk Mode*: Select between diskless (=none=), =data= or =sys=, as described
72 above.
73
74Once the setup script is finished, be sure to reboot the machine and remove the
75USB device.
8176
8277#+begin_src sh
8378reboot
@@ -86,9 +81,8 @@ reboot
8681** Post-Installation
8782
8883There 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
90going to walk through my personal post-installation setup for my web
91server.
84running, and it largely depends on what you'll use the machine for. I'm going to
85walk through my personal post-installation setup for my web server.
9286
93871. Upgrade the System
9488
@@ -100,9 +94,9 @@ server.
10094
101952. Adding a User
10296
103 I needed to add a user so that I don't need to log in as root. Note
104 that if you're used to using the =sudo= command, you will now need to
105 use the =doas= command on Alpine Linux.
97 I needed to add a user so that I don't need to log in as root. Note that if
98 you're used to using the =sudo= command, you will now need to use the =doas=
99 command on Alpine Linux.
106100
107101 #+begin_src sh
108102 apk add doas
@@ -118,16 +112,14 @@ server.
118112
1191133. Enable Community Packages
120114
121 In order to install more common packages that aren't found in the
122 =main= repository, you will need to enable the =community=
123 repository:
115 In order to install more common packages that aren't found in the =main=
116 repository, you will need to enable the =community= repository:
124117
125118 #+begin_src sh
126119 doas nano /etc/apk/repositories
127120 #+end_src
128121
129 Uncomment the community line for whichever version of Alpine you're
130 running:
122 Uncomment the community line for whichever version of Alpine you're running:
131123
132124 #+begin_src sh
133125 /media/usb/apks
@@ -140,9 +132,9 @@ server.
140132
1411334. Install Required Packages
142134
143 Now that the community packages are available, you can install any
144 packages you need. In my case, I installed the web server packages I
145 need for my services:
135 Now that the community packages are available, you can install any packages
136 you need. In my case, I installed the web server packages I need for my
137 services:
146138
147139 #+begin_src sh
148140 doas apk add nano nginx docker docker-compose ufw
@@ -150,15 +142,14 @@ server.
150142
1511435. SSH
152144
153 If you didn't install OpenSSH as part of the installation, you can do
154 so now:
145 If you didn't install OpenSSH as part of the installation, you can do so now:
155146
156147 #+begin_src sh
157148 doas apk add openssh
158149 #+end_src
159150
160 Next, either create a new key or copy your SSH key to the server from
161 your current machines:
151 Next, either create a new key or copy your SSH key to the server from your
152 current machines:
162153
163154 #+begin_src sh
164155 # Create a new key
@@ -174,9 +165,9 @@ server.
174165
1751666. Firewall
176167
177 Lastly, I installed =ufw= above as my firewall. To set up, default to
178 deny incoming and allow outgoing connections. Then selectively allow
179 other ports or apps as needed.
168 Lastly, I installed =ufw= above as my firewall. To set up, default to deny
169 incoming and allow outgoing connections. Then selectively allow other ports
170 or apps as needed.
180171
181172 #+begin_src sh
182173 doas ufw default deny incoming
@@ -188,8 +179,8 @@ server.
188179
1891807. Change Hostname
190181
191 If you don't like the hostname set during installation, you just need
192 to edit two files. First, edit the simple hostname file:
182 If you don't like the hostname set during installation, you just need to edit
183 two files. First, edit the simple hostname file:
193184
194185 #+begin_src sh
195186 doas nano /etc/hostname
@@ -223,17 +214,17 @@ doas chown -R www:www /var/lib/nginx/
223214doas chown -R www:www /www
224215#+end_src
225216
226If you're running a simple webroot, you can alter the main =nginx.conf=
227file. Otherwise, you can drop configuration files in the following
228directory. You don't need to enable or symlink the configuration file
229like you do in other systems.
217If you're running a simple webroot, you can alter the main =nginx.conf= file.
218Otherwise, you can drop configuration files in the following directory. You
219don't need to enable or symlink the configuration file like you do in other
220systems.
230221
231222#+begin_src sh
232223doas nano /etc/nginx/http.d/example_website.conf
233224#+end_src
234225
235Once the configuration is set and pointed at the =/www= directory to
236serve files, enable the Nginx service:
226Once the configuration is set and pointed at the =/www= directory to serve
227files, enable the Nginx service:
237228
238229#+begin_src sh
239230# Note that 'default' must be included or Nginx will not start on boot
@@ -242,18 +233,16 @@ doas rc-update add nginx default
242233
243234* Docker Containers
244235
245Docker works exactly the same as other systems. Either execute a
246=docker run= command or create a =docker-compose.yml= file and do
247=docker-compose up -d=.
236Docker works exactly the same as other systems. Either execute a =docker run=
237command or create a =docker-compose.yml= file and do =docker-compose up -d=.
248238
249239* Git Server
250240
251I went in-depth on how to self-host a git server in another post:
252[[../git-server/][Self-Hosting a Personal Git Server]].
241I went in-depth on how to self-host a git server in another post: [[https://cleberg.net/blog/git-server.html][Self-Hosting
242Guide: Git & cGit]].
253243
254However, there are a few differences with Alpine. First note that in
255order to change the =git= user's shell, you must do a few things a
256little different:
244However, there are a few differences with Alpine. First note that in order to
245change the =git= user's shell, you must do a few things a little different:
257246
258247#+begin_src sh
259248doas apk add libuser
@@ -265,12 +254,11 @@ doas lchsh git
265254
266255* Thoughts on Alpine
267256
268So far, I love Alpine Linux. I have no complaints about anything at this
269point, but I'm not completely finished with the migration yet. Once I'm
270able to upgrade my hardware to a rack-mounted server, I will migrate
271Plex and Syncthing over to Alpine as well - possibly putting Plex into a
272container or VM.
257So far, I love Alpine Linux. I have no complaints about anything at this point,
258but I'm not completely finished with the migration yet. Once I'm able to upgrade
259my hardware to a rack-mounted server, I will migrate Plex and Syncthing over to
260Alpine as well - possibly putting Plex into a container or VM.
273261
274The performance is stellar, the =apk= package manager is seamless, and
275system administration tasks are effortless. My only regret is that I
276didn't install Alpine sooner.
262The performance is stellar, the =apk= package manager is seamless, and system
263administration tasks are effortless. My only regret is that I didn't install
264Alpine sooner.
content/blog/2022-10-30-linux-display-manager.org +21 −24
@@ -5,18 +5,16 @@
55
66* Display Manager Services
77
8In order to change the
9[[https://en.wikipedia.org/wiki/Display_manager][display manager]] on
10Void Linux - or any other Linux distro - you need to identify the
11currently enabled display manager.
8In order to change the [[https://en.wikipedia.org/wiki/Display_manager][display manager]] on Void Linux - or any other Linux
9distribution - you need to identify the currently enabled display manager.
1210
1311** Disabling the Current Display Manager
1412
15Void Linux only has one ISO available for download with a pre-built
16display manager at the time of this post: the XFCE ISO. If you've
17installed this version, the pre-assigned display manager is =lxdm=. If
18you installed another display manager, replace =lxdm= in the following
19command with the display manager you have installed.
13Void Linux only has one optical disc image (ISO) available for download with a
14pre-built display manager at the time of this post: the XFCE ISO. If you've
15installed this version, the pre-assigned display manager is =lxdm=. If you
16installed another display manager, replace =lxdm= in the following command with
17the display manager you have installed.
2018
2119To disable =lxdm=, simply remove the service symlink:
2220
@@ -26,9 +24,9 @@ sudo rm /var/service/lxdm
2624
2725** Enabling a New Display Manager
2826
29If you want to enable a new display manager, you can do so after =lxdm=
30is disabled. Make sure to replace =<new_display_manager>= with your new
31DM, such as =gdm=, =xdm=, etc.
27If you want to enable a new display manager, you can do so after =lxdm= is
28disabled. Make sure to replace =<new_display_manager>= with your new DM, such as
29=gdm=, =xdm=, etc.
3230
3331#+begin_src sh
3432sudo ln -s /etc/sv/<new_display_manager> /var/service
@@ -37,8 +35,8 @@ sudo ln -s /etc/sv/<new_display_manager> /var/service
3735* Set Up =.xinitrc=
3836
3937Depending 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
41i3wm as my desktop.
38=~/.xinitrc=. For my personal set-up, I created this file to launch the i3wm as
39my desktop.
4240
4341#+begin_src sh
4442nano ~/.xinitrc
@@ -50,21 +48,20 @@ nano ~/.xinitrc
5048exec i3
5149#+end_src
5250
53If you run a desktop other than i3, simply replace =i3= with the shell
54command that launches that desktop.
51If you run a desktop other than i3, simply replace =i3= with the shell command
52that launches that desktop.
5553
5654* Set Up Your Shell Profile
5755
58Finally, in order to automatically launch an X session upon login, you
59will need to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files
60for your shell:
56Finally, in order to automatically launch an X session upon login, you will need
57to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files for your shell:
6158
6259#+begin_src sh
6360nano ~/.zprofile
6461#+end_src
6562
66Add the following snippet to the end of the shell profile file. This
67will execute the =startx= command upon login.
63Add the following snippet to the end of the shell profile file. This will
64execute the =startx= command upon login.
6865
6966#+begin_src sh
7067if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
@@ -72,6 +69,6 @@ if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
7269fi
7370#+end_src
7471
75Alternatively, you can ignore this step and simply choose to manually
76execute =startx= upon login. This can be useful if you have issues with
77your desktop or like to manually launch different desktops by choice.
72Alternatively, you can ignore this step and simply choose to manually execute
73=startx= upon login. This can be useful if you have issues with your desktop or
74like to manually launch different desktops by choice.
content/blog/2022-11-07-self-hosting-matrix.org +41 −48
@@ -5,21 +5,19 @@
55
66* Synapse
77
8If you're reading this, you likely know that
9[[https://github.com/matrix-org/synapse/][Synapse]] is a popular
10[[https://matrix.org/][Matrix]] home server software that allows users
11to run their own Matrix home server.
8If you're reading this, you likely know that [[https://github.com/matrix-org/synapse/][Synapse]] is a popular [[https://matrix.org/][Matrix]] home
9server software that allows users to run their own Matrix home server.
1210
13This post is a short guide describing how I was able to get Synapse
14working in a minimally-usable state on Alpine Linux.
11This post is a short guide describing how I was able to get Synapse working in a
12minimally-usable state on Alpine Linux.
1513
1614* Installation Process
1715
1816** Dependencies
1917
20First, since there is no Alpine-specific package for Synapse, we need to
21ensure that Alpine has the required dependencies for the Python-based
22installation method.
18First, since there is no Alpine-specific package for Synapse, we need to ensure
19that Alpine has the required dependencies for the Python-based installation
20method.
2321
2422#+begin_src sh
2523doas apk -U update
@@ -39,10 +37,9 @@ pip install matrix-synapse
3937
4038** Running Synapse
4139
42Once installed, running Synapse is easy. Simply execute the following
43command, replacing =example.com= with the domain name that will be used
44with this home server. This will generate the configuration files needed
45to run the server.
40Once installed, running Synapse is easy. Simply execute the following command,
41replacing =example.com= with the domain name that will be used with this home
42server. This will generate the configuration files needed to run the server.
4643
4744#+begin_src sh
4845python -m synapse.app.homeserver \
@@ -60,17 +57,15 @@ synctl start
6057
6158** Configuring Synapse
6259
63To make any change to Synapse, we need to edit the =YAML= configuration
64file:
60To make any change to Synapse, we need to edit the =YAML= configuration file:
6561
6662#+begin_src sh
6763nano ~/synapse/homeserver.yaml
6864#+end_src
6965
70For now, we just need to ensure the =server_name= is accurate. However,
71there are a lot of other configuration options found in the
72[[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring
73Synapse]] documentation that can be enabled/disabled at any point.
66For now, we just need to ensure the =server_name= is accurate. However, there
67are a lot of other configuration options found in the [[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring Synapse]]
68documentation that can be enabled/disabled at any point.
7469
7570#+begin_src yaml
7671server_name: "example.com"
@@ -84,9 +79,9 @@ synctl restart
8479
8580** Nginx Reverse-Proxy
8681
87To ensure that Synapse is reachable from the public, we need to connect
88our domain to the Synapse server. In my case, I use a Nginx
89reverse-proxy for this purpose.
82To ensure that Synapse is reachable from the public, we need to connect our
83domain to the Synapse server. In my case, I use a Nginx reverse-proxy for this
84purpose.
9085
9186To use Nginx, we need to create a reverse-proxy configuration file:
9287
@@ -94,9 +89,9 @@ To use Nginx, we need to create a reverse-proxy configuration file:
9489doas nano /etc/nginx/http.d/example.com.conf
9590#+end_src
9691
97If you already have TLS certificates for this domain (=example.com=),
98you can simply use the SSL configuration and point toward your TLS
99certificates.
92If you already have TLS (Transport Layer Security) certificates for this domain
93(=example.com=), you can simply use the SSL (Secure Socket Layer) configuration
94and point toward your TLS certificates.
10095
10196#+begin_src conf
10297server {
@@ -139,10 +134,9 @@ server {
139134}
140135#+end_src
141136
142If you need to generate TLS certificates (I recommend
143[[https://certbot.eff.org/][Certbot]]), you'll need a more minimal Nginx
144conf file before you can use the TLS-enabled example above. Instead, use
145this configuration file during the Certbot certificate generation
137If you need to generate TLS certificates (I recommend [[https://certbot.eff.org/][Certbot]]), you'll need a
138more minimal Nginx conf file before you can use the TLS-enabled example above.
139Instead, use this configuration file during the Certbot certificate generation
146140process:
147141
148142#+begin_src conf
@@ -161,13 +155,13 @@ Once you're done editing the Nginx conf file, restart Nginx:
161155doas rc-service nginx restart
162156#+end_src
163157
164If you still need to generate TLS certificates, run =certbot= now and
165obtain the certificates. Certbot will ask if you want to use a webroot
166or spin up a temporary web server. I *highly* recommend using the
167temporary web server due to the many issues with using a webroot.
158If you still need to generate TLS certificates, run =certbot= now and obtain the
159certificates. Certbot will ask if you want to use a webroot or spin up a
160temporary web server. I *highly* recommend using the temporary web server due to
161the many issues with using a webroot.
168162
169You will need to stop Nginx in order to user the temporary web server
170option with Certbot:
163You will need to stop Nginx in order to user the temporary web server option
164with Certbot:
171165
172166#+begin_src sh
173167# Stop Nginx so certbot can spin up a temp webserver for cert generation
@@ -178,11 +172,11 @@ doas rc-service nginx start
178172
179173** Open Firewall & Router Ports
180174
181If you use a firewall on the server, open the =8448= port for discovery
182and federation, as well as the normal web server ports if you're using a
183reverse proxy. If you want additional services, such as voice calls, you
184will need to read the Synapse documentation to see which ports need to
185be opened for those features.
175If you use a firewall on the server, open the =8448= port for discovery and
176federation, as well as the normal web server ports if you're using a reverse
177proxy. If you want additional services, such as voice calls, you will need to
178read the Synapse documentation to see which ports need to be opened for those
179features.
186180
187181Here's an example of the Universal Firewall (UFW) software:
188182
@@ -193,14 +187,13 @@ doas ufw allow 8448
193187doas ufw allow "Nginx Full"
194188#+end_src
195189
196Remember to forward any Synapse ports, such as =8448=, =80=, and =443=,
197in your Router from the internet to your server's IP address.
190Remember to forward any Synapse ports, such as =8448=, =80=, and =443=, in your
191Router from the internet to your server's internet protocol (IP) address.
198192
199193** Adding Matrix Users
200194
201Finally, if you didn't enable public registration in the
202=homeserver.yaml= file, you can manually create users via the
203command-line:
195Finally, if you didn't enable public registration in the =homeserver.yaml= file,
196you can manually create users via the command-line:
204197
205198#+begin_src sh
206199cd ~/synapse
@@ -210,6 +203,6 @@ register_new_matrix_user -c homeserver.yaml
210203Remember that the format for federated Matrix usernames is
211204=@username:example.com= when logging in to client applications.
212205
213Once Synapse is running, and you have a username, you are ready to log
214in to a Matrix client and start sending messages, joining rooms, and
215utilizing your very own Matrix server.
206Once Synapse is running, and you have a username, you are ready to log in to a
207Matrix client and start sending messages, joining rooms, and utilizing your very
208own Matrix server.
content/blog/2022-11-11-nginx-tmp-errors.org +16 −17
@@ -8,10 +8,10 @@ has occurred multiple times for me./
88
99* The Problem
1010
11After migrating to a new server OS, I started receiving quite a few
12permission errors like the one below. These popped up for various
13different websites I'm serving via Nginx on this server, but did not
14prevent the website from loading.
11After migrating to a new server operating system (OS), I started receiving quite
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 prevent the
14website from loading.
1515
1616I found the errors in the standard log file:
1717
@@ -23,19 +23,18 @@ cat /var/log/nginx/error.log
23232022/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/"
2424#+end_src
2525
26You can see that the error is =13: Permission denied= and it occurs in
27the =/var/lib/nginx/tmp/= directory. In my case, I had thousands of
28errors where Nginx was denied permission to read/write files in this
29directory.
26You can see that the error is =13: Permission denied= and it occurs in the
27=/var/lib/nginx/tmp/= directory. In my case, I had thousands of errors where
28Nginx was denied permission to read/write files in this directory.
3029
3130So how do I fix it?
3231
3332* The Solution
3433
35In order to resolve the issue, I had to ensure the =/var/lib/nginx=
36directory is owned by Nginx. Mine was owned by the =www= user and Nginx
37was not able to read or write files within that directory. This
38prevented Nginx from caching temporary files.
34In order to resolve the issue, I had to ensure the =/var/lib/nginx= directory is
35owned by Nginx. Mine was owned by the =www= user and Nginx was not able to read
36or write files within that directory. This prevented Nginx from caching
37temporary files.
3938
4039#+begin_src sh
4140# Alpine Linux
@@ -45,9 +44,9 @@ doas chown -R nginx:nginx /var/lib/nginx
4544sudo chown -R nginx:nginx /var/lib/nginx
4645#+end_src
4746
48You /may/ also be able to change the =proxy_temp_path= in your Nginx
49config, but I did not try this. Here's a suggestion I found online that
50may work if the above solution does not:
47You /may/ also be able to change the =proxy_temp_path= in your Nginx config, but
48I did not try this. Here's a suggestion I found online that may work if the
49above solution does not:
5150
5251#+begin_src sh
5352nano /etc/nginx/http.d/example.com.conf
@@ -65,8 +64,8 @@ server {
6564}
6665#+end_src
6766
68Finally, restart Nginx and your server should be able to cache temporary
69files again.
67Finally, restart Nginx and your server should be able to cache temporary files
68again.
7069
7170#+begin_src sh
7271# Alpine Linux (OpenRC)
content/blog/2022-11-27-server-build.org +60 −67
@@ -5,39 +5,37 @@
55
66* The Dilemma
77
8For years, I have been using desktops and a Raspberry Pi as the backbone
9of my homelab. I have always wanted to move toward a single dedicated
10server that could handle all of my tasks, but was often put off by the
11complexity of the choices (and financial roadblocks at some times).
8For years, I have been using desktops and a Raspberry Pi as the backbone of my
9homelab. I have always wanted to move toward a single dedicated server that
10could handle all of my tasks, but was often put off by the complexity of the
11choices (and financial roadblocks at some times).
1212
13However, after purchasing a small server rack this past year, I have
14been researching to see what kind of rack-mounted server I could buy. I
15initially bought a Dell R720XD loaded up with everything I could ever
16want in a server - but I did not care for it. It was far too loud, and
17the age of the CPU/RAM was something I wanted to improve upon.
13However, after purchasing a small server rack this past year, I have been
14researching to see what kind of rack-mounted server I could buy. I initially
15bought a Dell R720XD loaded up with everything I could ever want in a server -
16but I did not care for it. It was far too loud, and the age of the CPU/RAM was
17something I wanted to improve upon.
1818
19After returning the R720XD, I decided that I wanted to build my own
20server with modern, consumer-grade PC components. This time, I am very
21happy with the results of my server.
19After returning the R720XD, I decided that I wanted to build my own server with
20modern, consumer-grade PC components. This time, I am very happy with the
21results of my server.
2222
2323* Components
2424
2525I'll start by listing all the components I used for this server build:
2626
27- *Case*:
28 [[https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825][Rosewill
29 RSV-R4100U 4U Server Chassis Rackmount Case]]
27- *Case*: [[https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825][Rosewill RSV-R4100U 4U Server Chassis Rackmount Case]]
3028- *Motherboard*: [[https://nzxt.com/product/n7-b550][NZXT B550]]
3129- *CPU*: AMD Ryzen 7 5700G with Radeon Graphics
32- *GPU*: N/A - I specifically chose one of the few AMD CPUs that support
33 onboard graphics.
30- *GPU*: N/A - I specifically chose one of the few AMD CPUs that support onboard
31 graphics.
3432- *RAM*: 64GB RAM (2x32GB) /Max of 128GB RAM on this motherboard/
3533- *Boot Drive*: Western Digital 500GB M.2 NVME SSD
3634- *HDD Bay*:
3735 - 10TB WD White /(shucked, moved from previous server)/
3836 - 8TB WD White /(shucked, moved from previous server)/
39 - 2 x 8TB WD Red Plus /(Black Friday lined up perfectly with this
40 build, so I grabbed two of these)/
37 - 2 x 8TB WD Red Plus /(Black Friday lined up perfectly with this build, so I
38 grabbed two of these)/
4139- *PSU*: Corsair RM850 PSU
4240- *Extras*:
4341 - Corsair TM3Q Thermal Paste
@@ -47,54 +45,52 @@ I'll start by listing all the components I used for this server build:
4745
4846* Building the Server
4947
50This took quite a while for me to build (in my opinion of time),
51totaling around 3 hours from start to finish. The case has some peculiar
52construction, so you have to completely remove the ODD & HDD cages to
53install the motherboard and other components first.
48This took quite a while for me to build (in my opinion of time), totaling around
493 hours from start to finish. The case has some peculiar construction, so you
50have to completely remove the ODD & HDD cages to install the motherboard and
51other components first.
5452
55Now, I've never built a computer of any kind before, so I was quite
56nervous. Personally, the only challenging part was getting the CPU
57cooler to screw into the motherboard without sliding the thermal paste
58around too much underneath. I'm still not entirely sure if I did a great
59job of it, but nothing's broken yet.
53Now, I've never built a computer of any kind before, so I was quite nervous.
54Personally, the only challenging part was getting the CPU cooler to screw into
55the motherboard without sliding the thermal paste around too much underneath.
56I'm still not entirely sure if I did a great job of it, but nothing's broken
57yet.
6058
61The main components were all fine and simple. However, installing the
62hard drives is slightly tedious as I need to power off the server and
63completely unscrew the HDD cage to install or remove any drives.
64Additionally, the drives are screwed directly into the metal cage with
65small screws, which are quite a bit different from the HDD trays I'm
66used to in other machines.
59The main components were all fine and simple. However, installing the hard
60drives is slightly tedious as I need to power off the server and completely
61unscrew the HDD cage to install or remove any drives. Additionally, the drives
62are screwed directly into the metal cage with small screws, which are quite a
63bit different from the HDD trays I'm used to in other machines.
6764
68Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay
69dealing with the tedium of removing the cage to install new drives.
65Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay dealing
66with the tedium of removing the cage to install new drives.
7067
7168* Software
7269
73I'm not going to dive into the software as I have done so in other
74recent posts. However, I wanted to note that I am using Alpine Linux on
75this server and hosting most services inside Docker. No virtual machines
76(VMs) and very few bare-metal services.
70I'm not going to dive into the software as I have done so in other recent posts.
71However, I wanted to note that I am using Alpine Linux on this server and
72hosting most services inside Docker. No virtual machines (VMs) and very few
73bare-metal services.
7774
7875* The Results
7976
80How did my build turn out? Well, after migrating my other servers and
81their services over, I found that my server is blazing fast. The
82heaviest of my applications, Plex, is handled with ease. Even 4k
83streaming seems to be effortless.
77How did my build turn out? Well, after migrating my other servers and their
78services over, I found that my server is blazing fast. The heaviest of my
79applications, Plex, is handled with ease. Even 4k streaming seems to be
80effortless.
8481
85I am very happy with the results and will likely continue to improve on
86this server as the years go by rather than buying another used server
87online.
82I am very happy with the results and will likely continue to improve on this
83server as the years go by rather than buying another used server online.
8884
8985** Mistakes I Made
9086
91This post wouldn't be complete unless I wrote about the mistakes I made
92while building. The only real mistake I made beyond a "whoops I dropped
93a screw" related to airflow and fan direction.
87This post wouldn't be complete unless I wrote about the mistakes I made while
88building. The only real mistake I made beyond a "whoops I dropped a screw"
89related to airflow and fan direction.
9490
95While installing the two new hard drives that showed up on 2022-11-30
96and getting ready to install the case in my rack, I noticed that the
97hard drive temperatures were quite high.
91While installing the two new hard drives that showed up on 2022-11-30 and
92getting ready to install the case in my rack, I noticed that the hard drive
93temperatures were quite high.
9894
9995I used the =smartctl= command for each of my drives (=/dev/sda= through
10096=/dev/sdd=):
@@ -104,9 +100,8 @@ doas smartctl -a /dev/sda | grep Temperature_Celsius
104100#+end_src
105101
106102The 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
10838 degrees Celsius. I noted that this 10TB drive was also closest to the
109case fan.
103Celsius. The only drive that was cooler was my 10TB drive, which was at 38
104degrees Celsius. I noted that this 10TB drive was also closest to the case fan.
110105
111106#+begin_src sh
112107ID# 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_
120115194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56)
121116#+end_src
122117
123After looking to see if I could fit more fans into the case, I noticed
124that the 120mm fan used for intake from the front of the case was
125actually pushing air out of the case by mistake. This fan sits right in
126front of the hard drive bay.
118After looking to see if I could fit more fans into the case, I noticed that the
119120mm fan used for intake from the front of the case was actually pushing air
120out of the case by mistake. This fan sits right in front of the hard drive bay.
127121
128Once I flipped the fan around to act as an intake fan, the temperatures
129dropped immediately! They are now idling at ~31-33 degrees Celsius. A
130single fan spinning the wrong way caused my drives to idle 10-15 degrees
131higher than they should have.
122Once I flipped the fan around to act as an intake fan, the temperatures dropped
123immediately! They are now idling at ~31-33 degrees Celsius. A single fan
124spinning the wrong way caused my drives to idle 10-15 degrees higher than they
125should have.
132126
133127#+begin_src sh
134128ID# 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_
142136194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46)
143137#+end_src
144138
145This was a silly error to make, but I'm glad I found it today before I
146screwed the case into the rack and made things a lot more tedious to
147fix.
139This was a silly error to make, but I'm glad I found it today before I screwed
140the case into the rack and made things a lot more tedious to fix.
content/blog/2022-11-29-nginx-referrer-ban-list.org +23 −24
@@ -5,9 +5,9 @@
55
66* Creating the Ban List
77
8In order to ban list referral domains or websites with Nginx, you need
9to create a ban list file. The file below will accept regexes for
10different domains or websites you wish to block.
8In order to ban list referral domains or websites with Nginx, you need to create
9a ban list file. The file below will accept regexes for different domains or
10websites you wish to block.
1111
1212First, create the file in your nginx directory:
1313
@@ -15,8 +15,8 @@ First, create the file in your nginx directory:
1515doas nano /etc/nginx/banlist.conf
1616#+end_src
1717
18Next, paste the following contents in and fill out the regexes with
19whichever domains you're blocking.
18Next, paste the following contents in and fill out the regexes with whichever
19domains you're blocking.
2020
2121#+begin_src conf
2222# /etc/nginx/banlist.conf
@@ -33,15 +33,15 @@ map $http_referer $bad_referer {
3333
3434* Configuring Nginx
3535
36In order for the ban list to work, Nginx needs to know it exists and how
37to handle it. For this, edit the =nginx.conf= file.
36In order for the ban list to work, Nginx needs to know it exists and how to
37handle it. For this, edit the =nginx.conf= file.
3838
3939#+begin_src sh
4040doas nano /etc/nginx/nginx.conf
4141#+end_src
4242
43Within this file, find the =http= block and add your ban list file
44location to the end of the block.
43Within this file, find the =http= block and add your ban list file location to
44the end of the block.
4545
4646#+begin_src conf
4747# /etc/nginx/nginx.conf
@@ -56,23 +56,22 @@ http {
5656
5757* Enabling the Ban List
5858
59Finally, we need to take action when a bad referral site is found. To do
60so, edit the configuration file for your website. For example, I have
61all website configuration files in the =http.d= directory. You may have
62them in the =sites-available= directory on some distributions.
59Finally, we need to take action when a bad referral site is found. To do so,
60edit the configuration file for your website. For example, I have all website
61configuration files in the =http.d= directory. You may have them in the
62=sites-available= directory on some distributions.
6363
6464#+begin_src sh
6565doas nano /etc/nginx/http.d/example.com.conf
6666#+end_src
6767
68Within each website's configuration file, edit the =server= blocks that
69are listening to ports 80 and 443 and create a check for the
70=$bad_referrer= variable we created in the ban list file.
68Within each website's configuration file, edit the =server= blocks that are
69listening to ports 80 and 443 and create a check for the =$bad_referrer=
70variable we created in the ban list file.
7171
72If a matching site is found, you can return any
73[[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes][HTTP Status
74Code]] you want. Code 403 (Forbidden) is logical in this case since you
75are preventing a client connection due to a banned domain.
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
73403 (Forbidden) is logical in this case since you are preventing a client
74connection due to a banned domain.
7675
7776#+begin_src conf
7877server {
@@ -97,8 +96,8 @@ doas rc-service nginx restart
9796
9897* Testing Results
9998
100In order to test the results, let's curl the contents of our site. To
101start, I'll curl the site normally:
99In order to test the results, let's curl the contents of our site. To start,
100I'll curl the site normally:
102101
103102#+begin_src sh
104103curl https://cleberg.net
@@ -117,8 +116,8 @@ curl --referer https://news.ycombinator.com https://cleberg.net
117116#+end_src
118117
119118This 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
121met with this same response code.
119successful and any clients being referred from a banned domain will be met with
120this same response code.
122121
123122#+begin_src html
124123<html>
content/blog/2022-12-01-nginx-compression.org +31 −36
@@ -5,24 +5,23 @@
55
66* Text Compression
77
8Text compression allows a web server to serve text-based resources
9faster than uncompressed data. This can speed up things like First
10Contentful Paint, Tie to Interactive, and Speed Index.
8Text compression allows a web server to serve text-based resources faster than
9uncompressed data. This can speed up things like First Contentful Paint, Tie to
10Interactive, and Speed Index.
1111
1212* Enable Nginx Compression with gzip
1313
14In order to enable text compression on Nginx, we need to enable it
15within the configuration file:
14In order to enable text compression on Nginx, we need to enable it within the
15configuration file:
1616
1717#+begin_src sh
1818nano /etc/nginx/nginx.conf
1919#+end_src
2020
21Within the =http= block, find the section that shows something like the
22block below. This is the default gzip configuration I found in my
23=nginx.conf= file on Alpine Linux 3.17. Yours may look slightly
24different, just make sure that you're not creating any duplicate gzip
25options.
21Within the =http= block, find the section that shows something like the block
22below. This is the default gzip configuration I found in my =nginx.conf= file on
23Alpine Linux 3.17. Yours may look slightly different, just make sure that you're
24not creating any duplicate gzip options.
2625
2726#+begin_src conf
2827# Enable gzipping of responses.
@@ -46,31 +45,27 @@ gzip_disable "MSIE [1-6]";
4645
4746* Explanations of ngx_{httpgzipmodule} Options
4847
49Each of the lines above enables a different aspect of the gzip response
50for Nginx. Here are the full explanations:
48Each of the lines above enables a different aspect of the gzip response for
49Nginx. Here are the full explanations:
5150
52- =gzip= -- Enables or disables gzipping of responses.
53- =gzip_vary= -- Enables or disables inserting the "Vary:
54 Accept-Encoding" response header field if the directives gzip,
55 gzip_{static}, or gunzip are active.
56- =gzip_min_length= -- Sets the minimum length of a response that will
57 be gzipped. The length is determined only from the "Content-Length"
58 response header field.
59- =gzip_proxied= -- Enables or disables gzipping of responses for
60 proxied requests depending on the request and response. The fact that
61 the request is proxied is determined by the presence of the "Via"
62 request header field.
63- =gzip_types= -- Enables gzipping of responses for the specified MIME
64 types in addition to "text/html". The special value "*" matches any
65 MIME type (0.8.29). Responses with the "text/html" type are always
66 compressed.
67- =gzip_disable= -- Disables gzipping of responses for requests with
68 "User-Agent" header fields matching any of the specified regular
69 expressions.
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.
51- =gzip=: Enables or disables gzipping of responses.
52- =gzip_vary=: Enables or disables inserting the "Vary: Accept-Encoding"
53 response header field if the directives gzip, gzip_{static}, or gunzip are
54 active.
55- =gzip_min_length=: Sets the minimum length of a response that will be
56 gzipped. The length is determined only from the "Content-Length" response
57 header field.
58- =gzip_proxied=: Enables or disables gzipping of responses for proxied
59 requests depending on the request and response. The fact that the request is
60 proxied is determined by the presence of the "Via" request header field.
61- =gzip_types=: Enables gzipping of responses for the specified MIME types in
62 addition to "text/html". The special value "*" matches any MIME type (0.8.29).
63 Responses with the "text/html" type are always compressed.
64- =gzip_disable=: Disables gzipping of responses for requests with
65 "User-Agent" header fields matching any of the specified regular expressions.
66 - The special mask "msie6" (0.7.12) corresponds to the regular expression
67 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE 6.0;
68 ... SV1" is excluded from this mask.
7369
74More information on these directives and their options can be found on
75the [[https://nginx.org/en/docs/http/ngx_http_gzip_module.html][Module
76ngx_{httpgzipmodule}]] page in Nginx's documentation.
70More information on these directives and their options can be found on the
71[[https://nginx.org/en/docs/http/ngx_http_gzip_module.html][Module ngx_{httpgzipmodule}]] page in Nginx's documentation.
content/blog/2022-12-07-nginx-wildcard-redirect.org +29 −31
@@ -5,18 +5,18 @@
55
66* Problem
77
8I recently migrated domains and replaced the old webpage with a simple
9info page with instructions to users on how to edit their bookmarks and
10URLs to get to the page they were seeking.
8I recently migrated domains and replaced the old webpage with a simple info page
9with instructions to users on how to edit their bookmarks and URLs to get to the
10page they were seeking.
1111
12This was not ideal as it left the work up to the user and may have
13caused friction for users who accessed my RSS feed.
12This was not ideal as it left the work up to the user and may have caused
13friction for users who accessed my RSS (Really Simple Syndication) feed.
1414
1515* Solution
1616
17Instead, I finally found a solution that allows me to redirect both
18subdomains AND trailing content. For example, both of these URLs now
19redirect properly using the logic I'll explain below:
17Instead, I finally found a solution that allows me to redirect both subdomains
18AND trailing content. For example, both of these URLs now redirect properly
19using the logic I'll explain below:
2020
2121#+begin_src txt
2222# 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
2828https://libreddit.domain2.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/
2929#+end_src
3030
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.
3232
3333** Nginx Config
3434
35To make this possible. I needed to configure a proper redirect scheme in
36my Nginx configuration.
35To make this possible. I needed to configure a proper redirect scheme in my
36Nginx configuration.
3737
3838#+begin_src sh
3939doas nano /etc/nginx/http.d/domain1.conf
4040#+end_src
4141
42Within this file, I had one block configured to redirect HTTP requests
43to HTTPS for the base domain and all subdomains.
42Within this file, I had one block configured to redirect HTTP requests to HTTPS
43for the base domain and all subdomains.
4444
4545#+begin_src conf
4646server {
@@ -60,10 +60,9 @@ server {
6060}
6161#+end_src
6262
63For the base domain, I have another =server= block dedicated to
64redirecting all base domain requests. You can see that the =rewrite=
65line is instructing Nginx to gather all trailing content and append it
66to the new =domain2.com= URL.
63For the base domain, I have another =server= block dedicated to redirecting all
64base domain requests. You can see that the =rewrite= line is instructing Nginx
65to gather all trailing content and append it to the new =domain2.com= URL.
6766
6867#+begin_src conf
6968server {
@@ -79,17 +78,16 @@ server {
7978}
8079#+end_src
8180
82Finally, the tricky part is figuring out how to tell Nginx to redirect
83while keeping both a subdomain and trailing content intact. I found that
84the easiest way to do this is to give it a =server= block of its own.
81Finally, the tricky part is figuring out how to tell Nginx to redirect while
82keeping both a subdomain and trailing content intact. I found that the easiest
83way to do this is to give it a =server= block of its own.
8584
86Within this block, we need to do some regex on the =server_name= line
87before we can rewrite anything. This creates a variable called
88=subdomain=.
85Within this block, we need to do some regex on the =server_name= line before we
86can rewrite anything. This creates a variable called =subdomain=.
8987
90Once the server gets to the =rewrite= line, it pulls the =subdomain=
91variable from above and uses it on the new =domain2.com= domain before
92appending the trailing content (=$request_uri=).
88Once the server gets to the =rewrite= line, it pulls the =subdomain= variable
89from above and uses it on the new =domain2.com= domain before appending the
90trailing content (=$request_uri=).
9391
9492#+begin_src conf
9593server {
@@ -105,15 +103,15 @@ server {
105103}
106104#+end_src
107105
108That's all there is to it. With this, I simply restarted Nginx and
109watched the redirections work in-action.
106That's all there is to it. With this, I simply restarted Nginx and watched the
107redirections work in-action.
110108
111109#+begin_src sh
112110doas rc-service nginx restart
113111#+end_src
114112
115Looking back on it, I wish I had done this sooner. Who knows how many
116people went looking for my sites or bookmarks and gave up when they saw
117the redirect instructions page.
113Looking back on it, I wish I had done this sooner. Who knows how many people
114went looking for my sites or bookmarks and gave up when they saw the redirect
115instructions page.
118116
119117Oh well, it's done now. Live and learn.
content/blog/2022-12-17-st.org +20 −26
@@ -5,12 +5,11 @@
55
66* st
77
8[[https://st.suckless.org][st]] standards for Simple Terminal, a simple
9terminal implementation for X made by the
10[[https://suckless.org][suckless]] team.
8[[https://st.suckless.org][st]] standards for Simple Terminal, a simple terminal implementation for X made by
9the [[https://suckless.org][suckless]] team.
1110
12This post walks through the dependencies needed and process to build and
13install =st= on Fedora Workstation.
11This post walks through the dependencies needed and process to build and install
12=st= on Fedora Workstation.
1413
1514** Obtain Files
1615
@@ -23,8 +22,8 @@ git clone https://git.suckless.org/st && cd st
2322
2423** Dependencies
2524
26Once you have the files and are in the =st= directory, ensure the
27following packages are installed.
25Once you have the files and are in the =st= directory, ensure the following
26packages are installed.
2827
2928#+begin_src sh
3029sudo dnf update && sudo dnf upgrade
@@ -39,13 +38,12 @@ Before building, ensure that you read the README file.
3938cat README
4039#+end_src
4140
42Once you've read the instructions, open the =config.mk= file and ensure
43it matches your setup. If you're not sure, leave the default options
44within the file.
41Once you've read the instructions, open the =config.mk= file and ensure it
42matches your setup. If you're not sure, leave the default options within the
43file.
4544
46Finally, you can build =st= with the following command. Ensure you run
47as root (e.g., =sudo=) or else you may not end up with a usable
48application file.
45Finally, you can build =st= with the following command. Ensure you run as root
46(e.g., =sudo=) or else you may not end up with a usable application file.
4947
5048#+begin_src sh
5149sudo make clean install
@@ -54,38 +52,34 @@ sudo make clean install
5452** Customization (Patches)
5553
5654Note that customizing =st= requires you to modify the source files or to
57download one of the [[https://st.suckless.org/patches/][available
58patches]] for suckless.org.
55download one of the [[https://st.suckless.org/patches/][available patches]] for suckless.org.
5956
60If you've already installed =st= and want to customize or install a
61patch, start by uninstalling the current program.
57If you've already installed =st= and want to customize or install a patch, start
58by uninstalling the current program.
6259
6360#+begin_src sh
6461cd ~/suckless/st
6562sudo make uninstall
6663#+end_src
6764
68Next, grab the =<path>.diff= file from the page of the patch you chose.
69For example, I will be using the
70[[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]]
71patch in the below example.
65Next, grab the =<path>.diff= file from the page of the patch you chose. For
66example, I will be using the [[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]] patch in the below example.
7267
7368#+begin_src sh
7469wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff
7570#+end_src
7671
7772Once 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
79you don't have it installed already (you should have installed it
80above).
73re-install the program. You may need to install the =patch= command if you don't
74have it installed already (you should have installed it above).
8175
8276#+begin_src sh
8377patch -i st-defaultfontsize-20210225-4ef0cbd.diff
8478sudo make clean install
8579#+end_src
8680
87Once installed, you can use the default font size patch to launch =st=
88with any font size you wish:
81Once installed, you can use the default font size patch to launch =st= with any
82font size you wish:
8983
9084#+begin_src sh
9185st -z 16
content/blog/2022-12-23-alpine-desktop.org +43 −45
@@ -5,30 +5,31 @@
55
66* Isn't Alpine Linux for Servers?
77
8This is a question I see a lot when people are presented with an example
9of Alpine Linux running as a desktop OS.
8This is a question I see a lot when people are presented with an example of
9Alpine Linux running as a desktop operating system (OS).
1010
11While Alpine is small, fast, and minimal, that doesn't stop it from
12functioning at a productive level for desktop users.
11While Alpine is small, fast, and minimal, that doesn't stop it from functioning
12at a productive level for desktop users.
1313
14This post is documentation of how I installed and modified Alpine Linux
15to become my daily desktop OS.
14This post is documentation of how I installed and modified Alpine Linux to
15become my daily desktop OS.
1616
1717* Installation
1818
19Note that I cover the installation of Alpine Linux in my other post, so
20I won't repeat it here: [[../alpine-linux/][Alpine Linux: My New Server
21OS]].
19Note that I cover the installation of Alpine Linux in my other post, so I won't
20repeat it here: [[https://cleberg.net/blog/alpine-linux.html][Alpine Linux Essentials: Installing and Setting Up a Secure
21Minimal Server]].
2222
23Basically, get a bootable USB or whatever you prefer with Alpine on it,
24boot the ISO, and run the setup script.
23Basically, get a bootable USB (Universal Serial Bus) device or whatever you
24prefer with Alpine on it, boot the optical disc image (ISO), and run the setup
25script.
2526
2627#+begin_src sh
2728setup-alpine
2829#+end_src
2930
30Once you have gone through all the options and installer finishes
31without errors, reboot.
31Once you have gone through all the options and installer finishes without
32errors, reboot.
3233
3334#+begin_src sh
3435reboot
@@ -37,9 +38,9 @@ reboot
3738* Initial Setup
3839
3940Once 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
41should start by updating and upgrading the system in case the ISO was
42not fully up-to-date.
41initially or =su= to root once you log in as your user. From here, you should
42start by updating and upgrading the system in case the ISO was not fully
43up-to-date.
4344
4445#+begin_src sh
4546# Update and upgrade system
@@ -49,8 +50,8 @@ apk -U update && apk -U upgrade
4950apk add nano
5051#+end_src
5152
52You need to uncomment the =community= repository for your version of
53Alpine Linux.
53You need to uncomment the =community= repository for your version of Alpine
54Linux.
5455
5556For v3.17, the =repositories= file should look like this:
5657
@@ -77,11 +78,11 @@ adduser $USER wheel
7778
7879* Window Manager (Desktop)
7980
80The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]]
81has everything you need to get Sway working on Alpine.
81The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]] has everything you need to get Sway working on
82Alpine.
8283
83However, I'll include a brief list of the commands I ran and their
84purpose for posterity here.
84However, I'll include a brief list of the commands I ran and their purpose for
85posterity here.
8586
8687#+begin_src sh
8788# Add eudev and set it up
@@ -125,8 +126,8 @@ apk add \ # Install optional dependencies:
125126Once you have the packages installed and set-up, you need to export the
126127=XDG_RUNTIME_DIR= upon login. To do this, edit your =.profile= file.
127128
128If you use another shell, such as =zsh=, you need to edit that shell's
129profile (e.g., =~/.zprofile=)!
129If you use another shell, such as =zsh=, you need to edit that shell's profile
130(e.g., =~/.zprofile=)!
130131
131132#+begin_src sh
132133nano ~/.profile
@@ -152,8 +153,7 @@ dbus-run-session -- sway
152153
153154** Personal Touches
154155
155I also added the following packages, per my personal preferences and
156situation.
156I also added the following packages, per my personal preferences and situation.
157157
158158#+begin_src sh
159159doas apk add brightnessctl \ # Brightness controller
@@ -174,8 +174,8 @@ stored from prior desktops, such as my [[https://git.cleberg.net/dotfiles.git][d
174174
175175** WiFi Issues
176176
177I initially tried to set up my Wi-Fi the standard way with =iwd=, but it
178didn't work.
177I initially tried to set up my Wi-Fi the standard way with =iwd=, but it didn't
178work.
179179
180180Here is what I initially tried (I did all of this as =root=):
181181
@@ -186,8 +186,7 @@ iwctl station wlan0 connect <SSID> # This will prompt for the password
186186rc-update add iwd boot && rc-update add dbus boot
187187#+end_src
188188
189Then, I added the Wi-Fi entry to the bottom of the networking interface
190file:
189Then, I added the Wi-Fi entry to the bottom of the networking interface file:
191190
192191#+begin_src sh
193192nano /etc/network/interfaces
@@ -204,13 +203,13 @@ Finally, restart the networking service:
204203rc-service networking restart
205204#+end_src
206205
207My Wi-Fi interface would receive an IP address from the router, but it
208could not ping anything in the network. To solve the Wi-Fi issues, I
209originally upgraded to Alpine's =edge= repositories, which was
206My Wi-Fi interface would receive an internet protocol (IP) address from the
207router, but it could not ping anything in the network. To solve the Wi-Fi
208issues, I originally upgraded to Alpine's =edge= repositories, which was
210209unnecessary.
211210
212Really, the solution was to enable the =NameResolvingService=resolvconf=
213in =/etc/iwd/main.conf=.
211Really, the solution was to enable the =NameResolvingService=resolvconf= in
212=/etc/iwd/main.conf=.
214213
215214#+begin_src sh
216215doas nano /etc/iwd/main.conf
@@ -226,11 +225,10 @@ Once I finished this process, my Wi-Fi is working flawlessly.
226225
227226** Sound Issues
228227
229Same as with the Wi-Fi, I had no sound and could not control the
230mute/unmute or volume buttons on my laptop.
228Same as with the Wi-Fi, I had no sound and could not control the mute/unmute or
229volume buttons on my laptop.
231230
232To resolve this, I installed
233[[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]].
231To resolve this, I installed [[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]].
234232
235233#+begin_src sh
236234# Add your user to the following groups
@@ -242,8 +240,8 @@ apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa
242240#+end_src
243241
244242Finally, I needed to add =/usr/libexec/pipewire-launcher= to my
245=.config/sway/config= file so that Pipewire would run every time I
246launched sway.
243=.config/sway/config= file so that Pipewire would run every time I launched
244sway.
247245
248246#+begin_src sh
249247nano ~/.config/sway/config
@@ -260,8 +258,8 @@ bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ to
260258bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle
261259#+end_src
262260
263Note that I do not use bluetooth or screen sharing, so I won't cover
264those options in this post.
261Note that I do not use bluetooth or screen sharing, so I won't cover those
262options in this post.
265263
266Other than these issues, I have a working Alpine desktop. No other
267complaints thus far!
264Other than these issues, I have a working Alpine desktop. No other complaints
265thus far!