Commit 51a7a02f0c
Unsigned
Layout: unified · split
content/blog/2022-02-10-leaving-the-office.org +132 −150
| @@ -5,126 +5,114 @@ | ||
| 5 | 5 | |
| 6 | 6 | * The Working World is Changing |
| 7 | 7 | |
| 8 | There has been a trend for the past few years of companies slowly | |
| 9 | realizing that the pandemic is not just a temporary state that will go | |
| 10 | away eventually and let everything return to the way it was before. In | |
| 11 | terms of business and employment, this means that more and more jobs are | |
| 12 | being offered as permanently remote roles. | |
| 8 | There has been a trend for the past few years of companies slowly realizing that | |
| 9 | the pandemic is not just a temporary state that will go away eventually and let | |
| 10 | everything return to the way it was before. In terms of business and employment, | |
| 11 | this means that more and more jobs are being offered as permanently remote | |
| 12 | roles. | |
| 13 | 13 | |
| 14 | 14 | I had always dreamt of working from home but thought of it as a fantasy, |
| 15 | especially since I did not want to move over into the software | |
| 16 | development field. However, I have found that almost all roles being | |
| 17 | sent to me via recruiters are permanently remote (although most are | |
| 18 | limited to US citizens or even region-locked for companies who only | |
| 19 | operate in select states). | |
| 15 | especially since I did not want to move over into the software development | |
| 16 | field. However, I have found that almost all roles being sent to me via | |
| 17 | recruiters are permanently remote (although most are limited to US citizens or | |
| 18 | even region-locked for companies who only operate in select states). | |
| 20 | 19 | |
| 21 | I decided to take a look back at my relatively short career so far and | |
| 22 | compare the positive and negative effects of the different work | |
| 23 | environments I've been in. | |
| 20 | I decided to take a look back at my relatively short career so far and compare | |
| 21 | the positive and negative effects of the different work environments I've been | |
| 22 | in. | |
| 24 | 23 | |
| 25 | 24 | * In-Person Offices |
| 26 | 25 | |
| 27 | 26 | ** Retail Internship |
| 28 | 27 | |
| 29 | I started my first job as a management intern at a busy retail pharmacy, | |
| 30 | working my 40-hour weeks on my feet. As these retail stores don't | |
| 31 | believe in resting or sitting down, you can guarantee that you will | |
| 32 | spend entire shifts standing, walking, or running around the store. | |
| 33 | Unfortunately, I worked at a time when our store didn't have enough | |
| 34 | managers, so I spent the majority of my tenure at the store running and | |
| 35 | breaking a sweat. | |
| 36 | ||
| 37 | Now, things aren't all bad in retail stores like this. It is definitely | |
| 38 | tiring and inefficient to force employees to work constantly, or pretend | |
| 39 | to work if there's nothing to do, and not allow anyone to sit down. | |
| 40 | However, if you are able to operate a retail store with a limited crew | |
| 41 | and provide enough comfort and support, I believe these jobs could be | |
| 42 | both comfortable and efficient. | |
| 28 | I started my first job as a management intern at a busy retail pharmacy, working | |
| 29 | my 40-hour weeks on my feet. As these retail stores don't believe in resting or | |
| 30 | sitting down, you can guarantee that you will spend entire shifts standing, | |
| 31 | walking, or running around the store. Unfortunately, I worked at a time when our | |
| 32 | store didn't have enough managers, so I spent the majority of my tenure at the | |
| 33 | store running and breaking a sweat. | |
| 34 | ||
| 35 | Now, things aren't all bad in retail stores like this. It is definitely tiring | |
| 36 | and inefficient to force employees to work constantly, or pretend to work if | |
| 37 | there's nothing to do, and not allow anyone to sit down. However, if you are | |
| 38 | able to operate a retail store with a limited crew and provide enough comfort | |
| 39 | and support, I believe these jobs could be both comfortable and efficient. | |
| 43 | 40 | |
| 44 | 41 | ** Semi-Private Cubicles |
| 45 | 42 | |
| 46 | After about a year, I was able to find another internship - this time, | |
| 47 | it was in my field of interest: internal auditing. This was for a life | |
| 48 | insurance company that was well over 100 years old. The age of the | |
| 49 | company shows if you work there, as most people in management are well | |
| 50 | into their 40s-60s with little to no youthful leadership in the company. | |
| 51 | Likewise, they owned a large headquarters in a nice area of town with | |
| 52 | plenty of space, parking, etc. | |
| 53 | ||
| 54 | One upside is that each person gets their own large L-shaped desk, | |
| 55 | formed into cubicles that house 4 desks/employees. These "pods" of | |
| 56 | 4-person cubicles are linked throughout each floor of the headquarters | |
| 57 | (except the sales people, who had that open-floor concept going on). The | |
| 58 | walls of the cubicle were tall and provided a lot of privacy and | |
| 59 | sound-proofing, except when I used the standing desk feature (I'm over 6 | |
| 60 | feet tall, so probably not an issue for most people). | |
| 43 | After about a year, I was able to find another internship - this time, it was in | |
| 44 | my field of interest: internal auditing. This was for a life insurance company | |
| 45 | that was well over 100 years old. The age of the company shows if you work | |
| 46 | there, as most people in management are well into their 40s-60s with little to | |
| 47 | no youthful leadership in the company. Likewise, they owned a large headquarters | |
| 48 | in a nice area of town with plenty of space, parking, etc. | |
| 49 | ||
| 50 | One upside is that each person gets their own large L-shaped desk, formed into | |
| 51 | cubicles that house 4 desks/employees. These "pods" of 4-person cubicles are | |
| 52 | linked throughout each floor of the headquarters (except the sales people, who | |
| 53 | had that open-floor concept going on). The walls of the cubicle were tall and | |
| 54 | provided a lot of privacy and sound-proofing, except when I used the standing | |
| 55 | desk feature (I'm over 6 feet tall, so probably not an issue for most people). | |
| 61 | 56 | |
| 62 | 57 | I loved this environment, it allowed me to focus on my work with minimal |
| 63 | distractions, but also allowed easy access, so I could spin around in my | |
| 64 | chair and chat with my friends without leaving my chair. This is the | |
| 65 | closest I've been to a home office environment (which is my personal | |
| 66 | favorite, as I'll get to later in this post). | |
| 58 | distractions, but also allowed easy access, so I could spin around in my chair | |
| 59 | and chat with my friends without leaving my chair. This is the closest I've been | |
| 60 | to a home office environment (which is my personal favorite, as I'll get to | |
| 61 | later in this post). | |
| 67 | 62 | |
| 68 | 63 | ** Semi-Open Floor Concept |
| 69 | 64 | |
| 70 | When I shifted to my first full-time internal audit job out of college, | |
| 71 | I was working at a company that was headquartered on a floor in a | |
| 72 | downtown high-rise building. The company was only about 20 years old | |
| 73 | when I worked there and were trying a lot of new things to attract young | |
| 74 | talent, one of which was a semi-open floor concept for the office. My | |
| 75 | department worked just around the hallway corner from the executive | |
| 76 | offices and used that "modern" layout young tech companies started using | |
| 77 | in the 2000s/2010s. | |
| 78 | ||
| 79 | Each desk was brief, and you could look most coworkers in the face | |
| 80 | without moving from your chair, I hated this so much. Directly to my | |
| 81 | left was the Chief Audit Executive (our department's leading boss), and | |
| 82 | his desk was pointed so that his face would stare straight at my desk | |
| 83 | all day. I spent more time thinking about who was looking at me or | |
| 84 | checking on me than actually working. | |
| 85 | ||
| 86 | The other annoying part of the open concept they used was that the | |
| 87 | kitchen area and pathways were too close to everyone's desks (since the | |
| 88 | desks were spread out, to provide space or something), so noise and | |
| 89 | conversation would be constant throughout the day while you try to work. | |
| 90 | For someone like me, who needs silence to get work done, that was a | |
| 91 | non-starter. | |
| 65 | When I shifted to my first full-time internal audit job out of college, I was | |
| 66 | working at a company that was headquartered on a floor in a downtown high-rise | |
| 67 | building. The company was only about 20 years old when I worked there and were | |
| 68 | trying a lot of new things to attract young talent, one of which was a semi-open | |
| 69 | floor concept for the office. My department worked just around the hallway | |
| 70 | corner from the executive offices and used that "modern" layout young tech | |
| 71 | companies started using in the 2000s/2010s. | |
| 72 | ||
| 73 | Each desk was brief, and you could look most coworkers in the face without | |
| 74 | moving from your chair, I hated this so much. Directly to my left was the Chief | |
| 75 | Audit Executive (our department's leading boss), and his desk was pointed so | |
| 76 | that his face would stare straight at my desk all day. I spent more time | |
| 77 | thinking about who was looking at me or checking on me than actually working. | |
| 78 | ||
| 79 | The other annoying part of the open concept they used was that the kitchen area | |
| 80 | and pathways were too close to everyone's desks (since the desks were spread | |
| 81 | out, to provide space or something), so noise and conversation would be constant | |
| 82 | throughout the day while you try to work. For someone like me, who needs silence | |
| 83 | to get work done, that was a non-starter. | |
| 92 | 84 | |
| 93 | 85 | ** Hotel Office Concept |
| 94 | 86 | |
| 95 | I currently work for a company remotely (for now) and travel to the | |
| 96 | office every once in a while for events and to help coach the staff | |
| 97 | underneath me. The office I visit uses the hotel desk concept, where you | |
| 98 | need to check in at a touch screen when you enter the office and "rent" | |
| 99 | a desk for the day. The same goes for offices and meeting rooms. | |
| 87 | I currently work for a company remotely (for now) and travel to the office every | |
| 88 | once in a while for events and to help coach the staff underneath me. The office | |
| 89 | I visit uses the hotel desk concept, where you need to check in at a touch | |
| 90 | screen when you enter the office and "rent" a desk for the day. The same goes | |
| 91 | for offices and meeting rooms. | |
| 100 | 92 | |
| 101 | These desks are flat-top only and do not have any walls at all. In | |
| 102 | addition, they're stacked with one row of 4 desks facing another row of | |
| 103 | 4 desks. These pairs of desk rows are repeated through the office. | |
| 93 | These desks are flat-top only and do not have any walls at all. In addition, | |
| 94 | they're stacked with one row of 4 desks facing another row of 4 desks. These | |
| 95 | pairs of desk rows are repeated through the office. | |
| 104 | 96 | |
| 105 | This means that when I go, I need to rent a random desk or try to | |
| 106 | remember the unique ID numbers on desks I like. Once I rent it, I have | |
| 107 | to make sure no one sat down in that desk without renting it. Then, I | |
| 108 | can sit down and work, but will probably need to adjust the monitors so | |
| 109 | that I'm not staring in the face of the person across from me all day. | |
| 110 | Finally, I need to wear headphones as this environment does nothing to | |
| 111 | provide you with peace or quiet. | |
| 97 | This means that when I go, I need to rent a random desk or try to remember the | |
| 98 | unique identification (ID) numbers on desks I like. Once I rent it, I have to | |
| 99 | make sure no one sat down in that desk without renting it. Then, I can sit down | |
| 100 | and work, but will probably need to adjust the monitors so that I'm not staring | |
| 101 | in the face of the person across from me all day. Finally, I need to wear | |
| 102 | headphones as this environment does nothing to provide you with peace or quiet. | |
| 112 | 103 | |
| 113 | Luckily, you can rent offices with doors that offer quiet and privacy, | |
| 114 | which can be very nice if you have a lot of meetings or webinars on a | |
| 115 | certain day. | |
| 104 | Luckily, you can rent offices with doors that offer quiet and privacy, which can | |
| 105 | be very nice if you have a lot of meetings or webinars on a certain day. | |
| 116 | 106 | |
| 117 | 107 | * Home Office |
| 118 | 108 | |
| 119 | Okay, now let's finally get to the home office concept. I have worked | |
| 120 | from home for a little over two years at this point, across three | |
| 121 | different jobs/employers. Over this time, I have experimented with a | |
| 122 | plethora of different organizational ideas, desks, and room layouts to | |
| 123 | find what works best for me. | |
| 109 | Okay, now let's finally get to the home office concept. I have worked from home | |
| 110 | for a little over two years at this point, across three different | |
| 111 | jobs/employers. Over this time, I have experimented with a plethora of different | |
| 112 | organizational ideas, desks, and room layouts to find what works best for me. | |
| 124 | 113 | |
| 125 | These things might not apply to you, and that's fine. Everyone has a | |
| 126 | different situation, and I really don't think you'll know what works | |
| 127 | until you try. | |
| 114 | These things might not apply to you, and that's fine. Everyone has a different | |
| 115 | situation, and I really don't think you'll know what works until you try. | |
| 128 | 116 | |
| 129 | 117 | ** Tip #1 |
| 130 | 118 | |
| @@ -134,16 +122,15 @@ Let's start with my top rule for a home office: | ||
| 134 | 122 | If you live with others, working in a shared space is not effective. |
| 135 | 123 | #+end_quote |
| 136 | 124 | |
| 137 | It just does not work. If you have another person sleeping in your | |
| 138 | bedroom, it is difficult to manage your work schedule with their | |
| 139 | sleeping/work/school schedule. If they wake up after you need to start | |
| 140 | work, you might wake them up or have to suffer the agony of staring at | |
| 141 | bright screens in a dark room. | |
| 125 | It just does not work. If you have another person sleeping in your bedroom, it | |
| 126 | is difficult to manage your work schedule with their sleeping/work/school | |
| 127 | schedule. If they wake up after you need to start work, you might wake them up | |
| 128 | or have to suffer the agony of staring at bright screens in a dark room. | |
| 142 | 129 | |
| 143 | In a similar vein, working from a location such as the living room | |
| 144 | likely won't work either. Distractions will come far more frequently: | |
| 145 | televisions, cooking, cleaning, deliveries, etc. If you're like me, | |
| 146 | you'll end up playing a game instead of actually doing any work. | |
| 130 | In a similar vein, working from a location such as the living room likely won't | |
| 131 | work either. Distractions will come far more frequently: televisions, cooking, | |
| 132 | cleaning, deliveries, etc. If you're like me, you'll end up playing a game | |
| 133 | instead of actually doing any work. | |
| 147 | 134 | |
| 148 | 135 | ** Tip #2 |
| 149 | 136 | |
| @@ -154,39 +141,38 @@ Use the pomodoro method (or something similar) to balance work tasks | ||
| 154 | 141 | with personal tasks. |
| 155 | 142 | #+end_quote |
| 156 | 143 | |
| 157 | I use a very casual version of the pomodoro method where I will work for | |
| 158 | 1-2 hours (usually set in strict intervals like 1, 1.5, 2 hours) and | |
| 159 | then will allow myself 30-60 minutes for personal tasks. This schedule | |
| 160 | works for me, since my work schedule really only comes to 3-6 hours of | |
| 161 | work per day. | |
| 144 | I use a very casual version of the pomodoro method where I will work for 1-2 | |
| 145 | hours (usually set in strict intervals like 1, 1.5, 2 hours) and then will allow | |
| 146 | myself 30-60 minutes for personal tasks. This schedule works for me, since my | |
| 147 | work schedule really only comes to 3-6 hours of work per day. | |
| 162 | 148 | |
| 163 | In this case, I'll work through my list of tasks for an hour or two and | |
| 164 | then give myself personal time to get drinks and food, wash dishes, put | |
| 165 | clothes in the washer, get the mail, etc. If you're in a convenient | |
| 166 | location, this usually gives time for things like getting groceries (as | |
| 167 | long as you're not a slow shopper). | |
| 149 | In this case, I'll work through my list of tasks for an hour or two and then | |
| 150 | give myself personal time to get drinks and food, wash dishes, put clothes in | |
| 151 | the washer, get the mail, etc. If you're in a convenient location, this usually | |
| 152 | gives time for things like getting groceries (as long as you're not a slow | |
| 153 | shopper). | |
| 168 | 154 | |
| 169 | 155 | ** Tip #3 |
| 170 | 156 | |
| 171 | While I listed this one as number three, I don't think I'd accomplish | |
| 172 | anything without it: | |
| 157 | While I listed this one as number three, I don't think I'd accomplish anything | |
| 158 | without it: | |
| 173 | 159 | |
| 174 | 160 | #+begin_quote |
| 175 | 161 | Document everything: even things you didn't before - such as task lists |
| 176 | 162 | and notes from casual calls or meetings. |
| 177 | 163 | #+end_quote |
| 178 | 164 | |
| 179 | I've noticed that staying in an office gave me more constant reminders | |
| 180 | of outstanding tasks or facts I had learned in a conversation. | |
| 181 | Translating everything to a digital world has made me lose a bit of that | |
| 182 | focus (perhaps since I don't have visual reminders?). | |
| 165 | I've noticed that staying in an office gave me more constant reminders of | |
| 166 | outstanding tasks or facts I had learned in a conversation. Translating | |
| 167 | everything to a digital world has made me lose a bit of that focus (perhaps | |
| 168 | since I don't have visual reminders?). | |
| 183 | 169 | |
| 184 | Keeping a running task list of all things I have to do - even potential | |
| 185 | tasks! - has helped me keep up without missing anything small. Likewise, | |
| 186 | keeping notes for ALL meetings and calls, no matter how casual/quick, | |
| 187 | has improved my retention immensely. Beyond helping my mental | |
| 188 | recollection, it has saved me numerous times when I need to do a keyword | |
| 189 | search for some topic that was discussed 6+ months ago. | |
| 170 | Keeping a running task list of all things I have to do - even potential tasks! - | |
| 171 | has helped me keep up without missing anything small. Likewise, keeping notes | |
| 172 | for ALL meetings and calls, no matter how casual/quick, has improved my | |
| 173 | retention immensely. Beyond helping my mental recollection, it has saved me | |
| 174 | numerous times when I need to do a keyword search for some topic that was | |
| 175 | discussed 6+ months ago. | |
| 190 | 176 | |
| 191 | 177 | ** Tip #4 |
| 192 | 178 | |
| @@ -196,36 +182,32 @@ Okay, last one for now. | ||
| 196 | 182 | Keep your work area clean. |
| 197 | 183 | #+end_quote |
| 198 | 184 | |
| 199 | This one is straightforward, but I know some people struggle with | |
| 200 | cleanliness or may not believe it makes a difference. Trust me, keeping | |
| 201 | your desk area clean and organized makes a huge difference, both | |
| 202 | mentally and emotionally. | |
| 185 | This one is straightforward, but I know some people struggle with cleanliness or | |
| 186 | may not believe it makes a difference. Trust me, keeping your desk area clean | |
| 187 | and organized makes a huge difference, both mentally and emotionally. | |
| 203 | 188 | |
| 204 | Just think about it, you walk into your home office and see a clean desk | |
| 205 | with a laptop, dock, monitors, keyboard, mouse, and a notepad with a pen | |
| 206 | on top. | |
| 189 | Just think about it, you walk into your home office and see a clean desk with a | |
| 190 | laptop, dock, monitors, keyboard, mouse, and a notepad with a pen on top. | |
| 207 | 191 | |
| 208 | Now imagine the opposite, there's an office with the same equipment, but | |
| 209 | there are clothes hanging on the chair, empty drink bottles, candy | |
| 210 | wrappers and dirty plates. This can take both a mental and emotional | |
| 211 | toll by bringing constant disarray and stress into your working | |
| 212 | environment. | |
| 192 | Now imagine the opposite, there's an office with the same equipment, but there | |
| 193 | are clothes hanging on the chair, empty drink bottles, candy wrappers and dirty | |
| 194 | plates. This can take both a mental and emotional toll by bringing constant | |
| 195 | disarray and stress into your working environment. | |
| 213 | 196 | |
| 214 | Just keep things clean each day, and you won't need to do any big | |
| 215 | cleaning days to recover. | |
| 197 | Just keep things clean each day, and you won't need to do any big cleaning days | |
| 198 | to recover. | |
| 216 | 199 | |
| 217 | 200 | * My Preferences |
| 218 | 201 | |
| 219 | I've talked about the different environments I've worked in and | |
| 220 | expressed some honest thoughts on pros or cons to each, but what do I | |
| 221 | prefer? Well, if you're reading along, you should be able to tell that I | |
| 222 | much prefer a home office above all else. | |
| 202 | I've talked about the different environments I've worked in and expressed some | |
| 203 | honest thoughts on pros or cons to each, but what do I prefer? Well, if you're | |
| 204 | reading along, you should be able to tell that I much prefer a home office above | |
| 205 | all else. | |
| 223 | 206 | |
| 224 | Being able to control my own day and allot my time as needed has brought | |
| 225 | a calmness to my life and has allowed me to maximize each day. I feel | |
| 226 | far more effective and efficient in a home office than any other office, | |
| 227 | especially open-office layouts. | |
| 207 | Being able to control my own day and allot my time as needed has brought a | |
| 208 | calmness to my life and has allowed me to maximize each day. I feel far more | |
| 209 | effective and efficient in a home office than any other office, especially | |
| 210 | open-office layouts. | |
| 228 | 211 | |
| 229 | If I do need to return to an office part-time in the future, I really | |
| 230 | hope the office will have privacy and quietness in order for me to get | |
| 231 | my work done. | |
| 212 | If I do need to return to an office part-time in the future, I really hope the | |
| 213 | office 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 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Njalla's API |
| 7 | 7 | |
| 8 | As noted in my recent post about | |
| 9 | [[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from | |
| 10 | Cloudflare]], I was searching for a way to replace my very easy-to-use | |
| 11 | bash script to [[https://cleberg.net/blog/cloudflare-dns-api/][update Cloudflare's | |
| 12 | DNS via their API]]. | |
| 8 | As noted in my recent post about [[https://cleberg.net/blog/ditching-cloudflare/][switching to Njalla from Cloudflare]], I was | |
| 9 | searching for a way to replace my [[https://cleberg.net/blog/cloudflare-dns-api.html][bash script]] to update my domain's =A= record | |
| 10 | with my home's internet protocol (IP) address dynamically. | |
| 13 | 11 | |
| 14 | To reiterate what I said in those posts, this is a common necessity for | |
| 15 | those of us who have non-static IP addresses that can change at any | |
| 16 | moment due to ISP policy. | |
| 12 | To reiterate what I said in those posts, this is a common necessity for those of | |
| 13 | us who have non-static IP addresses that can change at any moment due to | |
| 14 | internet service provider (ISP) policy. | |
| 17 | 15 | |
| 18 | In order to keep a home server running smoothly, the server admin needs | |
| 19 | to have a process to constantly monitor their public IP address and | |
| 20 | update their domain's DNS records if it changes. | |
| 16 | In order to keep a home server running smoothly, the server admin needs to have | |
| 17 | a process to constantly monitor their public IP address and update their | |
| 18 | domain's DNS records if it changes. | |
| 21 | 19 | |
| 22 | This post explains how to use Python to update Njalla's DNS records | |
| 23 | whenever a machine's public IP address changes. | |
| 20 | This post explains how to use Python to update Njalla's DNS (domain name system) | |
| 21 | records whenever a machine's public IP address changes. | |
| 24 | 22 | |
| 25 | 23 | ** Creating a Token |
| 26 | 24 | |
| 27 | To use Njalla's API, you will first need to create a token that will be | |
| 28 | used to authenticate you every time you call the API. Luckily, this is | |
| 29 | very easy to do if you have an account with Njalla. | |
| 25 | To use Njalla's API, you will first need to create a token that will be used to | |
| 26 | authenticate you every time you call the API (application programming | |
| 27 | interface). Luckily, this is very easy to do if you have an account with Njalla. | |
| 30 | 28 | |
| 31 | Simply go the [[https://njal.la/settings/api/][API Settings]] page and | |
| 32 | click the =Add Token= button. Next, enter a name for the token and click | |
| 33 | =Add=. | |
| 29 | Simply go the [[https://njal.la/settings/api/][API Settings]] page and click the =Add Token= button. Next, enter a | |
| 30 | name for the token and click =Add=. | |
| 34 | 31 | |
| 35 | Finally, click the =Manage= button next to your newly created token and | |
| 36 | copy the =API Token= field. | |
| 32 | Finally, click the =Manage= button next to your newly created token and copy the | |
| 33 | =API Token= field. | |
| 37 | 34 | |
| 38 | 35 | ** Finding the Correct API Request |
| 39 | 36 | |
| 40 | Once you have a token, you're ready to call the Njalla API for any | |
| 41 | number of requests. For a full listing of available requests, see the | |
| 42 | [[https://njal.la/api/][Njalla API Documentation]]. | |
| 37 | Once you have a token, you're ready to call the Njalla API for any number of | |
| 38 | requests. For a full listing of available requests, see the [[https://njal.la/api/][Njalla API | |
| 39 | Documentation]]. | |
| 43 | 40 | |
| 44 | For this demo, we are using the =list-records= and =edit-record= | |
| 45 | requests. | |
| 41 | For this demo, we are using the =list-records= and =edit-record= requests. | |
| 46 | 42 | |
| 47 | The =list-records= request requires the following payload to be sent | |
| 48 | when calling the API: | |
| 43 | The =list-records= request requires the following payload to be sent when | |
| 44 | calling the API: | |
| 49 | 45 | |
| 50 | 46 | #+begin_src txt |
| 51 | 47 | params: { |
| @@ -53,8 +49,8 @@ params: { | ||
| 53 | 49 | } |
| 54 | 50 | #+end_src |
| 55 | 51 | |
| 56 | The =edit-record= request requires the following payload to be sent when | |
| 57 | calling the API: | |
| 52 | The =edit-record= request requires the following payload to be sent when calling | |
| 53 | the API: | |
| 58 | 54 | |
| 59 | 55 | #+begin_src txt |
| 60 | 56 | params: { |
| @@ -66,14 +62,14 @@ params: { | ||
| 66 | 62 | |
| 67 | 63 | * Server Set-Up |
| 68 | 64 | |
| 69 | To create this script, we will be using Python. By default, I use Python | |
| 70 | 3 on my servers, so please note that I did not test this in Python 2, | |
| 71 | and I do not know if Python 2 will work for this. | |
| 65 | To create this script, we will be using Python. By default, I use Python 3 on my | |
| 66 | servers, so please note that I did not test this in Python 2, and I do not know | |
| 67 | if Python 2 will work for this. | |
| 72 | 68 | |
| 73 | 69 | ** Creating the Script |
| 74 | 70 | |
| 75 | First, find a suitable place to create your script. Personally, I just | |
| 76 | create a directory called =ddns= in my home directory: | |
| 71 | First, find a suitable place to create your script. Personally, I just create a | |
| 72 | directory called =ddns= in my home directory: | |
| 77 | 73 | |
| 78 | 74 | #+begin_src sh |
| 79 | 75 | mkdir ~/ddns |
| @@ -85,20 +81,18 @@ Next, create a Python script file: | ||
| 85 | 81 | nano ~/ddns/ddns.py |
| 86 | 82 | #+end_src |
| 87 | 83 | |
| 88 | The following code snippet is quite long, so I won't go into depth on | |
| 89 | each part. However, I suggest you read through the entire script before | |
| 90 | running it; it is quite simple and contains comments to help explain | |
| 91 | each code block. | |
| 84 | The following code snippet is quite long, so I won't go into depth on each part. | |
| 85 | However, I suggest you read through the entire script before running it; it is | |
| 86 | quite simple and contains comments to help explain each code block. | |
| 92 | 87 | |
| 93 | :warning: *Note*: You will need to update the following variables for | |
| 94 | this to work: | |
| 88 | *Note*: You will need to update the following variables for this to work: | |
| 95 | 89 | |
| 96 | 90 | - =token=: This is the Njalla API token you created earlier. |
| 97 | 91 | - =user_domain=: This is the top-level domain you want to modify. |
| 98 | - =include_subdomains=: Set this to =True= if you also want to modify | |
| 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. | |
| 102 | 96 | |
| 103 | 97 | #+begin_src python |
| 104 | 98 | #!/usr/bin/python |
| @@ -183,8 +177,8 @@ for record in data['records']: | ||
| 183 | 177 | |
| 184 | 178 | ** Running the Script |
| 185 | 179 | |
| 186 | Once you've created the script and are ready to test it, run the | |
| 187 | following command: | |
| 180 | Once you've created the script and are ready to test it, run the following | |
| 181 | command: | |
| 188 | 182 | |
| 189 | 183 | #+begin_src sh |
| 190 | 184 | python3 ~/ddns/ddns.py |
| @@ -192,15 +186,15 @@ python3 ~/ddns/ddns.py | ||
| 192 | 186 | |
| 193 | 187 | ** Setting the Script to Run Automatically |
| 194 | 188 | |
| 195 | To make sure the scripts run automatically, add it to the =cron= file so | |
| 196 | that it will run on a schedule. To do this, open the =cron= file: | |
| 189 | To make sure the scripts run automatically, add it to the =cron= file so that it | |
| 190 | will run on a schedule. To do this, open the =cron= file: | |
| 197 | 191 | |
| 198 | 192 | #+begin_src sh |
| 199 | 193 | crontab -e |
| 200 | 194 | #+end_src |
| 201 | 195 | |
| 202 | In the cron file, paste the following at the bottom of the editor in | |
| 203 | order to check the IP every five minutes: | |
| 196 | In the cron file, paste the following at the bottom of the editor in order to | |
| 197 | check the IP every five minutes: | |
| 204 | 198 | |
| 205 | 199 | #+begin_src sh |
| 206 | 200 | */5 * * * * python3 /home/<your_username>/ddns/ddns.py |
content/blog/2022-02-16-debian-and-nginx.org +57 −64
| @@ -3,34 +3,31 @@ | ||
| 3 | 3 | #+description: Step-by-step protocol for transitioning web server infrastructure to Debian operating system, including installation, configuration, and security hardening of Nginx and Agate services. |
| 4 | 4 | #+slug: debian-and-nginx |
| 5 | 5 | |
| 6 | * Server OS: Debian | |
| 6 | * Server Operating System (OS): Debian | |
| 7 | 7 | |
| 8 | I've used various Linux distributions throughout the years, but I've | |
| 9 | never used anything except Ubuntu for my servers. Why? I really have no | |
| 10 | idea, mostly just comfort around the commands and software availability. | |
| 8 | I've used various Linux distributions throughout the years, but I've never used | |
| 9 | anything except Ubuntu for my servers. Why? I really have no idea, mostly just | |
| 10 | comfort around the commands and software availability. | |
| 11 | 11 | |
| 12 | However, I have always wanted to try Debian as a server OS after testing | |
| 13 | it out in a VM a few years ago (side-note: I'd love to try Alpine too, | |
| 14 | but I always struggle with compatibility). So, I decided to launch a new | |
| 15 | VPS and use [[https://www.debian.org][Debian]] 11 as the OS. Spoiler | |
| 16 | alert: it feels identical to Ubuntu for my purposes. | |
| 12 | However, I have always wanted to try Debian as a server OS after testing it out | |
| 13 | in a VM a few years ago (side-note: I'd love to try Alpine too, but I always | |
| 14 | struggle with compatibility). So, I decided to launch a new VPS and use [[https://www.debian.org][Debian]] | |
| 15 | 11 as the operating system (OS). Spoiler alert: it feels identical to Ubuntu for my purposes. | |
| 17 | 16 | |
| 18 | I did the normal things when first launching the VPS, such as adding a | |
| 19 | new user, locking down SSH, etc. If you want to see that level of | |
| 20 | detail, read my other post about | |
| 21 | [[https://cleberg.net/blog/how-to-set-up-a-vps-web-server/][How to Set | |
| 22 | Up a VPS Web Server]]. | |
| 17 | I did the normal things when first launching the VPS (virtual private server), | |
| 18 | such as adding a new user, locking down SSH (secure shell protocol), etc. If you | |
| 19 | want 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 | |
| 20 | Web Server]]. | |
| 23 | 21 | |
| 24 | All of this has been similar, apart from small things such as the | |
| 25 | location of users' home folders. No complaints at all from me - Debian | |
| 26 | seems great. | |
| 22 | All of this has been similar, apart from small things such as the location of | |
| 23 | users' home folders. No complaints at all from me - Debian seems great. | |
| 27 | 24 | |
| 28 | 25 | * Web Server: Nginx |
| 29 | 26 | |
| 30 | Once I had the baseline server configuration set-up for Debian, I moved | |
| 31 | on to trying out [[https://nginx.org][Nginx]] as my web server software. | |
| 32 | This required me to install the =nginx= and =ufw= packages, as well as | |
| 33 | setting up the initial UFW config: | |
| 27 | Once I had the baseline server configuration set-up for Debian, I moved on to | |
| 28 | trying 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 | |
| 30 | Firewall) config: | |
| 34 | 31 | |
| 35 | 32 | #+begin_src sh |
| 36 | 33 | sudo apt install nginx ufw |
| @@ -41,9 +38,9 @@ sudo ufw status | ||
| 41 | 38 | sudo systemctl status nginx |
| 42 | 39 | #+end_src |
| 43 | 40 | |
| 44 | Once I had the firewall set, I moved on to creating the directories and | |
| 45 | files for my website. This is very easy and is basically the same as | |
| 46 | setting up an Apache server, so no struggles here. | |
| 41 | Once I had the firewall set, I moved on to creating the directories and files | |
| 42 | for my website. This is very easy and is basically the same as setting up an | |
| 43 | Apache server, so no struggles here. | |
| 47 | 44 | |
| 48 | 45 | #+begin_src sh |
| 49 | 46 | sudo mkdir -p /var/www/your_domain/html |
| @@ -52,17 +49,17 @@ sudo chmod -R 755 /var/www/your_domain | ||
| 52 | 49 | nano /var/www/your_domain/html/index.html |
| 53 | 50 | #+end_src |
| 54 | 51 | |
| 55 | The next part, creating the Nginx configuration files, is quite a bit | |
| 56 | different from Apache. First, you need to create the files in the | |
| 57 | =sites-available= folder and symlink it the =sites-enabled= folder. | |
| 52 | The next part, creating the Nginx configuration files, is quite a bit different | |
| 53 | from Apache. First, you need to create the files in the =sites-available= folder | |
| 54 | and symlink it the =sites-enabled= folder. | |
| 58 | 55 | |
| 59 | Creating the config file for your domain: | |
| 56 | Creating the configuration file for your domain: | |
| 60 | 57 | |
| 61 | 58 | #+begin_src sh |
| 62 | 59 | sudo nano /etc/nginx/sites-available/your_domain |
| 63 | 60 | #+end_src |
| 64 | 61 | |
| 65 | Default content for an Nginx config file: | |
| 62 | Default content for an Nginx configuration file: | |
| 66 | 63 | |
| 67 | 64 | #+begin_src sh |
| 68 | 65 | server { |
| @@ -87,9 +84,9 @@ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/ | ||
| 87 | 84 | #+end_src |
| 88 | 85 | |
| 89 | 86 | This will make your site available to the public (as long as you have |
| 90 | =your_domain= DNS records pointed at the server's IP address)! | |
| 87 | =your_domain= DNS (Domain Name System) records pointed at the server's IP address)! | |
| 91 | 88 | |
| 92 | Next, I used [[https://certbot.eff.org/][certbot]] to issue an HTTPS | |
| 89 | Next, I used [[https://certbot.eff.org/][certbot]] to issue an HTTPS (Hypertext Transfer Protocol Secure) | |
| 93 | 90 | certificate for my domains using the following commands: |
| 94 | 91 | |
| 95 | 92 | #+begin_src sh |
| @@ -99,16 +96,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot | ||
| 99 | 96 | sudo certbot --nginx |
| 100 | 97 | #+end_src |
| 101 | 98 | |
| 102 | Now that certbot ran successfully and updated my Nginx config files to | |
| 99 | Now that =certbot= ran successfully and updated my Nginx configuration files to | |
| 103 | 100 | include a =443= server block of code, I went back in and edited the |
| 104 | config file to include security HTTP headers. This part is optional, but | |
| 105 | is recommended for security purposes; you can even test a website's HTTP | |
| 106 | header security at [[https://securityheaders.com/][Security Headers]]. | |
| 101 | configuration file to include security HTTP headers. This part is optional, but | |
| 102 | is recommended for security purposes; you can even test a website's HTTP header | |
| 103 | security at [[https://securityheaders.com/][Security Headers]]. | |
| 107 | 104 | |
| 108 | The configuration below shows a set-up where you only want your website | |
| 109 | to serve content from its own domain, except for images and scripts, | |
| 110 | which may come from =nullitics.com=. All other content would be blocked | |
| 111 | from loading in a browser. | |
| 105 | The configuration below shows a set-up where you only want your website to serve | |
| 106 | content 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. | |
| 112 | 108 | |
| 113 | 109 | #+begin_src sh |
| 114 | 110 | sudo nano /etc/nginx/sites-available/your_domain |
| @@ -133,35 +129,32 @@ sudo systemctl restart nginx | ||
| 133 | 129 | |
| 134 | 130 | ** Nginx vs. Apache |
| 135 | 131 | |
| 136 | As I stated at the beginning, my historical hesitation with trying Nginx | |
| 137 | was that the differences in configuration formats scared me away from | |
| 138 | leaving Apache. However, I prefer Nginx to Apache for a few reasons: | |
| 132 | As I stated at the beginning, my historical hesitation with trying Nginx was | |
| 133 | that the differences in configuration formats scared me away from leaving | |
| 134 | Apache. However, I prefer Nginx to Apache for a few reasons: | |
| 139 | 135 | |
| 140 | 1. Nginx uses only one config file (=your_domain=) vs. Apache's two-file | |
| 136 | 1. Nginx uses only one configuration file (=your_domain=) vs. Apache's two-file | |
| 141 | 137 | approach for HTTP vs. HTTPS (=your_domain.conf= and |
| 142 | 138 | =your_domain-le-ssl.conf=). |
| 143 | 2. 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. | |
| 148 | 3. 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 | ||
| 153 | They're both great software packages, but Nginx just seems more | |
| 154 | organized and easier to use these days. I will certainly be exploring | |
| 155 | the Nginx docs to see what other fun things I can do with all of this. | |
| 139 | 2. 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. | |
| 143 | 3. 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 | ||
| 148 | They're both great software packages, but Nginx just seems more organized and | |
| 149 | easier to use these days. I will certainly be exploring the Nginx docs to see | |
| 150 | what other fun things I can do with all of this. | |
| 156 | 151 | |
| 157 | 152 | * Gemini Server: Agate |
| 158 | 153 | |
| 159 | Finally, I set up the Agate software on this server again to host my | |
| 160 | Gemini server content, using Rust as I have before. You can read my | |
| 161 | other post for more information on installing Agate: | |
| 162 | [[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini | |
| 163 | Server]]. | |
| 154 | Finally, I set up the Agate software on this server again to host my Gemini | |
| 155 | server content, using Rust as I have before. You can read my other post for more | |
| 156 | information on installing Agate: [[https://cleberg.net/blog/hosting-a-gemini-server/][Hosting a Gemini Server]]. | |
| 164 | 157 | |
| 165 | All in all, Debian + Nginx is very slick and I prefer it over my old | |
| 166 | combination of Ubuntu + Apache (although it's really just Nginx > Apache | |
| 167 | for me, since Debian seems mostly the same as Ubuntu is so far). | |
| 158 | All in all, Debian + Nginx is very slick and I prefer it over my old combination | |
| 159 | of Ubuntu + Apache (although it's really just Nginx > Apache for me, since | |
| 160 | Debian seems mostly the same as Ubuntu is so far). | |
content/blog/2022-02-17-exiftool.org +18 −20
| @@ -5,14 +5,14 @@ | ||
| 5 | 5 | |
| 6 | 6 | ** Why Strip Metadata? |
| 7 | 7 | |
| 8 | Okay, so you want to strip metadata from your photos. Perhaps you take | |
| 9 | pictures of very rare birds, and the location metadata is a gold mine | |
| 10 | for poachers, or perhaps you're just privacy-oriented like me and prefer | |
| 11 | to strip metadata from publicly-available images. | |
| 8 | Okay, so you want to strip metadata from your photos. Perhaps you take pictures | |
| 9 | of very rare birds, and the location metadata is a gold mine for poachers, or | |
| 10 | perhaps you're just privacy-oriented like me and prefer to strip metadata from | |
| 11 | publicly-available images. | |
| 12 | 12 | |
| 13 | There are various components of image metadata that you may want to | |
| 14 | delete before releasing a photo to the public. Here's an incomplete list | |
| 15 | of things I could easily see just by inspecting a photo on my laptop: | |
| 13 | There are various components of image metadata that you may want to delete | |
| 14 | before releasing a photo to the public. Here's an incomplete list of things I | |
| 15 | could easily see just by inspecting a photo on my laptop: | |
| 16 | 16 | |
| 17 | 17 | - Location (Latitude & Longitude) |
| 18 | 18 | - Dimensions |
| @@ -25,15 +25,14 @@ of things I could easily see just by inspecting a photo on my laptop: | ||
| 25 | 25 | - Metering Mode |
| 26 | 26 | - F Number |
| 27 | 27 | |
| 28 | Regardless of your reasoning, I'm going to explain how I used the | |
| 29 | =exiftool= package in Linux to automatically strip metadata from all | |
| 30 | images in a directory (+ subdirectories). | |
| 28 | Regardless of your reasoning, I'm going to explain how I used the =exiftool= | |
| 29 | package in Linux to automatically strip metadata from all images in a directory | |
| 30 | (+ subdirectories). | |
| 31 | 31 | |
| 32 | 32 | ** Installing =exiftool= |
| 33 | 33 | |
| 34 | First things first: we need to install the tool. I'm running Debian 11 | |
| 35 | on my server (Ubuntu will work the same), so the command is as simple | |
| 36 | as: | |
| 34 | First things first: we need to install the tool. I'm running Debian 11 on my | |
| 35 | server (Ubuntu will work the same), so the command is as simple as: | |
| 37 | 36 | |
| 38 | 37 | #+begin_src sh |
| 39 | 38 | sudo apt install exiftool |
| @@ -44,16 +43,15 @@ distributions, but I really only care to test out this one package. | ||
| 44 | 43 | |
| 45 | 44 | ** Recursively Strip Data |
| 46 | 45 | |
| 47 | I actually use this tool extensively to strip any photos uploaded to the | |
| 48 | website that serves all the images for my blog (=img.cleberg.net=). | |
| 46 | I actually use this tool extensively to strip any photos uploaded to the website | |
| 47 | that serves all the images for my blog (=img.cleberg.net=). | |
| 49 | 48 | |
| 50 | The following command is incredibly useful and can be modified to | |
| 51 | include any image extensions that =exiftool= supports: | |
| 49 | The following command is incredibly useful and can be modified to include any | |
| 50 | image extensions that =exiftool= supports: | |
| 52 | 51 | |
| 53 | 52 | #+begin_src sh |
| 54 | 53 | exiftool -r -all= -ext jpg -ext png /path/to/directory/ |
| 55 | 54 | #+end_src |
| 56 | 55 | |
| 57 | The output of the command will let you know how many directories were | |
| 58 | scanned, how many images were updated, and how many images were | |
| 59 | unchanged. | |
| 56 | The output of the command will let you know how many directories were scanned, | |
| 57 | how many images were updated, and how many images were unchanged. | |
content/blog/2022-02-20-nginx-caching.org +31 −37
| @@ -5,16 +5,15 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Update Your Nginx Config to Cache Static Files |
| 7 | 7 | |
| 8 | If you run a website on Nginx that serves static content (i.e., content | |
| 9 | that is not dynamic and changing with interactions from the user), you | |
| 10 | would likely benefit from caching that content on the client-side. If | |
| 11 | you're used to Apache and looking for the Nginx equivalent, this post | |
| 12 | should help. | |
| 8 | If you run a website on Nginx that serves static content (i.e., content that is | |
| 9 | not dynamic and changing with interactions from the user), you would likely | |
| 10 | benefit from caching that content on the client-side. If you're used to Apache | |
| 11 | and looking for the Nginx equivalent, this post should help. | |
| 13 | 12 | |
| 14 | Luckily, setting up the cache is as easy as identifying the file types | |
| 15 | you want to cache and determining the expiration length. To include more | |
| 16 | file types, simply use the bar separator (=|=) and type the new file | |
| 17 | extension you want to include. | |
| 13 | Luckily, setting up the cache is as easy as identifying the file types you want | |
| 14 | to cache and determining the expiration length. To include more file types, | |
| 15 | simply use the bar separator (=|=) and type the new file extension you want to | |
| 16 | include. | |
| 18 | 17 | |
| 19 | 18 | #+begin_src config |
| 20 | 19 | server { |
| @@ -28,41 +27,36 @@ server { | ||
| 28 | 27 | } |
| 29 | 28 | #+end_src |
| 30 | 29 | |
| 31 | I 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 | |
| 33 | my site often changes (i.e., I'm never content with my website), I need | |
| 34 | to know that my readers are seeing the new content without waiting too | |
| 35 | long. | |
| 30 | I have seen some people who prefer to set =expires= as =365d= or even =max=, but | |
| 31 | that is only for stable, infrequently changing websites. As my site often | |
| 32 | changes (i.e., I'm never content with my website), I need to know that my | |
| 33 | readers are seeing the new content without waiting too long. | |
| 36 | 34 | |
| 37 | So, I went ahead and set the expiration date at =30d=, which is short | |
| 38 | enough to refresh for readers but long enough that clients/browsers | |
| 39 | won't be re-requesting the static files too often, hopefully resulting | |
| 40 | in faster loading times, as images should be the only thing slowing down | |
| 41 | my site. | |
| 35 | So, I went ahead and set the expiration date at =30d=, which is short enough to | |
| 36 | refresh for readers but long enough that clients/browsers won't be re-requesting | |
| 37 | the static files too often, hopefully resulting in faster loading times, as | |
| 38 | images should be the only thing slowing down my site. | |
| 42 | 39 | |
| 43 | 40 | * Testing Results |
| 44 | 41 | |
| 45 | To test my changes to the Nginx configuration, I used the | |
| 46 | [[https://addons.mozilla.org/en-US/firefox/addon/http-header-live/][HTTP | |
| 47 | Header Live]] extension on my Gecko browser and used the sidebar to | |
| 48 | inspect the headers of a recent image from my blog. | |
| 42 | To test my changes to the Nginx configuration, I used the [[https://addons.mozilla.org/en-US/firefox/addon/http-header-live/][HTTP Header Live]] | |
| 43 | extension on my Gecko browser and used the sidebar to inspect the headers of a | |
| 44 | recent image from my blog. | |
| 49 | 45 | |
| 50 | In the image below, you can see that the =Cache-Control= header is now | |
| 51 | present and set to 2592000, which is 30 days represented in seconds (30 | |
| 52 | days _ 24 hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000 | |
| 53 | seconds). | |
| 46 | In the image below, you can see that the =Cache-Control= header is now present | |
| 47 | and set to 2592000, which is 30 days represented in seconds (30 days _ 24 | |
| 48 | hours/day _ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds). | |
| 54 | 49 | |
| 55 | The =Expires= field is now showing 22 March 2022, which is 30 days from | |
| 56 | the day of this post, 20 February 2022. | |
| 50 | The =Expires= field is now showing 22 March 2022, which is 30 days from the day | |
| 51 | of this post, 20 February 2022. | |
| 57 | 52 | |
| 58 | 53 | * Caveats |
| 59 | 54 | |
| 60 | Remember that this caching system is *client-side*, which means that | |
| 61 | content is only cached for as long as a client allows it. For example, | |
| 62 | my browser purges all caches, data, etc. upon exit, so this caching | |
| 63 | policy will only work as long as my browser remains open and running. | |
| 55 | Remember that this caching system is *client-side*, which means that content is | |
| 56 | only cached for as long as a client allows it. For example, my browser purges | |
| 57 | all caches, data, etc. upon exit, so this caching policy will only work as long | |
| 58 | as my browser remains open and running. | |
| 64 | 59 | |
| 65 | If you need to test updates to your site, you'll need to clear the cache | |
| 66 | to see updates for any file extension you configured. This can often be | |
| 67 | done with the =Shift + F5= or =Ctrl + F5= key combinations in most | |
| 68 | browsers. | |
| 60 | If you need to test updates to your site, you'll need to clear the cache to see | |
| 61 | updates 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 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Tuesday, Twosday |
| 7 | 7 | |
| 8 | I'm taking a break from my usual technology-related posts and writing | |
| 9 | about something a little more enjoyable today. | |
| 8 | I'm taking a break from my usual technology-related posts and writing about | |
| 9 | something a little more enjoyable today. | |
| 10 | 10 | |
| 11 | Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is | |
| 12 | Twosday. | |
| 11 | Today is Tuesday, February 22nd, 2022. Today is 02-22-2022. Today is Twosday. | |
| 13 | 12 | |
| 14 | 13 | Let's look at everything that fell in place today: |
| 15 | 14 | |
| 16 | 1. 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.) | |
| 19 | 2. Today is Tuesday, which is why everyone is using the nickname Twosday | |
| 20 | to call out these similarities. | |
| 21 | 3. 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). | |
| 24 | 4. 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." | |
| 27 | 5. 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]]!). | |
| 31 | 6. 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. | |
| 15 | 1. 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.) | |
| 18 | 2. Today is Tuesday, which is why everyone is using the nickname Twosday to call | |
| 19 | out these similarities. | |
| 20 | 3. 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). | |
| 22 | 4. 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." | |
| 25 | 5. 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]]!). | |
| 27 | 6. 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 @@ | ||
| 4 | 4 | #+slug: reliable-notes |
| 5 | 5 | |
| 6 | 6 | * Choosing Durable File Formats |
| 7 | :PROPERTIES: | |
| 8 | :CUSTOM_ID: choosing-durable-file-formats | |
| 9 | :END: | |
| 10 | 7 | |
| 11 | 8 | #+begin_quote |
| 12 | TL;DR: Write in a format that can be easily rendered and read in | |
| 13 | plain-text mode (e.g., =.txt=, =.md=, etc.). | |
| 9 | TL;DR (Too Long; Didn't Read): Write in a format that can be easily rendered and | |
| 10 | read in plain-text mode (e.g., =.txt=, =.md=, etc.). | |
| 14 | 11 | #+end_quote |
| 15 | 12 | |
| 16 | 13 | As I've written more and more over the years, I've found that my love of |
| 17 | note-taking is always growing. Everything I learn or need to remember | |
| 18 | can be written down in a note and saved digitally, with no cost to | |
| 19 | myself. Unlike paper copies that need physical storage space, digital | |
| 20 | files simply need space on your local disk or cloud storage, which is | |
| 21 | fairly abundant these days. | |
| 22 | ||
| 23 | However, I had a historical struggle with migration of notes between | |
| 24 | different apps that require different formats and applied proprietary | |
| 25 | styling. This meant that I had to go through each note during migration | |
| 26 | and edit the file to look presentable again. | |
| 27 | ||
| 28 | For the last year or two, I have written everything exclusively in | |
| 29 | [[https://en.wikipedia.org/wiki/Markdown][Markdown]] format. Small | |
| 30 | notes, long-form writings, and even these blog posts are all written in | |
| 31 | Markdown. | |
| 32 | ||
| 33 | Why Markdown? While I do appreciate the simplicity of plain-text files | |
| 34 | without any formatting, I often need visual cues such as heading and | |
| 35 | code blocks to keep my thoughts straight. Markdown provides a minimal | |
| 36 | set of styling indicators for me to style my notes without adding any | |
| 37 | proprietary, embedded data into the files. If I want a top-level | |
| 38 | heading, I simply add a hash (=#=) before the line. An added bonus is | |
| 39 | that even if a system doesn't understand Markdown, it will render it as | |
| 40 | plain-text and I can read it just as easily. | |
| 41 | ||
| 42 | For example, here's how TextEdit on macOS will open and display a | |
| 43 | Markdown file in plain-text, since it does contain any features to | |
| 44 | preview Markdown as HTML: | |
| 14 | note-taking is always growing. Everything I learn or need to remember can be | |
| 15 | written down in a note and saved digitally, with no cost to myself. Unlike paper | |
| 16 | copies that need physical storage space, digital files simply need space on your | |
| 17 | local disk or cloud storage, which is fairly abundant these days. | |
| 18 | ||
| 19 | However, I had a historical struggle with migration of notes between different | |
| 20 | apps that require different formats and applied proprietary styling. This meant | |
| 21 | that I had to go through each note during migration and edit the file to look | |
| 22 | presentable again. | |
| 23 | ||
| 24 | For the last year or two, I have written everything exclusively in [[https://en.wikipedia.org/wiki/Markdown][Markdown]] | |
| 25 | format. Small notes, long-form writings, and even these blog posts are all | |
| 26 | written in Markdown. | |
| 27 | ||
| 28 | Why Markdown? While I do appreciate the simplicity of plain-text files without | |
| 29 | any formatting, I often need visual cues such as heading and code blocks to keep | |
| 30 | my thoughts straight. Markdown provides a minimal set of styling indicators for | |
| 31 | me to style my notes without adding any proprietary, embedded data into the | |
| 32 | files. If I want a top-level heading, I simply add a hash (=#=) before the line. | |
| 33 | An added bonus is that even if a system doesn't understand Markdown, it will | |
| 34 | render it as plain-text and I can read it just as easily. | |
| 35 | ||
| 36 | For example, here's how TextEdit on macOS will open and display a Markdown file | |
| 37 | in plain-text, since it does contain any features to preview Markdown as HTML: | |
| 45 | 38 | |
| 46 | 39 | #+caption: Plain Text Markdown |
| 47 | 40 | [[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/plain_markdown.webp]] |
| 48 | 41 | |
| 49 | 42 | ** Saving & Syncing Files |
| 50 | :PROPERTIES: | |
| 51 | :CUSTOM_ID: saving-syncing-files | |
| 52 | :END: | |
| 53 | In order to read and edit my notes across platforms, I use my personal | |
| 54 | cloud storage through Tresorit due to its native integration with macOS | |
| 55 | and iOS file managers. In addition, Tresorit works well on Debian-based | |
| 56 | Linux distros, which I used before macOS (and will likely switch back to | |
| 57 | in a few years). | |
| 58 | 43 | |
| 59 | You can use whatever sync software you want - syncing plain-text or | |
| 60 | markdown files is incredibly easy and fast, since the files are | |
| 61 | generally tiny. | |
| 44 | In order to read and edit my notes across platforms, I use my personal cloud | |
| 45 | storage through Tresorit due to its native integration with macOS and iOS file | |
| 46 | managers. In addition, Tresorit works well on Debian-based Linux distributions, | |
| 47 | which I used before macOS (and will likely switch back to in a few years). | |
| 62 | 48 | |
| 63 | Since the cloud storage syncs files automatically, there is no need for | |
| 64 | me to sync anything manually or kick-off a sync job to update my files. | |
| 65 | This means that I can edit on mobile, and it takes about 5-10 seconds to | |
| 66 | see the changes on desktop. | |
| 49 | You can use whatever sync software you want - syncing plain-text or markdown | |
| 50 | files is incredibly easy and fast, since the files are generally tiny. | |
| 51 | ||
| 52 | Since the cloud storage syncs files automatically, there is no need for me to | |
| 53 | sync anything manually or kick-off a sync job to update my files. This means | |
| 54 | that I can edit on mobile, and it takes about 5-10 seconds to see the changes on | |
| 55 | desktop. | |
| 67 | 56 | |
| 68 | 57 | *** Version Control with Git |
| 69 | 58 | :PROPERTIES: |
| 70 | 59 | :CUSTOM_ID: version-control-with-git |
| 71 | 60 | :END: |
| 72 | A different approach I've contemplated is storing my notes and | |
| 73 | attachments is using a hosted Git repository to track changes to the | |
| 74 | files. However, I don't want to rely on an external service that could | |
| 75 | potentially see into my data, even if the repository is private. | |
| 61 | A different approach I've contemplated is storing my notes and attachments is | |
| 62 | using a hosted Git repository to track changes to the files. However, I don't | |
| 63 | want to rely on an external service that could potentially see into my data, | |
| 64 | even if the repository is private. | |
| 76 | 65 | |
| 77 | I might just do =git init= locally and then commit my changes each time | |
| 78 | I write or update a note, but that seems to be a lot of work just for | |
| 79 | tracking changes - which I don't necessarily care to know. | |
| 66 | I might just do =git init= locally and then commit my changes each time I write | |
| 67 | or update a note, but that seems to be a lot of work just for tracking changes - | |
| 68 | which I don't necessarily care to know. | |
| 80 | 69 | |
| 81 | 70 | *** Backups! |
| 82 | 71 | :PROPERTIES: |
| 83 | 72 | :CUSTOM_ID: backups |
| 84 | 73 | :END: |
| 85 | One small addition to the storage/sync conversation is the idea of | |
| 86 | backups. Personally, I manually create periodic backups of my entire | |
| 87 | cloud storage, compress it into an archive, and store it on my home | |
| 88 | server. | |
| 74 | One small addition to the storage/sync conversation is the idea of backups. | |
| 75 | Personally, I manually create periodic backups of my entire cloud storage, | |
| 76 | compress it into an archive, and store it on my home server. | |
| 89 | 77 | |
| 90 | To improve my workflow, I am going to be exploring options to | |
| 91 | automatically compress the mounted cloud directory and send it over to | |
| 92 | my server on a set schedule. | |
| 78 | To improve my workflow, I am going to be exploring options to automatically | |
| 79 | compress the mounted cloud directory and send it over to my server on a set | |
| 80 | schedule. | |
| 93 | 81 | |
| 94 | 82 | ** Writing on Desktop |
| 95 | :PROPERTIES: | |
| 96 | :CUSTOM_ID: writing-on-desktop | |
| 97 | :END: | |
| 98 | 83 | |
| 99 | 84 | #+begin_quote |
| 100 | *Update (06.14.22)*: Since writing this post, I have reverted to simply | |
| 101 | keeping my =notes= folder open and opening notes individually in | |
| 102 | TextEdit for a more minimal and relaxing writing experience on the | |
| 103 | desktop. | |
| 85 | *Update (06.14.22)*: Since writing this post, I have reverted to simply keeping | |
| 86 | my =notes= folder open and opening notes individually in TextEdit for a more | |
| 87 | minimal and relaxing writing experience on the desktop. | |
| 104 | 88 | #+end_quote |
| 105 | 89 | |
| 106 | The bulk of my writing occurs in a desktop environment, with a full | |
| 107 | keyboard layout and wide screen. I don't illustrate with a smart pen, I | |
| 108 | rarely use embedded images, and I love being able to see all of my | |
| 109 | notes/directories in a sidebar. | |
| 90 | The bulk of my writing occurs in a desktop environment, with a full keyboard | |
| 91 | layout and wide screen. I don't illustrate with a smart pen, I rarely use | |
| 92 | embedded images, and I love being able to see all of my notes/directories in a | |
| 93 | sidebar. | |
| 110 | 94 | |
| 111 | With this simple set of requirements, I chose | |
| 112 | [[https://obsidian.md][Obsidian]] as my desktop text editor. Obsidian | |
| 113 | has some in-depth tools like a graph view, command palette, mentions, | |
| 114 | etc., but I've found that using it as a simple Markdown editor is | |
| 95 | With this simple set of requirements, I chose [[https://obsidian.md][Obsidian]] as my desktop text | |
| 96 | editor. Obsidian has some in-depth tools like a graph view, command palette, | |
| 97 | mentions, etc., but I've found that using it as a simple Markdown editor is | |
| 115 | 98 | incredibly easy and straightforward. |
| 116 | 99 | |
| 117 | Here's an example of how my Markdown notes look when opened in | |
| 118 | plain-text mode: | |
| 100 | Here's an example of how my Markdown notes look when opened in plain-text mode: | |
| 119 | 101 | |
| 120 | 102 | #+caption: Obsidian Markdown Source Mode |
| 121 | 103 | [[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.webp]] |
| 122 | 104 | |
| 123 | Here's the "live preview" version, where the Markdown is rendered into | |
| 124 | its HTML format: | |
| 105 | Here's the "live preview" version, where the Markdown is rendered into its HTML | |
| 106 | format: | |
| 125 | 107 | |
| 126 | 108 | #+caption: Obsidian Markdown Live Preview |
| 127 | 109 | [[https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.webp]] |
| 128 | 110 | |
| 129 | 111 | *** Programming on Desktop |
| 130 | :PROPERTIES: | |
| 131 | :CUSTOM_ID: programming-on-desktop | |
| 132 | :END: | |
| 133 | While I was writing this, I realized I should specify that I don't use | |
| 134 | the same editor for writing notes and for writing code. For programming | |
| 135 | purposes, I use [[https://vscodium.com][VSCodium]] as my development | |
| 136 | IDE. | |
| 112 | ||
| 113 | While I was writing this, I realized I should specify that I don't use the same | |
| 114 | editor for writing notes and for writing code. For programming purposes, I use | |
| 115 | [[https://vscodium.com][VSCodium]] as my development IDE. | |
| 137 | 116 | |
| 138 | 117 | ** Writing on Mobile |
| 139 | :PROPERTIES: | |
| 140 | :CUSTOM_ID: writing-on-mobile | |
| 141 | :END: | |
| 142 | Personally, I write very little on mobile, except when needing to take | |
| 143 | important notes on-the-go. Any long-form writing, journals, etc. are | |
| 144 | done at home, where I always have my laptop available. | |
| 145 | ||
| 146 | I wanted a simple and foolproof editor for iOS, preferably open-source. | |
| 147 | After a long journey of testing the few (& terrible) open-source iOS | |
| 148 | note-taking apps, I finally found a phenomenal one: | |
| 149 | [[https://github.com/simonbs/runestone][Runestone]]. This app is | |
| 150 | fantastic for note-taking, has plenty of optional features, and | |
| 151 | integrates natively with the iOS file manager. | |
| 152 | ||
| 153 | This app opens the iOS file manager and allows you to click any file you | |
| 154 | want, opens it up in an editor, and lets me save and close out of that | |
| 155 | note. | |
| 118 | ||
| 119 | Personally, I write very little on mobile, except when needing to take important | |
| 120 | notes on-the-go. Any long-form writing, journals, etc. are done at home, where I | |
| 121 | always have my laptop available. | |
| 122 | ||
| 123 | I wanted a simple and foolproof editor for iOS, preferably open-source. After a | |
| 124 | long journey of testing the few (& terrible) open-source iOS note-taking apps, I | |
| 125 | finally found a phenomenal one: [[https://github.com/simonbs/runestone][Runestone]]. This app is fantastic for | |
| 126 | note-taking, has plenty of optional features, and integrates natively with the | |
| 127 | iOS file manager. | |
| 128 | ||
| 129 | This app opens the iOS file manager and allows you to click any file you want, | |
| 130 | opens it up in an editor, and lets me save and close out of that note. | |
| 156 | 131 | |
| 157 | 132 | Quite simple but effective. |
content/blog/2022-03-03-financial-database.org +69 −90
| @@ -4,60 +4,49 @@ | ||
| 4 | 4 | #+slug: financial-database |
| 5 | 5 | |
| 6 | 6 | * Personal Financial Tracking |
| 7 | :PROPERTIES: | |
| 8 | :CUSTOM_ID: personal-financial-tracking | |
| 9 | :END: | |
| 10 | For the last 6-ish years, I've tracked my finances in a spreadsheet. | |
| 11 | This is common practice in the business world, but any good dev will | |
| 12 | cringe at the thought of storing long-term data in a spreadsheet. A | |
| 13 | spreadsheet is not for long-term storage or as a source of data to pull | |
| 14 | data/reports. | |
| 15 | ||
| 16 | As I wanted to expand the functionality of my financial data (e.g., | |
| 17 | adding more reports), I decided to migrate the data into a database. To | |
| 18 | run reports, I would query the database and use a language like Python | |
| 19 | or Javascript to process the data, perform calculations, and visualize | |
| 20 | the data. | |
| 7 | ||
| 8 | For the last 6-ish years, I've tracked my finances in a spreadsheet. This is | |
| 9 | common practice in the business world, but any good dev will cringe at the | |
| 10 | thought of storing long-term data in a spreadsheet. A spreadsheet is not for | |
| 11 | long-term storage or as a source of data to pull data/reports. | |
| 12 | ||
| 13 | As I wanted to expand the functionality of my financial data (e.g., adding more | |
| 14 | reports), I decided to migrate the data into a database. To run reports, I would | |
| 15 | query the database and use a language like Python or Javascript to process the | |
| 16 | data, perform calculations, and visualize the data. | |
| 21 | 17 | |
| 22 | 18 | * SQLite |
| 23 | :PROPERTIES: | |
| 24 | :CUSTOM_ID: sqlite | |
| 25 | :END: | |
| 26 | When choosing the type of database I wanted to use for this project, I | |
| 27 | was split between three options: | |
| 28 | ||
| 29 | 1. MySQL: The database I have the most experience with and have used for | |
| 30 | years. | |
| 19 | ||
| 20 | When choosing the type of database I wanted to use for this project, I was split | |
| 21 | between three options: | |
| 22 | ||
| 23 | 1. MySQL: The database I have the most experience with and have used for years. | |
| 31 | 24 | 2. PostgreSQL: A database I'm new to, but want to learn. |
| 32 | 3. SQLite: A database that I've used for a couple projects and have | |
| 33 | moderate experience. | |
| 34 | ||
| 35 | I ended up choosing SQLite since it can be maintained within a single | |
| 36 | =.sqlite= file, which allows me more flexibility for storage and backup. | |
| 37 | I 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: | |
| 43 | Since I didn't want to try and import 1000--1500 records into my new | |
| 44 | database via the command line, I opted to use | |
| 45 | [[https://sqlitebrowser.org/][DB Browser for SQLite (DB4S)]] as a GUI | |
| 46 | tool. This application is excellent, and I don't see myself going back | |
| 47 | to the CLI when working in this database. | |
| 25 | 3. SQLite: A database that I've used for a couple projects and have moderate | |
| 26 | experience. | |
| 27 | ||
| 28 | I ended up choosing SQLite since it can be maintained within a single =.sqlite= | |
| 29 | file, which allows me more flexibility for storage and backup. I keep this file | |
| 30 | in my cloud storage and pull it up whenever needed. | |
| 31 | ||
| 32 | ** Visual Editing | |
| 33 | ||
| 34 | Since I didn't want to try and import 1000--1500 records into my new database | |
| 35 | via 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 | |
| 37 | myself going back to the CLI (command line interface) when working in this | |
| 38 | database. | |
| 48 | 39 | |
| 49 | 40 | DB4S allows you to copy a range of cells from a spreadsheet and paste it |
| 50 | straight into the SQL table. I used this process for all 36 accounts, | |
| 51 | 1290 account statements, and 126 pay statements. Overall, I'm guessing | |
| 52 | this took anywhere between 4--8 hours. In comparison, it probably took | |
| 53 | me 2-3 days to initially create the spreadsheet. | |
| 41 | straight into the SQL table. I used this process for all 36 accounts, 1290 | |
| 42 | account statements, and 126 pay statements. Overall, I'm guessing this took | |
| 43 | anywhere between 4--8 hours. In comparison, it probably took me 2-3 days to | |
| 44 | initially create the spreadsheet. | |
| 54 | 45 | |
| 55 | 46 | ** Schema |
| 56 | :PROPERTIES: | |
| 57 | :CUSTOM_ID: schema | |
| 58 | :END: | |
| 59 | The schema for this database is actually extremely simple and involves | |
| 60 | only three tables (for now): | |
| 47 | ||
| 48 | The schema for this database is actually extremely simple and involves only | |
| 49 | three tables (for now): | |
| 61 | 50 | |
| 62 | 51 | 1. Accounts |
| 63 | 52 | 2. Statements |
| @@ -65,9 +54,9 @@ only three tables (for now): | ||
| 65 | 54 | |
| 66 | 55 | *Accounts* |
| 67 | 56 | |
| 68 | The Accounts table contains summary information about an account, such | |
| 69 | as a car loan or a credit card. By viewing this table, you can find | |
| 70 | high-level data, such as interest rate, credit line, or owner. | |
| 57 | The Accounts table contains summary information about an account, such as a car | |
| 58 | loan or a credit card. By viewing this table, you can find high-level data, such | |
| 59 | as interest rate, credit line, or owner. | |
| 71 | 60 | |
| 72 | 61 | #+begin_src sql |
| 73 | 62 | CREATE TABLE "Accounts" ( |
| @@ -85,10 +74,10 @@ CREATE TABLE "Accounts" ( | ||
| 85 | 74 | |
| 86 | 75 | *Statements* |
| 87 | 76 | |
| 88 | The Statements table uses the same unique identifier as the Accounts | |
| 89 | table, meaning you can join the tables to find a monthly statement for | |
| 90 | any of the accounts listed in the Accounts table. Each statement has an | |
| 91 | account ID, statement date, and total balance. | |
| 77 | The Statements table uses the same unique identifier as the Accounts table, | |
| 78 | meaning you can join the tables to find a monthly statement for any of the | |
| 79 | accounts listed in the Accounts table. Each statement has an account identified | |
| 80 | (ID), statement date, and total balance. | |
| 92 | 81 | |
| 93 | 82 | #+begin_src sql |
| 94 | 83 | CREATE TABLE "Statements" ( |
| @@ -103,10 +92,10 @@ CREATE TABLE "Statements" ( | ||
| 103 | 92 | |
| 104 | 93 | *Payroll* |
| 105 | 94 | |
| 106 | The Payroll table is a separate entity, unrelated to the Accounts or | |
| 107 | Statements tables. This table contains all information you would find on | |
| 108 | a pay statement from an employer. As you change employers or obtain new | |
| 109 | perks/benefits, just add new columns to adapt to the new data. | |
| 95 | The Payroll table is a separate entity, unrelated to the Accounts or Statements | |
| 96 | tables. This table contains all information you would find on a pay statement | |
| 97 | from an employer. As you change employers or obtain new perks/benefits, just add | |
| 98 | new columns to adapt to the new data. | |
| 110 | 99 | |
| 111 | 100 | #+begin_src sql |
| 112 | 101 | CREATE TABLE "Payroll" ( |
| @@ -141,23 +130,18 @@ CREATE TABLE "Payroll" ( | ||
| 141 | 130 | #+end_src |
| 142 | 131 | |
| 143 | 132 | ** Python Reporting |
| 144 | :PROPERTIES: | |
| 145 | :CUSTOM_ID: python-reporting | |
| 146 | :END: | |
| 147 | Once I created the database tables and imported all my data, the only | |
| 148 | step left was to create a process to report and visualize on various | |
| 149 | aspects of the data. | |
| 150 | 133 | |
| 151 | In order to explore and create the reports I'm interested in, I utilized | |
| 152 | a two-part process involving Jupyter Notebooks and Python scripts. | |
| 134 | Once I created the database tables and imported all my data, the only step left | |
| 135 | was to create a process to report and visualize on various aspects of the data. | |
| 136 | ||
| 137 | In order to explore and create the reports I'm interested in, I utilized a | |
| 138 | two-part process involving Jupyter Notebooks and Python scripts. | |
| 153 | 139 | |
| 154 | 140 | *** Step 1: Jupyter Notebooks |
| 155 | :PROPERTIES: | |
| 156 | :CUSTOM_ID: step-1-jupyter-notebooks | |
| 157 | :END: | |
| 141 | ||
| 158 | 142 | When I need to explore data, try different things, and re-run my code |
| 159 | cell-by-cell, I use Jupyter Notebooks. For example, I explored the | |
| 160 | =Accounts= table until I found the following useful information: | |
| 143 | cell-by-cell, I use Jupyter Notebooks. For example, I explored the =Accounts= | |
| 144 | table until I found the following useful information: | |
| 161 | 145 | |
| 162 | 146 | #+begin_src python |
| 163 | 147 | import sqlite3 |
| @@ -182,12 +166,9 @@ df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', | ||
| 182 | 166 | #+end_src |
| 183 | 167 | |
| 184 | 168 | *** Step 2: Python Scripts |
| 185 | :PROPERTIES: | |
| 186 | :CUSTOM_ID: step-2-python-scripts | |
| 187 | :END: | |
| 188 | Once I explored enough through the notebooks and had a list of reports I | |
| 189 | wanted, I moved on to create a Python project with the following | |
| 190 | structure: | |
| 169 | ||
| 170 | Once I explored enough through the notebooks and had a list of reports I wanted, | |
| 171 | I moved on to create a Python project with the following structure: | |
| 191 | 172 | |
| 192 | 173 | #+begin_src txt |
| 193 | 174 | finance/ |
| @@ -212,16 +193,15 @@ This structure allows me to: | ||
| 212 | 193 | |
| 213 | 194 | 1. Compile all required python packages into =requirements.txt= for easy |
| 214 | 195 | installation if I move to a new machine. |
| 215 | 2. Activate a virtual environment in =venv/= so I don't need to maintain | |
| 216 | a system-wide Python environment just for this project. | |
| 217 | 3. Keep my =notebooks/= folder to continuously explore the data as I see | |
| 218 | fit. | |
| 196 | 2. Activate a virtual environment in =venv/= so I don't need to maintain a | |
| 197 | system-wide Python environment just for this project. | |
| 198 | 3. Keep my =notebooks/= folder to continuously explore the data as I see fit. | |
| 219 | 199 | 4. Maintain a local copy of the database in =src/= for easy access. |
| 220 | 200 | 5. Export reports, images, HTML files, etc. to =public/=. |
| 221 | 201 | |
| 222 | Now, onto the differences between the code in a Jupyter Notebook and the | |
| 223 | actual Python files. To create the report in the Notebook snippet above, | |
| 224 | I created the following function inside =process.py=: | |
| 202 | Now, onto the differences between the code in a Jupyter Notebook and the actual | |
| 203 | Python files. To create the report in the Notebook snippet above, I created the | |
| 204 | following function inside =process.py=: | |
| 225 | 205 | |
| 226 | 206 | #+begin_src python |
| 227 | 207 | # Create summary pie chart |
| @@ -258,11 +238,10 @@ Other charts generated by this project include: | ||
| 258 | 238 | |
| 259 | 239 | - Charts of account balances over time. |
| 260 | 240 | - 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. | |
| 263 | 242 | - Multi-line chart of gross income, taxable income, and net income. |
| 264 | 243 | |
| 265 | The best thing about this project? I can improve it at any given time, | |
| 266 | shaping it into whatever helps me the most for that time. I imagine that | |
| 267 | I will be introducing an asset tracking table soon to track the | |
| 268 | depreciating value of cars, houses, etc. Who knows what's next? | |
| 244 | The best thing about this project? I can improve it at any given time, shaping | |
| 245 | it into whatever helps me the most for that time. I imagine that I will be | |
| 246 | introducing an asset tracking table soon to track the depreciating value of | |
| 247 | cars, houses, etc. Who knows what's next? | |
content/blog/2022-03-08-plex-migration.org +101 −137
| @@ -4,18 +4,15 @@ | ||
| 4 | 4 | #+slug: plex-migration |
| 5 | 5 | |
| 6 | 6 | * Migration Phases |
| 7 | :PROPERTIES: | |
| 8 | :CUSTOM_ID: migration-phases | |
| 9 | :END: | |
| 10 | I recently decided to migrate my server from an old OptiPlex desktop | |
| 11 | machine to a custom-built tower with better hardware in every category. | |
| 12 | In order to do this, I would need to properly migrate a full Plex | |
| 13 | installation. | |
| 14 | ||
| 15 | The second part of this migration is that the new server uses an Nvidia | |
| 16 | GPU and does not have any integrated graphics, which requires extra work | |
| 17 | for installation, but provides much better hardware transcoding options | |
| 18 | for Plex. | |
| 7 | ||
| 8 | I recently decided to migrate my server from an old OptiPlex desktop machine to | |
| 9 | a custom-built tower with better hardware in every category. In order to do | |
| 10 | this, I would need to properly migrate a full Plex installation. | |
| 11 | ||
| 12 | The 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 | |
| 14 | requires extra work for installation, but provides much better hardware | |
| 15 | transcoding options for Plex. | |
| 19 | 16 | |
| 20 | 17 | Therefore, I have broken this migration down into three phases: |
| 21 | 18 | |
| @@ -24,50 +21,41 @@ Therefore, I have broken this migration down into three phases: | ||
| 24 | 21 | 3. Configure GPU Transcoding |
| 25 | 22 | |
| 26 | 23 | * 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 | ||
| 34 | 27 | In order to migrate Plex to my new server, I first needed to choose an |
| 35 | appropriate operating system (OS) and install it on the machine. Given | |
| 36 | that I have encountered numerous issues installing other Linux | |
| 37 | distributions properly with Nvidia graphics, I chose | |
| 38 | [[https://ubuntu.com/download/server][Ubuntu Server]]. | |
| 28 | appropriate OS and install it on the machine. Given that I have encountered | |
| 29 | numerous issues installing other Linux distributions properly with Nvidia | |
| 30 | graphics, I chose [[https://ubuntu.com/download/server][Ubuntu Server]]. | |
| 39 | 31 | |
| 40 | The first step is to create a bootable USB with Ubuntu Server. This is | |
| 41 | easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on | |
| 42 | many different platforms. Just download the Ubuntu Server =.iso= image, | |
| 43 | launch Etcher, and install the =.iso= on the USB. | |
| 32 | The first step is to create a bootable USB (universal serial bus) with Ubuntu | |
| 33 | Server. This is easy with [[https://www.balena.io/etcher/][Etcher]], an app that runs on many different platforms. | |
| 34 | Just download the Ubuntu Server =.iso= image, launch Etcher, and install the | |
| 35 | =.iso= on the USB. | |
| 44 | 36 | |
| 45 | Once 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, | |
| 47 | launch the USB boot drive. | |
| 37 | Once the USB is created, insert it into my server, reboot, and click =Esc= (or | |
| 38 | any of the =F1-12= keys) until the BIOS (Basic Input/Output System) menu | |
| 39 | appears. Finally, launch the USB boot drive. | |
| 48 | 40 | |
| 49 | 41 | ** Booting with Nvidia |
| 50 | :PROPERTIES: | |
| 51 | :CUSTOM_ID: booting-with-nvidia | |
| 52 | :END: | |
| 42 | ||
| 53 | 43 | In order to install Ubuntu Server with an Nvidia Graphics card (and no |
| 54 | integrated graphics on this device for some reason), you'll have to | |
| 55 | configure the boot menu to allow different graphics drivers to be | |
| 56 | loaded. | |
| 44 | integrated graphics on this device for some reason), you'll have to configure | |
| 45 | the boot menu to allow different graphics drivers to be loaded. | |
| 57 | 46 | |
| 58 | When booting from the USB, the machine will launch the initial | |
| 59 | installation menu. From this menu, type =e= to view the default command | |
| 60 | options that come with the device - it's a good idea to take a photo of | |
| 61 | this screen, so you can enter these commands on the next screen (along | |
| 62 | with adding support for Nvidia). | |
| 47 | When booting from the USB, the machine will launch the initial installation | |
| 48 | menu. From this menu, type =e= to view the default command options that come | |
| 49 | with the device - it's a good idea to take a photo of this screen, so you can | |
| 50 | enter these commands on the next screen (along with adding support for Nvidia). | |
| 63 | 51 | |
| 64 | Finally, type =Ctrl + C= to enter the command line. From this command | |
| 65 | line, enter the commands found on the =e= screen. /Remember to add | |
| 66 | =nomodeset= to the =linux ...= line so that your Nvidia device will | |
| 67 | display the installation screens properly!/ | |
| 52 | Finally, type =Ctrl + C= to enter the command line. From this command line, | |
| 53 | enter 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 | |
| 55 | screens properly! | |
| 68 | 56 | |
| 69 | Here's an example of the commands I pulled from the =e= screen and | |
| 70 | entered on the command line. | |
| 57 | Here's an example of the commands I pulled from the =e= screen and entered on | |
| 58 | the command line. | |
| 71 | 59 | |
| 72 | 60 | #+begin_src sh |
| 73 | 61 | setparams 'Install Ubuntu Server' |
| @@ -77,12 +65,11 @@ initrd /casper/initrd | ||
| 77 | 65 | boot |
| 78 | 66 | #+end_src |
| 79 | 67 | |
| 80 | Once the machine is rebooted, enter the =e= screen again and add | |
| 81 | =nomodeset= to the =linux ...= line again and press =Ctrl + X= to save | |
| 82 | the boot options. | |
| 68 | Once the machine is rebooted, enter the =e= screen again and add =nomodeset= to | |
| 69 | the =linux ...= line again and press =Ctrl + X= to save the boot options. | |
| 83 | 70 | |
| 84 | The machine is now fully installed and can properly display on an | |
| 85 | external display using the Nvidia GPU. | |
| 71 | The machine is now fully installed and can properly display on an external | |
| 72 | display using the Nvidia GPU. | |
| 86 | 73 | |
| 87 | 74 | Always remember to update and upgrade on a new installation: |
| 88 | 75 | |
| @@ -91,40 +78,29 @@ sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y | ||
| 91 | 78 | #+end_src |
| 92 | 79 | |
| 93 | 80 | * Phase 2: Migrate Plex Data & Devices |
| 94 | :PROPERTIES: | |
| 95 | :CUSTOM_ID: phase-2-migrate-plex-data-devices | |
| 96 | :END: | |
| 97 | This phase uses the great Plex article on migrations | |
| 98 | ([[https://support.plex.tv/articles/201370363-move-an-install-to-another-system/][Move | |
| 99 | an Installation to Another System]]) and adds a bit more information to | |
| 100 | help with commands and context. | |
| 81 | ||
| 82 | This phase uses the great Plex article on migrations ([[https://support.plex.tv/articles/201370363-move-an-install-to-another-system/][Move an Installation to | |
| 83 | Another System]]) and adds a bit more information to help with commands and | |
| 84 | context. | |
| 101 | 85 | |
| 102 | 86 | ** 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 | |
| 109 | source/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. | |
| 110 | 92 | |
| 111 | 93 | ** Step 01: [Client] Update Settings |
| 112 | :PROPERTIES: | |
| 113 | :CUSTOM_ID: step-01-client-update-settings | |
| 114 | :END: | |
| 115 | Open up a Plex app and /disable/ the =Account= > =Library= > | |
| 116 | =Empty trash automatically after every scan= preference for the source | |
| 117 | server. | |
| 94 | ||
| 95 | Open up a Plex app and /disable/ the =Account= > =Library= > =Empty trash | |
| 96 | automatically after every scan= preference for the source server. | |
| 118 | 97 | |
| 119 | 98 | ** Step 02: [Destination] Install Plex |
| 120 | :PROPERTIES: | |
| 121 | :CUSTOM_ID: step-02-destination-install-plex | |
| 122 | :END: | |
| 123 | Open up the [[https://www.plex.tv/media-server-downloads/][Plex Media | |
| 124 | Server download page]] and copy the link for the appropriate platform. | |
| 125 | 99 | |
| 126 | Execute the following commands on the destination server to install | |
| 127 | Plex: | |
| 100 | Open up the [[https://www.plex.tv/media-server-downloads/][Plex Media Server download page]] and copy the link for the | |
| 101 | appropriate platform. | |
| 102 | ||
| 103 | Execute the following commands on the destination server to install Plex: | |
| 128 | 104 | |
| 129 | 105 | #+begin_src sh |
| 130 | 106 | wget <url> |
| @@ -133,50 +109,44 @@ sudo systemctl stop plexmediaserver.service | ||
| 133 | 109 | #+end_src |
| 134 | 110 | |
| 135 | 111 | ** Step 03: [Source] Stop Plex & Migrate Data |
| 136 | :PROPERTIES: | |
| 137 | :CUSTOM_ID: step-03-source-stop-plex-migrate-data | |
| 138 | :END: | |
| 139 | First, stop the Plex service so that no data is created or modified | |
| 140 | during the migration. | |
| 112 | ||
| 113 | First, stop the Plex service so that no data is created or modified during the | |
| 114 | migration. | |
| 141 | 115 | |
| 142 | 116 | #+begin_src sh |
| 143 | 117 | sudo systemctl stop plexmediaserver.service |
| 144 | 118 | #+end_src |
| 145 | 119 | |
| 146 | Next, copy the data to the new server. To find where the Plex data | |
| 147 | directory 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 | |
| 149 | is the Plex Media Server data directory located?]]. | |
| 120 | Next, copy the data to the new server. To find where the Plex data directory is | |
| 121 | located, 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 | |
| 122 | Server data directory located?]]. | |
| 150 | 123 | |
| 151 | There are many ways to copy the data to the new server and will largely | |
| 152 | depend on the size of the folder being copied. Personally, my data | |
| 153 | folder was ~23GB and I opted to simply use the =scp= command to copy the | |
| 154 | files over SSH. | |
| 124 | There are many ways to copy the data to the new server and will largely depend | |
| 125 | on the size of the folder being copied. Personally, my data folder was ~23GB and | |
| 126 | I opted to simply use the =scp= command to copy the files over SSH (Secure Shell | |
| 127 | Protocol). | |
| 155 | 128 | |
| 156 | This process was throttled by the old server's slow HDD and ports and | |
| 157 | took approximately 90 minutes to complete. In comparison, moving the | |
| 158 | data from the new server's =home/user/= directory to the | |
| 159 | =/var/.../Plex Media Server= directory took 2-3 minutes. | |
| 129 | This process was throttled by the old server's slow hard disk and ports and took | |
| 130 | approximately 90 minutes to complete. In comparison, moving the data from the | |
| 131 | new server's =home/user/= directory to the =/var/.../Plex Media Server= | |
| 132 | directory took 2-3 minutes. | |
| 160 | 133 | |
| 161 | 134 | #+begin_src sh |
| 162 | 135 | scp -r "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" your_user@xxx.xxx.xxx.xxx:"'/path/to/destination/'" |
| 163 | 136 | #+end_src |
| 164 | 137 | |
| 165 | 138 | ** Step 04: [Destination] Update File Permissions |
| 166 | :PROPERTIES: | |
| 167 | :CUSTOM_ID: step-04-destination-update-file-permissions | |
| 168 | :END: | |
| 169 | In case you move the data directory to a common area on the new server, | |
| 170 | it will have to be moved to the proper location before Plex can function | |
| 171 | properly: | |
| 139 | ||
| 140 | In case you move the data directory to a common area on the new server, it will | |
| 141 | have to be moved to the proper location before Plex can function properly: | |
| 172 | 142 | |
| 173 | 143 | #+begin_src sh |
| 174 | 144 | mv "Plex Media Server" /var/lib/plexmediaserver/Library/Application Support/ |
| 175 | 145 | #+end_src |
| 176 | 146 | |
| 177 | To ensure permissions were retained properly, the server will need to | |
| 178 | show that all files and folders in the data directory are owned by | |
| 179 | =plex:plex= (or whichever user is running the Plex application). | |
| 147 | To ensure permissions were retained properly, the server will need to show that | |
| 148 | all files and folders in the data directory are owned by =plex:plex= (or | |
| 149 | whichever user is running the Plex application). | |
| 180 | 150 | |
| 181 | 151 | #+begin_src sh |
| 182 | 152 | sudo chown -R plex:plex "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server" |
| @@ -190,43 +160,37 @@ sudo systemctl status plexmediaserver.service | ||
| 190 | 160 | #+end_src |
| 191 | 161 | |
| 192 | 162 | ** Step 05: [Client] Update Libraries & Metadata |
| 193 | :PROPERTIES: | |
| 194 | :CUSTOM_ID: step-05-client-update-libraries-metadata | |
| 195 | :END: | |
| 196 | The first step - now that the new server is up and running - is to sign | |
| 197 | out of the client and sign back in. Once this is done, update any | |
| 198 | library locations, if necessary. This was unnecessary in my case since I | |
| 199 | simply moved my storage drives from the source server to the destination | |
| 200 | server. | |
| 163 | ||
| 164 | The first step - now that the new server is up and running - is to sign out of | |
| 165 | the client and sign back in. Once this is done, update any library locations, if | |
| 166 | necessary. This was unnecessary in my case since I simply moved my storage | |
| 167 | drives from the source server to the destination server. | |
| 201 | 168 | |
| 202 | 169 | Next, perform the following actions in the client: |
| 203 | 170 | |
| 204 | 1. On the left sidebar, click =More= > Three-Dot Menu > | |
| 205 | =Scan Library Files= | |
| 206 | 2. /Enable/ the =Account= > =Library= > | |
| 207 | =Empty trash automatically after every scan= preference for the | |
| 208 | source server. | |
| 209 | 3. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= | |
| 210 | > =Empty Trash= | |
| 211 | 4. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= | |
| 212 | > =Clean Bundles= | |
| 213 | 5. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= | |
| 214 | > =Optimize Database= | |
| 171 | 1. On the left sidebar, click =More= > Three-Dot Menu > =Scan Library Files= | |
| 172 | 2. /Enable/ the =Account= > =Library= > =Empty trash automatically after every | |
| 173 | scan= preference for the source server. | |
| 174 | 3. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Empty | |
| 175 | Trash= | |
| 176 | 4. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > =Clean | |
| 177 | Bundles= | |
| 178 | 5. On the left sidebar, click =More= > Three-Dot Menu > =Manage Server= > | |
| 179 | =Optimize Database= | |
| 215 | 180 | |
| 216 | Finally, double-check the Remote Access settings to make sure no changes | |
| 217 | have caused issues with accessing the server from outside the network. | |
| 181 | Finally, double-check the Remote Access settings to make sure no changes have | |
| 182 | caused issues with accessing the server from outside the network. | |
| 218 | 183 | |
| 219 | In my case, I use a single port forwarding rule in my router and needed | |
| 220 | to update the Local LAN IP Address to the new server IP address. | |
| 184 | In my case, I use a single port forwarding rule in my router and needed to | |
| 185 | update the Local LAN (local area network) IP (internet protocol) Address to the | |
| 186 | new server IP address. | |
| 221 | 187 | |
| 222 | 188 | * Phase 3: Configure GPU Transcoding |
| 223 | :PROPERTIES: | |
| 224 | :CUSTOM_ID: phase-3-configure-gpu-transcoding | |
| 225 | :END: | |
| 226 | The final piece to the migration is enabling hardware transcoding so | |
| 227 | that Plex can fully utilize the new Nvidia GPU available in the server. | |
| 228 | The first step is to install Nvidia graphics drivers. This process may | |
| 229 | take a few minutes, but the commands are pretty simple: | |
| 189 | ||
| 190 | The final piece to the migration is enabling hardware transcoding so that Plex | |
| 191 | can fully utilize the new Nvidia GPU available in the server. The first step is | |
| 192 | to install Nvidia graphics drivers. This process may take a few minutes, but the | |
| 193 | commands are pretty simple: | |
| 230 | 194 | |
| 231 | 195 | #+begin_src sh |
| 232 | 196 | sudo add-apt-repository ppa:graphics-drivers/ppa |
| @@ -248,5 +212,5 @@ following command to view the available GPUs, statistics, and processes: | ||
| 248 | 212 | sudo nvidia-smi |
| 249 | 213 | #+end_src |
| 250 | 214 | |
| 251 | Finally, enable hardware transcoding settings in the Plex application to | |
| 252 | finish the process. | |
| 215 | Finally, enable hardware transcoding settings in the Plex application to finish | |
| 216 | the process. | |
content/blog/2022-03-23-cloudflare-dns-api.org +20 −22
| @@ -7,15 +7,15 @@ | ||
| 7 | 7 | :PROPERTIES: |
| 8 | 8 | :CUSTOM_ID: ddns-dynamic-dns |
| 9 | 9 | :END: |
| 10 | If you're hosting a service from a location with dynamic DNS (where your | |
| 11 | IP may change at any time), you must have a solution to update the DNS | |
| 12 | so that you can access your service even when the IP of the server | |
| 13 | changes. | |
| 10 | If you're hosting a service from a location with DDNS (Dynamic Domain Name | |
| 11 | System), where your internet protocol (IP)address may change at any time, you | |
| 12 | must have a solution to update the DNS (Domain Name System) so that you can | |
| 13 | access your service even when the IP of the server changes. | |
| 14 | 14 | |
| 15 | The process below uses the [[https://api.cloudflare.com/][Cloudflare | |
| 16 | API]] to update DNS =A= and =AAAA= records with the server's current IP. | |
| 17 | If you use another DNS provider, you will have to find a way to update | |
| 18 | your DNS (or find a way to get a static IP). | |
| 15 | The process below uses the [[https://api.cloudflare.com/][Cloudflare API]] (application programming interface) to | |
| 16 | update DNS =A= and =AAAA= records with the server's current IP. If you use | |
| 17 | another DNS provider, you will have to find a way to update your DNS (or find a | |
| 18 | way to get a static IP). | |
| 19 | 19 | |
| 20 | 20 | First, install =jq= since we will use it in the next script: |
| 21 | 21 | |
| @@ -23,18 +23,16 @@ First, install =jq= since we will use it in the next script: | ||
| 23 | 23 | sudo apt install jq |
| 24 | 24 | #+end_src |
| 25 | 25 | |
| 26 | Next, create a location for your DDNS update scripts and open the first | |
| 27 | script: | |
| 26 | Next, create a location for your DDNS update scripts and open the first script: | |
| 28 | 27 | |
| 29 | 28 | #+begin_src sh |
| 30 | 29 | mkdir ~/ddns |
| 31 | 30 | nano ~/ddns/update.sh |
| 32 | 31 | #+end_src |
| 33 | 32 | |
| 34 | The following =update.sh= script will take all of your domains and | |
| 35 | subdomains and check Cloudflare to see if the current =A= and =AAAA= | |
| 36 | records match your server's IP address. If not, it will update the | |
| 37 | records. | |
| 33 | The following =update.sh= script will take all of your domains and subdomains | |
| 34 | and check Cloudflare to see if the current =A= and =AAAA= records match your | |
| 35 | server's IP address. If not, it will update the records. | |
| 38 | 36 | |
| 39 | 37 | #+begin_src sh |
| 40 | 38 | # file: update.sh |
| @@ -60,16 +58,16 @@ do | ||
| 60 | 58 | done |
| 61 | 59 | #+end_src |
| 62 | 60 | |
| 63 | Next, open up the =ddns.sh= script. Paste the following into the script | |
| 64 | and update the =api_token= and =email= variables. | |
| 61 | Next, open up the =ddns.sh= script. Paste the following into the script and | |
| 62 | update the =api_token= and =email= variables. | |
| 65 | 63 | |
| 66 | 64 | #+begin_src sh |
| 67 | 65 | nano ~/ddns/ddns.sh |
| 68 | 66 | #+end_src |
| 69 | 67 | |
| 70 | *Note*: If you want your DNS records to be proxied through Cloudflare, | |
| 71 | find and update the following snippet: ="proxied":false}"= to say =true= | |
| 72 | instead of =false=. | |
| 68 | *Note*: If you want your DNS records to be proxied through Cloudflare, find and | |
| 69 | update the following snippet: ="proxied":false}"= to say =true= instead of | |
| 70 | =false=. | |
| 73 | 71 | |
| 74 | 72 | #+begin_src sh |
| 75 | 73 | # file: ddns.sh |
| @@ -179,14 +177,14 @@ You can test the script by running it manually: | ||
| 179 | 177 | ./update.sh |
| 180 | 178 | #+end_src |
| 181 | 179 | |
| 182 | To make sure the scripts run automatically, add it to the =cron= file so | |
| 183 | that it will run on a schedule. To do this, open the cron file: | |
| 180 | To make sure the scripts run automatically, add it to the =cron= file so that it | |
| 181 | will run on a schedule. To do this, open the cron file: | |
| 184 | 182 | |
| 185 | 183 | #+begin_src sh |
| 186 | 184 | crontab -e |
| 187 | 185 | #+end_src |
| 188 | 186 | |
| 189 | In the cron file, paste the following at the bottom of the editor: | |
| 187 | In the =cron= file, paste the following at the bottom of the editor: | |
| 190 | 188 | |
| 191 | 189 | #+begin_src sh |
| 192 | 190 | ,*/5 ** ** ** ** bash /home/<your_username>/ddns/update.sh |
content/blog/2022-03-23-nextcloud-on-ubuntu.org +28 −33
| @@ -7,8 +7,8 @@ | ||
| 7 | 7 | :PROPERTIES: |
| 8 | 8 | :CUSTOM_ID: what-is-nextcloud |
| 9 | 9 | :END: |
| 10 | [[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for | |
| 11 | storage, communications, editing, calendar, contacts, and more. | |
| 10 | [[https://nextcloud.com/][Nextcloud]] is a self-hosted solution for storage, communications, editing, | |
| 11 | calendar, contacts, and more. | |
| 12 | 12 | |
| 13 | 13 | This tutorial assumes that you have an Ubuntu server and a domain name |
| 14 | 14 | configured to point toward the server. |
| @@ -29,16 +29,14 @@ sudo apt install php7.4-gmp php7.4-bcmath php-imagick php7.4-xml php7.4-zip | ||
| 29 | 29 | :PROPERTIES: |
| 30 | 30 | :CUSTOM_ID: set-up-mysql |
| 31 | 31 | :END: |
| 32 | Next, you will need to log in to MySQL as the =root= user of the | |
| 33 | machine. | |
| 32 | Next, you will need to log in to MySQL as the =root= user of the machine. | |
| 34 | 33 | |
| 35 | 34 | #+begin_src sh |
| 36 | 35 | sudo mysql -uroot -p |
| 37 | 36 | #+end_src |
| 38 | 37 | |
| 39 | Once you've logged in, you must create a new user so that Nextcloud can | |
| 40 | manage the database. You will also create a =nextcloud= database and | |
| 41 | assign privileges: | |
| 38 | Once you've logged in, you must create a new user so that Nextcloud can manage | |
| 39 | the database. You will also create a =nextcloud= database and assign privileges: | |
| 42 | 40 | |
| 43 | 41 | #+begin_src sql |
| 44 | 42 | CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; |
| @@ -52,15 +50,12 @@ quit; | ||
| 52 | 50 | :PROPERTIES: |
| 53 | 51 | :CUSTOM_ID: download-install-nextcloud |
| 54 | 52 | :END: |
| 55 | To download Nextcloud, go the | |
| 56 | [[https://nextcloud.com/install/#instructions-server][Nextcloud | |
| 57 | downloads page]], click on =Archive File= and right-click the big blue | |
| 58 | button to copy the link. | |
| 53 | To download Nextcloud, go the [[https://nextcloud.com/install/#instructions-server][Nextcloud downloads page]], click on =Archive File= | |
| 54 | and right-click the big blue button to copy the link. | |
| 59 | 55 | |
| 60 | Then, go to your server and enter the following commands to download, | |
| 61 | unzip, and move the files to your destination directory. This example | |
| 62 | uses =example.com= as the destination, but you can put it wherever you | |
| 63 | want to server your files from. | |
| 56 | Then, go to your server and enter the following commands to download, unzip, and | |
| 57 | move the files to your destination directory. This example uses =example.com= as | |
| 58 | the destination, but you can put it wherever you want to server your files from. | |
| 64 | 59 | |
| 65 | 60 | #+begin_src sh |
| 66 | 61 | wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip |
| @@ -73,9 +68,9 @@ sudo cp -r nextcloud /var/www/example.com | ||
| 73 | 68 | :PROPERTIES: |
| 74 | 69 | :CUSTOM_ID: configure-the-apache-web-server |
| 75 | 70 | :END: |
| 76 | Now that the database is set up and Nextcloud is installed, you need to | |
| 77 | set up the Apache configuration files to tell the server how to handle | |
| 78 | requests for =example.com/nextcloud=. | |
| 71 | Now that the database is set up and Nextcloud is installed, you need to set up | |
| 72 | the Apache configuration files to tell the server how to handle requests for | |
| 73 | =example.com/nextcloud=. | |
| 79 | 74 | |
| 80 | 75 | First, open the following file in the editor: |
| 81 | 76 | |
| @@ -83,8 +78,8 @@ First, open the following file in the editor: | ||
| 83 | 78 | sudo nano /etc/apache2/sites-available/nextcloud.conf |
| 84 | 79 | #+end_src |
| 85 | 80 | |
| 86 | Once the editor is open, paste the following information in. Then, save | |
| 87 | and close the file. | |
| 81 | Once the editor is open, paste the following information in. Then, save and | |
| 82 | close the file. | |
| 88 | 83 | |
| 89 | 84 | #+begin_src config |
| 90 | 85 | <VirtualHost *:80> |
| @@ -113,14 +108,14 @@ Once the file is saved, enable it with Apache: | ||
| 113 | 108 | sudo a2ensite nextcloud.conf |
| 114 | 109 | #+end_src |
| 115 | 110 | |
| 116 | Next, enable the Apache mods required by Nextcloud: | |
| 111 | Next, enable the Apache modules required by Nextcloud: | |
| 117 | 112 | |
| 118 | 113 | #+begin_src sh |
| 119 | 114 | sudo a2enmod rewrite headers env dir mime |
| 120 | 115 | #+end_src |
| 121 | 116 | |
| 122 | Finally, restart Apache. If any errors arise, you must solve those | |
| 123 | before continuing. | |
| 117 | Finally, restart Apache. If any errors arise, you must solve those before | |
| 118 | continuing. | |
| 124 | 119 | |
| 125 | 120 | #+begin_src sh |
| 126 | 121 | sudo systemctl restart apache2 |
| @@ -137,20 +132,20 @@ sudo chown -R www-data:www-data /var/www/example.com/nextcloud/ | ||
| 137 | 132 | :PROPERTIES: |
| 138 | 133 | :CUSTOM_ID: dns |
| 139 | 134 | :END: |
| 140 | If you do not have a static IP address, you will need to update your DNS | |
| 141 | settings (at your DNS provider) whenever your dynamic IP address | |
| 142 | changes. | |
| 135 | If you do not have a static internet protocol (IP) address, you will need to | |
| 136 | update your DNS (Domain Name System) settings (at your DNS provider) whenever | |
| 137 | your dynamic IP address changes. | |
| 143 | 138 | |
| 144 | For an example on how I do that with Cloudflare, see my other post: | |
| 145 | [[../updating-dynamic-dns-with-cloudflare-api/][Updating Dynamic DNS | |
| 146 | with Cloudflare API]] | |
| 139 | For an example on how I do that with Cloudflare, see my other post: [[https://cleberg.net/blog/cloudflare-dns-api.html][Dynamic DNS | |
| 140 | Record Updates via Cloudflare API]]. | |
| 147 | 141 | |
| 148 | 142 | * Certbot |
| 149 | 143 | :PROPERTIES: |
| 150 | 144 | :CUSTOM_ID: certbot |
| 151 | 145 | :END: |
| 152 | If you want to serve Nextcloud from HTTPS rather than plain HTTP, use | |
| 153 | the following commands to issue Let's Encrypt SSL certificates: | |
| 146 | If you want to serve Nextcloud from HTTPS (Hypertext Transfer Protocol Secure) | |
| 147 | rather than plain HTTP (Hypertext Transfer Protocol), use the following commands | |
| 148 | to issue Let's Encrypt SSL (Secure Socket Layer) certificates: | |
| 154 | 149 | |
| 155 | 150 | #+begin_src sh |
| 156 | 151 | sudo apt install snapd |
| @@ -165,5 +160,5 @@ sudo certbot --apache | ||
| 165 | 160 | :PROPERTIES: |
| 166 | 161 | :CUSTOM_ID: results |
| 167 | 162 | :END: |
| 168 | Voilà! You're all done and should be able to access Nextcloud from your | |
| 169 | domain or IP address. | |
| 163 | Voilà! You're all done and should be able to access Nextcloud from your domain | |
| 164 | or 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=. | ||
| 27 | 27 | Let's start with the actual server itself. Think about the following: |
| 28 | 28 | |
| 29 | 29 | - 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? | |
| 32 | 33 | - Do I have any other security software installed? |
| 33 | 34 | - Are the services hosted inside Docker containers, behind a reverse proxy, or |
| 34 | 35 | virtualized? If so, are they configured to allow outside traffic? |
| @@ -37,7 +38,7 @@ Once the data leaves the server, where does it go? In my case, it goes to a | ||
| 37 | 38 | managed switch. In this case, I asked the following: |
| 38 | 39 | |
| 39 | 40 | - What configurations is the switch using? |
| 40 | - Am I using VLANs? | |
| 41 | - Am I using VLANs (virtual local area networks)? | |
| 41 | 42 | - Yes, I am using 802.1Q VLANs. |
| 42 | 43 | - Are the VLANs configured properly? |
| 43 | 44 | - Yes, as shown in the Switch section below, I have a separate VLAN to allow |
| @@ -47,7 +48,7 @@ managed switch. In this case, I asked the following: | ||
| 47 | 48 | At this point, the data has been processed through the switch. Where does it go |
| 48 | 49 | next? In my case, it's pretty simple: it goes to the router/modem device. |
| 49 | 50 | |
| 50 | - Does my ISP block any ports that I need? | |
| 51 | - Does my internet service provider (ISP) block any ports that I need? | |
| 51 | 52 | - This is an important step that a lot of people run into when self-hosting at |
| 52 | 53 | home. Use an online port-checker tool for your IP or call your ISP if you |
| 53 | 54 | think ports are blocked. |
| @@ -59,9 +60,9 @@ next? In my case, it's pretty simple: it goes to the router/modem device. | ||
| 59 | 60 | - Are there any other settings affecting inbound/outbound traffic? |
| 60 | 61 | - Schedules or access blocks |
| 61 | 62 | - Static Routing |
| 62 | - QoS | |
| 63 | - QoS (Quality of Service) | |
| 63 | 64 | - Port Forwarding |
| 64 | - DMZ Hosting | |
| 65 | - DMZ (demilitarized zone) hosting | |
| 65 | 66 | - Remote Management (this can sometimes mess with services that also require |
| 66 | 67 | the use of ports 80 and 443) |
| 67 | 68 | |
| @@ -70,27 +71,31 @@ publicly. | ||
| 70 | 71 | |
| 71 | 72 | *** Server |
| 72 | 73 | |
| 73 | The services I run on my server are installed straight into the OS, without any | |
| 74 | use of Docker or VMs, so I don't need any extra application configuration to | |
| 75 | make them accessible to the outside world.+ | |
| 74 | The 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 | |
| 76 | extra application configuration to make them accessible to the outside world. | |
| 76 | 77 | |
| 78 | #+BEGIN_QUOTE | |
| 77 | 79 | As of 2022-10-04, the paragraph above is no longer true as I now run a reverse |
| 78 | 80 | proxy with Nginx and host many services inside Docker. However, it doesn't |
| 79 | 81 | change anything regarding this post as I still just need to open ports 80 & 443 |
| 80 | 82 | and create the necessary website configuration files. |
| 83 | #+END_QUOTE | |
| 81 | 84 | |
| 82 | 85 | When creating new services - either installed directly on bare metal or within |
| 83 | 86 | something like Docker - I ensure that I read through the documentation |
| 84 | thoroughly to understand a few key things: - What network activities should this | |
| 85 | app perform (if any)? Using which ports and protocols? - Does this app require | |
| 86 | any commands/services to be run as =root=? - Does this app log errors, | |
| 87 | authentication failures/successes, or anything else that would be useful for an | |
| 88 | investigation? | |
| 87 | thoroughly 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? | |
| 89 | 94 | |
| 90 | 95 | For extra security, I use limit all incoming connections to SSH connections |
| 91 | through my server firewall (=ufw=) and disable common SSH settings. After all of | |
| 92 | that, I use =fail2ban= as a preventative measure against brute-force login | |
| 93 | attempts. | |
| 96 | through my server firewall [=ufw= (Uncomplicated Firewall)] and disable common | |
| 97 | SSH (Secure Shell Protocol) settings. After all of that, I use =fail2ban= as a | |
| 98 | preventative measure against brute-force login attempts. | |
| 94 | 99 | |
| 95 | 100 | As another piece of security, you can randomize your SSH port to ensure that |
| 96 | 101 | random scanners or attackers can't easily try to force their way into your |
| @@ -101,8 +106,8 @@ via your randomized port. | ||
| 101 | 106 | |
| 102 | 107 | ** =ufw= |
| 103 | 108 | |
| 104 | To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your | |
| 105 | Network with the Uncomplicated Firewall]]. | |
| 109 | To see how to configure =ufw=, see my other post: [[https://cleberg.net/blog/ufw.html][Secure Your Network with the | |
| 110 | Uncomplicated Firewall]]. | |
| 106 | 111 | |
| 107 | 112 | The general notion with an on-device firewall is that you want to deny all |
| 108 | 113 | incoming connections by default and then selectively open certain ports for |
| @@ -178,7 +183,7 @@ sudo ufw enable | ||
| 178 | 183 | lock yourself out at some point and will need to use a recovery method (e.g., |
| 179 | 184 | hooking monitor up to home server) to get yourself back in. |
| 180 | 185 | |
| 181 | 3. Enable MFA for =ssh= | |
| 186 | 3. Enable Multi-Factor Authentication (MFA) for =ssh= | |
| 182 | 187 | |
| 183 | 188 | This part is optional, but I highly recommend it. So far, we've ensured that |
| 184 | 189 | no one can log into our user on the server without using our secret key, and |
| @@ -187,8 +192,7 @@ sudo ufw enable | ||
| 187 | 192 | |
| 188 | 193 | This process involves editing a couple files and installing an MFA package, |
| 189 | 194 | so I will not include all the details in this post. To see how to configure |
| 190 | MFA for =ssh=, see my other post: [[https://cleberg.net/blog/ssh-mfa.html][Enabling MFA for | |
| 191 | SSH]]. | |
| 195 | MFA for =ssh=, see my other post: [[https://cleberg.net/blog/ssh-mfa.html][Enabling MFA for SSH]]. | |
| 192 | 196 | |
| 193 | 197 | ** =fail2ban= |
| 194 | 198 | |
| @@ -224,8 +228,8 @@ the server to manage it. | ||
| 224 | 228 | |
| 225 | 229 | | VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports | |
| 226 | 230 | |---------+-----------+--------------+--------------+----------------| |
| 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 | | | |
| 229 | 233 | |
| 230 | 234 | ** 802.1Q VLAN PVID Setting |
| 231 | 235 | |
| @@ -235,30 +239,30 @@ any related ports (in this case, see that ports =8= and =23= have a PVID of | ||
| 235 | 239 | |
| 236 | 240 | | Port | PVID | |
| 237 | 241 | |------+------| |
| 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 | | |
| 262 | 266 | |
| 263 | 267 | * Router |
| 264 | 268 | |
| @@ -266,9 +270,9 @@ On my router, the configuration was as easy as opening the firewall settings and | ||
| 266 | 270 | unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL, |
| 267 | 271 | etc.). |
| 268 | 272 | |
| 269 | Since I'm relying on an ISP-provided modem/router combo for now (not by | |
| 270 | choice), I do not use any other advanced settings on my router that would | |
| 271 | inhibit any valid traffic to these services. | |
| 273 | Since I'm relying on an ISP-provided modem/router combo for now (not by choice), | |
| 274 | I do not use any other advanced settings on my router that would inhibit any | |
| 275 | valid traffic to these services. | |
| 272 | 276 | |
| 273 | 277 | The paragraph above regarding the ISP-owned router is no longer accurate as I |
| 274 | 278 | now 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 | ||
| 287 | 291 | hosts a server like this. Exactly /how/ important it is depends on the server |
| 288 | 292 | use/purpose. |
| 289 | 293 | |
| 290 | If you self-host customer applications that hold protected data (HIPAA, GDPR, | |
| 291 | COPPA, etc.), then physical security is extremely important and cannot be | |
| 292 | ignored. If you simply host a blog and some hobby sites, then it's a relatively | |
| 293 | minor consideration, but one you still need to think about. | |
| 294 | If you self-host customer applications that hold protected data, then physical | |
| 295 | security is extremely important and cannot be ignored. If you simply host a blog | |
| 296 | and some hobby sites, then it's a relatively minor consideration, but one you | |
| 297 | still need to think about. | |
| 294 | 298 | |
| 295 | 299 | ** Location |
| 296 | 300 | |
| @@ -312,8 +316,9 @@ Secondly, consider the hardware itself: | ||
| 312 | 316 | - Are any other users able to access the server, even if your data/space is |
| 313 | 317 | segregated? |
| 314 | 318 | - If you're utilizing a third party, do they have any documentation to show |
| 315 | responsibility? This could be a SOC 1/2/3 report, ISO compliance report, | |
| 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. | |
| 317 | 322 | |
| 318 | 323 | ** Physical Controls |
| 319 | 324 | |
content/blog/2022-03-26-ssh-mfa.org +34 −35
| @@ -3,31 +3,29 @@ | ||
| 3 | 3 | #+description: Step-by-step deployment guide for enabling TOTP multi-factor authentication on SSH services using Google Authenticator and Pluggable Authentication Module (PAM) integration. |
| 4 | 4 | #+slug: ssh-mfa |
| 5 | 5 | |
| 6 | * Why Do I Need MFA for SSH? | |
| 6 | * Why Do I Need Multi-Factor Authentication (MFA) for SSH (Secure Shell Protocol)? | |
| 7 | 7 | |
| 8 | If you are a sysadmin of a server anywhere (that includes at home!), you | |
| 9 | may want an added layer of protection against intruders. This is not a | |
| 10 | replacement for other security measures, such as: | |
| 8 | If you are a sysadmin of a server anywhere (that includes at home!), you may | |
| 9 | want an added layer of protection against intruders. This is not a replacement | |
| 10 | for other security measures, such as: | |
| 11 | 11 | |
| 12 | 12 | - Disable root SSH |
| 13 | 13 | - Disable SSH password authentication |
| 14 | 14 | - Allow only certain users to login via SSH |
| 15 | - Allow SSH only from certain IPs | |
| 15 | - Allow SSH only from certain internet protocol (IP) addressess | |
| 16 | 16 | |
| 17 | However, MFA can be added as an additional security measure to ensure | |
| 18 | that your server is protected. This is especially important if you need | |
| 19 | to allow password authentication for SSH. | |
| 17 | However, MFA can be added as an additional security measure to ensure that your | |
| 18 | server is protected. This is especially important if you need to allow password | |
| 19 | authentication for SSH. | |
| 20 | 20 | |
| 21 | For more guidance on server security measures, see my other post: | |
| 22 | [[../hardening-a-public-facing-home-server/][Hardening a Public-Facing | |
| 23 | Home Server]]. | |
| 21 | For more guidance on server security measures, see my other post: [[https://cleberg.net/blog/server-hardening.html][Step-by-Step | |
| 22 | Guide to Securing Your Home Server with Firewalls, SSH, and VLANs]]. | |
| 24 | 23 | |
| 25 | 24 | * Install MFA PAM Module |
| 26 | 25 | |
| 27 | PAM, which stands for Pluggable Authentication Module, is an | |
| 28 | authentication infrastructure used on Linux systems to authenticate a | |
| 29 | user. In order to use this technology, let's install the | |
| 30 | =libpam-google-authenticator= package: | |
| 26 | PAM (Pluggable Authentication Module) is an authentication infrastructure used | |
| 27 | on Linux systems to authenticate a user. In order to use this technology, let's | |
| 28 | install the =libpam-google-authenticator= package: | |
| 31 | 29 | |
| 32 | 30 | #+begin_src sh |
| 33 | 31 | sudo apt-get update |
| @@ -41,16 +39,17 @@ sudo apt-get install libpam-google-authenticator | ||
| 41 | 39 | |
| 42 | 40 | ** Interactive Method |
| 43 | 41 | |
| 44 | Once the package is installed, initialize it and following the | |
| 45 | interactive prompts to generate your OTP or TOTP: | |
| 42 | Once the package is installed, initialize it and following the interactive | |
| 43 | prompts to generate your OTP (One-Time Password) or TOTP (Time-based One-Time | |
| 44 | Password): | |
| 46 | 45 | |
| 47 | 46 | #+begin_src sh |
| 48 | 47 | google-authenticator |
| 49 | 48 | #+end_src |
| 50 | 49 | |
| 51 | If you are not sure how to answer, read the prompts carefully and think | |
| 52 | about having to how each situation would affect your normal login | |
| 53 | attempts. If you are still not sure, use my default responses below. | |
| 50 | If you are not sure how to answer, read the prompts carefully and think about | |
| 51 | having to how each situation would affect your normal login attempts. If you are | |
| 52 | still not sure, use my default responses below. | |
| 54 | 53 | |
| 55 | 54 | #+begin_src txt |
| 56 | 55 | OUTPUT |
| @@ -58,8 +57,8 @@ OUTPUT | ||
| 58 | 57 | Do you want authentication tokens to be time-based (y/n) y |
| 59 | 58 | #+end_src |
| 60 | 59 | |
| 61 | At this point, use an authenticator app somewhere one of your devices to | |
| 62 | scan the QR code. Any future login attempts after our upcoming | |
| 60 | At this point, use an authenticator app somewhere one of your devices to scan | |
| 61 | the QR (quick-response) code. Any future login attempts after our upcoming | |
| 63 | 62 | configuration changes will require that TOTP. |
| 64 | 63 | |
| 65 | 64 | #+begin_src txt |
| @@ -134,23 +133,23 @@ google-authenticator [<options>] | ||
| 134 | 133 | -e, --emergency-codes=N Number of emergency codes to generate |
| 135 | 134 | #+end_src |
| 136 | 135 | |
| 137 | This fully configures the authenticator, saves it to a file, and then | |
| 138 | outputs the secret key, QR code, and recovery codes. (If you add the | |
| 139 | flag =-q=, then there won't be any output). If you use this command in | |
| 140 | an automated fashion, make sure your script captures the secret key | |
| 141 | and/or recovery codes and makes them available to the user. | |
| 136 | This fully configures the authenticator, saves it to a file, and then outputs | |
| 137 | the secret key, QR code, and recovery codes. (If you add the flag =-q=, then | |
| 138 | there won't be any output). If you use this command in an automated fashion, | |
| 139 | make sure your script captures the secret key and/or recovery codes and makes | |
| 140 | them available to the user. | |
| 142 | 141 | |
| 143 | 142 | * PAM Configuration Settings |
| 144 | 143 | |
| 145 | Once you've enabled the T/OTP and have it saved to an MFA app on your | |
| 146 | phone or other device, open the PAM =sshd= file: | |
| 144 | Once you've enabled MFA and have it saved to an MFA app on your phone or other | |
| 145 | device, open the PAM =sshd= file: | |
| 147 | 146 | |
| 148 | 147 | #+begin_src sh |
| 149 | 148 | sudo nano /etc/pam.d/sshd |
| 150 | 149 | #+end_src |
| 151 | 150 | |
| 152 | You need to do two things in this file. First, add the following lines | |
| 153 | to the bottom of the file: | |
| 151 | You need to do two things in this file. First, add the following lines to the | |
| 152 | bottom of the file: | |
| 154 | 153 | |
| 155 | 154 | #+begin_src config |
| 156 | 155 | auth required pam_google_authenticator.so nullok |
| @@ -159,8 +158,8 @@ auth required pam_permit.so | ||
| 159 | 158 | |
| 160 | 159 | Second, comment-out the following line near the top of the file. |
| 161 | 160 | |
| 162 | If you leave this line uncommented, every SSH login attempt will ask for | |
| 163 | the following three authentication factors: | |
| 161 | If you leave this line uncommented, every SSH login attempt will ask for the | |
| 162 | following three authentication factors: | |
| 164 | 163 | |
| 165 | 164 | 1. Publickey |
| 166 | 165 | 2. Password |
| @@ -178,8 +177,8 @@ Finally, edit the =sshd_config= file again: | ||
| 178 | 177 | sudo nano /etc/ssh/sshd_config |
| 179 | 178 | #+end_src |
| 180 | 179 | |
| 181 | You'll need to change =ChallengeResponseAuthentication= to yes and add | |
| 182 | the =AuthenticationMethods= line to the bottom of the file. | |
| 180 | You'll need to change =ChallengeResponseAuthentication= to yes and add the | |
| 181 | =AuthenticationMethods= line to the bottom of the file. | |
| 183 | 182 | |
| 184 | 183 | #+begin_src config |
| 185 | 184 | ChallengeResponseAuthentication yes |
content/blog/2022-04-02-nginx-reverse-proxy.org +64 −71
| @@ -5,10 +5,10 @@ | ||
| 5 | 5 | |
| 6 | 6 | * What is a Reverse Proxy? |
| 7 | 7 | |
| 8 | A reverse proxy is a server that is placed between local servers or | |
| 9 | services and clients/users (e.g., the internet). The reverse proxy | |
| 10 | intercepts all requests from clients at the network edge and uses its | |
| 11 | configuration files to determine where each request should be sent. | |
| 8 | A reverse proxy is a server that is placed between local servers or services and | |
| 9 | clients/users (e.g., the internet). The reverse proxy intercepts all requests | |
| 10 | from clients at the network edge and uses its configuration files to determine | |
| 11 | where each request should be sent. | |
| 12 | 12 | |
| 13 | 13 | ** A Brief Example |
| 14 | 14 | |
| @@ -18,23 +18,21 @@ For example, let's say that I run three servers in my home: | ||
| 18 | 18 | - Server02 (=service01.example.com=) |
| 19 | 19 | - Server03 (=service02.example.com=) |
| 20 | 20 | |
| 21 | I also run a reverse proxy in my home that intercepts all public | |
| 22 | traffic: | |
| 21 | I also run a reverse proxy in my home that intercepts all public traffic: | |
| 23 | 22 | |
| 24 | 23 | - Reverse Proxy |
| 25 | 24 | |
| 26 | Assume that I have a domain name (=example.com=) that allows clients to | |
| 27 | request websites or services from my home servers. | |
| 25 | Assume that I have a domain name (=example.com=) that allows clients to request | |
| 26 | websites or services from my home servers. | |
| 28 | 27 | |
| 29 | In this case, the reverse proxy will intercept all traffic from | |
| 30 | =example.com= that enters my network and determine if the client is | |
| 31 | requesting valid data, based on my configuration. | |
| 28 | In this case, the reverse proxy will intercept all traffic from =example.com= | |
| 29 | that enters my network and determine if the client is requesting valid data, | |
| 30 | based on my configuration. | |
| 32 | 31 | |
| 33 | If the user is requesting =example.com= and my configuration files say | |
| 34 | that Server_{01} holds that data, Nginx will send the user to | |
| 35 | Server_{01}. If I were to change the configuration so that =example.com= | |
| 36 | is routed to Server_{02}, that same user would be sent to Server_{02} | |
| 37 | instead. | |
| 32 | If the user is requesting =example.com= and my configuration files say that | |
| 33 | Server_{01} holds that data, Nginx will send the user to Server_{01}. If I were | |
| 34 | to change the configuration so that =example.com= is routed to Server_{02}, that | |
| 35 | same user would be sent to Server_{02} instead. | |
| 38 | 36 | |
| 39 | 37 | #+begin_src txt |
| 40 | 38 | ┌──────┐ ┌───────────┐ |
| @@ -50,9 +48,9 @@ instead. | ||
| 50 | 48 | |
| 51 | 49 | * Reverse Proxy Options |
| 52 | 50 | |
| 53 | There are a lot of options when it comes to reverse proxy servers, so | |
| 54 | I'm just going to list a few of the options I've heard recommended over | |
| 55 | the last few years: | |
| 51 | There are a lot of options when it comes to reverse proxy servers, so I'm just | |
| 52 | going to list a few of the options I've heard recommended over the last few | |
| 53 | years: | |
| 56 | 54 | |
| 57 | 55 | - [[https://nginx.com][Nginx]] |
| 58 | 56 | - [[https://caddyserver.com][Caddy]] |
| @@ -60,42 +58,41 @@ the last few years: | ||
| 60 | 58 | - [[https://www.haproxy.org/][HAProxy]] |
| 61 | 59 | - [[https://ubuntu.com/server/docs/proxy-servers-squid][Squid]] |
| 62 | 60 | |
| 63 | In this post, we will be using Nginx as our reverse proxy, running on | |
| 64 | Ubuntu Server 20.04.4 LTS. | |
| 61 | In this post, we will be using Nginx as our reverse proxy, running on Ubuntu | |
| 62 | Server 20.04.4 LTS. | |
| 65 | 63 | |
| 66 | 64 | * Nginx Reverse Proxy Example |
| 67 | 65 | |
| 68 | 66 | ** Local Applications |
| 69 | 67 | |
| 70 | You may be like me and have a lot of applications running on your local | |
| 71 | network that you'd like to expose publicly with a domain. | |
| 68 | You may be like me and have a lot of applications running on your local network | |
| 69 | that you'd like to expose publicly with a domain. | |
| 72 | 70 | |
| 73 | In my case, I have services running in multiple Docker containers within | |
| 74 | a single server and want a way to visit those services from anywhere | |
| 75 | with a URL. For example, on my local network, | |
| 76 | [[https://dashy.to][Dashy]] runs through port 4000 (=localhost:4000=) | |
| 77 | and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs | |
| 78 | through port 3001 (=localhost:3001=). | |
| 71 | In my case, I have services running in multiple Docker containers within a | |
| 72 | single server and want a way to visit those services from anywhere with a URL. | |
| 73 | For 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=). | |
| 79 | 75 | |
| 80 | 76 | In order to expose these services to the public, I will need to do the |
| 81 | 77 | following: |
| 82 | 78 | |
| 83 | 1. Set up DNS records for a domain or subdomain (one per service) to | |
| 84 | point toward the IP address of the server. | |
| 85 | 2. 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. | |
| 79 | 1. 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. | |
| 81 | 2. 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. | |
| 87 | 84 | 3. Install the reverse proxy software. |
| 88 | 4. Configure the reverse proxy to recognize which service should get | |
| 89 | traffic from any of the domains or subdomains. | |
| 85 | 4. Configure the reverse proxy to recognize which service should get traffic | |
| 86 | from any of the domains or subdomains. | |
| 90 | 87 | |
| 91 | 88 | ** Step 1: DNS Configuration |
| 92 | 89 | |
| 93 | To start, update your DNS configuration so that you have an =A= record | |
| 94 | for each domain or subdomain. | |
| 90 | To start, update your DNS configuration so that you have an =A= record for each | |
| 91 | domain or subdomain. | |
| 95 | 92 | |
| 96 | The =A= records should point toward the public IP address of the server. | |
| 97 | If you don't know the public IP address, log in to the server and run | |
| 98 | the following command: | |
| 93 | The =A= records should point toward the public IP address of the server. If you | |
| 94 | don't know the public IP address, log in to the server and run the following | |
| 95 | command: | |
| 99 | 96 | |
| 100 | 97 | #+begin_src sh |
| 101 | 98 | curl ifconfig.co |
| @@ -111,34 +108,30 @@ dashy.example.com A xxx.xxx.xxx.xxx | ||
| 111 | 108 | www CNAME example.com |
| 112 | 109 | #+end_src |
| 113 | 110 | |
| 114 | Finally, ensure the DNS has propagated correctly with | |
| 115 | [[https://dnschecker.org][DNS Checker]] by entering your domains or | |
| 116 | subdomains in the search box and ensuring the results are showing the | |
| 117 | correct IP address. | |
| 111 | Finally, ensure the DNS has propagated correctly with [[https://dnschecker.org][DNS Checker]] by entering | |
| 112 | your domains or subdomains in the search box and ensuring the results are | |
| 113 | showing the correct IP address. | |
| 118 | 114 | |
| 119 | 115 | ** Step 2: Open Network Ports |
| 120 | 116 | |
| 121 | This step will be different depending on which router you have in your | |
| 122 | home. If you're not sure, try to visit | |
| 123 | [[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials | |
| 124 | are usually written on a sticker somewhere on your modem/router. | |
| 117 | This step will be different depending on which router you have in your home. If | |
| 118 | you're not sure, try to visit [[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials are | |
| 119 | usually written on a sticker somewhere on your modem/router. | |
| 125 | 120 | |
| 126 | Once you're able to log in to your router, find the Port Forwarding | |
| 127 | settings. You will need to forward ports =80= and =443= to whichever | |
| 128 | machine is running the reverse proxy. | |
| 121 | Once you're able to log in to your router, find the Port Forwarding settings. | |
| 122 | You will need to forward ports =80= and =443= to whichever machine is running | |
| 123 | the reverse proxy. | |
| 129 | 124 | |
| 130 | In my case, the table below shows the port-forwarding rules I've | |
| 131 | created. In this table, =xxx.xxx.xxx.xxx= is the local device IP of the | |
| 132 | reverse proxy server, it will probably be an IP between =192.168.1.1= | |
| 133 | and =192.168.1.255=. | |
| 125 | In my case, the table below shows the port-forwarding rules I've created. In | |
| 126 | this table, =xxx.xxx.xxx.xxx= is the local device IP of the reverse proxy | |
| 127 | server, it will probably be an IP between =192.168.1.1= and =192.168.1.255=. | |
| 134 | 128 | |
| 135 | 129 | | NAME | FROM PORT | DEST PORT/IP | ENABLED | |
| 136 | 130 | |-------+-----------+-----------------+---------| |
| 137 | 131 | | HTTP | 80 | xxx.xxx.xxx.xxx | TRUE | |
| 138 | 132 | | HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE | |
| 139 | 133 | |
| 140 | Once configured, these rules will direct all web traffic to your reverse | |
| 141 | proxy. | |
| 134 | Once configured, these rules will direct all web traffic to your reverse proxy. | |
| 142 | 135 | |
| 143 | 136 | ** Step 3: Nginx Installation |
| 144 | 137 | |
| @@ -148,11 +141,11 @@ To install Nginx, simply run the following command: | ||
| 148 | 141 | sudo apt install nginx |
| 149 | 142 | #+end_src |
| 150 | 143 | |
| 151 | If you have a firewall enabled, open up ports =80= and =443= on your | |
| 152 | server so that Nginx can accept web traffic from the router. | |
| 144 | If you have a firewall enabled, open up ports =80= and =443= on your server so | |
| 145 | that Nginx can accept web traffic from the router. | |
| 153 | 146 | |
| 154 | For example, if you want to use =ufw= for web traffic and SSH, run the | |
| 155 | following commands: | |
| 147 | For example, if you want to use =ufw= for web traffic and SSH, run the following | |
| 148 | commands: | |
| 156 | 149 | |
| 157 | 150 | #+begin_src sh |
| 158 | 151 | sudo ufw allow 'Nginx Full' |
| @@ -162,9 +155,8 @@ sudo ufw enable | ||
| 162 | 155 | |
| 163 | 156 | ** Step 4: Nginx Configuration |
| 164 | 157 | |
| 165 | Now that we have domains pointing toward the server, the only step left | |
| 166 | is to configure the reverse proxy to direct traffic from domains to | |
| 167 | local services. | |
| 158 | Now that we have domains pointing toward the server, the only step left is to | |
| 159 | configure the reverse proxy to direct traffic from domains to local services. | |
| 168 | 160 | |
| 169 | 161 | To start, you'll need to create a configuration file for each domain in |
| 170 | 162 | =/etc/nginx/sites-available/=. They will look identical except for the |
| @@ -204,22 +196,23 @@ server { | ||
| 204 | 196 | } |
| 205 | 197 | #+end_src |
| 206 | 198 | |
| 207 | Once the configuration files are created, you will need to enable them | |
| 208 | with the =symlink= command: | |
| 199 | Once the configuration files are created, you will need to enable them with the | |
| 200 | =symlink= command: | |
| 209 | 201 | |
| 210 | 202 | #+begin_src sh |
| 211 | 203 | sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/ |
| 212 | 204 | #+end_src |
| 213 | 205 | |
| 214 | Voilà! Your local services should now be available through their URLs. | |
| 206 | Voilà! Your local services should now be available through their URLs (uniform | |
| 207 | resource locators). | |
| 215 | 208 | |
| 216 | 209 | * HTTPS with Certbot |
| 217 | 210 | |
| 218 | If you've followed along, you'll notice that your services are only | |
| 219 | available via HTTP (not HTTPS). | |
| 211 | If you've followed along, you'll notice that your services are only available | |
| 212 | via HTTP (not HTTPS). | |
| 220 | 213 | |
| 221 | If you want to enable HTTPS for your new domains, you will need to | |
| 222 | generate SSL/TLS certificates for them. The easiest way to generate | |
| 214 | If 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 | |
| 223 | 216 | certificates on Nginx is [[https://certbot.eff.org][Certbot]]: |
| 224 | 217 | |
| 225 | 218 | #+begin_src sh |
content/blog/2022-04-09-pinetime.org +57 −65
| @@ -7,17 +7,15 @@ | ||
| 7 | 7 | |
| 8 | 8 | ** Overview |
| 9 | 9 | |
| 10 | The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source | |
| 11 | smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally | |
| 12 | announced in September 2019, this ARM-based watch is a fantastic option | |
| 13 | for users who want the benefits of a modern smartwatch with the backing | |
| 14 | of open-source components and software. | |
| 10 | The [[https://www.pine64.org/pinetime/][PineTime]] is an open-source smartwatch, created by [[https://www.pine64.org][PINE64]]. Originally | |
| 11 | announced in September 2019, this ARM-based watch is a fantastic option for | |
| 12 | users who want the benefits of a modern smartwatch with the backing of | |
| 13 | open-source components and software. | |
| 15 | 14 | |
| 16 | 15 | ** Product Specifications |
| 17 | 16 | |
| 18 | I 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 | |
| 20 | point out the prices for each watch and the primary functions: | |
| 17 | I won't dive into too many details that you can find on [[https://www.pine64.org/pinetime/][the product page]], but I | |
| 18 | wanted to point out the prices for each watch and the primary functions: | |
| 21 | 19 | |
| 22 | 20 | 1. Price: |
| 23 | 21 | |
| @@ -38,52 +36,48 @@ point out the prices for each watch and the primary functions: | ||
| 38 | 36 | |
| 39 | 37 | * Unboxing |
| 40 | 38 | |
| 41 | Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and | |
| 42 | was delivered on 2022-03-23. With the current delays on shipping times | |
| 43 | around the world (and the semiconductor shortage), a month for delivery | |
| 44 | from China seems reasonable to me. | |
| 39 | Now, my PineTime was ordered on 2022-02-17, shipped on 2022-02-22, and was | |
| 40 | delivered on 2022-03-23. With the current delays on shipping times around the | |
| 41 | world (and the semiconductor shortage), a month for delivery from China seems | |
| 42 | reasonable to me. | |
| 45 | 43 | |
| 46 | The packaging is simple, and the watch comes with instructions, | |
| 47 | technical information, the watch, and a charger (it does not include a | |
| 48 | USB wall adapter). | |
| 44 | The packaging is simple, and the watch comes with instructions, technical | |
| 45 | information, the watch, and a charger (it does not include a USB wall adapter). | |
| 49 | 46 | |
| 50 | The watch itself was able to turn on immediately when I pulled it out of | |
| 51 | the box, but the battery was depleted and required charging right away. | |
| 47 | The watch itself was able to turn on immediately when I pulled it out of the | |
| 48 | box, but the battery was depleted and required charging right away. | |
| 52 | 49 | |
| 53 | 50 | * Software |
| 54 | 51 | |
| 55 | ** Watch OS: InfiniTime | |
| 52 | ** Watch Operating System (OS): InfiniTime | |
| 56 | 53 | |
| 57 | While turning on the watch for the first time, some of the main design | |
| 58 | choices you can see in the watch OS, | |
| 59 | [[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are: | |
| 54 | While turning on the watch for the first time, some of the main design choices | |
| 55 | you can see in the watch OS, [[https://wiki.pine64.org/wiki/InfiniTime][InfiniTime]], are: | |
| 60 | 56 | |
| 61 | 57 | - A square bezel, not too thin against the sides of the watch. |
| 62 | 58 | - A simple, rubber band. |
| 63 | 59 | - Basic font and screen pixel design. |
| 64 | 60 | - Swipe gestures to access other screens. |
| 65 | 61 | |
| 66 | The OS itself is fantastic in terms of functionality for me. It does | |
| 67 | exactly what a smartwatch should do - track time, steps, heart rates, | |
| 68 | and connect to another smart device, without being overly burdensome to | |
| 69 | the user. | |
| 62 | The OS itself is fantastic in terms of functionality for me. It does exactly | |
| 63 | what a smartwatch should do - track time, steps, heart rates, and connect to | |
| 64 | another smart device, without being overly burdensome to the user. | |
| 70 | 65 | |
| 71 | My only gripe so far is that it's /really/ difficult to swipe to | |
| 72 | different screens, such as pulling down the notification tray. I'm not | |
| 73 | sure if this is an OS or hardware issue, but it makes it quite hard to | |
| 74 | quickly move around the screens. | |
| 66 | My only gripe so far is that it's /really/ difficult to swipe to different | |
| 67 | screens, such as pulling down the notification tray. I'm not sure if this is an | |
| 68 | OS or hardware issue, but it makes it quite hard to quickly move around the | |
| 69 | screens. | |
| 75 | 70 | |
| 76 | However, my absolute favorite design choice is that the button the side | |
| 77 | turns the screen on and off and tilting/waving my wrist doesn't | |
| 78 | accidentally turn on the screen. With other watches, I absolutely hated | |
| 79 | not being able to turn off the raise-to-wake or wave features (i.e., | |
| 80 | blinding myself while wearing a watch at night because I moved my arm). | |
| 71 | However, my absolute favorite design choice is that the button the side turns | |
| 72 | the screen on and off and tilting/waving my wrist doesn't accidentally turn on | |
| 73 | the screen. With other watches, I absolutely hated not being able to turn off | |
| 74 | the raise-to-wake or wave features (i.e., blinding myself while wearing a watch | |
| 75 | at night because I moved my arm). | |
| 81 | 76 | |
| 82 | 77 | ** iOS App: InfiniLink |
| 83 | 78 | |
| 84 | Since 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 | |
| 86 | watch. | |
| 79 | Since I am using iOS as my primary mobile device OS, I am using the [[https://github.com/xan-m/InfiniLink][InfiniLink]] | |
| 80 | app to connect my watch. | |
| 87 | 81 | |
| 88 | 82 | This app provides the following for PineTime owners: |
| 89 | 83 | |
| @@ -92,47 +86,45 @@ This app provides the following for PineTime owners: | ||
| 92 | 86 | - Charts |
| 93 | 87 | - Notifications |
| 94 | 88 | |
| 95 | Another big feature of InfiniLink is the ability to track pedometer | |
| 96 | steps in a collection of beautiful graphs, with the option to change | |
| 97 | your step goal and add in manual steps. | |
| 89 | Another big feature of InfiniLink is the ability to track pedometer steps in a | |
| 90 | collection of beautiful graphs, with the option to change your step goal and add | |
| 91 | in manual steps. | |
| 98 | 92 | |
| 99 | Finally, there are charts to display the battery percentage and heart | |
| 100 | rates over time. This area also comes with an option to clear data. | |
| 93 | Finally, there are charts to display the battery percentage and heart rates over | |
| 94 | time. This area also comes with an option to clear data. | |
| 101 | 95 | |
| 102 | 96 | * Final Thoughts |
| 103 | 97 | |
| 104 | 98 | ** Pros |
| 105 | 99 | |
| 106 | After wearing my watch for a few weeks, I have mostly positive thoughts | |
| 107 | about the watch so far. In the past, I have owned smartwatches by | |
| 108 | FitBit, Fossil, Apple, etc. - *but I prefer the PineTime over all of | |
| 109 | those watches*. | |
| 100 | After wearing my watch for a few weeks, I have mostly positive thoughts about | |
| 101 | the watch so far. In the past, I have owned smartwatches by FitBit, Fossil, | |
| 102 | Apple, etc. - *but I prefer the PineTime over all of those watches*. | |
| 110 | 103 | |
| 111 | The PineTime strips out all the unnecessary features and performs the | |
| 112 | functions that it provides effectively and efficiently. | |
| 104 | The PineTime strips out all the unnecessary features and performs the functions | |
| 105 | that it provides effectively and efficiently. | |
| 113 | 106 | |
| 114 | The battery life is amazing on this device. By default, the watch seems | |
| 115 | to last anywhere from a few days to a week before dying. | |
| 107 | The battery life is amazing on this device. By default, the watch seems to last | |
| 108 | anywhere from a few days to a week before dying. | |
| 116 | 109 | |
| 117 | 110 | And of course, it's open source and backed by some of the most dedicated |
| 118 | enthusiasts and developers I've seen. Watching the Matrix channel, | |
| 119 | forums, and website have been exciting to see. | |
| 111 | enthusiasts and developers I've seen. Watching the Matrix channel, forums, and | |
| 112 | website have been exciting to see. | |
| 120 | 113 | |
| 121 | 114 | ** Cons |
| 122 | 115 | |
| 123 | If I had to complain about anything, it would simply be the small bugs | |
| 124 | in some features that can be contributed to the companion apps more than | |
| 125 | the watch itself. | |
| 116 | If I had to complain about anything, it would simply be the small bugs in some | |
| 117 | features that can be contributed to the companion apps more than the watch | |
| 118 | itself. | |
| 126 | 119 | |
| 127 | A regular user would want native notification support out-of-the-box, | |
| 128 | which is the biggest item not working for me at the moment. | |
| 120 | A regular user would want native notification support out-of-the-box, which is | |
| 121 | the biggest item not working for me at the moment. | |
| 129 | 122 | |
| 130 | My only other complaint is that the battery indicator on the watch | |
| 131 | doesn't seem accurate when it's nearing depletion - it seems that | |
| 132 | there's a bit of battery life left and then my watch is dead very | |
| 133 | suddenly after. This could just be me misinterpreting the battery level | |
| 134 | icons, but it has fooled me a few times into thinking I had more battery | |
| 135 | left than I actually did. | |
| 123 | My only other complaint is that the battery indicator on the watch doesn't seem | |
| 124 | accurate when it's nearing depletion - it seems that there's a bit of battery | |
| 125 | life left and then my watch is dead very suddenly after. This could just be me | |
| 126 | misinterpreting the battery level icons, but it has fooled me a few times into | |
| 127 | thinking I had more battery left than I actually did. | |
| 136 | 128 | |
| 137 | Other than those small items, I really do love this watch and am glad I | |
| 138 | replaced my Apple Watch with the PineTime. | |
| 129 | Other than those small items, I really do love this watch and am glad I replaced | |
| 130 | my Apple Watch with the PineTime. | |
content/blog/2022-06-01-ditching-cloudflare.org +49 −56
| @@ -5,91 +5,84 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Registrar |
| 7 | 7 | |
| 8 | After spending a year or so using Cloudflare for DNS only - no proxying | |
| 9 | or applications - I spent the last few months using Cloudflare Tunnels | |
| 10 | and Cloudflare Access to protect my self-hosted websites and | |
| 8 | After spending a year or so using Cloudflare for DNS (Domain Name System) only - | |
| 9 | no proxying or applications - I spent the last few months using Cloudflare | |
| 10 | Tunnels and Cloudflare Access to protect my self-hosted websites and | |
| 11 | 11 | applications via their proxy traffic model. |
| 12 | 12 | |
| 13 | However, I have never liked using Cloudflare due to their increasingly | |
| 14 | large share of control over web traffic, as well as their business model | |
| 15 | of being a MITM for all of your traffic. | |
| 13 | However, I have never liked using Cloudflare due to their increasingly large | |
| 14 | share of control over web traffic, as well as their business model of being a | |
| 15 | MITM (man-in-the-middle) for all of your traffic. | |
| 16 | 16 | |
| 17 | So, as of today, I have switched over to [[https://njal.la][Njalla]] as | |
| 18 | my registrar and DNS manager. I was able to easily transfer my domains | |
| 19 | over rapidly, with only one domain taking more than 15-30 minutes to | |
| 20 | propagate. | |
| 17 | So, as of today, I have switched over to [[https://njal.la][Njalla]] as my registrar and DNS manager. | |
| 18 | I was able to easily transfer my domains over rapidly, with only one domain | |
| 19 | taking more than 15-30 minutes to propagate. | |
| 21 | 20 | |
| 22 | +I do still have two domains sitting at Cloudflare for the moment while | |
| 23 | I decide if they're worth the higher rates (one domain is 30€ and the | |
| 24 | other is 45€).+ | |
| 21 | +I do still have two domains sitting at Cloudflare for the moment while I decide | |
| 22 | if they're worth the higher rates (one domain is 30€ and the other is 45€).+ | |
| 25 | 23 | |
| 26 | 24 | #+begin_quote |
| 27 | *Update (2022.06.03)*: I ended up transferring my final two domains over | |
| 28 | to Njalla, clearing my Cloudflare account of personal data, and deleting | |
| 29 | the Cloudflare account entirely. /I actually feel relieved to have moved | |
| 30 | on to a provider I trust./ | |
| 25 | *Update (2022.06.03)*: I ended up transferring my final two domains over to | |
| 26 | Njalla, clearing my Cloudflare account of personal data, and deleting the | |
| 27 | Cloudflare account entirely. /I actually feel relieved to have moved on to a | |
| 28 | provider I trust./ | |
| 31 | 29 | #+end_quote |
| 32 | 30 | |
| 33 | 31 | * DNS |
| 34 | 32 | |
| 35 | As noted above, I'm using Njalla exclusively for DNS configurations on | |
| 36 | my domains. | |
| 33 | As noted above, I'm using Njalla exclusively for DNS configurations on my | |
| 34 | domains. | |
| 37 | 35 | |
| 38 | However, the transfer process was not ideal. As soon as the domains | |
| 39 | transferred over, I switched the nameservers from Cloudflare to Njalla | |
| 40 | and lost most of the associated DNS records. So, the majority of the | |
| 41 | time spent during the migration was simply re-typing all the DNS records | |
| 42 | back in one-by-one. | |
| 36 | However, the transfer process was not ideal. As soon as the domains transferred | |
| 37 | over, I switched the nameservers from Cloudflare to Njalla and lost most of the | |
| 38 | associated DNS records. So, the majority of the time spent during the migration | |
| 39 | was simply re-typing all the DNS records back in one-by-one. | |
| 43 | 40 | |
| 44 | This would be much simpler if I were able to edit the plain-text format | |
| 45 | of 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 | |
| 47 | lot easier. | |
| 41 | This would be much simpler if I were able to edit the plain-text format of the | |
| 42 | DNS 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. | |
| 48 | 44 | |
| 49 | 45 | ** Dynamic DNS Updates |
| 50 | 46 | |
| 51 | 47 | I have built an easy Python script to run (or set-up in =cron= to run |
| 52 | automatically) that will check my server's IPv4 and IPv6, compare it to | |
| 53 | Njalla, and update the DNS records if they don't match. You can see the | |
| 54 | full script and process in my other post: [[../njalla-dns-api/][Updating | |
| 55 | Dynamic DNS with Njalla API]]. | |
| 48 | automatically) that will check my server's IPv4 (Internet Protocol version 4)and | |
| 49 | IPv6 (Internet Protocol version 6), compare it to Njalla, and update the DNS | |
| 50 | records if they don't match. You can see the full script and process in my other | |
| 51 | post: [[https://cleberg.net/blog/njalla-dns-api.html][Automating Dynamic DNS Record Updates via Njalla API]]. | |
| 56 | 52 | |
| 57 | I 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]]. | |
| 53 | I haven't used this other method, but I do know that you can create =Dynamic= | |
| 54 | DNS records with Njalla that [[https://njal.la/docs/ddns/][work for updating dynamic subdomains]]. | |
| 60 | 55 | |
| 61 | 56 | ** Njalla's DNS Tool |
| 62 | 57 | |
| 63 | One neat upside to Njalla is that they have a | |
| 64 | [[https://check.njal.la/dns/][DNS lookup tool]] that provides a lot of | |
| 65 | great information for those of you (AKA: me) who hate using the =dig= | |
| 58 | One neat upside to Njalla is that they have a [[https://check.njal.la/dns/][DNS lookup tool]] that provides a | |
| 59 | lot of great information for those of you (AKA: me) who hate using the =dig= | |
| 66 | 60 | command. |
| 67 | 61 | |
| 68 | This was very useful for monitoring a couple of my transferred domains | |
| 69 | to see when the changes in nameservers, records, and DNSSEC went into | |
| 70 | effect. | |
| 62 | This was very useful for monitoring a couple of my transferred domains to see | |
| 63 | when the changes in nameservers, records, and DNSSEC (Domain Name System | |
| 64 | Security Extensions) went into effect. | |
| 71 | 65 | |
| 72 | 66 | * Tunnel |
| 73 | 67 | |
| 74 | 68 | Cloudflare Tunnel is a service that acts as a reverse-proxy (hosted on |
| 75 | Cloudflare's servers) and allowed me to mask the private IP address of | |
| 76 | the server hosting my various websites and apps. | |
| 77 | ||
| 78 | However, as I was moving away from Cloudflare, I was not able to find a | |
| 79 | suitable replacement that was both inexpensive and simple. So, I simply | |
| 80 | went back to hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own | |
| 81 | reverse proxy with Nginx]]. With the recent additions of Unifi hardware | |
| 82 | in my server/network rack, I am much more protected against spam and | |
| 69 | Cloudflare's servers) and allowed me to mask the private internet protocol (IP) | |
| 70 | address of the server hosting my various websites and apps. | |
| 71 | ||
| 72 | However, as I was moving away from Cloudflare, I was not able to find a suitable | |
| 73 | replacement that was both inexpensive and simple. So, I simply went back to | |
| 74 | hosting [[https://cleberg.net/blog/set-up-nginx-reverse-proxy/][my own reverse proxy with Nginx]]. With the recent additions of Unifi | |
| 75 | hardware in my server/network rack, I am much more protected against spam and | |
| 83 | 76 | malicious attacks at the network edge than I was before I switched to |
| 84 | 77 | Cloudflare. |
| 85 | 78 | |
| 86 | 79 | * Access |
| 87 | 80 | |
| 88 | Cloudflare Access, another app I used in combination with Cloudflare | |
| 89 | Tunnel, provided an authentication screen that required you to enter | |
| 90 | valid credentials before Cloudflare would forward you to the actual | |
| 91 | website or app (if the website/app has their own authentication, you'd | |
| 92 | then have to authenticate a second time). | |
| 81 | Cloudflare Access, another app I used in combination with Cloudflare Tunnel, | |
| 82 | provided an authentication screen that required you to enter valid credentials | |
| 83 | before Cloudflare would forward you to the actual website or app (if the | |
| 84 | website/app has their own authentication, you'd then have to authenticate a | |
| 85 | second time). | |
| 93 | 86 | |
| 94 | I did not replace this service with anything since I only host a handful | |
| 95 | of non-sensitive apps that don't require duplicate authentication. | |
| 87 | I did not replace this service with anything since I only host a handful of | |
| 88 | non-sensitive apps that don't require duplicate authentication. | |
content/blog/2022-06-07-self-hosting-freshrss.org +71 −81
| @@ -3,47 +3,43 @@ | ||
| 3 | 3 | #+description: Stepwise instructions for installing FreshRSS using Docker and configuring Nginx as a reverse proxy to enable secure and synchronized RSS feed access. |
| 4 | 4 | #+slug: self-hosting-freshrss |
| 5 | 5 | |
| 6 | * Why RSS? | |
| 6 | * Why Use Really Simple Syndication (RSS)? | |
| 7 | 7 | |
| 8 | After noticing that I have collected 50+ blogs as bookmarks, I decided | |
| 9 | to migrate back to using RSS feeds to stay up-to-date with my favorite | |
| 10 | websites. 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 | |
| 12 | are available. | |
| 8 | After noticing that I have collected 50+ blogs as bookmarks, I decided to | |
| 9 | migrate back to using RSS feeds to stay up-to-date with my favorite websites. | |
| 10 | Using RSS allows me to read all of these posts in a single app (on both mobile & | |
| 11 | desktop) and allows me to be notified when new posts are available. | |
| 13 | 12 | |
| 14 | However, I ran into one issue: syncing subscriptions and read/unread | |
| 15 | posts across devices. Since I want to be able to easily read on both | |
| 16 | mobile and desktop, I decided to look for a self-hosted RSS solution. | |
| 13 | However, I ran into one issue: syncing subscriptions and read/unread posts | |
| 14 | across devices. Since I want to be able to easily read on both mobile and | |
| 15 | desktop, I decided to look for a self-hosted RSS solution. | |
| 17 | 16 | |
| 18 | Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to | |
| 19 | successfully install it on my server in about 30 minutes. | |
| 17 | Thus, I found [[https://www.freshrss.org/][FreshRSS]] and was able to successfully install it on my server in | |
| 18 | about 30 minutes. | |
| 20 | 19 | |
| 21 | 20 | * Documentation |
| 22 | 21 | |
| 23 | While it's certainly not robust, the | |
| 24 | [[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is | |
| 25 | helpful for figuring out basic information about the service. | |
| 22 | While it's certainly not robust, the [[https://freshrss.github.io/FreshRSS/][FreshRSS documentation]] is helpful for | |
| 23 | figuring out basic information about the service. | |
| 26 | 24 | |
| 27 | However, I wanted to install this service as a Docker container and | |
| 28 | stumbled across the | |
| 29 | [[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]] | |
| 30 | within the GitHub repository. | |
| 25 | However, I wanted to install this service as a Docker container and stumbled | |
| 26 | across the [[https://github.com/FreshRSS/FreshRSS/tree/edge/Docker][Docker README]] within the GitHub repository. | |
| 31 | 27 | |
| 32 | This README was the documentation I actually needed. However, as you'll | |
| 33 | see below, I still had to manually edit one file (=config.php=) to | |
| 34 | access the API externally via my RSS apps. | |
| 28 | This README was the documentation I actually needed. However, as you'll see | |
| 29 | below, I still had to manually edit one file (=config.php=) to access the API | |
| 30 | externally via my RSS apps. | |
| 35 | 31 | |
| 36 | 32 | * Installation |
| 37 | 33 | |
| 38 | 34 | ** DNS |
| 39 | 35 | |
| 40 | The first step, as required by any external web service, was assigning a | |
| 41 | domain name to use. I chose to use a subdomain, like =rss.example.com=. | |
| 36 | The first step, as required by any external web service, was assigning a domain | |
| 37 | name to use. I chose to use a subdomain, like =rss.example.com=. | |
| 42 | 38 | |
| 43 | 39 | To assign this, I created an =A= record in my DNS settings with the IPv4 |
| 44 | address of the server and an =AAAA= record with the IPv6 address of the | |
| 45 | server. Note: assigning an IPv6 (=AAAA=) record is optional, but I like | |
| 46 | to enable IPV6 for my services. | |
| 40 | (Internet Protocol version 4) address of the server and an =AAAA= record with | |
| 41 | the IPv6 (Internet Protocol version 6) address of the server. Note: assigning an | |
| 42 | IPv6 (=AAAA=) record is optional, but I like to enable IPV6 for my services. | |
| 47 | 43 | |
| 48 | 44 | #+begin_src config |
| 49 | 45 | rss.example.com A xxx.xxx.xxx.xxx |
| @@ -52,11 +48,10 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx | ||
| 52 | 48 | |
| 53 | 49 | ** Docker |
| 54 | 50 | |
| 55 | I initially tried to set up a =docker-compose.yml= file with a =.env= | |
| 56 | file because I prefer to have a file I can look back at later to see how | |
| 57 | I initially started the container, but it simply wouldn't work for me. | |
| 58 | I'm not sure why, but I assume I wasn't telling =docker-compose= where | |
| 59 | the =.env= file was. | |
| 51 | I initially tried to set up a =docker-compose.yml= file with a =.env= file | |
| 52 | because I prefer to have a file I can look back at later to see how I initially | |
| 53 | started the container, but it simply wouldn't work for me. I'm not sure why, but | |
| 54 | I assume I wasn't telling =docker-compose= where the =.env= file was. | |
| 60 | 55 | |
| 61 | 56 | Regardless, I chose to simply run the service with =docker run=. See the |
| 62 | 57 | following command for my =docker run= configuration: |
| @@ -72,25 +67,24 @@ sudo docker run -d --restart unless-stopped --log-opt max-size=10m \ | ||
| 72 | 67 | freshrss/freshrss |
| 73 | 68 | #+end_src |
| 74 | 69 | |
| 75 | This started the container successfully and allowed me to visit the | |
| 76 | FreshRSS instance at =localhost:8080=. | |
| 70 | This started the container successfully and allowed me to visit the FreshRSS | |
| 71 | instance at =localhost:8080=. | |
| 77 | 72 | |
| 78 | 73 | ** Fresh RSS Set-Up |
| 79 | 74 | |
| 80 | I *HIGHLY* suggest that you set up your user account prior to exposing | |
| 81 | this service to the public. It's unlikely that someone is trying to | |
| 82 | access the exact domain or IP/port you're assigning here, but as soon as | |
| 83 | you expose this service, the first person to open the URL will be able | |
| 84 | to create the admin user. | |
| 75 | I *HIGHLY* suggest that you set up your user account prior to exposing this | |
| 76 | service to the public. It's unlikely that someone is trying to access the exact | |
| 77 | domain or IP/port you're assigning here, but as soon as you expose this service, | |
| 78 | the first person to open the URL will be able to create the administrative user. | |
| 85 | 79 | |
| 86 | In order to set up your FreshRSS service, open the =localhost:8080= URL | |
| 87 | in your browser (you may need to use a local IP instead of =localhost= | |
| 88 | if you're accessing the page from a different machine on the network - | |
| 89 | e.g., =192.168.1.20:8080=). | |
| 80 | In order to set up your FreshRSS service, open the =localhost:8080= URL in your | |
| 81 | browser (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 | |
| 83 | network - e.g., =192.168.1.20:8080=). | |
| 90 | 84 | |
| 91 | 85 | Once the page loads, set up your default user with a strong username and |
| 92 | password. You may also choose to configure other settings prior to | |
| 93 | exposing this service. | |
| 86 | password. You may also choose to configure other settings prior to exposing this | |
| 87 | service. | |
| 94 | 88 | |
| 95 | 89 | ** Nginx Reverse-Proxy |
| 96 | 90 | |
| @@ -103,7 +97,7 @@ First, I created a new Nginx configuration file: | ||
| 103 | 97 | sudo nano /etc/nginx/sites-available/rss.example.com |
| 104 | 98 | #+end_src |
| 105 | 99 | |
| 106 | Within the config file, I pasted the following code: | |
| 100 | Within the configuration file, I pasted the following code: | |
| 107 | 101 | |
| 108 | 102 | #+begin_src config |
| 109 | 103 | upstream freshrss { |
| @@ -136,8 +130,7 @@ server { | ||
| 136 | 130 | } |
| 137 | 131 | #+end_src |
| 138 | 132 | |
| 139 | Finally, restart Nginx and you will be able to access your service via | |
| 140 | HTTP: | |
| 133 | Finally, restart Nginx and you will be able to access your service via HTTP (Hypertext Transfer Protocol): | |
| 141 | 134 | |
| 142 | 135 | #+begin_src sh |
| 143 | 136 | sudo systemctl restart nginx.service |
| @@ -145,49 +138,46 @@ sudo systemctl restart nginx.service | ||
| 145 | 138 | |
| 146 | 139 | ** HTTPS |
| 147 | 140 | |
| 148 | However, I don't want to access my RSS feeds via HTTP. I want it | |
| 149 | available only via HTTPS. In order to do this, I ran the | |
| 150 | [[https://certbot.eff.org/][certbot]] program to generate SSL | |
| 151 | certificates for me: | |
| 141 | However, I don't want to access my RSS feeds via HTTP. I want it available only | |
| 142 | via 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: | |
| 152 | 144 | |
| 153 | 145 | #+begin_src sh |
| 154 | 146 | sudo certbot --nginx |
| 155 | 147 | #+end_src |
| 156 | 148 | |
| 157 | This process will automatically generate an SSL certificate for you and | |
| 158 | modify the Nginx configuration file to include a redirect from HTTP to | |
| 159 | HTTPS. | |
| 149 | This process will automatically generate an SSL certificate for you and modify | |
| 150 | the Nginx configuration file to include a redirect from HTTP to HTTPS. | |
| 160 | 151 | |
| 161 | 152 | * Post-Installation Fixes |
| 162 | 153 | |
| 163 | At this point, we have a functional FreshRSS website, available from | |
| 164 | anywhere and secured with HTTPS. However, attempting to connect this | |
| 165 | service to an RSS app resulted in many errors regarding unavailable URLs | |
| 166 | and incorrect credentials. | |
| 154 | At this point, we have a functional FreshRSS website, available from anywhere | |
| 155 | and secured with HTTPS. However, attempting to connect this service to an RSS | |
| 156 | app resulted in many errors regarding unavailable URLs and incorrect | |
| 157 | credentials. | |
| 167 | 158 | |
| 168 | 159 | ** API Set-Up |
| 169 | 160 | |
| 170 | First, 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 | |
| 172 | the password you will need to provide to your RSS apps. | |
| 161 | First, you need to open your user profile in FreshRSS (=Settings= > =Profile=) | |
| 162 | and set an API password in the field at the bottom. This is the password you | |
| 163 | will need to provide to your RSS apps. | |
| 173 | 164 | |
| 174 | Once that is set and saved, click the link below the API password field | |
| 175 | to open the API check tool. It should look something like | |
| 176 | =https://localhost:8080/api/= or =https://rss.example.com/api/=. | |
| 165 | Once that is set and saved, click the link below the API password field to open | |
| 166 | the API (application programming interface) check tool. It should look something | |
| 167 | like =https://localhost:8080/api/= or =https://rss.example.com/api/=. | |
| 177 | 168 | |
| 178 | Within this page, you /should/ see your correct external URL and "PASS" | |
| 179 | at the bottom of each API type. This would mean everything is set up | |
| 180 | correctly, and you can now move on and login to any RSS apps that | |
| 181 | support self-hosted options. | |
| 169 | Within this page, you /should/ see your correct external URL and "PASS" at the | |
| 170 | bottom of each API type. This would mean everything is set up correctly, and you | |
| 171 | can now move on and login to any RSS apps that support self-hosted options. | |
| 182 | 172 | |
| 183 | 173 | In 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 | |
| 185 | next section for a fix. | |
| 174 | =base_url= variable may be misconfigured. If this is the case, see the next | |
| 175 | section for a fix. | |
| 186 | 176 | |
| 187 | 177 | ** Base URL Fix |
| 188 | 178 | |
| 189 | In order to fix the =base_url= for the API, I opened up my docker | |
| 190 | container with the following command: | |
| 179 | In order to fix the =base_url= for the API, I opened up my docker container with | |
| 180 | the following command: | |
| 191 | 181 | |
| 192 | 182 | #+begin_src sh |
| 193 | 183 | sudo docker exec -it freshrss bash |
| @@ -206,9 +196,10 @@ Finally, open up =config.php= in the =data= directory: | ||
| 206 | 196 | nano data/config.php |
| 207 | 197 | #+end_src |
| 208 | 198 | |
| 209 | Within =config.php=, you will need to update the =base_url= variable and | |
| 210 | update it to match your external URL. In my case, I simply commented-out | |
| 211 | the incorrect URL with =//= and added the correct one on a new line: | |
| 199 | Within =config.php=, you will need to update the =base_url= variable and update | |
| 200 | it to match your external URL (uniform resource locator). In my case, I simply | |
| 201 | commented-out the incorrect URL with =//= and added the correct one on a new | |
| 202 | line: | |
| 212 | 203 | |
| 213 | 204 | #+begin_src php |
| 214 | 205 | <?php |
| @@ -221,8 +212,8 @@ the incorrect URL with =//= and added the correct one on a new line: | ||
| 221 | 212 | > |
| 222 | 213 | #+end_src |
| 223 | 214 | |
| 224 | You can now exit the file with =Ctrl + x=, press =y= to save the file, | |
| 225 | and then click =Enter= to keep the same file name. | |
| 215 | You can now exit the file with =Ctrl + x=, press =y= to save the file, and then | |
| 216 | click =Enter= to keep the same file name. | |
| 226 | 217 | |
| 227 | 218 | Finally, just exit out of the docker container: |
| 228 | 219 | |
| @@ -236,8 +227,7 @@ Next, just restart the container: | ||
| 236 | 227 | sudo docker restart freshrss |
| 237 | 228 | #+end_src |
| 238 | 229 | |
| 239 | Voilà! Your API check should now "PASS" and you should be able to use | |
| 240 | one of the API URLs in your RSS apps. | |
| 230 | Voilà! Your API check should now "PASS" and you should be able to use one of the | |
| 231 | API URLs in your RSS apps. | |
| 241 | 232 | |
| 242 | In my case, I use [[https://netnewswire.com][NetNewsWire]] on my desktop | |
| 243 | and phone. | |
| 233 | In 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 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Text-Based Simplicity |
| 7 | 7 | |
| 8 | I've detailed my views on web-based minimalism and related topics in | |
| 9 | other posts throughout the years; e.g., JavaScript/CSS bloat slowing | |
| 10 | down websites that are essentially a text document. However, I have | |
| 11 | never really expanded beyond talking about the web and describing how I | |
| 12 | focus on minimizing distractions in other digital environments. | |
| 13 | ||
| 14 | This post is going to set the baseline for how I /try/ to live my | |
| 15 | digital life. It does not necessarily get into my physical life, which | |
| 16 | is often harder to control and contain all the noise in our modern | |
| 17 | world. | |
| 18 | ||
| 19 | While there are new things to do every day in our digital world, I find | |
| 20 | that keeping a core set of values and interests can ground you and keep | |
| 21 | you mindful of /why/ you are participating in the digital world. For | |
| 22 | example, if - at your core - you have no interest in what strangers | |
| 23 | think about random topics, it would be unwise to start participating in | |
| 24 | social media. However, I am someone who has been dragged in by effective | |
| 25 | advertising to participate in communities that I realize I do not care | |
| 26 | for. | |
| 27 | ||
| 28 | I won't dive much further into explaining the philosophy of all this, | |
| 29 | but I will link a few helpful articles that may pique your interest if | |
| 30 | you're in search of more meaningful experiences: | |
| 8 | I've detailed my views on web-based minimalism and related topics in other posts | |
| 9 | throughout the years; e.g., JavaScript/CSS (Cascading Style Sheets) bloat | |
| 10 | slowing down websites that are essentially a text document. However, I have | |
| 11 | never really expanded beyond talking about the web and describing how I focus on | |
| 12 | minimizing distractions in other digital environments. | |
| 13 | ||
| 14 | This post is going to set the baseline for how I /try/ to live my digital life. | |
| 15 | It does not necessarily get into my physical life, which is often harder to | |
| 16 | control and contain all the noise in our modern world. | |
| 17 | ||
| 18 | While there are new things to do every day in our digital world, I find that | |
| 19 | keeping a core set of values and interests can ground you and keep you mindful | |
| 20 | of /why/ you are participating in the digital world. For example, if - at your | |
| 21 | core - you have no interest in what strangers think about random topics, it | |
| 22 | would be unwise to start participating in social media. However, I am someone | |
| 23 | who has been dragged in by effective advertising to participate in communities | |
| 24 | that I realize I do not care for. | |
| 25 | ||
| 26 | I won't dive much further into explaining the philosophy of all this, but I will | |
| 27 | link a few helpful articles that may pique your interest if you're in search of | |
| 28 | more meaningful experiences: | |
| 31 | 29 | |
| 32 | 30 | - [[https://en.wikipedia.org/wiki/Mindfulness][Mindfulness]] |
| 33 | 31 | - [[https://en.wikipedia.org/wiki/Minimalism][Minimalism]] |
| @@ -35,125 +33,111 @@ you're in search of more meaningful experiences: | ||
| 35 | 33 | |
| 36 | 34 | * Living Life in the Terminal |
| 37 | 35 | |
| 38 | My personal approach to reducing digital distractions and increasing my | |
| 39 | focus on the task at hand is to use a terminal for as much as I possibly | |
| 40 | can. | |
| 36 | My personal approach to reducing digital distractions and increasing my focus on | |
| 37 | the task at hand is to use a terminal for as much as I possibly can. | |
| 41 | 38 | |
| 42 | Most days, this means that I have a few tabs open constantly in my | |
| 43 | terminal: | |
| 39 | Most days, this means that I have a few tabs open constantly in my terminal: | |
| 44 | 40 | |
| 45 | 41 | 1. A web browser |
| 46 | 42 | 2. A chat client |
| 47 | 43 | 3. An email client |
| 48 | 4. An RSS feed reader | |
| 44 | 4. An RSS (Really Simple Syndication) feed reader | |
| 49 | 45 | 5. A local shell for navigating my computer's files |
| 50 | 46 | 6. A remote shell for managing servers and other machines |
| 51 | 47 | |
| 52 | Beyond this, I rarely open other tabs or GUI applications, unless | |
| 53 | absolutely necessary. If you look, you may be surprised what can be | |
| 54 | accomplished in the terminal. | |
| 48 | Beyond this, I rarely open other tabs or graphical applications, unless | |
| 49 | absolutely necessary. If you look, you may be surprised what can be accomplished | |
| 50 | in the terminal. | |
| 55 | 51 | |
| 56 | For example, I have moved my music and entertainment downloads to the | |
| 57 | terminal, along with my device VPN connections. I am exploring options | |
| 58 | for moving my RSS subscriptions to something like | |
| 59 | [[https://newsboat.org/][Newsboat]], so that I can read my daily | |
| 60 | articles without all the fuss. | |
| 52 | For example, I have moved my music and entertainment downloads to the terminal, | |
| 53 | along with my device virtual private network (VPN) connections. I am exploring | |
| 54 | options for moving my RSS subscriptions to something like [[https://newsboat.org/][Newsboat]], so that I | |
| 55 | can read my daily articles without all the fuss. | |
| 61 | 56 | |
| 62 | Now that we have some examples out of the way, let's dive into the | |
| 63 | specifics. | |
| 57 | Now that we have some examples out of the way, let's dive into the specifics. | |
| 64 | 58 | |
| 65 | 59 | ** Browsing the Web |
| 66 | 60 | |
| 67 | I'm going to start off with a hard topic for those who prefer to live in | |
| 68 | the terminal: web browsing. This task is made hard mostly by websites | |
| 69 | and web apps that require JavaScript to run. The other difficult part is | |
| 70 | that if you're using a text-based browser, that means images won't load | |
| 71 | (hopefully that's obvious). | |
| 61 | I'm going to start off with a hard topic for those who prefer to live in the | |
| 62 | terminal: web browsing. This task is made hard mostly by websites and web apps | |
| 63 | that require JavaScript to run. The other difficult part is that if you're using | |
| 64 | a text-based browser, that means images won't load (hopefully that's obvious). | |
| 72 | 65 | |
| 73 | I am using [[https://lynx.invisible-island.net][Lynx]], a text-based | |
| 74 | browser that runs quickly and easily in the terminal. Lynx allows me to | |
| 75 | browser most websites by simply typing =g= and then typing in the URL I | |
| 76 | want. | |
| 66 | I am using [[https://lynx.invisible-island.net][Lynx]], a text-based browser that runs quickly and easily in the | |
| 67 | terminal. Lynx allows me to browser most websites by simply typing =g= and then | |
| 68 | typing in the URL I want. | |
| 77 | 69 | |
| 78 | If you need a search engine while in Lynx, I recommend | |
| 79 | [[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which allows | |
| 80 | you to search the web using their text-only interface. | |
| 70 | If you need a search engine while in Lynx, I recommend [[https://lite.duckduckgo.com/lite/][DuckDuckGo (Lite)]], which | |
| 71 | allows you to search the web using their text-only interface. | |
| 81 | 72 | |
| 82 | Eventually, you will run into websites that don't work (or are just too | |
| 83 | ugly and messy) in a text-only mode, and you'll be forced to switch over | |
| 84 | to a GUI browser to look at that site. Personally, I don't mind this as | |
| 85 | it doesn't happen as often as I thought it would. | |
| 73 | Eventually, you will run into websites that don't work (or are just too ugly and | |
| 74 | messy) in a text-only mode, and you'll be forced to switch over to a GUI browser | |
| 75 | to look at that site. Personally, I don't mind this as it doesn't happen as | |
| 76 | often as I thought it would. | |
| 86 | 77 | |
| 87 | The only time I need to do this is when I want to browse an | |
| 88 | image/video-focused webpage or if I need to log in to a site, and it | |
| 89 | doesn't support a text-only login page. For example, I am able to easily | |
| 90 | log in to [[https://sr.ht][Sourcehut]] in lynx. | |
| 78 | The only time I need to do this is when I want to browse an image/video-focused | |
| 79 | webpage or if I need to log in to a site, and it doesn't support a text-only | |
| 80 | login page. For example, I am able to easily log in to [[https://sr.ht][Sourcehut]] in lynx. | |
| 91 | 81 | |
| 92 | 82 | ** Chatting with Friends |
| 93 | 83 | |
| 94 | After web browsing activities, my main form of terminal communication is | |
| 95 | Matrix. I use the [[https://docs.mau.fi/gomuks/][gomuks]] client | |
| 96 | currently. | |
| 84 | After web browsing activities, my main form of terminal communication is Matrix. | |
| 85 | I use the [[https://docs.mau.fi/gomuks/][gomuks]] client currently. | |
| 97 | 86 | |
| 98 | This was incredibly easy to install on macOS (but I will need to see if | |
| 99 | it'll be just as easy on Linux when my new laptop arrives): | |
| 87 | This was incredibly easy to install on macOS (but I will need to see if it'll be | |
| 88 | just as easy on Linux when my new laptop arrives): | |
| 100 | 89 | |
| 101 | 90 | #+begin_src sh |
| 102 | 91 | brew install gomuks |
| 103 | 92 | #+end_src |
| 104 | 93 | |
| 105 | Once you launch gomuks, it will sync and require your username and | |
| 106 | password to login. After doing so, the only problem I ran into was | |
| 107 | verifying my gomuks client so that I could participate in rooms with | |
| 108 | E2EE. | |
| 94 | Once you launch gomuks, it will sync and require your username and password to | |
| 95 | login. After doing so, the only problem I ran into was verifying my gomuks | |
| 96 | client so that I could participate in rooms with E2EE (end-to-end encryption). | |
| 109 | 97 | |
| 110 | Finally, I was able to verify the session by opening the Element desktop | |
| 111 | app (I assume you can do this in the browser and mobile app too, but I'm | |
| 112 | not sure) and manually verifying myself with this process: | |
| 98 | Finally, I was able to verify the session by opening the Element desktop app (I | |
| 99 | assume you can do this in the browser and mobile app too, but I'm not sure) and | |
| 100 | manually verifying myself with this process: | |
| 113 | 101 | |
| 114 | 102 | 1. Open the Element desktop app |
| 115 | 103 | 2. Open a room I was a member of |
| 116 | 104 | 3. Open the =Room Info= pane |
| 117 | 105 | 4. Open the =People= menu and search for myself |
| 118 | 106 | 5. Click on my profile name |
| 119 | 6. Click on the session link under the =Security= section and follow the | |
| 120 | prompts to manually verify the session | |
| 107 | 6. Click on the session link under the =Security= section and follow the prompts | |
| 108 | to manually verify the session | |
| 121 | 109 | |
| 122 | Overall, I like gomuks and am able to enjoy all the features I was using | |
| 123 | in Element. The only hiccup I have occurred is manually downloading | |
| 124 | images to view them, which can be annoying. | |
| 110 | Overall, I like gomuks and am able to enjoy all the features I was using in | |
| 111 | Element. The only hiccup I have occurred is manually downloading images to view | |
| 112 | them, which can be annoying. | |
| 125 | 113 | |
| 126 | 114 | |
| 127 | 115 | |
| 128 | Moving email to the terminal has been the hardest of the tasks for me. | |
| 129 | Unlike web browsing, where I can simply decide to not look at a website | |
| 130 | that does not work in the terminal, I cannot simply ignore emails sent | |
| 131 | to me. | |
| 116 | Moving email to the terminal has been the hardest of the tasks for me. Unlike | |
| 117 | web browsing, where I can simply decide to not look at a website that does not | |
| 118 | work in the terminal, I cannot simply ignore emails sent to me. | |
| 132 | 119 | |
| 133 | Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as | |
| 134 | a potential email client. | |
| 120 | Personally, I am experimenting with [[https://neomutt.org/][neomutt]] as a potential email client. | |
| 135 | 121 | |
| 136 | However, this requires a *TON* of configuration and tweaking to get | |
| 137 | right. Even when I was able to set up neomutt, configure my email | |
| 138 | account, and customize a few personal preferences, a lot of emails still | |
| 139 | do not display correctly (mostly due to HTML and images). | |
| 122 | However, this requires a *TON* of configuration and tweaking to get right. Even | |
| 123 | when I was able to set up neomutt, configure my email account, and customize a | |
| 124 | few personal preferences, a lot of emails still do not display correctly (mostly | |
| 125 | due to HTML (Hypertext Markup Language) and images). | |
| 140 | 126 | |
| 141 | I won't get into the details of configuring =neomutt=; I mostly followed | |
| 142 | this blog post: | |
| 143 | [[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the | |
| 144 | Terminal: Configuring Neomutt]]. | |
| 127 | I won't get into the details of configuring =neomutt=; I mostly followed this | |
| 128 | blog post: [[https://gideonwolfe.com/posts/workflow/neomutt/intro/][Email in the Terminal: Configuring Neomutt]]. | |
| 145 | 129 | |
| 146 | Finally, I have yet to figure out how to connect my GPG keys to | |
| 147 | =neomutt=, but that's a problem for another day. | |
| 130 | Finally, I have yet to figure out how to connect my PGP (Pretty Good Privacy) | |
| 131 | keys to =neomutt=, but that's a problem for another day. | |
| 148 | 132 | |
| 149 | 133 | ** RSS Feed Reader |
| 150 | 134 | |
| 151 | I have just started using [[https://newsboat.org/][Newsboat]] to read | |
| 152 | articles in my terminal and have found quick success with it. | |
| 135 | I have just started using [[https://newsboat.org/][Newsboat]] to read articles in my terminal and have | |
| 136 | found quick success with it. | |
| 153 | 137 | |
| 154 | The configuration was super easy for this app; I simply installed the | |
| 155 | app, created a file for URLs, and imported my OPML subscriptions that I | |
| 156 | had exported out of my old feed reader: | |
| 138 | The configuration was super easy for this app; I simply installed the app, | |
| 139 | created a file for URLs, and imported my OPML (Outline Processor Markup | |
| 140 | Language) subscriptions that I had exported out of my old feed reader: | |
| 157 | 141 | |
| 158 | 142 | #+begin_src sh |
| 159 | 143 | brew install newsboat |
| @@ -169,13 +153,12 @@ newsboat -i=my_subscriptions.opml | ||
| 169 | 153 | |
| 170 | 154 | ** Writing & Programming |
| 171 | 155 | |
| 172 | Unfortunately, the weak link in my terminal-based environment right now | |
| 173 | is my grasp of the possibilities of editing files within a shell. | |
| 156 | Unfortunately, the weak link in my terminal-based environment right now is my | |
| 157 | grasp of the possibilities of editing files within a shell. | |
| 174 | 158 | |
| 175 | I am used to the easy extensions found in VSCodium and Kate, so I am | |
| 176 | slowly learning how to mold the default editing tools to my needs. | |
| 177 | Currently, this means I am using =nano= with the following | |
| 178 | configuration: | |
| 159 | I am used to the easy extensions found in VSCodium and Kate, so I am slowly | |
| 160 | learning how to mold the default editing tools to my needs. Currently, this | |
| 161 | means I am using =nano= with the following configuration: | |
| 179 | 162 | |
| 180 | 163 | #+begin_src config |
| 181 | 164 | set breaklonglines |
| @@ -187,15 +170,14 @@ set fill 80 | ||
| 187 | 170 | #+end_src |
| 188 | 171 | |
| 189 | 172 | This configuration allows nano to automatically hard-wrap lines at 80 |
| 190 | characters, autoindent the wrapped lines (if the previous line was | |
| 191 | indented), use 2 spaces per tab, and display line numbers within each | |
| 192 | file I open. | |
| 193 | ||
| 194 | I am currently looking to see if =vim= or =emacs= would be more useful | |
| 195 | for my current needs, but I'm not in any rush, so I don't expect to find | |
| 196 | an answer anytime soon. | |
| 197 | ||
| 198 | With my current life demands, I am not programming at the moment and | |
| 199 | have not explored the best terminal set-up for programming. However, I | |
| 200 | have seen many peers find success configuring =vim= and =emacs=, so | |
| 201 | that's where I will start when I pick my projects back up. | |
| 173 | characters, autoindent the wrapped lines (if the previous line was indented), | |
| 174 | use 2 spaces per tab, and display line numbers within each file I open. | |
| 175 | ||
| 176 | I am currently looking to see if =vim= or =emacs= would be more useful for my | |
| 177 | current needs, but I'm not in any rush, so I don't expect to find an answer | |
| 178 | anytime soon. | |
| 179 | ||
| 180 | With my current life demands, I am not programming at the moment and have not | |
| 181 | explored the best terminal set-up for programming. However, I have seen many | |
| 182 | peers find success configuring =vim= and =emacs=, so that's where I will start | |
| 183 | when I pick my projects back up. | |
content/blog/2022-06-22-daily-poetry.org +35 −39
| @@ -14,8 +14,8 @@ I use to email myself plaintext poems daily, visit the repository: | ||
| 14 | 14 | Most of my programming projects are small, random projects that are made |
| 15 | 15 | strictly to fix some small problem I have or enhance my quality of life. |
| 16 | 16 | |
| 17 | In this case, I was looking for a simply and easy way to get a daily | |
| 18 | dose of literature or poetry to read in the mornings. | |
| 17 | In this case, I was looking for a simply and easy way to get a daily dose of | |
| 18 | literature or poetry to read in the mornings. | |
| 19 | 19 | |
| 20 | 20 | However, I don't want to sign up for a random mailing list on just any |
| 21 | 21 | website. 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. | ||
| 29 | 29 | This solution uses Python and email, so the following process requires |
| 30 | 30 | the following to be installed: |
| 31 | 31 | |
| 32 | 1. An SMTP server, which can be as easy as installing =mailutils= if | |
| 33 | you're on a Debian-based distro. | |
| 32 | 1. A Simple Mail Transfer Protocol (SMTP) server, which can be as easy as | |
| 33 | installing =mailutils= if you're on a Debian-based distribution. | |
| 34 | 34 | 2. Python (& pip!) |
| 35 | 3. The following Python packages: =email=, =smtplib=, =json=, and | |
| 36 | =requests= | |
| 35 | 3. The following Python packages: =email=, =smtplib=, =json=, and =requests= | |
| 37 | 36 | |
| 38 | 37 | * Breaking Down the Logic |
| 39 | 38 | |
| 40 | I want to break down the logic for this program, as it's quite simple | |
| 41 | and informational. | |
| 39 | I want to break down the logic for this program, as it's quite simple and | |
| 40 | informational. | |
| 42 | 41 | |
| 43 | 42 | ** Required Packages |
| 44 | 43 | |
| 45 | This program starts with a simple import of the required packages, so I | |
| 46 | wanted to explain why each package is used: | |
| 44 | This program starts with a simple import of the required packages, so I wanted | |
| 45 | to explain why each package is used: | |
| 47 | 46 | |
| 48 | 47 | #+begin_src python |
| 49 | 48 | from email.mime.text import MIMEText # Required for translating MIMEText |
| @@ -54,15 +53,15 @@ import requests # Required to send out a request to the API | ||
| 54 | 53 | |
| 55 | 54 | ** Sending the API Request |
| 56 | 55 | |
| 57 | Next, we need to actually send the API request. In my case, I'm calling | |
| 58 | a random poem from the entire API. If you want, you can call specific | |
| 59 | poems or authors from this API. | |
| 56 | Next, we need to actually send the application programming interface (API) | |
| 57 | request. In my case, I'm calling a random poem from the entire API. If you want, | |
| 58 | you can call specific poems or authors from this API. | |
| 60 | 59 | |
| 61 | 60 | #+begin_src python |
| 62 | 61 | json_data = requests.get('https://poetrydb.org/random').json() |
| 63 | 62 | #+end_src |
| 64 | 63 | |
| 65 | This gives us the following result in JSON: | |
| 64 | This gives us the following result in JSON (JavaScript Object Notation): | |
| 66 | 65 | |
| 67 | 66 | #+begin_src json |
| 68 | 67 | [ |
| @@ -94,12 +93,12 @@ This gives us the following result in JSON: | ||
| 94 | 93 | |
| 95 | 94 | ** Parsing the API Results |
| 96 | 95 | |
| 97 | In order to parse this into a readable format, we need to use the =json= | |
| 98 | package and extract the fields we want. In the example below, I am | |
| 99 | grabbing every field presented by the API. | |
| 96 | In order to parse this into a readable format, we need to use the =json= package | |
| 97 | and extract the fields we want. In the example below, I am grabbing every field | |
| 98 | presented by the API. | |
| 100 | 99 | |
| 101 | For 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. | |
| 100 | For the actual poem content, we need to loop over each line in the =lines= | |
| 101 | variable since each line is a separate string by default. | |
| 103 | 102 | |
| 104 | 103 | #+begin_quote |
| 105 | 104 | You /could/ also extract the title or author and make another call out |
| @@ -125,21 +124,20 @@ for line in json_data[0]['lines']: | ||
| 125 | 124 | |
| 126 | 125 | ** Composing the Email |
| 127 | 126 | |
| 128 | Now that I have all the data I need, I just need to compose it into a | |
| 129 | message and prepare the message metadata. | |
| 127 | Now that I have all the data I need, I just need to compose it into a message | |
| 128 | and prepare the message metadata. | |
| 130 | 129 | |
| 131 | For my daily email, I want to see the title of the poem first, followed | |
| 132 | by the author, then a blank line, and finally the full poem. This code | |
| 133 | snippet combines that data and packages it into a MIMEText container, | |
| 134 | ready to be emailed. | |
| 130 | For my daily email, I want to see the title of the poem first, followed by the | |
| 131 | author, then a blank line, and finally the full poem. This code snippet combines | |
| 132 | that data and packages it into a MIMEText container, ready to be emailed. | |
| 135 | 133 | |
| 136 | 134 | #+begin_src python |
| 137 | 135 | msg_body = title + "\n" + author + "\n\n" + lines |
| 138 | 136 | msg = MIMEText(msg_body) |
| 139 | 137 | #+end_src |
| 140 | 138 | |
| 141 | Before we send the email, we need to prepare the metadata (subject, | |
| 142 | from, to, etc.): | |
| 139 | Before we send the email, we need to prepare the metadata (subject, from, to, | |
| 140 | etc.): | |
| 143 | 141 | |
| 144 | 142 | #+begin_src python |
| 145 | 143 | sender_email = 'example@server.local' |
| @@ -151,10 +149,9 @@ msg['To'] = recipient_email | ||
| 151 | 149 | |
| 152 | 150 | ** Sending the Email |
| 153 | 151 | |
| 154 | Now that I have everything ready to be emailed, the last step is to | |
| 155 | simply connect to an SMTP server and send the email out to the | |
| 156 | recipients. In my case, I installed =mailutils= on Ubuntu and let my | |
| 157 | SMTP server be =localhost=. | |
| 152 | Now that I have everything ready to be emailed, the last step is to simply | |
| 153 | connect to an SMTP server and send the email out to the recipients. In my case, | |
| 154 | I installed =mailutils= on Ubuntu and let my SMTP server be =localhost=. | |
| 158 | 155 | |
| 159 | 156 | #+begin_src python |
| 160 | 157 | smtp_server = 'localhost' |
| @@ -165,9 +162,8 @@ s.quit() | ||
| 165 | 162 | |
| 166 | 163 | * The Result! |
| 167 | 164 | |
| 168 | Instead of including a screenshot, I've copied the contents of the email | |
| 169 | that was delivered to my inbox below since I set this process up in | |
| 170 | plaintext format. | |
| 165 | Instead of including a screenshot, I've copied the contents of the email that | |
| 166 | was delivered to my inbox below since I set this process up in plaintext format. | |
| 171 | 167 | |
| 172 | 168 | #+begin_src txt |
| 173 | 169 | Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC) |
| @@ -200,16 +196,16 @@ Some, wise in show, more fools indeed than they. | ||
| 200 | 196 | * Scheduling the Daily Email |
| 201 | 197 | |
| 202 | 198 | Last, but not least, is scheduling this Python script with =crontab=. To |
| 203 | schedule a script to run daily, you can add it to the =crontab= file. To | |
| 204 | do this, open =crontab= in editing mode: | |
| 199 | schedule a script to run daily, you can add it to the =crontab= file. To do | |
| 200 | this, open =crontab= in editing mode: | |
| 205 | 201 | |
| 206 | 202 | #+begin_src sh |
| 207 | 203 | crontab -e |
| 208 | 204 | #+end_src |
| 209 | 205 | |
| 210 | In the file, simply paste the following snippet at the bottom of the | |
| 211 | file and ensure that the file path is correctly pointing to wherever you | |
| 212 | saved your Python script: | |
| 206 | In the file, simply paste the following snippet at the bottom of the file and | |
| 207 | ensure that the file path is correctly pointing to wherever you saved your | |
| 208 | Python script: | |
| 213 | 209 | |
| 214 | 210 | #+begin_src config |
| 215 | 211 | 0 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py |
content/blog/2022-06-24-fedora-i3.org +53 −57
| @@ -5,61 +5,57 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Leaving macOS |
| 7 | 7 | |
| 8 | As I noted [[../foss-macos-apps][in a recent post]], I have been | |
| 9 | planning on migrating from macOS back to a Linux-based OS. I am happy to | |
| 10 | say that I have finally completed my migration and am now stuck in the | |
| 11 | wonderful world of Linux again. | |
| 8 | As I noted in a recent post, I have been planning on migrating from macOS back | |
| 9 | to a Linux-based operating system (OS). I am happy to say that I have finally | |
| 10 | completed my migration and am now stuck in the wonderful world of Linux again. | |
| 12 | 11 | |
| 13 | 12 | My decision to leave macOS really came down to just a few important |
| 14 | 13 | things: |
| 15 | 14 | |
| 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 | ||
| 28 | Now that I've covered macOS, I'm going to move on to more exciting | |
| 29 | topics: 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 | ||
| 26 | Now that I've covered macOS, I'm going to move on to more exciting topics: my | |
| 27 | personal choice of OS, desktop environment (DE), and various customizations I'm | |
| 30 | 28 | using. |
| 31 | 29 | |
| 32 | 30 | * Fedora |
| 33 | 31 | |
| 34 | After trying a ton of distros (I think I booted and tested around 20-25 | |
| 35 | distros), I finally landed on [[https://getfedora.org/][Fedora Linux]]. | |
| 36 | I have quite a bit of experience with Fedora and enjoy the =dnf= package | |
| 37 | manager. Fedora allows me to keep up-to-date with recent software (I'm | |
| 38 | looking at you, Debian), but still provides a level of stability you | |
| 39 | don't find in every distro. | |
| 40 | ||
| 41 | In a very close second place was Arch Linux, as well as its spin-off: | |
| 42 | Garuda Linux (Garuda w/ sway is /beautiful/). Arch is great for | |
| 43 | compatibility and the massive community it has, but I have just never | |
| 44 | had the time to properly sit down and learn the methodology behind their | |
| 45 | packaging systems. | |
| 46 | ||
| 47 | Basically, everything else I tested was unacceptable in at least one way | |
| 48 | or another. Void (=glibc=) was great, but doesn't support all the | |
| 49 | software I need. Slackware worked well as a tui, but I wasn't skilled | |
| 32 | After trying a ton of distributions (I think I booted and tested around 20-25 | |
| 33 | distributions), I finally landed on [[https://getfedora.org/][Fedora Linux]]. I have quite a bit of experience | |
| 34 | with Fedora and enjoy the =dnf= package manager. Fedora allows me to keep | |
| 35 | up-to-date with recent software (I'm looking at you, Debian), but still provides | |
| 36 | a level of stability you don't find in every distribution. | |
| 37 | ||
| 38 | In a very close second place was Arch Linux, as well as its spin-off: Garuda | |
| 39 | Linux (Garuda w/ sway is /beautiful/). Arch is great for compatibility and the | |
| 40 | massive community it has, but I have just never had the time to properly sit | |
| 41 | down and learn the methodology behind their packaging systems. | |
| 42 | ||
| 43 | Basically, everything else I tested was unacceptable in at least one way or | |
| 44 | another. Void (=glibc=) was great, but doesn't support all the software I need. | |
| 45 | Slackware worked well as a text-based user interface (TUI), but I wasn't skilled | |
| 50 | 46 | enough to get a tiling window manager (WM) working on it. |
| 51 | 47 | |
| 52 | 48 | ** i3 |
| 53 | 49 | |
| 54 | One of the reasons I settled on Fedora is that it comes with an official | |
| 55 | i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of | |
| 56 | the biggest things I wanted to do as soon as I adopted Linux again. | |
| 50 | One of the reasons I settled on Fedora is that it comes with an official i3 | |
| 51 | spin. Being able to use a tiling WM, such as i3 or sway, is one of the biggest | |
| 52 | things I wanted to do as soon as I adopted Linux again. | |
| 57 | 53 | |
| 58 | I will probably set up a dotfile repository soon, so that I don't lose | |
| 59 | any of my configurations, but nothing big has been configured thus far. | |
| 54 | I will probably set up a dotfile repository soon, so that I don't lose any of my | |
| 55 | configurations, but nothing big has been configured thus far. | |
| 60 | 56 | |
| 61 | The two main things I have updated in i3wm are natural scrolling and | |
| 62 | binding my brightness keys to the =brightnessctl= program. | |
| 57 | The two main things I have updated in i3wm are natural scrolling and binding my | |
| 58 | brightness keys to the =brightnessctl= program. | |
| 63 | 59 | |
| 64 | 60 | 1. Natural Scrolling |
| 65 | 61 | |
| @@ -69,8 +65,8 @@ binding my brightness keys to the =brightnessctl= program. | ||
| 69 | 65 | sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf |
| 70 | 66 | #+end_src |
| 71 | 67 | |
| 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. | |
| 74 | 70 | |
| 75 | 71 | This is the =pointer= section: |
| 76 | 72 | |
| @@ -98,10 +94,10 @@ binding my brightness keys to the =brightnessctl= program. | ||
| 98 | 94 | |
| 99 | 95 | 2. Enabling Brightness Keys |
| 100 | 96 | |
| 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. | |
| 103 | 99 | |
| 104 | To do this, open up your i3 config file. Mine is located here: | |
| 100 | To do this, open up your i3 configuration file. Mine is located here: | |
| 105 | 101 | |
| 106 | 102 | #+begin_src sh |
| 107 | 103 | nano /home/<my-user>/.config/i3/config |
| @@ -115,24 +111,24 @@ binding my brightness keys to the =brightnessctl= program. | ||
| 115 | 111 | |
| 116 | 112 | 3. =polybar= |
| 117 | 113 | |
| 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). | |
| 120 | 116 | |
| 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. | |
| 124 | 120 | |
| 125 | 121 | 4. =alacritty= |
| 126 | 122 | |
| 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. | |
| 130 | 126 | |
| 131 | 127 | * Software Choices |
| 132 | 128 | |
| 133 | Again, I'm not going to say much that I haven't said yet in other blog | |
| 134 | posts, so I'll just do a quick rundown of the apps I installed | |
| 135 | immediately after I set up the environment. | |
| 129 | Again, I'm not going to say much that I haven't said yet in other blog posts, so | |
| 130 | I'll just do a quick rundown of the apps I installed immediately after I set up | |
| 131 | the environment. | |
| 136 | 132 | |
| 137 | 133 | Flatpak Apps: |
| 138 | 134 | |
content/blog/2022-07-01-git-server.org +139 −156
| @@ -5,56 +5,55 @@ | ||
| 5 | 5 | |
| 6 | 6 | * My Approach to Self-Hosting Git |
| 7 | 7 | |
| 8 | I have often tried to self-host my Git repositories, but have always | |
| 9 | fallen short when I tried to find a suitable web interface to show on | |
| 10 | the front-end. | |
| 8 | I have often tried to self-host my Git repositories, but have always fallen | |
| 9 | short when I tried to find a suitable web interface to show on the front-end. | |
| 11 | 10 | |
| 12 | After a few years, I have finally found a combination of methods that | |
| 13 | allow me to easily self-host my projects, view them on the web, and | |
| 14 | access them from anywhere. | |
| 11 | After a few years, I have finally found a combination of methods that allow me | |
| 12 | to easily self-host my projects, view them on the web, and access them from | |
| 13 | anywhere. | |
| 15 | 14 | |
| 16 | Before I dive into the details, I want to state a high-level summary of | |
| 17 | my self-hosted Git approach: | |
| 15 | Before I dive into the details, I want to state a high-level summary of my | |
| 16 | self-hosted Git approach: | |
| 18 | 17 | |
| 19 | 18 | - This method uses the =ssh://= (read & write) and =git://= (read-only) |
| 20 | 19 | 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. | |
| 31 | 30 | - 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. | |
| 36 | 35 | |
| 37 | 36 | * Assumptions |
| 38 | 37 | |
| 39 | 38 | For 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 | |
| 41 | server that you will be using to host your git repositories. | |
| 39 | (=git.example.com=) or internet protocol (IP) address (=207.84.26.991=) | |
| 40 | addressed to the server that you will be using to host your git repositories. | |
| 42 | 41 | |
| 43 | 42 | * Adding a Git User |
| 44 | 43 | |
| 45 | In order to use the SSH method associated with git, we will need to add | |
| 46 | a user named =git=. If you have used the SSH method for other git | |
| 47 | hosting sites, you are probably used to the following syntax: | |
| 44 | In order to use the SSH method associated with Git, we will need to add a user | |
| 45 | named =git=. If you have used the SSH method for other git hosting sites, you | |
| 46 | are probably used to the following syntax: | |
| 48 | 47 | |
| 49 | 48 | #+begin_src sh |
| 50 | 49 | git clone [user@]server:project.git |
| 51 | 50 | #+end_src |
| 52 | 51 | |
| 53 | The syntax above is an =scp=-like syntax for using SSH on the =git= user | |
| 54 | on the server to access your repository. | |
| 52 | The syntax above is an =scp=-like syntax for using SSH on the =git= user on the | |
| 53 | server to access your repository. | |
| 55 | 54 | |
| 56 | Let's delete any remnants of an old =git= user, if any, and create the | |
| 57 | new user account: | |
| 55 | Let's delete any remnants of an old =git= user, if any, and create the new user | |
| 56 | account: | |
| 58 | 57 | |
| 59 | 58 | #+begin_src sh |
| 60 | 59 | sudo deluser --remove-home git |
| @@ -63,8 +62,8 @@ sudo adduser git | ||
| 63 | 62 | |
| 64 | 63 | ** Import Your SSH Keys to the Git User |
| 65 | 64 | |
| 66 | Once the =git= user is created, you will need to copy your public SSH | |
| 67 | key on your local development machine to the =git= user on the server. | |
| 65 | Once the =git= user is created, you will need to copy your public SSH key on | |
| 66 | your local development machine to the =git= user on the server. | |
| 68 | 67 | |
| 69 | 68 | If you don't have an SSH key yet, create one with this command: |
| 70 | 69 | |
| @@ -72,11 +71,10 @@ If you don't have an SSH key yet, create one with this command: | ||
| 72 | 71 | ssh-keygen |
| 73 | 72 | #+end_src |
| 74 | 73 | |
| 75 | Once you create the key pair, the public should be saved to | |
| 76 | =~/.ssh/id_rsa.pub=. | |
| 74 | Once you create the key pair, the public should be saved to =~/.ssh/id_rsa.pub=. | |
| 77 | 75 | |
| 78 | If your server still has password-based authentication available, you | |
| 79 | can copy it over to your user's home directory like this: | |
| 76 | If your server still has password-based authentication available, you can copy | |
| 77 | it over to your user's home directory like this: | |
| 80 | 78 | |
| 81 | 79 | #+begin_src sh |
| 82 | 80 | ssh-copy-id git@server |
| @@ -88,8 +86,8 @@ Otherwise, copy it over to any user that you can access. | ||
| 88 | 86 | scp ~/.ssh/id_rsa.pub your_user@your_server: |
| 89 | 87 | #+end_src |
| 90 | 88 | |
| 91 | Once on the server, you will need to copy the contents into the =git= | |
| 92 | user's =authorized_keys= file: | |
| 89 | Once on the server, you will need to copy the contents into the =git= user's | |
| 90 | =authorized_keys= file: | |
| 93 | 91 | |
| 94 | 92 | #+begin_src sh |
| 95 | 93 | cat id_rsa.pub > /home/git/.ssh/authorized_keys |
| @@ -97,16 +95,15 @@ cat id_rsa.pub > /home/git/.ssh/authorized_keys | ||
| 97 | 95 | |
| 98 | 96 | ** (Optional) Disable Password-Based SSH |
| 99 | 97 | |
| 100 | If you want to lock down your server and ensure that no one can | |
| 101 | authenticate in via SSH with a password, you will need to edit your SSH | |
| 102 | configuration. | |
| 98 | If you want to lock down your server and ensure that no one can authenticate in | |
| 99 | via SSH with a password, you will need to edit your SSH configuration. | |
| 103 | 100 | |
| 104 | 101 | #+begin_src sh |
| 105 | 102 | sudo nano /etc/ssh/sshd_config |
| 106 | 103 | #+end_src |
| 107 | 104 | |
| 108 | Within this file, find the following settings and set them to the values | |
| 109 | I am showing below: | |
| 105 | Within this file, find the following settings and set them to the values I am | |
| 106 | showing below: | |
| 110 | 107 | |
| 111 | 108 | #+begin_src conf |
| 112 | 109 | PermitRootLogin no |
| @@ -114,18 +111,17 @@ PasswordAuthentication no | ||
| 114 | 111 | AuthenticationMethods publickey |
| 115 | 112 | #+end_src |
| 116 | 113 | |
| 117 | You may have other Authentication Methods required in your personal | |
| 118 | set-up, so the key here is just to ensure that =AuthenticationMethods= | |
| 119 | does not allow passwords. | |
| 114 | You may have other Authentication Methods required in your personal set-up, so | |
| 115 | the key here is just to ensure that =AuthenticationMethods= does not allow | |
| 116 | passwords. | |
| 120 | 117 | |
| 121 | 118 | *** Setting up the Base Directory |
| 122 | 119 | |
| 123 | Now that we have set up a =git= user to handle all transport methods, we | |
| 124 | need to set up the directory that we will be using as our base of all | |
| 125 | repositories. | |
| 120 | Now that we have set up a =git= user to handle all transport methods, we need to | |
| 121 | set up the directory that we will be using as our base of all repositories. | |
| 126 | 122 | |
| 127 | In my case, I am using =/git= as my source folder. To create this folder | |
| 128 | and assign it to the user we created, execute the following commands: | |
| 123 | In my case, I am using =/git= as my source folder. To create this folder and | |
| 124 | assign it to the user we created, execute the following commands: | |
| 129 | 125 | |
| 130 | 126 | #+begin_src sh |
| 131 | 127 | sudo mkdir /git |
| @@ -134,15 +130,15 @@ sudo chown -R git:git /git | ||
| 134 | 130 | |
| 135 | 131 | *** Creating a Test Repository |
| 136 | 132 | |
| 137 | On your server, switch over to the =git= user in order to start managing | |
| 138 | git files. | |
| 133 | On your server, switch over to the =git= user in order to start managing git | |
| 134 | files. | |
| 139 | 135 | |
| 140 | 136 | #+begin_src sh |
| 141 | 137 | su git |
| 142 | 138 | #+end_src |
| 143 | 139 | |
| 144 | Once logged-in as the =git= user, go to your base directory and create a | |
| 145 | test repository. | |
| 140 | Once logged-in as the =git= user, go to your base directory and create a test | |
| 141 | repository. | |
| 146 | 142 | |
| 147 | 143 | #+begin_src sh |
| 148 | 144 | cd /git |
| @@ -150,9 +146,9 @@ mkdir test.git && cd test.git | ||
| 150 | 146 | git init --bare |
| 151 | 147 | #+end_src |
| 152 | 148 | |
| 153 | If 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 | |
| 155 | inside the repository. | |
| 149 | If you want to make this repo viewable/cloneable to the public via the =git://= | |
| 150 | protocol, you need to create a =git-daemon-export-ok= file inside the | |
| 151 | repository. | |
| 156 | 152 | |
| 157 | 153 | #+begin_src sh |
| 158 | 154 | touch git-daemon-export-ok |
| @@ -160,34 +156,33 @@ touch git-daemon-export-ok | ||
| 160 | 156 | |
| 161 | 157 | * Change the Login Shell for =git= |
| 162 | 158 | |
| 163 | To make sure that the =git= user is only used for git operations and | |
| 164 | nothing else, you need to change the user's login shell. To do this, | |
| 165 | simply use the =chsh= command: | |
| 159 | To make sure that the =git= user is only used for git operations and nothing | |
| 160 | else, you need to change the user's login shell. To do this, simply use the | |
| 161 | =chsh= command: | |
| 166 | 162 | |
| 167 | 163 | #+begin_src sh |
| 168 | 164 | sudo chsh git |
| 169 | 165 | #+end_src |
| 170 | 166 | |
| 171 | The interactive prompt will ask which shell you want the =git= user to | |
| 172 | use. You must use the following value: | |
| 167 | The interactive prompt will ask which shell you want the =git= user to use. You | |
| 168 | must use the following value: | |
| 173 | 169 | |
| 174 | 170 | #+begin_src sh |
| 175 | 171 | /usr/bin/git-shell |
| 176 | 172 | #+end_src |
| 177 | 173 | |
| 178 | Once done, no one will be able to SSH to the =git= user or execute | |
| 179 | commands other than the standard git commands. | |
| 174 | Once done, no one will be able to SSH to the =git= user or execute commands | |
| 175 | other than the standard git commands. | |
| 180 | 176 | |
| 181 | 177 | * Opening the Firewall |
| 182 | 178 | |
| 183 | Don't forget to open up ports on the device firewall and network | |
| 184 | firewall if you want to access these repositories publicly. If you're | |
| 185 | using default ports, forward ports =22= (ssh) and =9418= (git) from your | |
| 186 | router to your server's IP address. | |
| 179 | Don't forget to open up ports on the device firewall and network firewall if you | |
| 180 | want to access these repositories publicly. If you're using default ports, | |
| 181 | forward ports =22= (ssh) and =9418= (git) from your router to your server's IP | |
| 182 | address. | |
| 187 | 183 | |
| 188 | If your server also has a firewall, ensure that the firewall allows the | |
| 189 | same ports that are forwarded from the router. For example, if you use | |
| 190 | =ufw=: | |
| 184 | If your server also has a firewall, ensure that the firewall allows the same | |
| 185 | ports that are forwarded from the router. For example, if you use =ufw=: | |
| 191 | 186 | |
| 192 | 187 | #+begin_src sh |
| 193 | 188 | sudo ufw allow 22 |
| @@ -196,12 +191,12 @@ sudo ufw allow 9418 | ||
| 196 | 191 | |
| 197 | 192 | ** Non-Standard SSH Ports |
| 198 | 193 | |
| 199 | If you use a non-standard port for SSH, such as =9876=, you will need to | |
| 200 | create an SSH configuration file on your local development machine in | |
| 201 | order to connect to your server's git repositories. | |
| 194 | If you use a non-standard port for SSH, such as =9876=, you will need to create | |
| 195 | an SSH configuration file on your local development machine in order to connect | |
| 196 | to your server's git repositories. | |
| 202 | 197 | |
| 203 | To do this, you'll need to define your custom port on your client | |
| 204 | machine in your =~/.ssh/config= file: | |
| 198 | To do this, you'll need to define your custom port on your client machine in | |
| 199 | your =~/.ssh/config= file: | |
| 205 | 200 | |
| 206 | 201 | #+begin_src sh |
| 207 | 202 | nano ~/.ssh/config |
| @@ -222,8 +217,8 @@ There are two main syntaxes you can use to manage git over SSH: | ||
| 222 | 217 | - =git clone [user@]server:project.git= |
| 223 | 218 | - =git clone ssh://[user@]server/project.git= |
| 224 | 219 | |
| 225 | I prefer the first, which is an =scp=-like syntax. To test it, try to | |
| 226 | clone the test repository you set up on the server: | |
| 220 | I prefer the first, which is an =scp=-like syntax. To test it, try to clone the | |
| 221 | test repository you set up on the server: | |
| 227 | 222 | |
| 228 | 223 | #+begin_src sh |
| 229 | 224 | git clone git@git.example.com:/git/test.git |
| @@ -231,9 +226,8 @@ git clone git@git.example.com:/git/test.git | ||
| 231 | 226 | |
| 232 | 227 | * Enabling Read-Only Access |
| 233 | 228 | |
| 234 | If you want people to be able to clone any repository where you've | |
| 235 | placed a =git-daemon-export-ok= file, you will need to start the git | |
| 236 | daemon. | |
| 229 | If 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. | |
| 237 | 231 | |
| 238 | 232 | To do this on a system with =systemd=, create a service file: |
| 239 | 233 | |
| @@ -271,8 +265,7 @@ sudo systemctl enable git-daemon.service | ||
| 271 | 265 | sudo systemctl start git-daemon.service |
| 272 | 266 | #+end_src |
| 273 | 267 | |
| 274 | To clone read-only via the =git://= protocol, you can use the following | |
| 275 | syntax: | |
| 268 | To clone read-only via the =git://= protocol, you can use the following syntax: | |
| 276 | 269 | |
| 277 | 270 | #+begin_src sh |
| 278 | 271 | git clone git://git.example.com/test.git |
| @@ -283,9 +276,9 @@ git clone git://git.example.com/test.git | ||
| 283 | 276 | At this point, we have a working git server that works with both SSH and |
| 284 | 277 | read-only access. |
| 285 | 278 | |
| 286 | For each of the repositories I had hosted a different provider, I | |
| 287 | executed the following commands in order to place a copy on my server as | |
| 288 | my new source of truth: | |
| 279 | For each of the repositories I had hosted a different provider, I executed the | |
| 280 | following commands in order to place a copy on my server as my new source of | |
| 281 | truth: | |
| 289 | 282 | |
| 290 | 283 | Server: |
| 291 | 284 | |
| @@ -308,20 +301,20 @@ git push | ||
| 308 | 301 | |
| 309 | 302 | * Optional Web View: =cgit= |
| 310 | 303 | |
| 311 | If you want a web viewer for your repositories, you can use various | |
| 312 | tools, such as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its | |
| 313 | simple interface and fairly easy set-up (compared to others). Not to | |
| 314 | mention that the [[https://git.kernel.org/][Linux kernel uses =cgit=]]. | |
| 304 | If you want a web viewer for your repositories, you can use various tools, such | |
| 305 | as =gitweb=, =cgit=, or =klaus=. I chose =cgit= due to its simple interface and | |
| 306 | fairly easy set-up (compared to others). Not to mention that the [[https://git.kernel.org/][Linux kernel | |
| 307 | uses =cgit=]]. | |
| 315 | 308 | |
| 316 | 309 | ** Docker Compose |
| 317 | 310 | |
| 318 | Instead of using my previous method of using a =docker run= command, | |
| 319 | I've updated this section to use =docker-compose= instead for an easier | |
| 320 | installation and simpler management and configuration. | |
| 311 | Instead of using my previous method of using a =docker run= command, I've | |
| 312 | updated this section to use =docker-compose= instead for an easier installation | |
| 313 | and simpler management and configuration. | |
| 321 | 314 | |
| 322 | In order to use Docker Compose, you will set up a =docker-compose.yml= | |
| 323 | file to automatically connect resources like the repositories, =cgitrc=, | |
| 324 | and various files or folders to the =cgit= container you're creating: | |
| 315 | In order to use Docker Compose, you will set up a =docker-compose.yml= file to | |
| 316 | automatically connect resources like the repositories, =cgitrc=, and various | |
| 317 | files or folders to the =cgit= container you're creating: | |
| 325 | 318 | |
| 326 | 319 | #+begin_src sh |
| 327 | 320 | mkdir ~/cgit && cd ~/cgit |
| @@ -352,16 +345,16 @@ Then, just start the container: | ||
| 352 | 345 | sudo docker-compose up -d |
| 353 | 346 | #+end_src |
| 354 | 347 | |
| 355 | Once 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 | |
| 357 | URL, such as =git.example.com=. See the next section for more details on | |
| 358 | reverse proxying a URL to a local port. | |
| 348 | Once it's finished installing, you can access the site at =<SERVER_IP>:8763= or | |
| 349 | use 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 | |
| 351 | URL to a local port. | |
| 359 | 352 | |
| 360 | 353 | ** Nginx Reverse Proxy |
| 361 | 354 | |
| 362 | I am using Nginx as my reverse proxy so that the =cgit= Docker container | |
| 363 | can use =git.example.com= as its URL. To do so, I simply created the | |
| 364 | following configuration file: | |
| 355 | I 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 | |
| 357 | created the following configuration file: | |
| 365 | 358 | |
| 366 | 359 | #+begin_src sh |
| 367 | 360 | sudo 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/ | ||
| 410 | 403 | sudo systemctl restart nginx.service |
| 411 | 404 | #+end_src |
| 412 | 405 | |
| 413 | As we can see below, my site at =git.example.com= is available and | |
| 414 | running: | |
| 406 | As we can see below, my site at =git.example.com= is available and running: | |
| 415 | 407 | |
| 416 | 408 | ** Settings Up Git Details |
| 417 | 409 | |
| 418 | Once you have =cgit= running, you can add some small details, such as | |
| 419 | repository owners and descriptions by editing the following files within | |
| 420 | each repository. | |
| 410 | Once you have =cgit= running, you can add some small details, such as repository | |
| 411 | owners and descriptions by editing the following files within each repository. | |
| 421 | 412 | |
| 422 | Alternatively, you can use the =cgitrc= file to edit these details if | |
| 423 | you only care to edit them for the purpose of seeing them on your | |
| 424 | website. | |
| 413 | Alternatively, you can use the =cgitrc= file to edit these details if you only | |
| 414 | care to edit them for the purpose of seeing them on your website. | |
| 425 | 415 | |
| 426 | The =description= file within the repository on your server will display | |
| 427 | the description online. | |
| 416 | The =description= file within the repository on your server will display the | |
| 417 | description online. | |
| 428 | 418 | |
| 429 | 419 | #+begin_src sh |
| 430 | 420 | cd /git/example.git |
| 431 | 421 | nano description |
| 432 | 422 | #+end_src |
| 433 | 423 | |
| 434 | You can add a =[gitweb]= block to the =config= file in order to display | |
| 435 | the owner of the repository. | |
| 424 | You can add a =[gitweb]= block to the =config= file in order to display the | |
| 425 | owner of the repository. | |
| 436 | 426 | |
| 437 | 427 | #+begin_src sh |
| 438 | 428 | cd /git/example.git |
| @@ -444,22 +434,20 @@ nano config | ||
| 444 | 434 | owner = "YourName" |
| 445 | 435 | #+end_src |
| 446 | 436 | |
| 447 | Note that you can ignore the configuration within each repository and | |
| 448 | simply set up this information in the =cgitrc= file, if you want to do | |
| 449 | it that way. | |
| 437 | Note that you can ignore the configuration within each repository and simply set | |
| 438 | up this information in the =cgitrc= file, if you want to do it that way. | |
| 450 | 439 | |
| 451 | 440 | ** Editing =cgit= |
| 452 | 441 | |
| 453 | In order to edit certain items within =cgit=, you need to edit the | |
| 454 | =cgitrc= file. | |
| 442 | In order to edit certain items within =cgit=, you need to edit the =cgitrc= | |
| 443 | file. | |
| 455 | 444 | |
| 456 | 445 | #+begin_src sh |
| 457 | 446 | nano ~/cgit/cgitrc |
| 458 | 447 | #+end_src |
| 459 | 448 | |
| 460 | 449 | Below is an example configuration for =cgitrc=. You can find all the |
| 461 | configuration options within the [configuration manual] | |
| 462 | ([[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt]]). | |
| 450 | configuration options within the [[https://git.zx2c4.com/cgit/plain/cgitrc.5.txt][configuration manual]]. | |
| 463 | 451 | |
| 464 | 452 | #+begin_src conf |
| 465 | 453 | css=/cgit.css |
| @@ -537,15 +525,14 @@ repo.desc=An example repository! | ||
| 537 | 525 | |
| 538 | 526 | ** Final Fixes: Syntax Highlighting & README Rendering |
| 539 | 527 | |
| 540 | After completing my initial install and playing around with it for a few | |
| 541 | days, I noticed two issues: | |
| 528 | After completing my initial install and playing around with it for a few days, I | |
| 529 | noticed two issues: | |
| 542 | 530 | |
| 543 | 1. Syntax highlighting did not work when viewing the source code within | |
| 544 | a file. | |
| 531 | 1. Syntax highlighting did not work when viewing the source code within a file. | |
| 545 | 532 | 2. The =about= tab within a repository was not rendered to HTML. |
| 546 | 533 | |
| 547 | The following process fixes these issues. To start, let's go to the | |
| 548 | =cgit= directory where we were editing our configuration file earlier. | |
| 534 | The following process fixes these issues. To start, let's go to the =cgit= | |
| 535 | directory where we were editing our configuration file earlier. | |
| 549 | 536 | |
| 550 | 537 | #+begin_src sh |
| 551 | 538 | cd ~/cgit |
| @@ -575,14 +562,12 @@ curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html | ||
| 575 | 562 | chmod 755 md2html |
| 576 | 563 | #+end_src |
| 577 | 564 | |
| 578 | If you need other filters or html-converters found within | |
| 579 | [[https://git.zx2c4.com/cgit/tree/filters][the cgit project files]], | |
| 580 | repeat the =curl= and =chmod= process above for whichever files you | |
| 581 | need. | |
| 565 | If you need other filters or html-converters found within [[https://git.zx2c4.com/cgit/tree/filters][the cgit project | |
| 566 | files]], repeat the =curl= and =chmod= process above for whichever files you need. | |
| 582 | 567 | |
| 583 | However, formatting will not work quite yet since the Docker cgit | |
| 584 | container we're using doesn't have the formatting package installed. You | |
| 585 | can install this easily by install Python 3+ and the =pygments= package: | |
| 568 | However, formatting will not work quite yet since the Docker cgit container | |
| 569 | we're using doesn't have the formatting package installed. You can install this | |
| 570 | easily by install Python 3+ and the =pygments= package: | |
| 586 | 571 | |
| 587 | 572 | #+begin_src sh |
| 588 | 573 | # Enter the container's command line |
| @@ -601,8 +586,8 @@ exit | ||
| 601 | 586 | *You will need to enter the cgit docker container and re-run these =yum= |
| 602 | 587 | commands every time you kill and restart the container!* |
| 603 | 588 | |
| 604 | If 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: | |
| 589 | If not done already, we need to add the following variables to our =cgitrc= file | |
| 590 | in order for =cgit= to know where our filtering files are: | |
| 606 | 591 | |
| 607 | 592 | #+begin_src conf |
| 608 | 593 | # Highlight source code with python pygments-based highlighter |
| @@ -613,26 +598,24 @@ source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py | ||
| 613 | 598 | about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh |
| 614 | 599 | #+end_src |
| 615 | 600 | |
| 616 | Now you should see that syntax highlighting and README rendering to the | |
| 617 | =about= tab is fixed. | |
| 601 | Now you should see that syntax highlighting and README rendering to the =about= | |
| 602 | tab is fixed. | |
| 618 | 603 | |
| 619 | 604 | ** Theming |
| 620 | 605 | |
| 621 | I won't go into much detail in this section, but you can fully theme | |
| 622 | your installation of =cgit= since you have access to the =cgit.css= file | |
| 623 | in 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 | |
| 625 | container's command line. | |
| 606 | I won't go into much detail in this section, but you can fully theme your | |
| 607 | installation of =cgit= since you have access to the =cgit.css= file in your web | |
| 608 | root. This is another file you can add as a volume to the =docker-compose.yml= | |
| 609 | file if you want to edit this without entering the container's command line. | |
| 626 | 610 | |
| 627 | *** :warning: Remember to Back Up Your Data! | |
| 611 | *** Remember to Back Up Your Data! | |
| 628 | 612 | |
| 629 | The last thing to note is that running services on your own equipment | |
| 630 | means that you're assuming a level of risk that exists regarding data | |
| 631 | loss, catastrophes, etc. In order to reduce the impact of any such | |
| 632 | occurrence, I suggest backing up your data regularly. | |
| 613 | The last thing to note is that running services on your own equipment means that | |
| 614 | you're assuming a level of risk that exists regarding data loss, catastrophes, | |
| 615 | etc. In order to reduce the impact of any such occurrence, I suggest backing up | |
| 616 | your data regularly. | |
| 633 | 617 | |
| 634 | Backups can be automated via =cron=, by hooking your base directory up | |
| 635 | to a cloud provider, or even setting up hooks to push all repository | |
| 636 | info to git mirrors on other git hosts. Whatever the method, make sure | |
| 637 | that your data doesn't vanish in the event that your drives or servers | |
| 638 | fail. | |
| 618 | Backups can be automated via =cron=, by hooking your base directory up to a | |
| 619 | cloud provider, or even setting up hooks to push all repository info to git | |
| 620 | mirrors on other git hosts. Whatever the method, make sure that your data | |
| 621 | doesn't vanish in the event that your drives or servers fail. | |
content/blog/2022-07-14-gnupg.org +111 −127
| @@ -5,33 +5,30 @@ | ||
| 5 | 5 | |
| 6 | 6 | * The History of GPG |
| 7 | 7 | |
| 8 | [[https://gnupg.org/][GNU Privacy Guard]], also known as GnuPG and GPG, | |
| 9 | is a free ("free" as in both speech and beer) software that fully | |
| 10 | implements the OpenPGP Message Format documented in | |
| 11 | [[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]]. | |
| 12 | ||
| 13 | I won't go in-depth on the full history of the software in this post, | |
| 14 | but 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. | |
| 16 | However, GPG was designed to interoperate with PGP. | |
| 17 | ||
| 18 | GPG 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 | |
| 9 | speech and beer) software that fully implements the OpenPGP Message Format | |
| 10 | documented in [[https://www.rfc-editor.org/rfc/rfc4880][RFC 4880]]. | |
| 11 | ||
| 12 | I won't go in-depth on the full history of the software in this post, but it is | |
| 13 | important to understand that GPG is not the same as PGP (Pretty Good Privacy), | |
| 14 | which is a different implementation of RFC 4880. However, GPG was designed to | |
| 15 | interoperate with PGP. | |
| 16 | ||
| 17 | GPG was originally developed in the late 1990s by [[https://en.wikipedia.org/wiki/Werner_Koch][Werner Koch]] and has | |
| 20 | 18 | historically been funded generously by the German government. |
| 21 | 19 | |
| 22 | Now that we have all the high-level info out of the way, let's dive into | |
| 23 | the different aspects of GPG and its uses. | |
| 20 | Now that we have all the high-level info out of the way, let's dive into the | |
| 21 | different aspects of GPG and its uses. | |
| 24 | 22 | |
| 25 | 23 | * Encryption Algorithms |
| 26 | 24 | |
| 27 | 25 | GPG supports a wide range of different encryption algorithms, including |
| 28 | public-key, cipher, hash, and compression algorithms. The support for | |
| 29 | these algorithms has grown since the adoption of the Libgcrypt library | |
| 30 | in the 2.x versions of GPG. | |
| 26 | public-key, cipher, hash, and compression algorithms. The support for these | |
| 27 | algorithms has grown since the adoption of the Libgcrypt library in the 2.x | |
| 28 | versions of GPG. | |
| 31 | 29 | |
| 32 | As you will be able to see below in an example of a full key generation | |
| 33 | with the GPG command line tool, GPG recommends the following algorithms | |
| 34 | to new users: | |
| 30 | As you will be able to see below in an example of a full key generation with the | |
| 31 | GPG command line tool, GPG recommends the following algorithms to new users: | |
| 35 | 32 | |
| 36 | 33 | #+begin_src sh |
| 37 | 34 | Please select what kind of key you want: |
| @@ -43,46 +40,39 @@ Please select what kind of key you want: | ||
| 43 | 40 | (10) ECC (sign only) |
| 44 | 41 | #+end_src |
| 45 | 42 | |
| 46 | I am not doing an in-depth explanation here in order to keep the focus | |
| 47 | on GPG and not encryption algorithms. If you want a deep dive into | |
| 48 | cryptography or encryption algorithms, please read my other posts: | |
| 43 | I am not doing an in-depth explanation here in order to keep the focus on GPG | |
| 44 | and not encryption algorithms. If you want a deep dive into cryptography or | |
| 45 | encryption algorithms, please read my other posts: | |
| 49 | 46 | |
| 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) | |
| 52 | 49 | |
| 53 | 50 | ** Vulnerabilities |
| 54 | 51 | |
| 55 | As of 2022-07-14, there are a few different vulnerabilities associated | |
| 56 | with 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. ( | |
| 52 | As of 2022-07-14, there are a few different vulnerabilities associated with GPG | |
| 53 | or 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. ( | |
| 67 | 61 | [[https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html][Source]]) |
| 68 | - Libgcrypt, a library used by GPG, contained a bug which enabled full | |
| 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. | |
| 73 | 66 | ([[https://crocs.fi.muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf][Source]]) |
| 74 | - The [[https://en.wikipedia.org/wiki/SigSpoof][SigSpoof Attack]] allows | |
| 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]]) | |
| 80 | 70 | |
| 81 | 71 | *** Platforms |
| 82 | 72 | |
| 83 | Originally developed as a command-line program for *nix systems, GPG now | |
| 84 | has a wealth of front-end applications and libraries available for | |
| 85 | end-users. However, the most recommended programs remain the same: | |
| 73 | Originally developed as a command-line program for *nix systems, GPG now has a | |
| 74 | wealth of front-end applications and libraries available for end-users. However, | |
| 75 | the most recommended programs remain the same: | |
| 86 | 76 | |
| 87 | 77 | - [[https://gnupg.org][GnuPG]] for Linux (depending on distro) |
| 88 | 78 | - [[https://gpg4win.org][Gpg4win]] for Windows |
| @@ -90,27 +80,25 @@ end-users. However, the most recommended programs remain the same: | ||
| 90 | 80 | |
| 91 | 81 | * Creating a Key Pair |
| 92 | 82 | |
| 93 | In order to create a GPG key pair, a user would first need to install | |
| 94 | GPG on their system. If we're assuming that the user is on Fedora Linux, | |
| 95 | they would execute the following: | |
| 83 | In order to create a GPG key pair, a user would first need to install GPG on | |
| 84 | their system. If we're assuming that the user is on Fedora Linux, they would | |
| 85 | execute the following: | |
| 96 | 86 | |
| 97 | 87 | #+begin_src sh |
| 98 | 88 | sudo dnf install gpg |
| 99 | 89 | #+end_src |
| 100 | 90 | |
| 101 | Once installed, a user can create a new key pair with the following | |
| 102 | command(s): | |
| 91 | Once installed, a user can create a new key pair with the following command(s): | |
| 103 | 92 | |
| 104 | 93 | #+begin_src sh |
| 105 | 94 | gpg --full-generate-key |
| 106 | 95 | #+end_src |
| 107 | 96 | |
| 108 | GPG will walk the user through an interactive setup that asks for an | |
| 109 | algorithm preference, expiration date, name, and email to associate with | |
| 110 | this key. | |
| 97 | GPG will walk the user through an interactive setup that asks for an algorithm | |
| 98 | preference, expiration date, name, and email to associate with this key. | |
| 111 | 99 | |
| 112 | See the following example key set-up for a default key generation using | |
| 113 | the GnuPG command-line interface: | |
| 100 | See the following example key set-up for a default key generation using the | |
| 101 | GnuPG command-line interface: | |
| 114 | 102 | |
| 115 | 103 | #+begin_src sh |
| 116 | 104 | gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc. |
| @@ -166,12 +154,13 @@ uid John Doe (test key) <johndoe@example.com> | ||
| 166 | 154 | sub cv25519 2022-07-14 [E] |
| 167 | 155 | #+end_src |
| 168 | 156 | |
| 169 | Please note that GUI apps may differ slightly from the GPG command-line | |
| 157 | Please note that graphical apps may differ slightly from the GPG command-line | |
| 170 | 158 | interface. |
| 171 | 159 | |
| 172 | 160 | * Common Usage |
| 173 | 161 | |
| 174 | As noted in RFC 4880, the general functions of OpenPGP are as follows: | |
| 162 | As noted in RFC (Request for Comments) 4880, the general functions of OpenPGP | |
| 163 | are as follows: | |
| 175 | 164 | |
| 176 | 165 | - digital signatures |
| 177 | 166 | - encryption |
| @@ -179,59 +168,57 @@ As noted in RFC 4880, the general functions of OpenPGP are as follows: | ||
| 179 | 168 | - Radix-64 conversion |
| 180 | 169 | - key management and certificate services |
| 181 | 170 | |
| 182 | From this, you can probably gather that the main use of GPG is for | |
| 183 | encrypting data and/or signing the data with a key. The purpose of | |
| 184 | encrypting data with GPG is to ensure that no one except the intended | |
| 185 | recipient(s) can access the data. | |
| 171 | From this, you can probably gather that the main use of GPG is for encrypting | |
| 172 | data and/or signing the data with a key. The purpose of encrypting data with GPG | |
| 173 | is to ensure that no one except the intended recipient(s) can access the data. | |
| 186 | 174 | |
| 187 | 175 | Let's explore some specific GPG use-cases. |
| 188 | 176 | |
| 189 | 177 | |
| 190 | 178 | |
| 191 | One of the more popular uses of GPG is to sign and/or encrypt emails. | |
| 192 | With the use of a GPG keypair, you can encrypt a message, its subject, | |
| 193 | and even the attachments within. | |
| 194 | ||
| 195 | The first process, regarding the signing of a message without any | |
| 196 | encryption, is generally used to provide assurance that an email is | |
| 197 | truly coming from the sender that the message claims. When I send an | |
| 198 | email, and it's signed with my public key, the recipient(s) of the | |
| 199 | message can verify that the message was signed with my personal key. | |
| 200 | ||
| 201 | The second process, regarding the actual encryption of the message and | |
| 202 | its contents, works by using a combination of the sender's keys and the | |
| 203 | recipient's keys. This process may vary slightly by implementation, but | |
| 204 | it most commonly uses asymmetric cryptography, also known as public-key | |
| 205 | cryptography. In this version of encryption, the sender's private key to | |
| 206 | sign the message and a combination of the sender's keys and the | |
| 207 | recipient's public key to encrypt the message. | |
| 208 | ||
| 209 | If two people each have their own private keys and exchange their public | |
| 210 | keys, they can send encrypted messages back and forth with GPG. This is | |
| 211 | also possible with symmetric cryptography, but the process differs since | |
| 212 | there are no key pairs. | |
| 213 | ||
| 214 | Implementation of email encryption varies greatly between email clients, | |
| 215 | so you will need to reference your email client's documentation to | |
| 216 | ensure you are setting it up correctly for that specific client. | |
| 179 | One of the more popular uses of GPG is to sign and/or encrypt emails. With the | |
| 180 | use of a GPG keypair, you can encrypt a message, its subject, and even the | |
| 181 | attachments within. | |
| 182 | ||
| 183 | The first process, regarding the signing of a message without any encryption, is | |
| 184 | generally used to provide assurance that an email is truly coming from the | |
| 185 | sender that the message claims. When I send an email, and it's signed with my | |
| 186 | public key, the recipient(s) of the message can verify that the message was | |
| 187 | signed with my personal key. | |
| 188 | ||
| 189 | The second process, regarding the actual encryption of the message and its | |
| 190 | contents, works by using a combination of the sender's keys and the recipient's | |
| 191 | keys. This process may vary slightly by implementation, but it most commonly | |
| 192 | uses asymmetric cryptography, also known as public-key cryptography. In this | |
| 193 | version of encryption, the sender's private key to sign the message and a | |
| 194 | combination of the sender's keys and the recipient's public key to encrypt the | |
| 195 | message. | |
| 196 | ||
| 197 | If two people each have their own private keys and exchange their public keys, | |
| 198 | they can send encrypted messages back and forth with GPG. This is also possible | |
| 199 | with symmetric cryptography, but the process differs since there are no key | |
| 200 | pairs. | |
| 201 | ||
| 202 | Implementation of email encryption varies greatly between email clients, so you | |
| 203 | will need to reference your email client's documentation to ensure you are | |
| 204 | setting it up correctly for that specific client. | |
| 217 | 205 | |
| 218 | 206 | ** File Encryption |
| 219 | 207 | |
| 220 | As noted in the section above regarding emails, GPG enables users to be | |
| 221 | able to send a message to each other if they are both set-up with GPG | |
| 222 | keys. In this example, I am going to show how a user could send a file | |
| 223 | called =example_file.txt= to another user via the recipient's email. | |
| 208 | As noted in the section above regarding emails, GPG enables users to be able to | |
| 209 | send a message to each other if they are both set-up with GPG keys. In this | |
| 210 | example, 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. | |
| 224 | 212 | |
| 225 | The sender would find the file they want to send and execute the | |
| 226 | following command: | |
| 213 | The sender would find the file they want to send and execute the following | |
| 214 | command: | |
| 227 | 215 | |
| 228 | 216 | #+begin_src sh |
| 229 | 217 | gpg --encrypt --output example_file.txt.gpg --recipient \ |
| 230 | 218 | recipient@example.com example_file.txt |
| 231 | 219 | #+end_src |
| 232 | 220 | |
| 233 | Once received, the recipient can decrypt the file with the following | |
| 234 | command: | |
| 221 | Once received, the recipient can decrypt the file with the following command: | |
| 235 | 222 | |
| 236 | 223 | #+begin_src sh |
| 237 | 224 | gpg --decrypt --output example_file.txt example_file.txt.gpg |
| @@ -239,29 +226,28 @@ gpg --decrypt --output example_file.txt example_file.txt.gpg | ||
| 239 | 226 | |
| 240 | 227 | ** Ownership Signatures |
| 241 | 228 | |
| 242 | One important aspect of GPG, especially for developers, is the ability | |
| 243 | to sign data without encrypting it. For example, developers often sign | |
| 244 | code changes when they commit the changes back to a central repository, | |
| 245 | in order to display ownership of who made the changes. This allows other | |
| 246 | users to look at a code change and determine that the change was valid. | |
| 229 | One important aspect of GPG, especially for developers, is the ability to sign | |
| 230 | data without encrypting it. For example, developers often sign code changes when | |
| 231 | they commit the changes back to a central repository, in order to display | |
| 232 | ownership of who made the changes. This allows other users to look at a code | |
| 233 | change and determine that the change was valid. | |
| 247 | 234 | |
| 248 | In order to do this using [[https://git-scm.com][Git]], the developer | |
| 249 | simply needs to alter the =git commit= command to include the =-S= flag. | |
| 250 | Here's an example: | |
| 235 | In order to do this using [[https://git-scm.com][Git]], the developer simply needs to alter the =git | |
| 236 | commit= command to include the =-S= flag. Here's an example: | |
| 251 | 237 | |
| 252 | 238 | #+begin_src sh |
| 253 | 239 | git commit -S -m "my commit message" |
| 254 | 240 | #+end_src |
| 255 | 241 | |
| 256 | As an expansion of the example above, Git users can configure their | |
| 257 | environment with a default key to use by adding their GPG signature: | |
| 242 | As an expansion of the example above, Git users can configure their environment | |
| 243 | with a default key to use by adding their GPG signature: | |
| 258 | 244 | |
| 259 | 245 | #+begin_src sh |
| 260 | 246 | git config --global user.signingkey XXXXXXXXXXXXXXXX |
| 261 | 247 | #+end_src |
| 262 | 248 | |
| 263 | If you're not sure what your signature is, you can find it titled =sig= | |
| 264 | in the output of this command: | |
| 249 | If you're not sure what your signature is, you can find it titled =sig= in the | |
| 250 | output of this command: | |
| 265 | 251 | |
| 266 | 252 | #+begin_src sh |
| 267 | 253 | gpg --list-signatures |
| @@ -269,12 +255,11 @@ gpg --list-signatures | ||
| 269 | 255 | |
| 270 | 256 | ** File Integrity |
| 271 | 257 | |
| 272 | When a person generates a signature for data, they are allowing users | |
| 273 | the ability to verify the signature on that data in the future to ensure | |
| 274 | the data has not been corrupted. This is most common with software | |
| 275 | applications hosted on the internet - developers provide signatures so | |
| 276 | that users can verify a website was not hijacked and download links | |
| 277 | replaced with dangerous software. | |
| 258 | When a person generates a signature for data, they are allowing users the | |
| 259 | ability to verify the signature on that data in the future to ensure the data | |
| 260 | has not been corrupted. This is most common with software applications hosted on | |
| 261 | the internet - developers provide signatures so that users can verify a website | |
| 262 | was not hijacked and download links replaced with dangerous software. | |
| 278 | 263 | |
| 279 | 264 | In order to verify signed data, a user needs to have: |
| 280 | 265 | |
| @@ -282,9 +267,8 @@ In order to verify signed data, a user needs to have: | ||
| 282 | 267 | 2. A signature file |
| 283 | 268 | 3. The public GPG key of the signer |
| 284 | 269 | |
| 285 | Once the signer's public key is imported on the user's system, and they | |
| 286 | have the data and signature, they can verify the data with the following | |
| 287 | commands: | |
| 270 | Once the signer's public key is imported on the user's system, and they have the | |
| 271 | data and signature, they can verify the data with the following commands: | |
| 288 | 272 | |
| 289 | 273 | #+begin_src sh |
| 290 | 274 | # If the signature is attached to the data |
| @@ -296,11 +280,11 @@ gpg --verify [signature-file] [original-file] | ||
| 296 | 280 | |
| 297 | 281 | *** Finding Public Keys |
| 298 | 282 | |
| 299 | In order to use GPG with others, a user needs to know the other user(s) | |
| 300 | keys. This is easy to do if the user knows the other user(s) in person, | |
| 301 | but may be hard if the relationship is strictly digital. Luckily, there | |
| 302 | are a few options. The first option is to look at a user's web page or | |
| 303 | social pages if they have them. | |
| 283 | In order to use GPG with others, a user needs to know the other user(s) keys. | |
| 284 | This is easy to do if the user knows the other user(s) in person, but may be | |
| 285 | hard if the relationship is strictly digital. Luckily, there are a few options. | |
| 286 | The first option is to look at a user's web page or social pages if they have | |
| 287 | them. | |
| 304 | 288 | |
| 305 | 289 | Otherwise, the best option is to use a keyserver, such as: |
| 306 | 290 | |
content/blog/2022-07-25-curseradio.org +24 −28
| @@ -6,28 +6,25 @@ | ||
| 6 | 6 | * Overview |
| 7 | 7 | |
| 8 | 8 | While exploring some interesting Linux applications, I stumbled across |
| 9 | [[https://github.com/chronitis/curseradio][curseradio]], a command-line | |
| 10 | radio player based on Python. | |
| 9 | [[https://github.com/chronitis/curseradio][curseradio]], a command-line radio player based on Python. | |
| 11 | 10 | |
| 12 | This application is fantastic and incredibly easy to install, so I | |
| 13 | wanted to dedicate a post today to this app. Let's look at the features | |
| 14 | within the app and then walk through the installation process I took to | |
| 15 | get =curseradio= working. | |
| 11 | This application is fantastic and incredibly easy to install, so I wanted to | |
| 12 | dedicate a post today to this app. Let's look at the features within the app and | |
| 13 | then walk through the installation process I took to get =curseradio= working. | |
| 16 | 14 | |
| 17 | 15 | * Features |
| 18 | 16 | |
| 19 | The radio player itself is quite minimal. As you can see in the | |
| 20 | screenshot above, it contains a simple plaintext list of all available | |
| 21 | categories, which can be broken down further and further. In addition, | |
| 22 | radio shows are available for listening, alongside regular radio | |
| 23 | stations. | |
| 17 | The radio player itself is quite minimal. As you can see in the screenshot | |
| 18 | above, it contains a simple plaintext list of all available categories, which | |
| 19 | can be broken down further and further. In addition, radio shows are available | |
| 20 | for listening, alongside regular radio stations. | |
| 24 | 21 | |
| 25 | For example, the =Sports= > =Pro Basketball= > =Shows= category contains | |
| 26 | a number of specific shows related to Professional Basketball. | |
| 22 | For example, the =Sports= > =Pro Basketball= > =Shows= category contains a | |
| 23 | number of specific shows related to Professional Basketball. | |
| 27 | 24 | |
| 28 | Aside from being able to play any of the listed stations/shows, you can | |
| 29 | make a channel your favorite by pressing =f=. It will now show up at the | |
| 30 | top of the radio player in the =Favourites= category. | |
| 25 | Aside from being able to play any of the listed stations/shows, you can make a | |
| 26 | channel your favorite by pressing =f=. It will now show up at the top of the | |
| 27 | radio player in the =Favourites= category. | |
| 31 | 28 | |
| 32 | 29 | ** Commands/Shortcuts |
| 33 | 30 | |
| @@ -45,11 +42,10 @@ top of the radio player in the =Favourites= category. | ||
| 45 | 42 | |
| 46 | 43 | ** Dependencies |
| 47 | 44 | |
| 48 | Before installing =curseradio=, a handful of system and Python packages | |
| 49 | are required. To get started, install =python3=, =pip3=, and =mpv= on | |
| 50 | your 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 | |
| 52 | different system. | |
| 45 | Before installing =curseradio=, a handful of system and Python packages are | |
| 46 | required. To get started, install =python3=, =pip3=, and =mpv= on your system. | |
| 47 | In this example, I'm using Fedora Linux, which uses the =dnf= package manager. | |
| 48 | You may need to adjust this if you're using a different system. | |
| 53 | 49 | |
| 54 | 50 | #+begin_src sh |
| 55 | 51 | sudo dnf install python3 pip3 mpv |
| @@ -63,23 +59,23 @@ pip3 install requests xdg lxml | ||
| 63 | 59 | |
| 64 | 60 | ** Repository Source Installation |
| 65 | 61 | |
| 66 | Once all the dependencies are installed, we can clone the source code | |
| 67 | and enter that directory: | |
| 62 | Once all the dependencies are installed, we can clone the source code and enter | |
| 63 | that directory: | |
| 68 | 64 | |
| 69 | 65 | #+begin_src sh |
| 70 | 66 | git clone https://github.com/chronitis/curseradio && cd curseradio |
| 71 | 67 | #+end_src |
| 72 | 68 | |
| 73 | Once you're within the =curseradio= directory, you can install the | |
| 74 | application with the provided =setup.py= script. | |
| 69 | Once you're within the =curseradio= directory, you can install the application | |
| 70 | with the provided =setup.py= script. | |
| 75 | 71 | |
| 76 | 72 | #+begin_src sh |
| 77 | 73 | sudo python3 setup.py install |
| 78 | 74 | #+end_src |
| 79 | 75 | |
| 80 | In my case, I ran into a few errors and needed to create the folders | |
| 81 | that curseradio wanted to use for its installation. If you don't get any | |
| 82 | errors, you can skip this and run the app. | |
| 76 | In my case, I ran into a few errors and needed to create the folders that | |
| 77 | curseradio wanted to use for its installation. If you don't get any errors, you | |
| 78 | can skip this and run the app. | |
| 83 | 79 | |
| 84 | 80 | #+begin_src sh |
| 85 | 81 | sudo mkdir /usr/local/lib/python3.10/ |
content/blog/2022-07-30-flac-to-opus.org +35 −38
| @@ -6,17 +6,15 @@ | ||
| 6 | 6 | * Converting FLAC to OPUS |
| 7 | 7 | |
| 8 | 8 | I am currently rebuilding my music library from scratch so that I can |
| 9 | effectively archive all the music I own in the | |
| 10 | [[https://en.wikipedia.org/wiki/FLAC][FLAC file format]], a lossless | |
| 11 | audio codec. | |
| 9 | effectively archive all the music I own in [[https://wikipedia.org/wiki/FLAC][FLAC]] (Free Lossless Audio Codec) | |
| 10 | files. | |
| 12 | 11 | |
| 13 | However, streaming FLAC files outside the home can be difficult due to | |
| 14 | the size of the files, especially if you're using a weak connection. | |
| 12 | However, streaming FLAC files outside the home can be difficult due to the size | |
| 13 | of the files, especially if you're using a weak connection. | |
| 15 | 14 | |
| 16 | So, in order to archive the music in a lossless format and still be able | |
| 17 | to 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]]. | |
| 19 | This allows me to archive a quality, lossless version of the music and | |
| 15 | So, in order to archive the music in a lossless format and still be able to | |
| 16 | stream it easily, I opted to create a copy of my FLAC files in the [[https://en.wikipedia.org/wiki/Opus_(audio_format)][Opus audio | |
| 17 | codec]]. This allows me to archive a quality, lossless version of the music and | |
| 20 | 18 | then point my streaming service to the smaller, stream-ready version. |
| 21 | 19 | |
| 22 | 20 | ** Dependencies |
| @@ -28,39 +26,38 @@ proceeding, install the package: | ||
| 28 | 26 | sudo apt install opus-tools |
| 29 | 27 | #+end_src |
| 30 | 28 | |
| 31 | If you want to use a different conversion method, such as =ffmpeg= or | |
| 32 | =avconv=, simply install that package instead. | |
| 29 | If you want to use a different conversion method, such as =ffmpeg= or =avconv=, | |
| 30 | simply install that package instead. | |
| 33 | 31 | |
| 34 | 32 | ** Conversion Process |
| 35 | 33 | |
| 36 | The script I'm using is stored in my home directory, but feel free to | |
| 37 | create it wherever you want. It does not need to be in the same | |
| 38 | directory as your music files. | |
| 34 | The script I'm using is stored in my home directory, but feel free to create it | |
| 35 | wherever you want. It does not need to be in the same directory as your music | |
| 36 | files. | |
| 39 | 37 | |
| 40 | 38 | #+begin_src sh |
| 41 | 39 | cd ~ && nano transform.sh |
| 42 | 40 | #+end_src |
| 43 | 41 | |
| 44 | Once you have your new bash script opened in an editor, go ahead and | |
| 45 | paste the following logic into the script. | |
| 42 | Once you have your new bash script opened in an editor, go ahead and paste the | |
| 43 | following logic into the script. | |
| 46 | 44 | |
| 47 | 45 | You *MUST* edit the following variables in order for it to work: |
| 48 | 46 | |
| 49 | 47 | - =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. | |
| 52 | 50 | |
| 53 | 51 | You *MAY* want to edit the following variables to suit your needs: |
| 54 | 52 | |
| 55 | - =filename=: If you are converting to a file format other than Opus, | |
| 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. | |
| 64 | 61 | |
| 65 | 62 | #+begin_src sh |
| 66 | 63 | #!/bin/bash |
| @@ -126,8 +123,8 @@ opusenc --vbr --bitrate 128 --date "$DATE" \ | ||
| 126 | 123 | done |
| 127 | 124 | #+end_src |
| 128 | 125 | |
| 129 | Once you're done, simply save the file and exit your editor. Don't | |
| 130 | forget to enable execution of the script: | |
| 126 | Once you're done, simply save the file and exit your editor. Don't forget to | |
| 127 | enable execution of the script: | |
| 131 | 128 | |
| 132 | 129 | #+begin_src sh |
| 133 | 130 | chmod +x transform.sh |
| @@ -139,16 +136,16 @@ Finally, you may now run the script: | ||
| 139 | 136 | ./transform.sh |
| 140 | 137 | #+end_src |
| 141 | 138 | |
| 142 | If you used =opusenc=, you'll see the conversions happen within the | |
| 143 | terminal as it progresses. You will also see variables printed if you | |
| 144 | uncommented any of the bash script's comments. | |
| 139 | If you used =opusenc=, you'll see the conversions happen within the terminal as | |
| 140 | it progresses. You will also see variables printed if you uncommented any of the | |
| 141 | bash script's comments. | |
| 145 | 142 | |
| 146 | 143 | ** Cleanup |
| 147 | 144 | |
| 148 | As I noted above, I didn't customize my =reldir= variable in the script, | |
| 149 | which caused my output directory to be =/mnt/music/library/archives= | |
| 150 | instead of =/mnt/music/library=. So, I moved the output up one level and | |
| 151 | deleted the accidental directory. | |
| 145 | As I noted above, I didn't customize my =reldir= variable in the script, which | |
| 146 | caused 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 | |
| 148 | accidental directory. | |
| 152 | 149 | |
| 153 | 150 | #+begin_src sh |
| 154 | 151 | cd /mnt/music/library |
| @@ -158,8 +155,8 @@ rm -rf archives | ||
| 158 | 155 | |
| 159 | 156 | ** Check the Resulting Size |
| 160 | 157 | |
| 161 | If you want to see what kind of file size savings you've gained, you can | |
| 162 | always use the =du= command to check: | |
| 158 | If you want to see what kind of file size savings you've gained, you can always | |
| 159 | use the =du= command to check: | |
| 163 | 160 | |
| 164 | 161 | #+begin_src sh |
| 165 | 162 | cd /mnt/music |
content/blog/2022-07-31-bash-it.org +57 −66
| @@ -5,14 +5,12 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Bash |
| 7 | 7 | |
| 8 | For those who are not familiar, | |
| 9 | [[https://en.wikipedia.org/wiki/Bash_(Unix_shell)][Bash]] is a Unix | |
| 10 | shell that is used as the default login shell for most Linux | |
| 11 | distributions. This shell and command processor should be familiar if | |
| 12 | you've used Linux (or older version of macOS) before. | |
| 8 | For those who are not familiar, [[https://en.wikipedia.org/wiki/Bash_(Unix_shell)][Bash]] is a Unix shell that is used as the default | |
| 9 | login shell for most Linux distributions. This shell and command processor | |
| 10 | should be familiar if you've used Linux (or older version of macOS) before. | |
| 13 | 11 | |
| 14 | However, bash is not the only option. There are numerous other shells | |
| 15 | that exist. Here are some popular examples: | |
| 12 | However, bash is not the only option. There are numerous other shells that | |
| 13 | exist. Here are some popular examples: | |
| 16 | 14 | |
| 17 | 15 | - [[https://en.wikipedia.org/wiki/Z_shell][zsh]] |
| 18 | 16 | - [[https://en.wikipedia.org/wiki/Fish_(Unix_shell)][fish]] |
| @@ -20,16 +18,15 @@ that exist. Here are some popular examples: | ||
| 20 | 18 | - [[https://wiki.gentoo.org/wiki/Mksh][mksh]] |
| 21 | 19 | - [[https://en.wikipedia.org/wiki/Debian_Almquist_shell][dash]] |
| 22 | 20 | |
| 23 | While each shell has its differences, bash is POSIX compliant and the | |
| 24 | default for many Linux users. Because of this, I am going to explore a | |
| 25 | program called =bash-it= below that helps bash users increase the | |
| 26 | utility of their shell without installing a completely new shell. | |
| 21 | While each shell has its differences, bash is POSIX compliant and the default | |
| 22 | for 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 | |
| 24 | without installing a completely new shell. | |
| 27 | 25 | |
| 28 | 26 | ** Installation |
| 29 | 27 | |
| 30 | First, if bash is not already installed on your system, you can | |
| 31 | [[https://www.gnu.org/software/bash/][download bash from GNU]] or use | |
| 32 | your package manager to install it. | |
| 28 | First, if bash is not already installed on your system, you can [[https://www.gnu.org/software/bash/][download bash | |
| 29 | from GNU]] or use your package manager to install it. | |
| 33 | 30 | |
| 34 | 31 | For example, this is how you can install bash on Fedora Linux: |
| 35 | 32 | |
| @@ -37,19 +34,19 @@ For example, this is how you can install bash on Fedora Linux: | ||
| 37 | 34 | sudo dnf install bash |
| 38 | 35 | #+end_src |
| 39 | 36 | |
| 40 | If you are not using bash as your default shell, use the =chsh= command | |
| 41 | to change your shell: | |
| 37 | If you are not using bash as your default shell, use the =chsh= command to | |
| 38 | change your shell: | |
| 42 | 39 | |
| 43 | 40 | #+begin_src sh |
| 44 | 41 | chsh |
| 45 | 42 | #+end_src |
| 46 | 43 | |
| 47 | You should see a prompt like the one below. If the brackets (=[]=) | |
| 48 | contain =bash= already, you're done, and you can simply continue by | |
| 49 | hitting the Enter key. | |
| 44 | You 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 | |
| 46 | key. | |
| 50 | 47 | |
| 51 | If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter | |
| 52 | the path to the bash program on your system (it's most likely located at | |
| 48 | If the brackets contain another shell path (e.g. =/usr/bin/zsh=), enter the path | |
| 49 | to the bash program on your system (it's most likely located at | |
| 53 | 50 | =/usr/bin/bash=). |
| 54 | 51 | |
| 55 | 52 | #+begin_src sh |
| @@ -57,9 +54,9 @@ Changing shell for <user>. | ||
| 57 | 54 | New shell [/usr/bin/bash]: |
| 58 | 55 | #+end_src |
| 59 | 56 | |
| 60 | You must log out or restart the machine in order for the login shell to | |
| 61 | be refreshed. You can do it now or wait until you're finished | |
| 62 | customizing the shell. | |
| 57 | You must log out or restart the machine in order for the login shell to be | |
| 58 | refreshed. You can do it now or wait until you're finished customizing the | |
| 59 | shell. | |
| 63 | 60 | |
| 64 | 61 | #+begin_src sh |
| 65 | 62 | sudo reboot now |
| @@ -67,31 +64,30 @@ sudo reboot now | ||
| 67 | 64 | |
| 68 | 65 | * Bash-it |
| 69 | 66 | |
| 70 | As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]] | |
| 71 | repository: | |
| 67 | As noted on the [[https://github.com/Bash-it/bash-it][Bash-it]] repository: | |
| 72 | 68 | |
| 73 | 69 | #+begin_quote |
| 74 | 70 | Bash-it is a collection of community Bash commands and scripts for Bash |
| 75 | 71 | 3.2+. (And a shameless ripoff of oh-my-zsh 😃) |
| 76 | 72 | #+end_quote |
| 77 | 73 | |
| 78 | Bash-it makes it easy to install plugins, set up aliases for common | |
| 79 | commands, and easily change the visual theme of your shell. | |
| 74 | Bash-it makes it easy to install plugins, set up aliases for common commands, | |
| 75 | and easily change the visual theme of your shell. | |
| 80 | 76 | |
| 81 | 77 | ** Installation |
| 82 | 78 | |
| 83 | 79 | To install the framework, simply copy the repository files and use the |
| 84 | =install.sh= script provided. If you want, you can (and should!) inspect | |
| 85 | the contents of the installation script before you run it. | |
| 80 | =install.sh= script provided. If you want, you can (and should!) inspect the | |
| 81 | contents of the installation script before you run it. | |
| 86 | 82 | |
| 87 | 83 | #+begin_src sh |
| 88 | 84 | git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it |
| 89 | 85 | ~/.bash_it/install.sh |
| 90 | 86 | #+end_src |
| 91 | 87 | |
| 92 | If you didn't restart your session after making bash the default, and | |
| 93 | are currently working within another shell, be sure to enter a bash | |
| 94 | session before using =bash-it=: | |
| 88 | If you didn't restart your session after making bash the default, and are | |
| 89 | currently working within another shell, be sure to enter a bash session before | |
| 90 | using =bash-it=: | |
| 95 | 91 | |
| 96 | 92 | #+begin_src sh |
| 97 | 93 | bash |
| @@ -100,16 +96,16 @@ bash | ||
| 100 | 96 | ** Aliases |
| 101 | 97 | |
| 102 | 98 | Bash-it contains a number of aliases for common commands to help improve |
| 103 | efficiency in the terminal. To list all available options, use the | |
| 104 | following command: | |
| 99 | efficiency in the terminal. To list all available options, use the following | |
| 100 | command: | |
| 105 | 101 | |
| 106 | 102 | #+begin_src sh |
| 107 | 103 | bash-it show aliases |
| 108 | 104 | #+end_src |
| 109 | 105 | |
| 110 | This will provide you a list that looks like the following text block. | |
| 111 | Within this screen, you will be able to see all available options and | |
| 112 | which ones are currently enabled. | |
| 106 | This will provide you a list that looks like the following text block. Within | |
| 107 | this screen, you will be able to see all available options and which ones are | |
| 108 | currently enabled. | |
| 113 | 109 | |
| 114 | 110 | #+begin_src txt |
| 115 | 111 | Alias Enabled? Description |
| @@ -140,9 +136,8 @@ bash-it disable alias <alias name> [alias name]... -or- $ bash-it disable alias | ||
| 140 | 136 | |
| 141 | 137 | ** Plugins |
| 142 | 138 | |
| 143 | Similar to aliases, plugins are available with bash-it. You can find a | |
| 144 | complete list of plugins in the same way as aliases. Simply execute the | |
| 145 | following: | |
| 139 | Similar to aliases, plugins are available with bash-it. You can find a complete | |
| 140 | list of plugins in the same way as aliases. Simply execute the following: | |
| 146 | 141 | |
| 147 | 142 | #+begin_src sh |
| 148 | 143 | bash-it show plugins |
| @@ -177,9 +172,7 @@ bash-it disable plugin <plugin name> [plugin name]... -or- $ bash-it disable plu | ||
| 177 | 172 | |
| 178 | 173 | ** Themes |
| 179 | 174 | |
| 180 | There are quite a few pre-defined | |
| 181 | [[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]] | |
| 182 | available with bash-it. | |
| 175 | There are quite a few pre-defined [[https://bash-it.readthedocs.io/en/latest/themes-list/#list-of-themes][themes]] available with bash-it. | |
| 183 | 176 | |
| 184 | 177 | To list all themes: |
| 185 | 178 | |
| @@ -187,9 +180,8 @@ To list all themes: | ||
| 187 | 180 | ls ~/.bash_it/themes/ |
| 188 | 181 | #+end_src |
| 189 | 182 | |
| 190 | To 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 | |
| 192 | the =zork= theme. | |
| 183 | To use a new theme, you'll need to edit =.bashrc= and alter the =BASH_IT_THEME= | |
| 184 | variable to your desired theme. For example, I am using the =zork= theme. | |
| 193 | 185 | |
| 194 | 186 | #+begin_src sh |
| 195 | 187 | nano ~/.bashrc |
| @@ -199,23 +191,22 @@ nano ~/.bashrc | ||
| 199 | 191 | export BASH_IT_THEME='zork' |
| 200 | 192 | #+end_src |
| 201 | 193 | |
| 202 | Once you save your changes, you just need to exit your terminal and | |
| 203 | create a new one in order to see your changes to the =.bashrc= file. You | |
| 204 | can also =source= the file to see changes, but I recommend starting a | |
| 205 | completely new shell instead. | |
| 194 | Once you save your changes, you just need to exit your terminal and create a new | |
| 195 | one in order to see your changes to the =.bashrc= file. You can also =source= | |
| 196 | the file to see changes, but I recommend starting a completely new shell | |
| 197 | instead. | |
| 206 | 198 | |
| 207 | 199 | *** ble.sh |
| 208 | 200 | |
| 209 | One big feature I was missing in Bash that both =zsh= and =fish= have is | |
| 210 | an autosuggestion feature. To explain: as you type, an autosuggestion | |
| 211 | feature in the shell will offer suggestions in a lighter font color | |
| 212 | beyond the characters already typed. Once you see the command you want, | |
| 213 | you can click the right arrow and have the shell auto-complete that line | |
| 214 | for you. | |
| 201 | One big feature I was missing in Bash that both =zsh= and =fish= have is an | |
| 202 | autosuggestion feature. To explain: as you type, an autosuggestion feature in | |
| 203 | the shell will offer suggestions in a lighter font color beyond the characters | |
| 204 | already typed. Once you see the command you want, you can click the right arrow | |
| 205 | and have the shell auto-complete that line for you. | |
| 215 | 206 | |
| 216 | Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]] | |
| 217 | (ble.sh) exists! This program provides a wonderful autosuggestions | |
| 218 | feature perfectly, among other features that I haven't tested yet. | |
| 207 | Luckily, the [[https://github.com/akinomyoga/ble.sh][Bash Line Editor]] (ble.sh) exists! This program provides a wonderful | |
| 208 | autosuggestions feature perfectly, among other features that I haven't tested | |
| 209 | yet. | |
| 219 | 210 | |
| 220 | 211 | In order to install ble.sh, execute the following: |
| 221 | 212 | |
| @@ -225,16 +216,16 @@ make -C ble.sh install PREFIX=~/.local | ||
| 225 | 216 | echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc |
| 226 | 217 | #+end_src |
| 227 | 218 | |
| 228 | Again, exit the terminal and open a new one in order to see the | |
| 229 | newly-configured shell. | |
| 219 | Again, exit the terminal and open a new one in order to see the newly-configured | |
| 220 | shell. | |
| 230 | 221 | |
| 231 | 222 | * Restart the Session |
| 232 | 223 | |
| 233 | Finally, as mentioned above, you'll need to restart the session to | |
| 234 | ensure that your user is using bash by default. | |
| 224 | Finally, as mentioned above, you'll need to restart the session to ensure that | |
| 225 | your user is using bash by default. | |
| 235 | 226 | |
| 236 | You will also need to exit and re-open a shell (e.g., terminal or | |
| 237 | terminal tab) any time you make changes to the =.bashrc= file. | |
| 227 | You will also need to exit and re-open a shell (e.g., terminal or terminal tab) | |
| 228 | any time you make changes to the =.bashrc= file. | |
| 238 | 229 | |
| 239 | 230 | #+begin_src sh |
| 240 | 231 | sudo reboot now |
content/blog/2022-08-31-privacy-com-changes.org +49 −56
| @@ -5,50 +5,46 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Privacy.com Changes Their Terms |
| 7 | 7 | |
| 8 | Recently, Privacy.com reached out to their customers regarding a change | |
| 9 | in their terms of use. Further, all customers are required to agree to | |
| 10 | the changes in order to continue using their accounts. | |
| 8 | Recently, Privacy.com reached out to their customers regarding a change in their | |
| 9 | terms of use. Further, all customers are required to agree to the changes in | |
| 10 | order to continue using their accounts. | |
| 11 | 11 | |
| 12 | [[https://privacy.com/commercial-cardholder-agreement][You can view the | |
| 13 | new cardholder agreement here]]. | |
| 12 | [[https://privacy.com/commercial-cardholder-agreement][You can view the new cardholder agreement here]]. | |
| 14 | 13 | |
| 15 | When you log in, you'll be greeted with a pop-up window asking you to | |
| 16 | review and agree to the new terms of use. You will also not be able to | |
| 17 | open any new cards until the terms are agreed to. | |
| 14 | When you log in, you'll be greeted with a pop-up window asking you to review and | |
| 15 | agree to the new terms of use. You will also not be able to open any new cards | |
| 16 | until the terms are agreed to. | |
| 18 | 17 | |
| 19 | 18 | ** Changing from a "Prepaid Debit" Model to a "Charge Card" Model |
| 20 | 19 | |
| 21 | The actual content of the changes is interesting. While the historical | |
| 22 | model of using Privacy.com was akin to prepaid debit cards, the new | |
| 23 | model is very similar to a credit card (they use the term "charge | |
| 24 | card"). | |
| 20 | The actual content of the changes is interesting. While the historical model of | |
| 21 | using Privacy.com was akin to prepaid debit cards, the new model is very similar | |
| 22 | to a credit card (they use the term "charge card"). | |
| 25 | 23 | |
| 26 | I have used Privacy.com for 1-2 years, and the process was always that | |
| 27 | you would create a single-use or merchant-locked card. This card could | |
| 28 | be used for any dollar limit you set and would immediately draw the | |
| 29 | funds from whatever funding source you connected, e.g. PayPal account or | |
| 30 | a bank account. | |
| 24 | I have used Privacy.com for 1-2 years, and the process was always that you would | |
| 25 | create a single-use or merchant-locked card. This card could be used for any | |
| 26 | dollar limit you set and would immediately draw the funds from whatever funding | |
| 27 | source you connected, e.g. PayPal account or a bank account. | |
| 31 | 28 | |
| 32 | The benefit this service provides with a premium account is masking the | |
| 33 | merchant names from your funding source. If you have a concern that your | |
| 34 | bank account uses merchant data from your account, you could direct all | |
| 35 | charges through Privacy.com and set the merchant as one of their pre-set | |
| 36 | options, such as "Smiley's Corner Store" or "NSA Gift Shop." | |
| 29 | The benefit this service provides with a premium account is masking the merchant | |
| 30 | names from your funding source. If you have a concern that your bank account | |
| 31 | uses merchant data from your account, you could direct all charges through | |
| 32 | Privacy.com and set the merchant as one of their pre-set options, such as | |
| 33 | "Smiley's Corner Store" or "NSA Gift Shop." | |
| 37 | 34 | |
| 38 | The new model still works with a bank account as a funding source, but | |
| 39 | the model is changed so that you get a "line of credit" set according to | |
| 40 | a 14-day billing cycle. It seems that Privacy.com will now allow charges | |
| 41 | to be incurred without being immediately paid. | |
| 35 | The new model still works with a bank account as a funding source, but the model | |
| 36 | is changed so that you get a "line of credit" set according to a 14-day billing | |
| 37 | cycle. It seems that Privacy.com will now allow charges to be incurred without | |
| 38 | being immediately paid. | |
| 42 | 39 | |
| 43 | 40 | ** Daily Payments and Available Credit |
| 44 | 41 | |
| 45 | Instead of paying as charges are incurred, you must make a "Daily | |
| 46 | Payment" and your "Available Credit" will be locked until you make that | |
| 47 | payment. There are also "End of Billing Cycle Payments" that are | |
| 48 | assigned a due date. | |
| 42 | Instead of paying as charges are incurred, you must make a "Daily Payment" and | |
| 43 | your "Available Credit" will be locked until you make that payment. There are | |
| 44 | also "End of Billing Cycle Payments" that are assigned a due date. | |
| 49 | 45 | |
| 50 | Further, Privacy.com will decline charges that would cause you to exceed | |
| 51 | your Available Credit or Credit Limit. | |
| 46 | Further, Privacy.com will decline charges that would cause you to exceed your | |
| 47 | Available Credit or Credit Limit. | |
| 52 | 48 | |
| 53 | 49 | One particular interesting section states the following: |
| 54 | 50 | |
| @@ -63,37 +59,34 @@ FOR MORE INFORMATION. | ||
| 63 | 59 | |
| 64 | 60 | ** Personal Information |
| 65 | 61 | |
| 66 | Now that Privacy.com is more of a financial institution, they are | |
| 67 | obligated to comply with the | |
| 68 | [[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]] | |
| 69 | guidelines/laws. | |
| 62 | Now that Privacy.com is more of a financial institution, they are obligated to | |
| 63 | comply with the [[https://en.wikipedia.org/wiki/Know_your_customer][know your customer]] guidelines/laws. | |
| 70 | 64 | |
| 71 | I did not proceed with the change to my Privacy.com account, but I have | |
| 72 | heard from some peers that the changes require more personal information | |
| 73 | to be submitted, such as SSN. I am not aware of all new personal | |
| 74 | information required or if the funding source is now required to only be | |
| 75 | a bank account. | |
| 65 | I did not proceed with the change to my Privacy.com account, but I have heard | |
| 66 | from some peers that the changes require more personal information to be | |
| 67 | submitted, such as SSN (Social Security Number). I am not aware of all new | |
| 68 | personal information required or if the funding source is now required to only | |
| 69 | be a bank account. | |
| 76 | 70 | |
| 77 | 71 | ** Fees |
| 78 | 72 | |
| 79 | Luckily, the fees section did not change much. The subscription fees for | |
| 80 | a premium account are still the only fees. | |
| 73 | Luckily, the fees section did not change much. The subscription fees for a | |
| 74 | premium account are still the only fees. | |
| 81 | 75 | |
| 82 | 76 | * My Thoughts |
| 83 | 77 | |
| 84 | Personally, I wiped my personal information from my account and then | |
| 85 | permanently deleted it when I heard about these changes. I have no | |
| 86 | interest in yet another method of credit lending offered by private | |
| 87 | companies. While I accepted that they would have access to my bank | |
| 88 | account information for the purposes of paying off my prepaid debit | |
| 89 | payments, I have no interest in incurring charges that will need to be | |
| 90 | paid back at a later date. I also have no interest in submitting | |
| 78 | Personally, I wiped my personal information from my account and then permanently | |
| 79 | deleted it when I heard about these changes. I have no interest in yet another | |
| 80 | method of credit lending offered by private companies. While I accepted that | |
| 81 | they would have access to my bank account information for the purposes of paying | |
| 82 | off my prepaid debit payments, I have no interest in incurring charges that will | |
| 83 | need to be paid back at a later date. I also have no interest in submitting | |
| 91 | 84 | personal information to Privacy.com. |
| 92 | 85 | |
| 93 | This type of change toward a "buy it now, pay us later" model is | |
| 94 | concerning, and I will be watching Privacy.com to see if they further | |
| 95 | their interests in the credit model as time goes on. | |
| 86 | This type of change toward a "buy it now, pay us later" model is concerning, and | |
| 87 | I will be watching Privacy.com to see if they further their interests in the | |
| 88 | credit model as time goes on. | |
| 96 | 89 | |
| 97 | Could we see them start charging interest, fees, etc.? I'm not sure, but | |
| 98 | this change does not inspire confidence in their mission as a | |
| 99 | privacy-focused company. | |
| 90 | Could we see them start charging interest, fees, etc.? I'm not sure, but this | |
| 91 | change does not inspire confidence in their mission as a privacy-focused | |
| 92 | company. | |
content/blog/2022-09-17-serenity-os.org +35 −41
| @@ -5,13 +5,13 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Overview |
| 7 | 7 | |
| 8 | [[https://serenityos.org][SerenityOS]] is a unique operating system (OS) | |
| 9 | that I have seen pop up in my news feed a few times over the last few | |
| 10 | years, 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 | |
| 9 | feed a few times over the last few years, but I have never had time to test it | |
| 10 | out until now. | |
| 11 | 11 | |
| 12 | 12 | Testing out this system brought back fond memories of yellowed, |
| 13 | modem-screeching, 100-pound computers that brought so many fond memories | |
| 14 | to my youth. | |
| 13 | modem-screeching, 100-pound computers that brought so many fond memories to my | |
| 14 | youth. | |
| 15 | 15 | |
| 16 | 16 | Per their website: |
| 17 | 17 | |
| @@ -31,11 +31,10 @@ This is a system by us, for us, based on the things we like. | ||
| 31 | 31 | |
| 32 | 32 | * Building |
| 33 | 33 | |
| 34 | Your first question may be "Where's the iso?" and the answer is... there | |
| 35 | are none. SerenityOS does not provide pre-built images for testing. You | |
| 36 | must build the images yourself. This seems intentionally to limit | |
| 37 | participation to only those who are truly interested enough to learn how | |
| 38 | to build the OS. | |
| 34 | Your first question may be "Where's the iso?" and the answer is... there are | |
| 35 | none. SerenityOS does not provide pre-built images for testing. You must build | |
| 36 | the images yourself. This seems intentionally to limit participation to only | |
| 37 | those who are truly interested enough to learn how to build the OS. | |
| 39 | 38 | |
| 40 | 39 | ** Clone |
| 41 | 40 | |
| @@ -47,25 +46,22 @@ git clone https://github.com/SerenityOS/serenity && cd serenity | ||
| 47 | 46 | |
| 48 | 47 | ** Build |
| 49 | 48 | |
| 50 | Note that I followed the | |
| 51 | [[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build | |
| 52 | Instructions]] in the SerenityOS repository as of commit | |
| 53 | =660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed | |
| 54 | since my installation, and you should double-check the instructions | |
| 55 | first. | |
| 49 | Note that I followed the [[https://github.com/SerenityOS/serenity/blob/master/Documentation/BuildInstructions.md][Build Instructions]] in the SerenityOS repository as of | |
| 50 | commit =660d2b53b1206e868d5470eee80b5e62d7e30da7=. Things may have changed since | |
| 51 | my installation, and you should double-check the instructions first. | |
| 56 | 52 | |
| 57 | Regardless, I want to repeat my steps here to illustrate any errors or | |
| 58 | differing commands I needed to run in order to build and run SerenityOS. | |
| 53 | Regardless, I want to repeat my steps here to illustrate any errors or differing | |
| 54 | commands I needed to run in order to build and run SerenityOS. | |
| 59 | 55 | |
| 60 | Since I am running Fedora, I needed to install these packages in order | |
| 61 | to build the OS images: | |
| 56 | Since I am running Fedora, I needed to install these packages in order to build | |
| 57 | the OS images: | |
| 62 | 58 | |
| 63 | 59 | #+begin_src sh |
| 64 | 60 | sudo dnf install texinfo binutils-devel curl cmake mpfr-devel libmpc-devel gmp-devel e2fsprogs ninja-build patch ccache rsync @"C Development Tools and Libraries" @Virtualization |
| 65 | 61 | #+end_src |
| 66 | 62 | |
| 67 | Next, make sure you're inside the =serenity= directory created earlier | |
| 68 | during the git cloning process and process to build the toolchain: | |
| 63 | Next, make sure you're inside the =serenity= directory created earlier during | |
| 64 | the git cloning process and process to build the toolchain: | |
| 69 | 65 | |
| 70 | 66 | #+begin_src sh |
| 71 | 67 | Meta/serenity.sh rebuild-toolchain |
| @@ -82,29 +78,27 @@ launch. | ||
| 82 | 78 | |
| 83 | 79 | * Issues |
| 84 | 80 | |
| 85 | I played around in SerenityOS for an hour or two in order to see what I | |
| 86 | could do and had a lot of fun with it. The only issue I ran into was a | |
| 87 | lack of working internet. I didn't try very hard, but I could tell that | |
| 88 | the main network link wasn't connecting to my Fedora host properly. | |
| 81 | I played around in SerenityOS for an hour or two in order to see what I could do | |
| 82 | and had a lot of fun with it. The only issue I ran into was a lack of working | |
| 83 | internet. I didn't try very hard, but I could tell that the main network link | |
| 84 | wasn't connecting to my Fedora host properly. | |
| 89 | 85 | |
| 90 | 86 | * Screenshots |
| 91 | 87 | |
| 92 | The initial launch of the image displays the SerenityOS desktop, with a | |
| 93 | simple terminal already launched. | |
| 88 | The initial launch of the image displays the SerenityOS desktop, with a simple | |
| 89 | terminal already launched. | |
| 94 | 90 | |
| 95 | There is also a "Fire" application (literally just shows fire burning), | |
| 96 | a browser with the local Serenity Browser page loaded, and a text | |
| 97 | editor. | |
| 91 | There is also a "Fire" application (literally just shows fire burning), a | |
| 92 | browser with the local Serenity Browser page loaded, and a text editor. | |
| 98 | 93 | |
| 99 | I also poked around the system utilities and found most tools you'd | |
| 100 | expect to find within a standard desktop, such as a system monitoring | |
| 101 | tool. | |
| 94 | I also poked around the system utilities and found most tools you'd expect to | |
| 95 | find within a standard desktop, such as a system monitoring tool. | |
| 102 | 96 | |
| 103 | Lastly, I noted that the default desktop contains numerous pre-defined | |
| 104 | themes to choose from. This is a small piece, but it's actually | |
| 105 | wonderful to see desktop developers consider theming directly out of the | |
| 106 | box rather than using an addon-based mentality. | |
| 97 | Lastly, I noted that the default desktop contains numerous pre-defined themes to | |
| 98 | choose from. This is a small piece, but it's actually wonderful to see desktop | |
| 99 | developers consider theming directly out of the box rather than using an | |
| 100 | addon-based mentality. | |
| 107 | 101 | |
| 108 | I didn't take a screenshot of the other pre-installed games, but I did | |
| 109 | spend nearly 30 minutes playing Solitaire before remembering that I was | |
| 110 | supposed to be writing a post about the OS. | |
| 102 | I didn't take a screenshot of the other pre-installed games, but I did spend | |
| 103 | nearly 30 minutes playing Solitaire before remembering that I was supposed to be | |
| 104 | writing a post about the OS. | |
content/blog/2022-09-21-graphene-os.org +51 −58
| @@ -5,26 +5,24 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Introduction |
| 7 | 7 | |
| 8 | After using iOS for a couple of years, I finally took the plunge and | |
| 9 | purchased a Pixel 6 Pro in order to test and use [GrapheneOS] | |
| 10 | ([[https://grapheneos.org]]). | |
| 8 | After using iOS for a couple of years, I finally took the plunge and purchased a | |
| 9 | Pixel 6 Pro in order to test and use [[https://grapheneos.org][GrapheneOS]]. | |
| 11 | 10 | |
| 12 | The installation process was rather quick once you have the tools and | |
| 13 | files you need. Overall, it can be done in just a few minutes. | |
| 11 | The installation process was rather quick once you have the tools and files you | |
| 12 | need. Overall, it can be done in just a few minutes. | |
| 14 | 13 | |
| 15 | 14 | * Gathering Tools & Files |
| 16 | 15 | |
| 17 | 16 | ** Android Tools |
| 18 | 17 | |
| 19 | First, in order to interact with the device, we will need the | |
| 20 | [[https://developer.android.com/studio/releases/platform-tools.html][Android | |
| 21 | platform tools]]. Find the Linux download and save the ZIP folder to | |
| 22 | your preferred location. | |
| 18 | First, in order to interact with the device, we will need the [[https://developer.android.com/studio/releases/platform-tools.html][Android platform | |
| 19 | tools]]. Find the Linux download and save the ZIP folder to your preferred | |
| 20 | location. | |
| 23 | 21 | |
| 24 | 22 | Once we've downloaded the files, we will need to unzip them, enter the |
| 25 | directory, and move the necessary executables to a central location, | |
| 26 | such as =/usr/bin/=. For this installation, we only need the =fastboot= | |
| 27 | and =adb= executables. | |
| 23 | directory, and move the necessary executables to a central location, such as | |
| 24 | =/usr/bin/=. For this installation, we only need the =fastboot= and =adb= | |
| 25 | executables. | |
| 28 | 26 | |
| 29 | 27 | #+begin_src sh |
| 30 | 28 | cd ~/Downloads |
| @@ -39,9 +37,8 @@ sudo mv adb /usr/bin | ||
| 39 | 37 | |
| 40 | 38 | ** GrapheneOS Files |
| 41 | 39 | |
| 42 | Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]] | |
| 43 | for our device and model. For example, the Pixel 6 Pro is codenamed | |
| 44 | =raven= on the release page. | |
| 40 | Next, we need the [[https://grapheneos.org/releases][GrapheneOS files]] for our device and model. For example, the | |
| 41 | Pixel 6 Pro is codenamed =raven= on the release page. | |
| 45 | 42 | |
| 46 | 43 | Once we have the links, let's download them to our working directory: |
| 47 | 44 | |
| @@ -53,8 +50,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig | ||
| 53 | 50 | |
| 54 | 51 | 1. Validate Integrity |
| 55 | 52 | |
| 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. | |
| 58 | 55 | |
| 59 | 56 | #+begin_src sh |
| 60 | 57 | sudo dnf install signify |
| @@ -64,8 +61,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig | ||
| 64 | 61 | curl -O https://releases.grapheneos.org/factory.pub |
| 65 | 62 | #+end_src |
| 66 | 63 | |
| 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. | |
| 69 | 66 | |
| 70 | 67 | #+begin_src sh |
| 71 | 68 | signify -Cqp factory.pub -x raven-factory-2022091400.zip.sig && echo verified |
| @@ -73,8 +70,8 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig | ||
| 73 | 70 | |
| 74 | 71 | 2. Unzip Files |
| 75 | 72 | |
| 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: | |
| 78 | 75 | |
| 79 | 76 | #+begin_src sh |
| 80 | 77 | unzip raven-factory-2022091400.zip && cd raven-factory-2022091400 |
| @@ -84,35 +81,35 @@ curl -0 https://releases.grapheneos.org/raven-factory-2022091400.zip.sig | ||
| 84 | 81 | |
| 85 | 82 | ** Enable Developer Debugging & OEM Unlock |
| 86 | 83 | |
| 87 | Before we can actually flash anything to the phone, we will need to | |
| 88 | enable OEM Unlocking, as well as either USB Debugging or Wireless | |
| 89 | Debugging, depending on which method we will be using. | |
| 84 | Before 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 | |
| 86 | Serial Bus) Debugging or Wireless Debugging, depending on which method we will | |
| 87 | be using. | |
| 90 | 88 | |
| 91 | To start, enable developer mode by going to =Settings= > =About= and | |
| 92 | tapping =Build Number= seven (7) times. You may need to enter your PIN | |
| 93 | to enable this mode. | |
| 89 | To 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 | |
| 91 | number (PIN) to enable this mode. | |
| 94 | 92 | |
| 95 | Once developer mode is enabled, go to =Settings= > =System= > | |
| 96 | =Devloper Options= and enable OEM Unlocking, as well as USB or Wireless | |
| 97 | Debugging. In my case, I chose USB Debugging and performed all actions | |
| 98 | via USB cable. | |
| 93 | Once developer mode is enabled, go to =Settings= > =System= > =Devloper Options= | |
| 94 | and enable OEM Unlocking, as well as USB or Wireless Debugging. In my case, I | |
| 95 | chose USB Debugging and performed all actions via USB cable. | |
| 99 | 96 | |
| 100 | Once these options are enabled, plug the phone into the computer and | |
| 101 | execute the following command: | |
| 97 | Once these options are enabled, plug the phone into the computer and execute the | |
| 98 | following command: | |
| 102 | 99 | |
| 103 | 100 | #+begin_src sh |
| 104 | 101 | adb devices |
| 105 | 102 | #+end_src |
| 106 | 103 | |
| 107 | If an unauthorized error occurs, make sure the USB mode on the phone is | |
| 108 | changed from charging to something like "File Transfer" or "PTP." You | |
| 109 | can find the USB mode in the notification tray. | |
| 104 | If an unauthorized error occurs, make sure the USB mode on the phone is changed | |
| 105 | from charging to something like "File Transfer" or "PTP" (Picture Transfer | |
| 106 | Protocol). You can find the USB mode in the notification tray. | |
| 110 | 107 | |
| 111 | 108 | ** Reboot Device |
| 112 | 109 | |
| 113 | Once we have found the device via =adb=, we can either boot into the | |
| 114 | bootloader interface by holding the volume down button while the phone | |
| 115 | reboots or by executing the following command: | |
| 110 | Once we have found the device via =adb=, we can either boot into the bootloader | |
| 111 | interface by holding the volume down button while the phone reboots or by | |
| 112 | executing the following command: | |
| 116 | 113 | |
| 117 | 114 | #+begin_src sh |
| 118 | 115 | adb reboot bootloader |
| @@ -120,17 +117,14 @@ adb reboot bootloader | ||
| 120 | 117 | |
| 121 | 118 | ** Unlock the Bootloader |
| 122 | 119 | |
| 123 | The phone will reboot and load the bootloader screen upon startup. At | |
| 124 | this point, we are ready to start the actual flashing of GrapheneOS onto | |
| 125 | the device. | |
| 120 | The phone will reboot and load the bootloader screen upon startup. At this | |
| 121 | point, we are ready to start the actual flashing of GrapheneOS onto the device. | |
| 126 | 122 | |
| 127 | *NOTE*: In my situation, I needed to use =sudo= with every =fastboot= | |
| 128 | command, but not with =adb= commands. I am not sure if this is standard | |
| 129 | or a Fedora quirk, but I'm documenting my commands verbatim in this | |
| 130 | post. | |
| 123 | *NOTE*: In my situation, I needed to use =sudo= with every =fastboot= command, | |
| 124 | but not with =adb= commands. I am not sure if this is standard or a Fedora | |
| 125 | quirk, but I'm documenting my commands verbatim in this post. | |
| 131 | 126 | |
| 132 | First, we start by unlocking the bootloader so that we can load other | |
| 133 | ROMs: | |
| 127 | First, we start by unlocking the bootloader so that we can load other ROMs: | |
| 134 | 128 | |
| 135 | 129 | #+begin_src sh |
| 136 | 130 | sudo fastboot flashing unlock |
| @@ -138,24 +132,23 @@ sudo fastboot flashing unlock | ||
| 138 | 132 | |
| 139 | 133 | ** Flashing Factory Images |
| 140 | 134 | |
| 141 | Once the phone is unlocked, we can flash it with the =flash-all.sh= | |
| 142 | script found inside the =raven-factory-2022091400= folder we entered | |
| 143 | earlier: | |
| 135 | Once the phone is unlocked, we can flash it with the =flash-all.sh= script found | |
| 136 | inside the =raven-factory-2022091400= folder we entered earlier: | |
| 144 | 137 | |
| 145 | 138 | #+begin_src sh |
| 146 | 139 | sudo ./flash-all.sh |
| 147 | 140 | #+end_src |
| 148 | 141 | |
| 149 | This process should take a few minutes and will print informational | |
| 150 | messages as things progress. Avoid doing anything on the phone while | |
| 151 | this process is operating. | |
| 142 | This process should take a few minutes and will print informational messages as | |
| 143 | things progress. Avoid doing anything on the phone while this process is | |
| 144 | operating. | |
| 152 | 145 | |
| 153 | 146 | ** Lock the Bootloader |
| 154 | 147 | |
| 155 | If everything was successful, the phone should reboot a few times and | |
| 156 | finally land back on the bootloader screen. At this point, we can | |
| 157 | re-lock the bootloader to enable full verified boot and protect the | |
| 158 | device from unwanted flashing or erasure of data. | |
| 148 | If everything was successful, the phone should reboot a few times and finally | |
| 149 | land back on the bootloader screen. At this point, we can re-lock the bootloader | |
| 150 | to enable full verified boot and protect the device from unwanted flashing or | |
| 151 | erasure of data. | |
| 159 | 152 | |
| 160 | 153 | #+begin_src sh |
| 161 | 154 | sudo fastboot flashing lock |
content/blog/2022-10-04-mtp-linux.org +22 −25
| @@ -3,31 +3,29 @@ | ||
| 3 | 3 | #+description: Instructions for mounting and accessing Media Transfer Protocol (MTP) compatible mobile devices on Fedora Linux using jmtpfs for file transfer and management. |
| 4 | 4 | #+slug: mtp-linux |
| 5 | 5 | |
| 6 | I recently ran into trouble attempting to mount my GrapheneOS phone to | |
| 7 | my laptop running Fedora Linux via the | |
| 8 | [[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer | |
| 9 | Protocol]] (MTP) and discovered a simple and effective solution. | |
| 6 | I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop | |
| 7 | running Fedora Linux via the [[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer Protocol]] (MTP) and discovered a | |
| 8 | simple and effective solution. | |
| 10 | 9 | |
| 11 | * Use a USB 3.0 Port | |
| 10 | * Use a Universal Serial Bus (USB) 3.0 Port | |
| 12 | 11 | |
| 13 | First, ensure that the device was plugged in to the laptop through a USB | |
| 14 | 3.0 port, if possible. From a brief glance online, it seems that USB 2.0 | |
| 15 | ports may cause issues with dropped connections over MTP. This is purely | |
| 16 | anecdotal since I don't have any evidence to link showing that USB 2.0 | |
| 17 | causes issues, but I can confirm that switching to a USB 3.0 port seemed | |
| 18 | to cut out most of my issues. | |
| 12 | First, ensure that the device was plugged in to the laptop through a USB 3.0 | |
| 13 | port, if possible. From a brief glance online, it seems that USB 2.0 ports may | |
| 14 | cause issues with dropped connections over MTP. This is purely anecdotal since I | |
| 15 | don't have any evidence to link showing that USB 2.0 causes issues, but I can | |
| 16 | confirm that switching to a USB 3.0 port seemed to cut out most of my issues. | |
| 19 | 17 | |
| 20 | 18 | * Switch USB Preferences to MTP |
| 21 | 19 | |
| 22 | Secondly, you need to ensure that the phone's USB preferences/mode is | |
| 23 | changed to MTP or File Transfer once the phone is plugged in. Other | |
| 24 | modes will not allow you to access the phone's file system. | |
| 20 | Secondly, you need to ensure that the phone's USB preferences/mode is changed to | |
| 21 | MTP or File Transfer once the phone is plugged in. Other modes will not allow | |
| 22 | you to access the phone's file system. | |
| 25 | 23 | |
| 26 | 24 | * Install =jmtpfs= |
| 27 | 25 | |
| 28 | Next, I used the =jmtpfs= package to mount my phone to my laptop. There | |
| 29 | are other packages that exist, but this one worked perfectly for me. On | |
| 30 | Fedora Linux, you can install it like this: | |
| 26 | Next, I used the =jmtpfs= package to mount my phone to my laptop. There are | |
| 27 | other packages that exist, but this one worked perfectly for me. On Fedora | |
| 28 | Linux, you can install it like this: | |
| 31 | 29 | |
| 32 | 30 | #+begin_src sh |
| 33 | 31 | sudo dnf install jmtpfs -y |
| @@ -35,8 +33,8 @@ sudo dnf install jmtpfs -y | ||
| 35 | 33 | |
| 36 | 34 | * Create a Mount Point |
| 37 | 35 | |
| 38 | Once you have the package installed, you just need to create a folder | |
| 39 | for the device to use as a mount point. In my case, I used =/mnt/pixel=: | |
| 36 | Once you have the package installed, you just need to create a folder for the | |
| 37 | device to use as a mount point. In my case, I used =/mnt/pixel=: | |
| 40 | 38 | |
| 41 | 39 | #+begin_src sh |
| 42 | 40 | sudo mkdir /mnt/pixel |
| @@ -45,8 +43,8 @@ sudo chown -R $USER:$USER /mnt/pixel | ||
| 45 | 43 | |
| 46 | 44 | * Mount & Access the Phone's File System |
| 47 | 45 | |
| 48 | Finally, plug-in and mount the device, and you should be able to see all | |
| 49 | storage (internal and external) inside your new folder! | |
| 46 | Finally, plug-in and mount the device, and you should be able to see all storage | |
| 47 | (internal and external) inside your new folder! | |
| 50 | 48 | |
| 51 | 49 | #+begin_src sh |
| 52 | 50 | jmtpfs /mnt/pixel |
| @@ -59,16 +57,15 @@ Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP). | ||
| 59 | 57 | Android device detected, assigning default bug flags |
| 60 | 58 | #+end_src |
| 61 | 59 | |
| 62 | Now you are mounted and can do anything you'd like with the device's | |
| 63 | files: | |
| 60 | Now you are mounted and can do anything you'd like with the device's files: | |
| 64 | 61 | |
| 65 | 62 | #+begin_src sh |
| 66 | 63 | cd /mnt/pixel |
| 67 | 64 | ls -lha |
| 68 | 65 | #+end_src |
| 69 | 66 | |
| 70 | From here, you will be able to see any internal or external storage | |
| 71 | available on the device: | |
| 67 | From here, you will be able to see any internal or external storage available on | |
| 68 | the device: | |
| 72 | 69 | |
| 73 | 70 | #+begin_src sh |
| 74 | 71 | total 0 |
content/blog/2022-10-04-syncthing.org +78 −93
| @@ -5,26 +5,24 @@ | ||
| 5 | 5 | |
| 6 | 6 | * An Overview of Syncthing |
| 7 | 7 | |
| 8 | If you've been looking around the self-hosted cloud storage space for a | |
| 9 | while, you've undoubtedly run into someone suggesting | |
| 10 | [[https://syncthing.net][Syncthing]] as an option. However, it is an | |
| 11 | unusual alternative for those users out there who are used to having a | |
| 8 | If you've been looking around the self-hosted cloud storage space for a while, | |
| 9 | you've undoubtedly run into someone suggesting [[https://syncthing.net][Syncthing]] as an option. However, | |
| 10 | it is an unusual alternative for those users out there who are used to having a | |
| 12 | 11 | centralized cloud server that serves as the "controller" of the data and |
| 13 | 12 | interacts with clients on devices to fetch files. |
| 14 | 13 | |
| 15 | This post is a walkthrough of the Syncthing software, how I set up my | |
| 16 | personal storage, and some pros and cons of using the software. | |
| 14 | This post is a walkthrough of the Syncthing software, how I set up my personal | |
| 15 | storage, and some pros and cons of using the software. | |
| 17 | 16 | |
| 18 | 17 | * Installing Syncthing |
| 19 | 18 | |
| 20 | To install Syncthing, visit the | |
| 21 | [[https://syncthing.net/downloads/][Downloads]] page or install via your | |
| 22 | device's package manager. | |
| 19 | To install Syncthing, visit the [[https://syncthing.net/downloads/][Downloads]] page or install via your device's | |
| 20 | package manager. | |
| 23 | 21 | |
| 24 | 22 | ** Server & Desktop |
| 25 | 23 | |
| 26 | You can install Syncthing on servers and desktops via the Downloads page | |
| 27 | linked above or via the command-line. | |
| 24 | You can install Syncthing on servers and desktops via the Downloads page linked | |
| 25 | above or via the command-line. | |
| 28 | 26 | |
| 29 | 27 | For Debian-based distros: |
| 30 | 28 | |
| @@ -40,19 +38,13 @@ sudo dnf install syncthing | ||
| 40 | 38 | |
| 41 | 39 | ** Mobile |
| 42 | 40 | |
| 43 | Syncthing for Android is available on | |
| 44 | [[https://f-droid.org/packages/com.nutomic.syncthingandroid/][F-Droid]] | |
| 45 | and | |
| 46 | [[https://play.google.com/store/apps/details?id=com.nutomic.syncthingandroid][Google | |
| 47 | Play]]. Syncthing does not have an official iOS client, but there is a | |
| 48 | third-party client called | |
| 49 | [[https://apps.apple.com/us/app/m%C3%B6bius-sync/id1539203216][Möbius | |
| 41 | Syncthing 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 | |
| 42 | not 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 | |
| 50 | 43 | Sync]]. |
| 51 | 44 | |
| 52 | 45 | * How Does Syncthing Work? |
| 53 | 46 | |
| 54 | To start, I wanted to include the main marketing blurb from their | |
| 55 | website: | |
| 47 | To start, I wanted to include the main marketing blurb from their website: | |
| 56 | 48 | |
| 57 | 49 | #+begin_quote |
| 58 | 50 | Syncthing 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 | ||
| 62 | 54 | it's transmitted over the internet. |
| 63 | 55 | #+end_quote |
| 64 | 56 | |
| 65 | Let's break this apart and add in some other details to help explain | |
| 66 | what exactly Syncthing does in order to sync files between devices. | |
| 57 | Let's break this apart and add in some other details to help explain what | |
| 58 | exactly Syncthing does in order to sync files between devices. | |
| 67 | 59 | |
| 68 | 60 | ** Local Syncthing Server(s) |
| 69 | 61 | |
| 70 | Syncthing syncs files between multiple devices by creating a local | |
| 71 | server on each device. These local servers handle a few different | |
| 72 | things, such as watching files and directories for changes, hosting an | |
| 73 | administrative GUI website, and authenticating with connected devices. | |
| 62 | Syncthing syncs files between multiple devices by creating a local server on | |
| 63 | each device. These local servers handle a few different things, such as watching | |
| 64 | files and directories for changes, hosting an administrative GUI website, and | |
| 65 | authenticating with connected devices. | |
| 74 | 66 | |
| 75 | You can also start, stop, and restart the Syncthing server via the | |
| 76 | command-line or web dashboard. If you're running Syncthing on a device | |
| 77 | with =systemd=, you can use the following commands: | |
| 67 | You can also start, stop, and restart the Syncthing server via the command-line | |
| 68 | or web dashboard. If you're running Syncthing on a device with =systemd=, you | |
| 69 | can use the following commands: | |
| 78 | 70 | |
| 79 | 71 | #+begin_src sh |
| 80 | 72 | sudo systemctl start syncthing@username.service |
| @@ -84,13 +76,13 @@ sudo systemctl stop syncthing@username.service | ||
| 84 | 76 | |
| 85 | 77 | ** Syncthing Dashboard |
| 86 | 78 | |
| 87 | This biggest part of Syncthing is the admin GUI website that runs on | |
| 88 | each device (note that mobile devices will use the Syncthing app rather | |
| 89 | than the web GUI). The admin GUI is available through the web browser on | |
| 90 | the local device that is running Syncthing - simply go to | |
| 91 | =http://localhost:8384= or =http://127.0.0.1:8384=. This web page is the | |
| 92 | place where you will change settings, add/modify synced files, and | |
| 93 | add/modify connected devices. | |
| 79 | This 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). | |
| 81 | The administrative graphical user interface (GUI) is available through the web | |
| 82 | browser 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 | |
| 84 | where you will change settings, add/modify synced files, and add/modify | |
| 85 | connected devices. | |
| 94 | 86 | |
| 95 | 87 | Here's an example web GUI dashboard: |
| 96 | 88 | |
| @@ -99,81 +91,74 @@ Here's an example web GUI dashboard: | ||
| 99 | 91 | |
| 100 | 92 | ** Remote Devices |
| 101 | 93 | |
| 102 | A cloud storage solution wouldn't be very useful if you aren't able to | |
| 103 | share data among various devices. Syncthing does this by sharing Device | |
| 104 | IDs to connect servers, and then by manually sharing Folders with | |
| 105 | devices that have been connected. | |
| 94 | A cloud storage solution wouldn't be very useful if you aren't able to share | |
| 95 | data among various devices. Syncthing does this by sharing Device IDs to connect | |
| 96 | servers, and then by manually sharing Folders with devices that have been | |
| 97 | connected. | |
| 106 | 98 | |
| 107 | For instance, if you have a laptop running Syncthing and then install | |
| 108 | the Syncthing mobile app on a phone, you could scan the laptop's QR code | |
| 109 | for Device ID and then accept the authentication on the laptop's | |
| 110 | dashboard. Next, you can use either device to select a folder for | |
| 111 | sharing and dictating which device should send, receive, or both. | |
| 99 | For instance, if you have a laptop running Syncthing and then install the | |
| 100 | Syncthing mobile app on a phone, you could scan the laptop's QR (quick-response) | |
| 101 | code for Device ID and then accept the authentication on the laptop's dashboard. | |
| 102 | Next, you can use either device to select a folder for sharing and dictating | |
| 103 | which device should send, receive, or both. | |
| 112 | 104 | |
| 113 | When you connect devices, you can set one device as an "Introducer," | |
| 114 | which can add devices from the introducer to the device list, for | |
| 115 | mutually shared folders. You can also configure Auto Accept, | |
| 116 | compression, rate limits, and more settings per device. | |
| 105 | When you connect devices, you can set one device as an "Introducer," which can | |
| 106 | add devices from the introducer to the device list, for mutually shared folders. | |
| 107 | You can also configure Auto Accept, compression, rate limits, and more settings | |
| 108 | per device. | |
| 117 | 109 | |
| 118 | 110 | * My Personal Cloud Storage Set-up |
| 119 | 111 | |
| 120 | Personally, I use a model similar to a traditional cloud storage | |
| 121 | service. I have a "centralized" server running 24/7 that acts as an | |
| 122 | Introducer for my Syncthing network. I think of this as my main storage | |
| 123 | and all other devices as tertiary client devices. I will likely add | |
| 124 | additional servers as backups as time goes on so that I don't have to | |
| 125 | rely on my laptop or phone as the only backups. | |
| 112 | Personally, I use a model similar to a traditional cloud storage service. I have | |
| 113 | a "centralized" server running 24/7 that acts as an Introducer for my Syncthing | |
| 114 | network. I think of this as my main storage and all other devices as tertiary | |
| 115 | client devices. I will likely add additional servers as backups as time goes on | |
| 116 | so that I don't have to rely on my laptop or phone as the only backups. | |
| 126 | 117 | |
| 127 | Currently, I have one desktop and one mobile device connected to the | |
| 128 | network, both running intermittently as they are not powered-on 24/7. | |
| 118 | Currently, I have one desktop and one mobile device connected to the network, | |
| 119 | both running intermittently as they are not powered-on 24/7. | |
| 129 | 120 | |
| 130 | The initial set-up of the software was easy enough, but data transfer | |
| 131 | rates were incredibly slow for me due to the Wi-Fi. Instead, I plugged | |
| 132 | my laptop into the ethernet network that my server is on and manually | |
| 133 | copied my folders over to the server with =scp=. Once complete, | |
| 134 | Syncthing validated that all files were there and not missing, and it | |
| 135 | did not need to transfer any data through the WAN. | |
| 121 | The initial set-up of the software was easy enough, but data transfer rates were | |
| 122 | incredibly slow for me due to the Wi-Fi. Instead, I plugged my laptop into the | |
| 123 | ethernet network that my server is on and manually copied my folders over to the | |
| 124 | server with =scp=. Once complete, Syncthing validated that all files were there | |
| 125 | and not missing, and it did not need to transfer any data through the WAN. | |
| 136 | 126 | |
| 137 | As slow as the transfer was going, this probably saved me a few days of | |
| 138 | waiting for my ~100GB sync. | |
| 127 | As slow as the transfer was going, this probably saved me a few days of waiting | |
| 128 | for my ~100 gigabytes to sync. | |
| 139 | 129 | |
| 140 | 130 | * Pros & Cons |
| 141 | 131 | |
| 142 | I've put together a short list of pros and cons for Syncthing. I thought | |
| 143 | about my experiences with Nextcloud, WebDAV, proprietary services | |
| 144 | (Google Drive, iCloud, etc.), and privacy-focused cloud solutions | |
| 145 | (pCloud, Tresorit, etc.). | |
| 132 | I've put together a short list of pros and cons for Syncthing. I thought about | |
| 133 | my experiences with Nextcloud, WebDAV, proprietary services (Google Drive, | |
| 134 | iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.). | |
| 146 | 135 | |
| 147 | 136 | *Pros:* |
| 148 | 137 | |
| 149 | 138 | - I've faced no data loss at all through my two-month trial run. |
| 150 | 139 | - No third-parties store your data on their servers. |
| 151 | - You have full control over your data and can take your data and leave | |
| 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. | |
| 157 | 144 | |
| 158 | 145 | *Cons:* |
| 159 | 146 | |
| 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. | |
| 165 | 152 | - Syncing can be slow due to the clients/servers initially connecting or |
| 166 | 153 | 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 | ||
| 171 | Overall, I've had a great experience with Syncthing so far. I've had no | |
| 172 | data loss, syncing has been quick and easy when changes are made to | |
| 173 | files, device connections are reliable, and I love the freedom of | |
| 174 | controlling the clients and servers as I choose. | |
| 175 | ||
| 176 | Not to mention that I appreciate that I - or someone else - could pull | |
| 177 | the Syncthing [[https://github.com/syncthing][source code]] and continue | |
| 178 | development/support if the Syncthing Foundation decides to stop | |
| 179 | developing 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 | ||
| 157 | Overall, I've had a great experience with Syncthing so far. I've had no data | |
| 158 | loss, syncing has been quick and easy when changes are made to files, device | |
| 159 | connections are reliable, and I love the freedom of controlling the clients and | |
| 160 | servers as I choose. | |
| 161 | ||
| 162 | Not to mention that I appreciate that I - or someone else - could pull the | |
| 163 | Syncthing [[https://github.com/syncthing][source code]] and continue development/support if the Syncthing | |
| 164 | Foundation decides to stop developing the software or sells the business. | |
content/blog/2022-10-22-alpine-linux.org +91 −103
| @@ -5,43 +5,40 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Alpine Linux |
| 7 | 7 | |
| 8 | [[https://alpinelinux.org][Alpine Linux]] is a very small distro, built | |
| 9 | on musl libc and busybox. It uses ash as the default shell, OpenRC as | |
| 10 | the init system, and apk as the package manager. According to their | |
| 11 | website, an Alpine container "requires no more than 8 MB and a minimal | |
| 12 | installation to disk requires around 130 MB of storage." An actual bare | |
| 13 | metal machine is recommended to have 100 MB of RAM and 0-700 MB of | |
| 14 | storage space. | |
| 15 | ||
| 16 | Historically, I've used Ubuntu's minimal installation image as my server | |
| 17 | OS for the last five years. Ubuntu worked well and helped as my original | |
| 18 | server contained an nVidia GPU and no onboard graphics, so quite a few | |
| 19 | distros won't boot or install without a lot of tinkering. | |
| 20 | ||
| 21 | Alpine has given me a huge increase in performance across my Docker apps | |
| 22 | and Nginx websites. CPU load for the new server I'm using to test Alpine | |
| 23 | hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100 CPU @ | |
| 24 | 3.70GHz. | |
| 25 | ||
| 26 | The only services I haven't moved over to Alpine are Plex Media Server | |
| 27 | and Syncthing, which may increase CPU load quite a bit depending on how | |
| 28 | many streams are running. | |
| 8 | [[https://alpinelinux.org][Alpine Linux]] is a very small distribution, built on musl libc and busybox. It | |
| 9 | uses ash as the default shell, OpenRC as the init system, and apk as the package | |
| 10 | manager. According to their website, an Alpine container "requires no more than | |
| 11 | 8 megabytes (MB) and a minimal installation to disk requires around 130 MB of | |
| 12 | storage." An actual bare metal machine is recommended to have 100 MB of RAM and | |
| 13 | 0-700 MB of storage space. | |
| 14 | ||
| 15 | Historically, I've used Ubuntu's minimal installation image as my server OS for | |
| 16 | the last five years. Ubuntu worked well and helped as my original server | |
| 17 | contained an nVidia GPU (graphics processing unit) and no onboard graphics, so | |
| 18 | quite a few distributions won't boot or install without a lot of tinkering. | |
| 19 | ||
| 20 | Alpine has given me a huge increase in performance across my Docker apps and | |
| 21 | Nginx websites. CPU (central processing unit) load for the new server I'm using | |
| 22 | to test Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100 | |
| 23 | CPU @ 3.70 Gigahertz (GHz). | |
| 24 | ||
| 25 | The only services I haven't moved over to Alpine are Plex Media Server and | |
| 26 | Syncthing, which may increase CPU load quite a bit depending on how many streams | |
| 27 | are running. | |
| 29 | 28 | |
| 30 | 29 | ** Installation |
| 31 | 30 | |
| 32 | In terms of installation, Alpine has an incredibly useful | |
| 33 | [[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide | |
| 34 | a user throughout the installation and post-installation processes, as | |
| 35 | well as various other articles and guides. | |
| 31 | In terms of installation, Alpine has an incredibly useful [[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide a | |
| 32 | user throughout the installation and post-installation processes, as well as | |
| 33 | various other articles and guides. | |
| 36 | 34 | |
| 37 | To install Alpine, find an appropriate | |
| 38 | [[https://alpinelinux.org/downloads/][image to download]] and flash it | |
| 39 | to a USB using software such as Rufus or Etcher. I opted to use the | |
| 40 | Standard image for my x86_{64} architecture. | |
| 35 | To 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 | |
| 37 | the Standard image for my x86_{64} architecture. | |
| 41 | 38 | |
| 42 | Once the USB is ready, plug it into the machine and reboot. Note that | |
| 43 | you may have to use a key such as =Esc= or =F1-12= to access the boot | |
| 44 | menu. The Alpine Linux terminal will load quickly and for a login. | |
| 39 | Once the USB is ready, plug it into the machine and reboot. Note that you may | |
| 40 | have to use a key such as =Esc= or =F1-12= to access the boot menu. The Alpine | |
| 41 | Linux terminal will load quickly and for a login. | |
| 45 | 42 | |
| 46 | 43 | To log in to the installation image, use the =root= account; there is no |
| 47 | 44 | password. Once logged-in, execute the setup command: |
| @@ -50,34 +47,32 @@ password. Once logged-in, execute the setup command: | ||
| 50 | 47 | setup-alpine |
| 51 | 48 | #+end_src |
| 52 | 49 | |
| 53 | The setup script will ask a series of questions to configure the system. | |
| 54 | Be sure to answer carefully or else you may have to re-configure the | |
| 55 | system after boot. | |
| 50 | The setup script will ask a series of questions to configure the system. Be sure | |
| 51 | to answer carefully or else you may have to re-configure the system after boot. | |
| 56 | 52 | |
| 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 | |
| 63 | 59 | 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 | ||
| 79 | Once the setup script is finished, be sure to reboot the machine and | |
| 80 | remove 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 | ||
| 74 | Once the setup script is finished, be sure to reboot the machine and remove the | |
| 75 | USB device. | |
| 81 | 76 | |
| 82 | 77 | #+begin_src sh |
| 83 | 78 | reboot |
| @@ -86,9 +81,8 @@ reboot | ||
| 86 | 81 | ** Post-Installation |
| 87 | 82 | |
| 88 | 83 | There are many things you can do once your Alpine Linux system is up and |
| 89 | running, and it largely depends on what you'll use the machine for. I'm | |
| 90 | going to walk through my personal post-installation setup for my web | |
| 91 | server. | |
| 84 | running, and it largely depends on what you'll use the machine for. I'm going to | |
| 85 | walk through my personal post-installation setup for my web server. | |
| 92 | 86 | |
| 93 | 87 | 1. Upgrade the System |
| 94 | 88 | |
| @@ -100,9 +94,9 @@ server. | ||
| 100 | 94 | |
| 101 | 95 | 2. Adding a User |
| 102 | 96 | |
| 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. | |
| 106 | 100 | |
| 107 | 101 | #+begin_src sh |
| 108 | 102 | apk add doas |
| @@ -118,16 +112,14 @@ server. | ||
| 118 | 112 | |
| 119 | 113 | 3. Enable Community Packages |
| 120 | 114 | |
| 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: | |
| 124 | 117 | |
| 125 | 118 | #+begin_src sh |
| 126 | 119 | doas nano /etc/apk/repositories |
| 127 | 120 | #+end_src |
| 128 | 121 | |
| 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: | |
| 131 | 123 | |
| 132 | 124 | #+begin_src sh |
| 133 | 125 | /media/usb/apks |
| @@ -140,9 +132,9 @@ server. | ||
| 140 | 132 | |
| 141 | 133 | 4. Install Required Packages |
| 142 | 134 | |
| 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: | |
| 146 | 138 | |
| 147 | 139 | #+begin_src sh |
| 148 | 140 | doas apk add nano nginx docker docker-compose ufw |
| @@ -150,15 +142,14 @@ server. | ||
| 150 | 142 | |
| 151 | 143 | 5. SSH |
| 152 | 144 | |
| 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: | |
| 155 | 146 | |
| 156 | 147 | #+begin_src sh |
| 157 | 148 | doas apk add openssh |
| 158 | 149 | #+end_src |
| 159 | 150 | |
| 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: | |
| 162 | 153 | |
| 163 | 154 | #+begin_src sh |
| 164 | 155 | # Create a new key |
| @@ -174,9 +165,9 @@ server. | ||
| 174 | 165 | |
| 175 | 166 | 6. Firewall |
| 176 | 167 | |
| 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. | |
| 180 | 171 | |
| 181 | 172 | #+begin_src sh |
| 182 | 173 | doas ufw default deny incoming |
| @@ -188,8 +179,8 @@ server. | ||
| 188 | 179 | |
| 189 | 180 | 7. Change Hostname |
| 190 | 181 | |
| 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: | |
| 193 | 184 | |
| 194 | 185 | #+begin_src sh |
| 195 | 186 | doas nano /etc/hostname |
| @@ -223,17 +214,17 @@ doas chown -R www:www /var/lib/nginx/ | ||
| 223 | 214 | doas chown -R www:www /www |
| 224 | 215 | #+end_src |
| 225 | 216 | |
| 226 | If you're running a simple webroot, you can alter the main =nginx.conf= | |
| 227 | file. Otherwise, you can drop configuration files in the following | |
| 228 | directory. You don't need to enable or symlink the configuration file | |
| 229 | like you do in other systems. | |
| 217 | If you're running a simple webroot, you can alter the main =nginx.conf= file. | |
| 218 | Otherwise, you can drop configuration files in the following directory. You | |
| 219 | don't need to enable or symlink the configuration file like you do in other | |
| 220 | systems. | |
| 230 | 221 | |
| 231 | 222 | #+begin_src sh |
| 232 | 223 | doas nano /etc/nginx/http.d/example_website.conf |
| 233 | 224 | #+end_src |
| 234 | 225 | |
| 235 | Once the configuration is set and pointed at the =/www= directory to | |
| 236 | serve files, enable the Nginx service: | |
| 226 | Once the configuration is set and pointed at the =/www= directory to serve | |
| 227 | files, enable the Nginx service: | |
| 237 | 228 | |
| 238 | 229 | #+begin_src sh |
| 239 | 230 | # Note that 'default' must be included or Nginx will not start on boot |
| @@ -242,18 +233,16 @@ doas rc-update add nginx default | ||
| 242 | 233 | |
| 243 | 234 | * Docker Containers |
| 244 | 235 | |
| 245 | Docker 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=. | |
| 236 | Docker works exactly the same as other systems. Either execute a =docker run= | |
| 237 | command or create a =docker-compose.yml= file and do =docker-compose up -d=. | |
| 248 | 238 | |
| 249 | 239 | * Git Server |
| 250 | 240 | |
| 251 | I went in-depth on how to self-host a git server in another post: | |
| 252 | [[../git-server/][Self-Hosting a Personal Git Server]]. | |
| 241 | I went in-depth on how to self-host a git server in another post: [[https://cleberg.net/blog/git-server.html][Self-Hosting | |
| 242 | Guide: Git & cGit]]. | |
| 253 | 243 | |
| 254 | However, there are a few differences with Alpine. First note that in | |
| 255 | order to change the =git= user's shell, you must do a few things a | |
| 256 | little different: | |
| 244 | However, there are a few differences with Alpine. First note that in order to | |
| 245 | change the =git= user's shell, you must do a few things a little different: | |
| 257 | 246 | |
| 258 | 247 | #+begin_src sh |
| 259 | 248 | doas apk add libuser |
| @@ -265,12 +254,11 @@ doas lchsh git | ||
| 265 | 254 | |
| 266 | 255 | * Thoughts on Alpine |
| 267 | 256 | |
| 268 | So far, I love Alpine Linux. I have no complaints about anything at this | |
| 269 | point, but I'm not completely finished with the migration yet. Once I'm | |
| 270 | able to upgrade my hardware to a rack-mounted server, I will migrate | |
| 271 | Plex and Syncthing over to Alpine as well - possibly putting Plex into a | |
| 272 | container or VM. | |
| 257 | So far, I love Alpine Linux. I have no complaints about anything at this point, | |
| 258 | but I'm not completely finished with the migration yet. Once I'm able to upgrade | |
| 259 | my hardware to a rack-mounted server, I will migrate Plex and Syncthing over to | |
| 260 | Alpine as well - possibly putting Plex into a container or VM. | |
| 273 | 261 | |
| 274 | The performance is stellar, the =apk= package manager is seamless, and | |
| 275 | system administration tasks are effortless. My only regret is that I | |
| 276 | didn't install Alpine sooner. | |
| 262 | The performance is stellar, the =apk= package manager is seamless, and system | |
| 263 | administration tasks are effortless. My only regret is that I didn't install | |
| 264 | Alpine sooner. | |
content/blog/2022-10-30-linux-display-manager.org +21 −24
| @@ -5,18 +5,16 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Display Manager Services |
| 7 | 7 | |
| 8 | In order to change the | |
| 9 | [[https://en.wikipedia.org/wiki/Display_manager][display manager]] on | |
| 10 | Void Linux - or any other Linux distro - you need to identify the | |
| 11 | currently enabled display manager. | |
| 8 | In order to change the [[https://en.wikipedia.org/wiki/Display_manager][display manager]] on Void Linux - or any other Linux | |
| 9 | distribution - you need to identify the currently enabled display manager. | |
| 12 | 10 | |
| 13 | 11 | ** Disabling the Current Display Manager |
| 14 | 12 | |
| 15 | Void Linux only has one ISO available for download with a pre-built | |
| 16 | display manager at the time of this post: the XFCE ISO. If you've | |
| 17 | installed this version, the pre-assigned display manager is =lxdm=. If | |
| 18 | you installed another display manager, replace =lxdm= in the following | |
| 19 | command with the display manager you have installed. | |
| 13 | Void Linux only has one optical disc image (ISO) available for download with a | |
| 14 | pre-built display manager at the time of this post: the XFCE ISO. If you've | |
| 15 | installed this version, the pre-assigned display manager is =lxdm=. If you | |
| 16 | installed another display manager, replace =lxdm= in the following command with | |
| 17 | the display manager you have installed. | |
| 20 | 18 | |
| 21 | 19 | To disable =lxdm=, simply remove the service symlink: |
| 22 | 20 | |
| @@ -26,9 +24,9 @@ sudo rm /var/service/lxdm | ||
| 26 | 24 | |
| 27 | 25 | ** Enabling a New Display Manager |
| 28 | 26 | |
| 29 | If you want to enable a new display manager, you can do so after =lxdm= | |
| 30 | is disabled. Make sure to replace =<new_display_manager>= with your new | |
| 31 | DM, such as =gdm=, =xdm=, etc. | |
| 27 | If you want to enable a new display manager, you can do so after =lxdm= is | |
| 28 | disabled. Make sure to replace =<new_display_manager>= with your new DM, such as | |
| 29 | =gdm=, =xdm=, etc. | |
| 32 | 30 | |
| 33 | 31 | #+begin_src sh |
| 34 | 32 | sudo ln -s /etc/sv/<new_display_manager> /var/service |
| @@ -37,8 +35,8 @@ sudo ln -s /etc/sv/<new_display_manager> /var/service | ||
| 37 | 35 | * Set Up =.xinitrc= |
| 38 | 36 | |
| 39 | 37 | Depending 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 | |
| 41 | i3wm as my desktop. | |
| 38 | =~/.xinitrc=. For my personal set-up, I created this file to launch the i3wm as | |
| 39 | my desktop. | |
| 42 | 40 | |
| 43 | 41 | #+begin_src sh |
| 44 | 42 | nano ~/.xinitrc |
| @@ -50,21 +48,20 @@ nano ~/.xinitrc | ||
| 50 | 48 | exec i3 |
| 51 | 49 | #+end_src |
| 52 | 50 | |
| 53 | If you run a desktop other than i3, simply replace =i3= with the shell | |
| 54 | command that launches that desktop. | |
| 51 | If you run a desktop other than i3, simply replace =i3= with the shell command | |
| 52 | that launches that desktop. | |
| 55 | 53 | |
| 56 | 54 | * Set Up Your Shell Profile |
| 57 | 55 | |
| 58 | Finally, in order to automatically launch an X session upon login, you | |
| 59 | will need to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files | |
| 60 | for your shell: | |
| 56 | Finally, in order to automatically launch an X session upon login, you will need | |
| 57 | to edit the =.bash_profile= (bash) or =.zprofile= (zsh) files for your shell: | |
| 61 | 58 | |
| 62 | 59 | #+begin_src sh |
| 63 | 60 | nano ~/.zprofile |
| 64 | 61 | #+end_src |
| 65 | 62 | |
| 66 | Add the following snippet to the end of the shell profile file. This | |
| 67 | will execute the =startx= command upon login. | |
| 63 | Add the following snippet to the end of the shell profile file. This will | |
| 64 | execute the =startx= command upon login. | |
| 68 | 65 | |
| 69 | 66 | #+begin_src sh |
| 70 | 67 | if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then |
| @@ -72,6 +69,6 @@ if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then | ||
| 72 | 69 | fi |
| 73 | 70 | #+end_src |
| 74 | 71 | |
| 75 | Alternatively, you can ignore this step and simply choose to manually | |
| 76 | execute =startx= upon login. This can be useful if you have issues with | |
| 77 | your desktop or like to manually launch different desktops by choice. | |
| 72 | Alternatively, 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 | |
| 74 | like to manually launch different desktops by choice. | |
content/blog/2022-11-07-self-hosting-matrix.org +41 −48
| @@ -5,21 +5,19 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Synapse |
| 7 | 7 | |
| 8 | If 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 | |
| 11 | to run their own Matrix home server. | |
| 8 | If you're reading this, you likely know that [[https://github.com/matrix-org/synapse/][Synapse]] is a popular [[https://matrix.org/][Matrix]] home | |
| 9 | server software that allows users to run their own Matrix home server. | |
| 12 | 10 | |
| 13 | This post is a short guide describing how I was able to get Synapse | |
| 14 | working in a minimally-usable state on Alpine Linux. | |
| 11 | This post is a short guide describing how I was able to get Synapse working in a | |
| 12 | minimally-usable state on Alpine Linux. | |
| 15 | 13 | |
| 16 | 14 | * Installation Process |
| 17 | 15 | |
| 18 | 16 | ** Dependencies |
| 19 | 17 | |
| 20 | First, since there is no Alpine-specific package for Synapse, we need to | |
| 21 | ensure that Alpine has the required dependencies for the Python-based | |
| 22 | installation method. | |
| 18 | First, since there is no Alpine-specific package for Synapse, we need to ensure | |
| 19 | that Alpine has the required dependencies for the Python-based installation | |
| 20 | method. | |
| 23 | 21 | |
| 24 | 22 | #+begin_src sh |
| 25 | 23 | doas apk -U update |
| @@ -39,10 +37,9 @@ pip install matrix-synapse | ||
| 39 | 37 | |
| 40 | 38 | ** Running Synapse |
| 41 | 39 | |
| 42 | Once installed, running Synapse is easy. Simply execute the following | |
| 43 | command, replacing =example.com= with the domain name that will be used | |
| 44 | with this home server. This will generate the configuration files needed | |
| 45 | to run the server. | |
| 40 | Once installed, running Synapse is easy. Simply execute the following command, | |
| 41 | replacing =example.com= with the domain name that will be used with this home | |
| 42 | server. This will generate the configuration files needed to run the server. | |
| 46 | 43 | |
| 47 | 44 | #+begin_src sh |
| 48 | 45 | python -m synapse.app.homeserver \ |
| @@ -60,17 +57,15 @@ synctl start | ||
| 60 | 57 | |
| 61 | 58 | ** Configuring Synapse |
| 62 | 59 | |
| 63 | To make any change to Synapse, we need to edit the =YAML= configuration | |
| 64 | file: | |
| 60 | To make any change to Synapse, we need to edit the =YAML= configuration file: | |
| 65 | 61 | |
| 66 | 62 | #+begin_src sh |
| 67 | 63 | nano ~/synapse/homeserver.yaml |
| 68 | 64 | #+end_src |
| 69 | 65 | |
| 70 | For now, we just need to ensure the =server_name= is accurate. However, | |
| 71 | there are a lot of other configuration options found in the | |
| 72 | [[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring | |
| 73 | Synapse]] documentation that can be enabled/disabled at any point. | |
| 66 | For now, we just need to ensure the =server_name= is accurate. However, there | |
| 67 | are a lot of other configuration options found in the [[https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html][Configuring Synapse]] | |
| 68 | documentation that can be enabled/disabled at any point. | |
| 74 | 69 | |
| 75 | 70 | #+begin_src yaml |
| 76 | 71 | server_name: "example.com" |
| @@ -84,9 +79,9 @@ synctl restart | ||
| 84 | 79 | |
| 85 | 80 | ** Nginx Reverse-Proxy |
| 86 | 81 | |
| 87 | To ensure that Synapse is reachable from the public, we need to connect | |
| 88 | our domain to the Synapse server. In my case, I use a Nginx | |
| 89 | reverse-proxy for this purpose. | |
| 82 | To ensure that Synapse is reachable from the public, we need to connect our | |
| 83 | domain to the Synapse server. In my case, I use a Nginx reverse-proxy for this | |
| 84 | purpose. | |
| 90 | 85 | |
| 91 | 86 | To use Nginx, we need to create a reverse-proxy configuration file: |
| 92 | 87 | |
| @@ -94,9 +89,9 @@ To use Nginx, we need to create a reverse-proxy configuration file: | ||
| 94 | 89 | doas nano /etc/nginx/http.d/example.com.conf |
| 95 | 90 | #+end_src |
| 96 | 91 | |
| 97 | If you already have TLS certificates for this domain (=example.com=), | |
| 98 | you can simply use the SSL configuration and point toward your TLS | |
| 99 | certificates. | |
| 92 | If you already have TLS (Transport Layer Security) certificates for this domain | |
| 93 | (=example.com=), you can simply use the SSL (Secure Socket Layer) configuration | |
| 94 | and point toward your TLS certificates. | |
| 100 | 95 | |
| 101 | 96 | #+begin_src conf |
| 102 | 97 | server { |
| @@ -139,10 +134,9 @@ server { | ||
| 139 | 134 | } |
| 140 | 135 | #+end_src |
| 141 | 136 | |
| 142 | If you need to generate TLS certificates (I recommend | |
| 143 | [[https://certbot.eff.org/][Certbot]]), you'll need a more minimal Nginx | |
| 144 | conf file before you can use the TLS-enabled example above. Instead, use | |
| 145 | this configuration file during the Certbot certificate generation | |
| 137 | If you need to generate TLS certificates (I recommend [[https://certbot.eff.org/][Certbot]]), you'll need a | |
| 138 | more minimal Nginx conf file before you can use the TLS-enabled example above. | |
| 139 | Instead, use this configuration file during the Certbot certificate generation | |
| 146 | 140 | process: |
| 147 | 141 | |
| 148 | 142 | #+begin_src conf |
| @@ -161,13 +155,13 @@ Once you're done editing the Nginx conf file, restart Nginx: | ||
| 161 | 155 | doas rc-service nginx restart |
| 162 | 156 | #+end_src |
| 163 | 157 | |
| 164 | If you still need to generate TLS certificates, run =certbot= now and | |
| 165 | obtain the certificates. Certbot will ask if you want to use a webroot | |
| 166 | or spin up a temporary web server. I *highly* recommend using the | |
| 167 | temporary web server due to the many issues with using a webroot. | |
| 158 | If you still need to generate TLS certificates, run =certbot= now and obtain the | |
| 159 | certificates. Certbot will ask if you want to use a webroot or spin up a | |
| 160 | temporary web server. I *highly* recommend using the temporary web server due to | |
| 161 | the many issues with using a webroot. | |
| 168 | 162 | |
| 169 | You will need to stop Nginx in order to user the temporary web server | |
| 170 | option with Certbot: | |
| 163 | You will need to stop Nginx in order to user the temporary web server option | |
| 164 | with Certbot: | |
| 171 | 165 | |
| 172 | 166 | #+begin_src sh |
| 173 | 167 | # Stop Nginx so certbot can spin up a temp webserver for cert generation |
| @@ -178,11 +172,11 @@ doas rc-service nginx start | ||
| 178 | 172 | |
| 179 | 173 | ** Open Firewall & Router Ports |
| 180 | 174 | |
| 181 | If you use a firewall on the server, open the =8448= port for discovery | |
| 182 | and federation, as well as the normal web server ports if you're using a | |
| 183 | reverse proxy. If you want additional services, such as voice calls, you | |
| 184 | will need to read the Synapse documentation to see which ports need to | |
| 185 | be opened for those features. | |
| 175 | If you use a firewall on the server, open the =8448= port for discovery and | |
| 176 | federation, as well as the normal web server ports if you're using a reverse | |
| 177 | proxy. If you want additional services, such as voice calls, you will need to | |
| 178 | read the Synapse documentation to see which ports need to be opened for those | |
| 179 | features. | |
| 186 | 180 | |
| 187 | 181 | Here's an example of the Universal Firewall (UFW) software: |
| 188 | 182 | |
| @@ -193,14 +187,13 @@ doas ufw allow 8448 | ||
| 193 | 187 | doas ufw allow "Nginx Full" |
| 194 | 188 | #+end_src |
| 195 | 189 | |
| 196 | Remember to forward any Synapse ports, such as =8448=, =80=, and =443=, | |
| 197 | in your Router from the internet to your server's IP address. | |
| 190 | Remember to forward any Synapse ports, such as =8448=, =80=, and =443=, in your | |
| 191 | Router from the internet to your server's internet protocol (IP) address. | |
| 198 | 192 | |
| 199 | 193 | ** Adding Matrix Users |
| 200 | 194 | |
| 201 | Finally, if you didn't enable public registration in the | |
| 202 | =homeserver.yaml= file, you can manually create users via the | |
| 203 | command-line: | |
| 195 | Finally, if you didn't enable public registration in the =homeserver.yaml= file, | |
| 196 | you can manually create users via the command-line: | |
| 204 | 197 | |
| 205 | 198 | #+begin_src sh |
| 206 | 199 | cd ~/synapse |
| @@ -210,6 +203,6 @@ register_new_matrix_user -c homeserver.yaml | ||
| 210 | 203 | Remember that the format for federated Matrix usernames is |
| 211 | 204 | =@username:example.com= when logging in to client applications. |
| 212 | 205 | |
| 213 | Once Synapse is running, and you have a username, you are ready to log | |
| 214 | in to a Matrix client and start sending messages, joining rooms, and | |
| 215 | utilizing your very own Matrix server. | |
| 206 | Once Synapse is running, and you have a username, you are ready to log in to a | |
| 207 | Matrix client and start sending messages, joining rooms, and utilizing your very | |
| 208 | own Matrix server. | |
content/blog/2022-11-11-nginx-tmp-errors.org +16 −17
| @@ -8,10 +8,10 @@ has occurred multiple times for me./ | ||
| 8 | 8 | |
| 9 | 9 | * The Problem |
| 10 | 10 | |
| 11 | After migrating to a new server OS, I started receiving quite a few | |
| 12 | permission errors like the one below. These popped up for various | |
| 13 | different websites I'm serving via Nginx on this server, but did not | |
| 14 | prevent the website from loading. | |
| 11 | After migrating to a new server operating system (OS), I started receiving quite | |
| 12 | a few permission errors like the one below. These popped up for various | |
| 13 | different websites I'm serving via Nginx on this server, but did not prevent the | |
| 14 | website from loading. | |
| 15 | 15 | |
| 16 | 16 | I found the errors in the standard log file: |
| 17 | 17 | |
| @@ -23,19 +23,18 @@ cat /var/log/nginx/error.log | ||
| 23 | 23 | 2022/11/11 11:30:34 [crit] 8970#8970: *10 open() "/var/lib/nginx/tmp/proxy/3/00/0000000003" failed (13: Permission denied) while reading upstream, client: 169.150.203.10, server: cyberchef.example.com, request: "GET /assets/main.css HTTP/2.0", upstream: "http://127.0.0.1:8111/assets/main.css", host: "cyberchef.example.com", referrer: "https://cyberchef.example.com/" |
| 24 | 24 | #+end_src |
| 25 | 25 | |
| 26 | You can see that the error is =13: Permission denied= and it occurs in | |
| 27 | the =/var/lib/nginx/tmp/= directory. In my case, I had thousands of | |
| 28 | errors where Nginx was denied permission to read/write files in this | |
| 29 | directory. | |
| 26 | You 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 | |
| 28 | Nginx was denied permission to read/write files in this directory. | |
| 30 | 29 | |
| 31 | 30 | So how do I fix it? |
| 32 | 31 | |
| 33 | 32 | * The Solution |
| 34 | 33 | |
| 35 | In order to resolve the issue, I had to ensure the =/var/lib/nginx= | |
| 36 | directory is owned by Nginx. Mine was owned by the =www= user and Nginx | |
| 37 | was not able to read or write files within that directory. This | |
| 38 | prevented Nginx from caching temporary files. | |
| 34 | In order to resolve the issue, I had to ensure the =/var/lib/nginx= directory is | |
| 35 | owned by Nginx. Mine was owned by the =www= user and Nginx was not able to read | |
| 36 | or write files within that directory. This prevented Nginx from caching | |
| 37 | temporary files. | |
| 39 | 38 | |
| 40 | 39 | #+begin_src sh |
| 41 | 40 | # Alpine Linux |
| @@ -45,9 +44,9 @@ doas chown -R nginx:nginx /var/lib/nginx | ||
| 45 | 44 | sudo chown -R nginx:nginx /var/lib/nginx |
| 46 | 45 | #+end_src |
| 47 | 46 | |
| 48 | You /may/ also be able to change the =proxy_temp_path= in your Nginx | |
| 49 | config, but I did not try this. Here's a suggestion I found online that | |
| 50 | may work if the above solution does not: | |
| 47 | You /may/ also be able to change the =proxy_temp_path= in your Nginx config, but | |
| 48 | I did not try this. Here's a suggestion I found online that may work if the | |
| 49 | above solution does not: | |
| 51 | 50 | |
| 52 | 51 | #+begin_src sh |
| 53 | 52 | nano /etc/nginx/http.d/example.com.conf |
| @@ -65,8 +64,8 @@ server { | ||
| 65 | 64 | } |
| 66 | 65 | #+end_src |
| 67 | 66 | |
| 68 | Finally, restart Nginx and your server should be able to cache temporary | |
| 69 | files again. | |
| 67 | Finally, restart Nginx and your server should be able to cache temporary files | |
| 68 | again. | |
| 70 | 69 | |
| 71 | 70 | #+begin_src sh |
| 72 | 71 | # Alpine Linux (OpenRC) |
content/blog/2022-11-27-server-build.org +60 −67
| @@ -5,39 +5,37 @@ | ||
| 5 | 5 | |
| 6 | 6 | * The Dilemma |
| 7 | 7 | |
| 8 | For years, I have been using desktops and a Raspberry Pi as the backbone | |
| 9 | of my homelab. I have always wanted to move toward a single dedicated | |
| 10 | server that could handle all of my tasks, but was often put off by the | |
| 11 | complexity of the choices (and financial roadblocks at some times). | |
| 8 | For years, I have been using desktops and a Raspberry Pi as the backbone of my | |
| 9 | homelab. I have always wanted to move toward a single dedicated server that | |
| 10 | could handle all of my tasks, but was often put off by the complexity of the | |
| 11 | choices (and financial roadblocks at some times). | |
| 12 | 12 | |
| 13 | However, after purchasing a small server rack this past year, I have | |
| 14 | been researching to see what kind of rack-mounted server I could buy. I | |
| 15 | initially bought a Dell R720XD loaded up with everything I could ever | |
| 16 | want in a server - but I did not care for it. It was far too loud, and | |
| 17 | the age of the CPU/RAM was something I wanted to improve upon. | |
| 13 | However, after purchasing a small server rack this past year, I have been | |
| 14 | researching to see what kind of rack-mounted server I could buy. I initially | |
| 15 | bought a Dell R720XD loaded up with everything I could ever want in a server - | |
| 16 | but I did not care for it. It was far too loud, and the age of the CPU/RAM was | |
| 17 | something I wanted to improve upon. | |
| 18 | 18 | |
| 19 | After returning the R720XD, I decided that I wanted to build my own | |
| 20 | server with modern, consumer-grade PC components. This time, I am very | |
| 21 | happy with the results of my server. | |
| 19 | After returning the R720XD, I decided that I wanted to build my own server with | |
| 20 | modern, consumer-grade PC components. This time, I am very happy with the | |
| 21 | results of my server. | |
| 22 | 22 | |
| 23 | 23 | * Components |
| 24 | 24 | |
| 25 | 25 | I'll start by listing all the components I used for this server build: |
| 26 | 26 | |
| 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]] | |
| 30 | 28 | - *Motherboard*: [[https://nzxt.com/product/n7-b550][NZXT B550]] |
| 31 | 29 | - *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. | |
| 34 | 32 | - *RAM*: 64GB RAM (2x32GB) /Max of 128GB RAM on this motherboard/ |
| 35 | 33 | - *Boot Drive*: Western Digital 500GB M.2 NVME SSD |
| 36 | 34 | - *HDD Bay*: |
| 37 | 35 | - 10TB WD White /(shucked, moved from previous server)/ |
| 38 | 36 | - 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)/ | |
| 41 | 39 | - *PSU*: Corsair RM850 PSU |
| 42 | 40 | - *Extras*: |
| 43 | 41 | - Corsair TM3Q Thermal Paste |
| @@ -47,54 +45,52 @@ I'll start by listing all the components I used for this server build: | ||
| 47 | 45 | |
| 48 | 46 | * Building the Server |
| 49 | 47 | |
| 50 | This took quite a while for me to build (in my opinion of time), | |
| 51 | totaling around 3 hours from start to finish. The case has some peculiar | |
| 52 | construction, so you have to completely remove the ODD & HDD cages to | |
| 53 | install the motherboard and other components first. | |
| 48 | This took quite a while for me to build (in my opinion of time), totaling around | |
| 49 | 3 hours from start to finish. The case has some peculiar construction, so you | |
| 50 | have to completely remove the ODD & HDD cages to install the motherboard and | |
| 51 | other components first. | |
| 54 | 52 | |
| 55 | Now, I've never built a computer of any kind before, so I was quite | |
| 56 | nervous. Personally, the only challenging part was getting the CPU | |
| 57 | cooler to screw into the motherboard without sliding the thermal paste | |
| 58 | around too much underneath. I'm still not entirely sure if I did a great | |
| 59 | job of it, but nothing's broken yet. | |
| 53 | Now, I've never built a computer of any kind before, so I was quite nervous. | |
| 54 | Personally, the only challenging part was getting the CPU cooler to screw into | |
| 55 | the motherboard without sliding the thermal paste around too much underneath. | |
| 56 | I'm still not entirely sure if I did a great job of it, but nothing's broken | |
| 57 | yet. | |
| 60 | 58 | |
| 61 | The main components were all fine and simple. However, installing the | |
| 62 | hard drives is slightly tedious as I need to power off the server and | |
| 63 | completely unscrew the HDD cage to install or remove any drives. | |
| 64 | Additionally, the drives are screwed directly into the metal cage with | |
| 65 | small screws, which are quite a bit different from the HDD trays I'm | |
| 66 | used to in other machines. | |
| 59 | The main components were all fine and simple. However, installing the hard | |
| 60 | drives is slightly tedious as I need to power off the server and completely | |
| 61 | unscrew the HDD cage to install or remove any drives. Additionally, the drives | |
| 62 | are screwed directly into the metal cage with small screws, which are quite a | |
| 63 | bit different from the HDD trays I'm used to in other machines. | |
| 67 | 64 | |
| 68 | Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay | |
| 69 | dealing with the tedium of removing the cage to install new drives. | |
| 65 | Seeing that the cases with hot-swap bays were 3-4x the price, I'm okay dealing | |
| 66 | with the tedium of removing the cage to install new drives. | |
| 70 | 67 | |
| 71 | 68 | * Software |
| 72 | 69 | |
| 73 | I'm not going to dive into the software as I have done so in other | |
| 74 | recent posts. However, I wanted to note that I am using Alpine Linux on | |
| 75 | this server and hosting most services inside Docker. No virtual machines | |
| 76 | (VMs) and very few bare-metal services. | |
| 70 | I'm not going to dive into the software as I have done so in other recent posts. | |
| 71 | However, I wanted to note that I am using Alpine Linux on this server and | |
| 72 | hosting most services inside Docker. No virtual machines (VMs) and very few | |
| 73 | bare-metal services. | |
| 77 | 74 | |
| 78 | 75 | * The Results |
| 79 | 76 | |
| 80 | How did my build turn out? Well, after migrating my other servers and | |
| 81 | their services over, I found that my server is blazing fast. The | |
| 82 | heaviest of my applications, Plex, is handled with ease. Even 4k | |
| 83 | streaming seems to be effortless. | |
| 77 | How did my build turn out? Well, after migrating my other servers and their | |
| 78 | services over, I found that my server is blazing fast. The heaviest of my | |
| 79 | applications, Plex, is handled with ease. Even 4k streaming seems to be | |
| 80 | effortless. | |
| 84 | 81 | |
| 85 | I am very happy with the results and will likely continue to improve on | |
| 86 | this server as the years go by rather than buying another used server | |
| 87 | online. | |
| 82 | I am very happy with the results and will likely continue to improve on this | |
| 83 | server as the years go by rather than buying another used server online. | |
| 88 | 84 | |
| 89 | 85 | ** Mistakes I Made |
| 90 | 86 | |
| 91 | This post wouldn't be complete unless I wrote about the mistakes I made | |
| 92 | while building. The only real mistake I made beyond a "whoops I dropped | |
| 93 | a screw" related to airflow and fan direction. | |
| 87 | This post wouldn't be complete unless I wrote about the mistakes I made while | |
| 88 | building. The only real mistake I made beyond a "whoops I dropped a screw" | |
| 89 | related to airflow and fan direction. | |
| 94 | 90 | |
| 95 | While installing the two new hard drives that showed up on 2022-11-30 | |
| 96 | and getting ready to install the case in my rack, I noticed that the | |
| 97 | hard drive temperatures were quite high. | |
| 91 | While installing the two new hard drives that showed up on 2022-11-30 and | |
| 92 | getting ready to install the case in my rack, I noticed that the hard drive | |
| 93 | temperatures were quite high. | |
| 98 | 94 | |
| 99 | 95 | I used the =smartctl= command for each of my drives (=/dev/sda= through |
| 100 | 96 | =/dev/sdd=): |
| @@ -104,9 +100,8 @@ doas smartctl -a /dev/sda | grep Temperature_Celsius | ||
| 104 | 100 | #+end_src |
| 105 | 101 | |
| 106 | 102 | The results were unusual - all four drives were idling at ~44-46 degrees |
| 107 | Celsius. The only drive that was cooler was my 10TB drive, which was at | |
| 108 | 38 degrees Celsius. I noted that this 10TB drive was also closest to the | |
| 109 | case fan. | |
| 103 | Celsius. The only drive that was cooler was my 10TB drive, which was at 38 | |
| 104 | degrees Celsius. I noted that this 10TB drive was also closest to the case fan. | |
| 110 | 105 | |
| 111 | 106 | #+begin_src sh |
| 112 | 107 | ID# 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_ | ||
| 120 | 115 | 194 Temperature_Celsius 0x0002 171 171 000 Old_age Always - 38 (Min/Max 14/56) |
| 121 | 116 | #+end_src |
| 122 | 117 | |
| 123 | After looking to see if I could fit more fans into the case, I noticed | |
| 124 | that the 120mm fan used for intake from the front of the case was | |
| 125 | actually pushing air out of the case by mistake. This fan sits right in | |
| 126 | front of the hard drive bay. | |
| 118 | After looking to see if I could fit more fans into the case, I noticed that the | |
| 119 | 120mm fan used for intake from the front of the case was actually pushing air | |
| 120 | out of the case by mistake. This fan sits right in front of the hard drive bay. | |
| 127 | 121 | |
| 128 | Once I flipped the fan around to act as an intake fan, the temperatures | |
| 129 | dropped immediately! They are now idling at ~31-33 degrees Celsius. A | |
| 130 | single fan spinning the wrong way caused my drives to idle 10-15 degrees | |
| 131 | higher than they should have. | |
| 122 | Once I flipped the fan around to act as an intake fan, the temperatures dropped | |
| 123 | immediately! They are now idling at ~31-33 degrees Celsius. A single fan | |
| 124 | spinning the wrong way caused my drives to idle 10-15 degrees higher than they | |
| 125 | should have. | |
| 132 | 126 | |
| 133 | 127 | #+begin_src sh |
| 134 | 128 | ID# 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_ | ||
| 142 | 136 | 194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 33 (Min/Max 22/46) |
| 143 | 137 | #+end_src |
| 144 | 138 | |
| 145 | This was a silly error to make, but I'm glad I found it today before I | |
| 146 | screwed the case into the rack and made things a lot more tedious to | |
| 147 | fix. | |
| 139 | This was a silly error to make, but I'm glad I found it today before I screwed | |
| 140 | the 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 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Creating the Ban List |
| 7 | 7 | |
| 8 | In order to ban list referral domains or websites with Nginx, you need | |
| 9 | to create a ban list file. The file below will accept regexes for | |
| 10 | different domains or websites you wish to block. | |
| 8 | In order to ban list referral domains or websites with Nginx, you need to create | |
| 9 | a ban list file. The file below will accept regexes for different domains or | |
| 10 | websites you wish to block. | |
| 11 | 11 | |
| 12 | 12 | First, create the file in your nginx directory: |
| 13 | 13 | |
| @@ -15,8 +15,8 @@ First, create the file in your nginx directory: | ||
| 15 | 15 | doas nano /etc/nginx/banlist.conf |
| 16 | 16 | #+end_src |
| 17 | 17 | |
| 18 | Next, paste the following contents in and fill out the regexes with | |
| 19 | whichever domains you're blocking. | |
| 18 | Next, paste the following contents in and fill out the regexes with whichever | |
| 19 | domains you're blocking. | |
| 20 | 20 | |
| 21 | 21 | #+begin_src conf |
| 22 | 22 | # /etc/nginx/banlist.conf |
| @@ -33,15 +33,15 @@ map $http_referer $bad_referer { | ||
| 33 | 33 | |
| 34 | 34 | * Configuring Nginx |
| 35 | 35 | |
| 36 | In order for the ban list to work, Nginx needs to know it exists and how | |
| 37 | to handle it. For this, edit the =nginx.conf= file. | |
| 36 | In order for the ban list to work, Nginx needs to know it exists and how to | |
| 37 | handle it. For this, edit the =nginx.conf= file. | |
| 38 | 38 | |
| 39 | 39 | #+begin_src sh |
| 40 | 40 | doas nano /etc/nginx/nginx.conf |
| 41 | 41 | #+end_src |
| 42 | 42 | |
| 43 | Within this file, find the =http= block and add your ban list file | |
| 44 | location to the end of the block. | |
| 43 | Within this file, find the =http= block and add your ban list file location to | |
| 44 | the end of the block. | |
| 45 | 45 | |
| 46 | 46 | #+begin_src conf |
| 47 | 47 | # /etc/nginx/nginx.conf |
| @@ -56,23 +56,22 @@ http { | ||
| 56 | 56 | |
| 57 | 57 | * Enabling the Ban List |
| 58 | 58 | |
| 59 | Finally, we need to take action when a bad referral site is found. To do | |
| 60 | so, edit the configuration file for your website. For example, I have | |
| 61 | all website configuration files in the =http.d= directory. You may have | |
| 62 | them in the =sites-available= directory on some distributions. | |
| 59 | Finally, we need to take action when a bad referral site is found. To do so, | |
| 60 | edit the configuration file for your website. For example, I have all website | |
| 61 | configuration files in the =http.d= directory. You may have them in the | |
| 62 | =sites-available= directory on some distributions. | |
| 63 | 63 | |
| 64 | 64 | #+begin_src sh |
| 65 | 65 | doas nano /etc/nginx/http.d/example.com.conf |
| 66 | 66 | #+end_src |
| 67 | 67 | |
| 68 | Within each website's configuration file, edit the =server= blocks that | |
| 69 | are listening to ports 80 and 443 and create a check for the | |
| 70 | =$bad_referrer= variable we created in the ban list file. | |
| 68 | Within each website's configuration file, edit the =server= blocks that are | |
| 69 | listening to ports 80 and 443 and create a check for the =$bad_referrer= | |
| 70 | variable we created in the ban list file. | |
| 71 | 71 | |
| 72 | If a matching site is found, you can return any | |
| 73 | [[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes][HTTP Status | |
| 74 | Code]] you want. Code 403 (Forbidden) is logical in this case since you | |
| 75 | are preventing a client connection due to a banned domain. | |
| 72 | If a matching site is found, you can return any [[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes][HTTP Status Code]] you want. Code | |
| 73 | 403 (Forbidden) is logical in this case since you are preventing a client | |
| 74 | connection due to a banned domain. | |
| 76 | 75 | |
| 77 | 76 | #+begin_src conf |
| 78 | 77 | server { |
| @@ -97,8 +96,8 @@ doas rc-service nginx restart | ||
| 97 | 96 | |
| 98 | 97 | * Testing Results |
| 99 | 98 | |
| 100 | In order to test the results, let's curl the contents of our site. To | |
| 101 | start, I'll curl the site normally: | |
| 99 | In order to test the results, let's curl the contents of our site. To start, | |
| 100 | I'll curl the site normally: | |
| 102 | 101 | |
| 103 | 102 | #+begin_src sh |
| 104 | 103 | curl https://cleberg.net |
| @@ -117,8 +116,8 @@ curl --referer https://news.ycombinator.com https://cleberg.net | ||
| 117 | 116 | #+end_src |
| 118 | 117 | |
| 119 | 118 | This time, I'm met with a 403 Forbidden response page. That means we are |
| 120 | successful and any clients being referred from a banned domain will be | |
| 121 | met with this same response code. | |
| 119 | successful and any clients being referred from a banned domain will be met with | |
| 120 | this same response code. | |
| 122 | 121 | |
| 123 | 122 | #+begin_src html |
| 124 | 123 | <html> |
content/blog/2022-12-01-nginx-compression.org +31 −36
| @@ -5,24 +5,23 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Text Compression |
| 7 | 7 | |
| 8 | Text compression allows a web server to serve text-based resources | |
| 9 | faster than uncompressed data. This can speed up things like First | |
| 10 | Contentful Paint, Tie to Interactive, and Speed Index. | |
| 8 | Text compression allows a web server to serve text-based resources faster than | |
| 9 | uncompressed data. This can speed up things like First Contentful Paint, Tie to | |
| 10 | Interactive, and Speed Index. | |
| 11 | 11 | |
| 12 | 12 | * Enable Nginx Compression with gzip |
| 13 | 13 | |
| 14 | In order to enable text compression on Nginx, we need to enable it | |
| 15 | within the configuration file: | |
| 14 | In order to enable text compression on Nginx, we need to enable it within the | |
| 15 | configuration file: | |
| 16 | 16 | |
| 17 | 17 | #+begin_src sh |
| 18 | 18 | nano /etc/nginx/nginx.conf |
| 19 | 19 | #+end_src |
| 20 | 20 | |
| 21 | Within the =http= block, find the section that shows something like the | |
| 22 | block below. This is the default gzip configuration I found in my | |
| 23 | =nginx.conf= file on Alpine Linux 3.17. Yours may look slightly | |
| 24 | different, just make sure that you're not creating any duplicate gzip | |
| 25 | options. | |
| 21 | Within the =http= block, find the section that shows something like the block | |
| 22 | below. This is the default gzip configuration I found in my =nginx.conf= file on | |
| 23 | Alpine Linux 3.17. Yours may look slightly different, just make sure that you're | |
| 24 | not creating any duplicate gzip options. | |
| 26 | 25 | |
| 27 | 26 | #+begin_src conf |
| 28 | 27 | # Enable gzipping of responses. |
| @@ -46,31 +45,27 @@ gzip_disable "MSIE [1-6]"; | ||
| 46 | 45 | |
| 47 | 46 | * Explanations of ngx_{httpgzipmodule} Options |
| 48 | 47 | |
| 49 | Each of the lines above enables a different aspect of the gzip response | |
| 50 | for Nginx. Here are the full explanations: | |
| 48 | Each of the lines above enables a different aspect of the gzip response for | |
| 49 | Nginx. Here are the full explanations: | |
| 51 | 50 | |
| 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. | |
| 73 | 69 | |
| 74 | More information on these directives and their options can be found on | |
| 75 | the [[https://nginx.org/en/docs/http/ngx_http_gzip_module.html][Module | |
| 76 | ngx_{httpgzipmodule}]] page in Nginx's documentation. | |
| 70 | More 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 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Problem |
| 7 | 7 | |
| 8 | I recently migrated domains and replaced the old webpage with a simple | |
| 9 | info page with instructions to users on how to edit their bookmarks and | |
| 10 | URLs to get to the page they were seeking. | |
| 8 | I recently migrated domains and replaced the old webpage with a simple info page | |
| 9 | with instructions to users on how to edit their bookmarks and URLs to get to the | |
| 10 | page they were seeking. | |
| 11 | 11 | |
| 12 | This was not ideal as it left the work up to the user and may have | |
| 13 | caused friction for users who accessed my RSS feed. | |
| 12 | This was not ideal as it left the work up to the user and may have caused | |
| 13 | friction for users who accessed my RSS (Really Simple Syndication) feed. | |
| 14 | 14 | |
| 15 | 15 | * Solution |
| 16 | 16 | |
| 17 | Instead, I finally found a solution that allows me to redirect both | |
| 18 | subdomains AND trailing content. For example, both of these URLs now | |
| 19 | redirect properly using the logic I'll explain below: | |
| 17 | Instead, I finally found a solution that allows me to redirect both subdomains | |
| 18 | AND trailing content. For example, both of these URLs now redirect properly | |
| 19 | using the logic I'll explain below: | |
| 20 | 20 | |
| 21 | 21 | #+begin_src txt |
| 22 | 22 | # Example 1 - Simple base domain redirect with trailing content |
| @@ -28,19 +28,19 @@ https://libreddit.domain1.com/r/history/comments/7z8cbg/new_discovery_mode_turns | ||
| 28 | 28 | https://libreddit.domain2.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/ |
| 29 | 29 | #+end_src |
| 30 | 30 | |
| 31 | Go ahead, try the URLs if you want to test them. | |
| 31 | Go ahead, try the URLs (uniform resource locators) if you want to test them. | |
| 32 | 32 | |
| 33 | 33 | ** Nginx Config |
| 34 | 34 | |
| 35 | To make this possible. I needed to configure a proper redirect scheme in | |
| 36 | my Nginx configuration. | |
| 35 | To make this possible. I needed to configure a proper redirect scheme in my | |
| 36 | Nginx configuration. | |
| 37 | 37 | |
| 38 | 38 | #+begin_src sh |
| 39 | 39 | doas nano /etc/nginx/http.d/domain1.conf |
| 40 | 40 | #+end_src |
| 41 | 41 | |
| 42 | Within this file, I had one block configured to redirect HTTP requests | |
| 43 | to HTTPS for the base domain and all subdomains. | |
| 42 | Within this file, I had one block configured to redirect HTTP requests to HTTPS | |
| 43 | for the base domain and all subdomains. | |
| 44 | 44 | |
| 45 | 45 | #+begin_src conf |
| 46 | 46 | server { |
| @@ -60,10 +60,9 @@ server { | ||
| 60 | 60 | } |
| 61 | 61 | #+end_src |
| 62 | 62 | |
| 63 | For the base domain, I have another =server= block dedicated to | |
| 64 | redirecting all base domain requests. You can see that the =rewrite= | |
| 65 | line is instructing Nginx to gather all trailing content and append it | |
| 66 | to the new =domain2.com= URL. | |
| 63 | For the base domain, I have another =server= block dedicated to redirecting all | |
| 64 | base domain requests. You can see that the =rewrite= line is instructing Nginx | |
| 65 | to gather all trailing content and append it to the new =domain2.com= URL. | |
| 67 | 66 | |
| 68 | 67 | #+begin_src conf |
| 69 | 68 | server { |
| @@ -79,17 +78,16 @@ server { | ||
| 79 | 78 | } |
| 80 | 79 | #+end_src |
| 81 | 80 | |
| 82 | Finally, the tricky part is figuring out how to tell Nginx to redirect | |
| 83 | while keeping both a subdomain and trailing content intact. I found that | |
| 84 | the easiest way to do this is to give it a =server= block of its own. | |
| 81 | Finally, the tricky part is figuring out how to tell Nginx to redirect while | |
| 82 | keeping both a subdomain and trailing content intact. I found that the easiest | |
| 83 | way to do this is to give it a =server= block of its own. | |
| 85 | 84 | |
| 86 | Within this block, we need to do some regex on the =server_name= line | |
| 87 | before we can rewrite anything. This creates a variable called | |
| 88 | =subdomain=. | |
| 85 | Within this block, we need to do some regex on the =server_name= line before we | |
| 86 | can rewrite anything. This creates a variable called =subdomain=. | |
| 89 | 87 | |
| 90 | Once the server gets to the =rewrite= line, it pulls the =subdomain= | |
| 91 | variable from above and uses it on the new =domain2.com= domain before | |
| 92 | appending the trailing content (=$request_uri=). | |
| 88 | Once the server gets to the =rewrite= line, it pulls the =subdomain= variable | |
| 89 | from above and uses it on the new =domain2.com= domain before appending the | |
| 90 | trailing content (=$request_uri=). | |
| 93 | 91 | |
| 94 | 92 | #+begin_src conf |
| 95 | 93 | server { |
| @@ -105,15 +103,15 @@ server { | ||
| 105 | 103 | } |
| 106 | 104 | #+end_src |
| 107 | 105 | |
| 108 | That's all there is to it. With this, I simply restarted Nginx and | |
| 109 | watched the redirections work in-action. | |
| 106 | That's all there is to it. With this, I simply restarted Nginx and watched the | |
| 107 | redirections work in-action. | |
| 110 | 108 | |
| 111 | 109 | #+begin_src sh |
| 112 | 110 | doas rc-service nginx restart |
| 113 | 111 | #+end_src |
| 114 | 112 | |
| 115 | Looking back on it, I wish I had done this sooner. Who knows how many | |
| 116 | people went looking for my sites or bookmarks and gave up when they saw | |
| 117 | the redirect instructions page. | |
| 113 | Looking back on it, I wish I had done this sooner. Who knows how many people | |
| 114 | went looking for my sites or bookmarks and gave up when they saw the redirect | |
| 115 | instructions page. | |
| 118 | 116 | |
| 119 | 117 | Oh well, it's done now. Live and learn. |
content/blog/2022-12-17-st.org +20 −26
| @@ -5,12 +5,11 @@ | ||
| 5 | 5 | |
| 6 | 6 | * st |
| 7 | 7 | |
| 8 | [[https://st.suckless.org][st]] standards for Simple Terminal, a simple | |
| 9 | terminal 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 | |
| 9 | the [[https://suckless.org][suckless]] team. | |
| 11 | 10 | |
| 12 | This post walks through the dependencies needed and process to build and | |
| 13 | install =st= on Fedora Workstation. | |
| 11 | This post walks through the dependencies needed and process to build and install | |
| 12 | =st= on Fedora Workstation. | |
| 14 | 13 | |
| 15 | 14 | ** Obtain Files |
| 16 | 15 | |
| @@ -23,8 +22,8 @@ git clone https://git.suckless.org/st && cd st | ||
| 23 | 22 | |
| 24 | 23 | ** Dependencies |
| 25 | 24 | |
| 26 | Once you have the files and are in the =st= directory, ensure the | |
| 27 | following packages are installed. | |
| 25 | Once you have the files and are in the =st= directory, ensure the following | |
| 26 | packages are installed. | |
| 28 | 27 | |
| 29 | 28 | #+begin_src sh |
| 30 | 29 | sudo dnf update && sudo dnf upgrade |
| @@ -39,13 +38,12 @@ Before building, ensure that you read the README file. | ||
| 39 | 38 | cat README |
| 40 | 39 | #+end_src |
| 41 | 40 | |
| 42 | Once you've read the instructions, open the =config.mk= file and ensure | |
| 43 | it matches your setup. If you're not sure, leave the default options | |
| 44 | within the file. | |
| 41 | Once you've read the instructions, open the =config.mk= file and ensure it | |
| 42 | matches your setup. If you're not sure, leave the default options within the | |
| 43 | file. | |
| 45 | 44 | |
| 46 | Finally, you can build =st= with the following command. Ensure you run | |
| 47 | as root (e.g., =sudo=) or else you may not end up with a usable | |
| 48 | application file. | |
| 45 | Finally, 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. | |
| 49 | 47 | |
| 50 | 48 | #+begin_src sh |
| 51 | 49 | sudo make clean install |
| @@ -54,38 +52,34 @@ sudo make clean install | ||
| 54 | 52 | ** Customization (Patches) |
| 55 | 53 | |
| 56 | 54 | Note that customizing =st= requires you to modify the source files or to |
| 57 | download one of the [[https://st.suckless.org/patches/][available | |
| 58 | patches]] for suckless.org. | |
| 55 | download one of the [[https://st.suckless.org/patches/][available patches]] for suckless.org. | |
| 59 | 56 | |
| 60 | If you've already installed =st= and want to customize or install a | |
| 61 | patch, start by uninstalling the current program. | |
| 57 | If you've already installed =st= and want to customize or install a patch, start | |
| 58 | by uninstalling the current program. | |
| 62 | 59 | |
| 63 | 60 | #+begin_src sh |
| 64 | 61 | cd ~/suckless/st |
| 65 | 62 | sudo make uninstall |
| 66 | 63 | #+end_src |
| 67 | 64 | |
| 68 | Next, grab the =<path>.diff= file from the page of the patch you chose. | |
| 69 | For example, I will be using the | |
| 70 | [[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]] | |
| 71 | patch in the below example. | |
| 65 | Next, grab the =<path>.diff= file from the page of the patch you chose. For | |
| 66 | example, I will be using the [[https://st.suckless.org/patches/defaultfontsize/][defaultfontsize]] patch in the below example. | |
| 72 | 67 | |
| 73 | 68 | #+begin_src sh |
| 74 | 69 | wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225-4ef0cbd.diff |
| 75 | 70 | #+end_src |
| 76 | 71 | |
| 77 | 72 | Once the file is downloaded inside the =st= folder, apply the patch and |
| 78 | re-install the program. You may need to install the =patch= command if | |
| 79 | you don't have it installed already (you should have installed it | |
| 80 | above). | |
| 73 | re-install the program. You may need to install the =patch= command if you don't | |
| 74 | have it installed already (you should have installed it above). | |
| 81 | 75 | |
| 82 | 76 | #+begin_src sh |
| 83 | 77 | patch -i st-defaultfontsize-20210225-4ef0cbd.diff |
| 84 | 78 | sudo make clean install |
| 85 | 79 | #+end_src |
| 86 | 80 | |
| 87 | Once installed, you can use the default font size patch to launch =st= | |
| 88 | with any font size you wish: | |
| 81 | Once installed, you can use the default font size patch to launch =st= with any | |
| 82 | font size you wish: | |
| 89 | 83 | |
| 90 | 84 | #+begin_src sh |
| 91 | 85 | st -z 16 |
content/blog/2022-12-23-alpine-desktop.org +43 −45
| @@ -5,30 +5,31 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Isn't Alpine Linux for Servers? |
| 7 | 7 | |
| 8 | This is a question I see a lot when people are presented with an example | |
| 9 | of Alpine Linux running as a desktop OS. | |
| 8 | This is a question I see a lot when people are presented with an example of | |
| 9 | Alpine Linux running as a desktop operating system (OS). | |
| 10 | 10 | |
| 11 | While Alpine is small, fast, and minimal, that doesn't stop it from | |
| 12 | functioning at a productive level for desktop users. | |
| 11 | While Alpine is small, fast, and minimal, that doesn't stop it from functioning | |
| 12 | at a productive level for desktop users. | |
| 13 | 13 | |
| 14 | This post is documentation of how I installed and modified Alpine Linux | |
| 15 | to become my daily desktop OS. | |
| 14 | This post is documentation of how I installed and modified Alpine Linux to | |
| 15 | become my daily desktop OS. | |
| 16 | 16 | |
| 17 | 17 | * Installation |
| 18 | 18 | |
| 19 | Note that I cover the installation of Alpine Linux in my other post, so | |
| 20 | I won't repeat it here: [[../alpine-linux/][Alpine Linux: My New Server | |
| 21 | OS]]. | |
| 19 | Note that I cover the installation of Alpine Linux in my other post, so I won't | |
| 20 | repeat it here: [[https://cleberg.net/blog/alpine-linux.html][Alpine Linux Essentials: Installing and Setting Up a Secure | |
| 21 | Minimal Server]]. | |
| 22 | 22 | |
| 23 | Basically, get a bootable USB or whatever you prefer with Alpine on it, | |
| 24 | boot the ISO, and run the setup script. | |
| 23 | Basically, get a bootable USB (Universal Serial Bus) device or whatever you | |
| 24 | prefer with Alpine on it, boot the optical disc image (ISO), and run the setup | |
| 25 | script. | |
| 25 | 26 | |
| 26 | 27 | #+begin_src sh |
| 27 | 28 | setup-alpine |
| 28 | 29 | #+end_src |
| 29 | 30 | |
| 30 | Once you have gone through all the options and installer finishes | |
| 31 | without errors, reboot. | |
| 31 | Once you have gone through all the options and installer finishes without | |
| 32 | errors, reboot. | |
| 32 | 33 | |
| 33 | 34 | #+begin_src sh |
| 34 | 35 | reboot |
| @@ -37,9 +38,9 @@ reboot | ||
| 37 | 38 | * Initial Setup |
| 38 | 39 | |
| 39 | 40 | Once Alpine is installed and the machine has rebooted, login is as root |
| 40 | initially or =su= to root once you log in as your user. From here, you | |
| 41 | should start by updating and upgrading the system in case the ISO was | |
| 42 | not fully up-to-date. | |
| 41 | initially or =su= to root once you log in as your user. From here, you should | |
| 42 | start by updating and upgrading the system in case the ISO was not fully | |
| 43 | up-to-date. | |
| 43 | 44 | |
| 44 | 45 | #+begin_src sh |
| 45 | 46 | # Update and upgrade system |
| @@ -49,8 +50,8 @@ apk -U update && apk -U upgrade | ||
| 49 | 50 | apk add nano |
| 50 | 51 | #+end_src |
| 51 | 52 | |
| 52 | You need to uncomment the =community= repository for your version of | |
| 53 | Alpine Linux. | |
| 53 | You need to uncomment the =community= repository for your version of Alpine | |
| 54 | Linux. | |
| 54 | 55 | |
| 55 | 56 | For v3.17, the =repositories= file should look like this: |
| 56 | 57 | |
| @@ -77,11 +78,11 @@ adduser $USER wheel | ||
| 77 | 78 | |
| 78 | 79 | * Window Manager (Desktop) |
| 79 | 80 | |
| 80 | The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]] | |
| 81 | has everything you need to get Sway working on Alpine. | |
| 81 | The [[https://wiki.alpinelinux.org/wiki/Sway][Sway installation guide]] has everything you need to get Sway working on | |
| 82 | Alpine. | |
| 82 | 83 | |
| 83 | However, I'll include a brief list of the commands I ran and their | |
| 84 | purpose for posterity here. | |
| 84 | However, I'll include a brief list of the commands I ran and their purpose for | |
| 85 | posterity here. | |
| 85 | 86 | |
| 86 | 87 | #+begin_src sh |
| 87 | 88 | # Add eudev and set it up |
| @@ -125,8 +126,8 @@ apk add \ # Install optional dependencies: | ||
| 125 | 126 | Once you have the packages installed and set-up, you need to export the |
| 126 | 127 | =XDG_RUNTIME_DIR= upon login. To do this, edit your =.profile= file. |
| 127 | 128 | |
| 128 | If you use another shell, such as =zsh=, you need to edit that shell's | |
| 129 | profile (e.g., =~/.zprofile=)! | |
| 129 | If you use another shell, such as =zsh=, you need to edit that shell's profile | |
| 130 | (e.g., =~/.zprofile=)! | |
| 130 | 131 | |
| 131 | 132 | #+begin_src sh |
| 132 | 133 | nano ~/.profile |
| @@ -152,8 +153,7 @@ dbus-run-session -- sway | ||
| 152 | 153 | |
| 153 | 154 | ** Personal Touches |
| 154 | 155 | |
| 155 | I also added the following packages, per my personal preferences and | |
| 156 | situation. | |
| 156 | I also added the following packages, per my personal preferences and situation. | |
| 157 | 157 | |
| 158 | 158 | #+begin_src sh |
| 159 | 159 | doas apk add brightnessctl \ # Brightness controller |
| @@ -174,8 +174,8 @@ stored from prior desktops, such as my [[https://git.cleberg.net/dotfiles.git][d | ||
| 174 | 174 | |
| 175 | 175 | ** WiFi Issues |
| 176 | 176 | |
| 177 | I initially tried to set up my Wi-Fi the standard way with =iwd=, but it | |
| 178 | didn't work. | |
| 177 | I initially tried to set up my Wi-Fi the standard way with =iwd=, but it didn't | |
| 178 | work. | |
| 179 | 179 | |
| 180 | 180 | Here is what I initially tried (I did all of this as =root=): |
| 181 | 181 | |
| @@ -186,8 +186,7 @@ iwctl station wlan0 connect <SSID> # This will prompt for the password | ||
| 186 | 186 | rc-update add iwd boot && rc-update add dbus boot |
| 187 | 187 | #+end_src |
| 188 | 188 | |
| 189 | Then, I added the Wi-Fi entry to the bottom of the networking interface | |
| 190 | file: | |
| 189 | Then, I added the Wi-Fi entry to the bottom of the networking interface file: | |
| 191 | 190 | |
| 192 | 191 | #+begin_src sh |
| 193 | 192 | nano /etc/network/interfaces |
| @@ -204,13 +203,13 @@ Finally, restart the networking service: | ||
| 204 | 203 | rc-service networking restart |
| 205 | 204 | #+end_src |
| 206 | 205 | |
| 207 | My Wi-Fi interface would receive an IP address from the router, but it | |
| 208 | could not ping anything in the network. To solve the Wi-Fi issues, I | |
| 209 | originally upgraded to Alpine's =edge= repositories, which was | |
| 206 | My Wi-Fi interface would receive an internet protocol (IP) address from the | |
| 207 | router, but it could not ping anything in the network. To solve the Wi-Fi | |
| 208 | issues, I originally upgraded to Alpine's =edge= repositories, which was | |
| 210 | 209 | unnecessary. |
| 211 | 210 | |
| 212 | Really, the solution was to enable the =NameResolvingService=resolvconf= | |
| 213 | in =/etc/iwd/main.conf=. | |
| 211 | Really, the solution was to enable the =NameResolvingService=resolvconf= in | |
| 212 | =/etc/iwd/main.conf=. | |
| 214 | 213 | |
| 215 | 214 | #+begin_src sh |
| 216 | 215 | doas nano /etc/iwd/main.conf |
| @@ -226,11 +225,10 @@ Once I finished this process, my Wi-Fi is working flawlessly. | ||
| 226 | 225 | |
| 227 | 226 | ** Sound Issues |
| 228 | 227 | |
| 229 | Same as with the Wi-Fi, I had no sound and could not control the | |
| 230 | mute/unmute or volume buttons on my laptop. | |
| 228 | Same as with the Wi-Fi, I had no sound and could not control the mute/unmute or | |
| 229 | volume buttons on my laptop. | |
| 231 | 230 | |
| 232 | To resolve this, I installed | |
| 233 | [[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]]. | |
| 231 | To resolve this, I installed [[https://wiki.alpinelinux.org/wiki/PipeWire][pipewire]]. | |
| 234 | 232 | |
| 235 | 233 | #+begin_src sh |
| 236 | 234 | # Add your user to the following groups |
| @@ -242,8 +240,8 @@ apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa | ||
| 242 | 240 | #+end_src |
| 243 | 241 | |
| 244 | 242 | Finally, I needed to add =/usr/libexec/pipewire-launcher= to my |
| 245 | =.config/sway/config= file so that Pipewire would run every time I | |
| 246 | launched sway. | |
| 243 | =.config/sway/config= file so that Pipewire would run every time I launched | |
| 244 | sway. | |
| 247 | 245 | |
| 248 | 246 | #+begin_src sh |
| 249 | 247 | nano ~/.config/sway/config |
| @@ -260,8 +258,8 @@ bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ to | ||
| 260 | 258 | bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle |
| 261 | 259 | #+end_src |
| 262 | 260 | |
| 263 | Note that I do not use bluetooth or screen sharing, so I won't cover | |
| 264 | those options in this post. | |
| 261 | Note that I do not use bluetooth or screen sharing, so I won't cover those | |
| 262 | options in this post. | |
| 265 | 263 | |
| 266 | Other than these issues, I have a working Alpine desktop. No other | |
| 267 | complaints thus far! | |
| 264 | Other than these issues, I have a working Alpine desktop. No other complaints | |
| 265 | thus far! | |