Commit ce7749abd0
Unsigned
Layout: unified · split
content/blog/2021-01-01-seum.org +6 −8
| @@ -5,12 +5,9 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Game Description |
| 7 | 7 | |
| 8 | [[https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/][SEUM: | |
| 9 | Speedrunners from Hell]] is an incredibly fast-paced mashup of a puzzle | |
| 10 | game and a free-running game. Created by [[https://pinestudio.co][Pine | |
| 11 | Studio]] in early 2016 and first released as a | |
| 12 | [[https://gamejolt.com/games/seum-speedrunners-from-hell-demo/154868][demo | |
| 13 | on GameJolt]], this game was successfully green-lit on Steam and has | |
| 8 | [[https://store.steampowered.com/app/457210/SEUM_Speedrunners_from_Hell/][SEUM: Speedrunners from Hell]] is an incredibly fast-paced mashup of a puzzle game | |
| 9 | and a free-running game. Created by [[https://pinestudio.co][Pine Studio]] in early 2016 and first released | |
| 10 | as a [[https://gamejolt.com/games/seum-speedrunners-from-hell-demo/154868][demo on GameJolt]], this game was successfully green-lit on Steam and has | |
| 14 | 11 | amassed a cult following on multiple consoles. |
| 15 | 12 | |
| 16 | 13 | Here's the game description straight from the developers: |
| @@ -57,8 +54,9 @@ contains nine regular levels, one boss level, and one bonus level; | ||
| 57 | 54 | although you don't technically need to beat all levels to advance to the |
| 58 | 55 | next floor. # In-Game Screenshots |
| 59 | 56 | |
| 60 | The main menu gives you plenty of options for tuning your system, | |
| 61 | playing main levels, playing the DLC, or exploring the other game modes. | |
| 57 | The main menu gives you plenty of options for tuning your system, playing main | |
| 58 | levels, playing the downloadable content (DLC), or exploring the other game | |
| 59 | modes. | |
| 62 | 60 | |
| 63 | 61 | Once you enter a level, you can look around and strategize before |
| 64 | 62 | starting. Clicking any button will start the menu, and you'll have to |
content/blog/2021-01-04-fediverse.org +41 −44
| @@ -5,53 +5,51 @@ | ||
| 5 | 5 | |
| 6 | 6 | * What is the Fediverse? |
| 7 | 7 | |
| 8 | The fediverse is a federated universe of servers commonly used for | |
| 9 | sharing content, like social media. So, instead of having to rely on a | |
| 10 | single organization to run the server (e.g. Facebook), the fediverse is | |
| 11 | a giant collection of servers across the world, owned by many people and | |
| 12 | organizations. | |
| 13 | ||
| 14 | Take a look at this depiction of a federated network. Each server in | |
| 15 | this photo is owned and run by different administrators/owners. | |
| 16 | Federated networks are best explained as email servers: you have an | |
| 17 | email account that exists on a server (e.g. Outlook), your friend has an | |
| 18 | account on a different server (e.g. GMail), and another friend has an | |
| 19 | account on a third server (e.g. ProtonMail). All three of you can talk | |
| 20 | and communicate back and forth without having to be on the same server. | |
| 21 | However, responsible email admins are there to set rules and control the | |
| 8 | The fediverse is a federated universe of servers commonly used for sharing | |
| 9 | content, like social media. So, instead of having to rely on a single | |
| 10 | organization to run the server (e.g. Facebook), the fediverse is a giant | |
| 11 | collection of servers across the world, owned by many people and organizations. | |
| 12 | ||
| 13 | Take a look at this depiction of a federated network. Each server in this photo | |
| 14 | is owned and run by different administrators/owners. Federated networks are best | |
| 15 | explained as email servers: you have an email account that exists on a server | |
| 16 | (e.g. Outlook), your friend has an account on a different server (e.g. GMail), | |
| 17 | and another friend has an account on a third server (e.g. ProtonMail). All three | |
| 18 | of you can talk and communicate back and forth without having to be on the same | |
| 19 | server. However, responsible email admins are there to set rules and control the | |
| 22 | 20 | traffic going in/out of the server. |
| 23 | 21 | |
| 24 | The main objective of this architecture is to decentralize the control | |
| 25 | within the internet connections. For example, if you run your own | |
| 26 | Mastodon instance, you and your users can't be censored or impacted in | |
| 27 | any way by authorities of another Mastodon instance. Some users have | |
| 28 | praised these features due to recent criticism of popular social media | |
| 29 | websites that may be over-censoring their users. | |
| 22 | The main objective of this architecture is to decentralize the control within | |
| 23 | the internet connections. For example, if you run your own Mastodon instance, | |
| 24 | you and your users can't be censored or impacted in any way by authorities of | |
| 25 | another Mastodon instance. Some users have praised these features due to recent | |
| 26 | criticism of popular social media websites that may be over-censoring their | |
| 27 | users. | |
| 30 | 28 | |
| 31 | 29 | This strategy is great for making sure control of the social web isn't |
| 32 | controlled by a single organization, but it also has some downsides. If | |
| 33 | I create a Mastodon instance and get a ton of users to sign up, I can | |
| 34 | shut the server down at any time. That means you're at risk of losing | |
| 35 | the content you've created unless you back it up, or the server backs it | |
| 36 | up for you. Also, depending on the software used (e.g. Mastodon, | |
| 37 | Pixelfed, etc.), censorship may still be an issue if the server admins | |
| 38 | decide they want to censor their users. Now, censorship isn't always a | |
| 39 | bad thing and can even benefit the community as a whole, but you'll want | |
| 40 | to determine which servers align with your idea of proper censorship. | |
| 41 | ||
| 42 | However, these are risks that we take when we sign up for any online | |
| 43 | platform. Whatever your reason is for trying out federated social | |
| 44 | networks, they are part of the future of the internet. However, the | |
| 45 | popularity of these services is still yet to be determined, especially | |
| 46 | with the increased difficulty understanding and signing up for these | |
| 47 | platforms. Perhaps increased regulation and litigation against current | |
| 48 | social media sites will push more users into the fediverse. | |
| 30 | controlled by a single organization, but it also has some downsides. If I create | |
| 31 | a Mastodon instance and get a ton of users to sign up, I can shut the server | |
| 32 | down at any time. That means you're at risk of losing the content you've created | |
| 33 | unless you back it up, or the server backs it up for you. Also, depending on the | |
| 34 | software used (e.g. Mastodon, Pixelfed, etc.), censorship may still be an issue | |
| 35 | if the server admins decide they want to censor their users. Now, censorship | |
| 36 | isn't always a bad thing and can even benefit the community as a whole, but | |
| 37 | you'll want to determine which servers align with your idea of proper | |
| 38 | censorship. | |
| 39 | ||
| 40 | However, these are risks that we take when we sign up for any online platform. | |
| 41 | Whatever your reason is for trying out federated social networks, they are part | |
| 42 | of the future of the internet. However, the popularity of these services is | |
| 43 | still yet to be determined, especially with the increased difficulty | |
| 44 | understanding and signing up for these platforms. Perhaps increased regulation | |
| 45 | and litigation against current social media sites will push more users into the | |
| 46 | fediverse. | |
| 49 | 47 | |
| 50 | 48 | * Federated Alternatives to Popular Sites |
| 51 | 49 | |
| 52 | The list below is a small guide that will show you federated | |
| 53 | alternatives to current popular websites. There are many more out there, | |
| 54 | so go and explore: you might just find the perfect home. | |
| 50 | The list below is a small guide that will show you federated alternatives to | |
| 51 | current popular websites. There are many more out there, so go and explore: you | |
| 52 | might just find the perfect home. | |
| 55 | 53 | |
| 56 | 54 | |
| 57 | 55 | |
| @@ -91,10 +89,9 @@ so go and explore: you might just find the perfect home. | ||
| 91 | 89 | |
| 92 | 90 | * Get Started |
| 93 | 91 | |
| 94 | The best way to get started is to simply sign up and learn as you go. If | |
| 95 | you're comfortable signing up through a Mastodon, Pleroma, or Friendica | |
| 96 | server, here is [[https://fediverse.party/en/portal/servers][a list of | |
| 97 | themed servers]] to choose from. If you're looking for something else, | |
| 92 | The best way to get started is to simply sign up and learn as you go. If you're | |
| 93 | comfortable signing up through a Mastodon, Pleroma, or Friendica server, here is | |
| 94 | [[https://fediverse.party/en/portal/servers][a list of themed servers]] to choose from. If you're looking for something else, | |
| 98 | 95 | try a web search for a federated alternative to your favorite sites. |
| 99 | 96 | |
| 100 | 97 | Find a server that focuses on your passions and start there! |
content/blog/2021-01-07-ufw.org +49 −53
| @@ -5,22 +5,21 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Uncomplicated Firewall |
| 7 | 7 | |
| 8 | Uncomplicated Firewall, also known as ufw, is a convenient and | |
| 9 | beginner-friendly way to enforce OS-level firewall rules. For those who | |
| 10 | are hosting servers or any device that is accessible to the world (i.e., | |
| 11 | by public IP or domain name), it's critical that a firewall is properly | |
| 12 | implemented and active. | |
| 13 | ||
| 14 | Ufw is available by default in all Ubuntu installations after 8.04 LTS. | |
| 15 | For other distributions, you can look to install ufw or check if there | |
| 16 | are alternative firewalls installed already. There are usually | |
| 17 | alternatives available, such as Fedora's =firewall= and the package | |
| 18 | available on most distributions: =iptables=. Ufw is considered a | |
| 19 | beginner-friendly front-end to iptables. | |
| 20 | ||
| 21 | [[https://gufw.org][Gufw]] is available as a graphical user interface | |
| 22 | (GUI) application for users who are uncomfortable setting up a firewall | |
| 23 | through a terminal. | |
| 8 | Uncomplicated Firewall (UFW) is a convenient and beginner-friendly | |
| 9 | way to enforce operating system (OS)-level firewall rules. For those who are | |
| 10 | hosting servers or any device that is accessible to the world (i.e., by public | |
| 11 | IP or domain name), it's critical that a firewall is properly implemented and | |
| 12 | active. | |
| 13 | ||
| 14 | UFW is available by default in all Ubuntu installations after 8.04 LTS | |
| 15 | (long-term support). For other distributions, you can look to install UFW or | |
| 16 | check if there are alternative firewalls installed already. There are usually | |
| 17 | alternatives available, such as Fedora's =firewall= and the package available on | |
| 18 | most distributions: =iptables=. UFW is considered a beginner-friendly front-end | |
| 19 | to iptables. | |
| 20 | ||
| 21 | [[https://gufw.org][Gufw]] is available as a graphical user interface (GUI) application for users who | |
| 22 | are uncomfortable setting up a firewall through a terminal. | |
| 24 | 23 | |
| 25 | 24 | * Getting Help |
| 26 | 25 | |
| @@ -33,20 +32,19 @@ sudo ufw --help | ||
| 33 | 32 | |
| 34 | 33 | * Set Default State |
| 35 | 34 | |
| 36 | The proper way to run a firewall is to set a strict default state and | |
| 37 | slowly open up ports that you want to allow. This helps prevent anything | |
| 38 | malicious from slipping through the cracks. The following command | |
| 39 | prevents all incoming traffic (other than the rules we specify later), | |
| 40 | but you can also set this for outgoing connections, if necessary. | |
| 35 | The proper way to run a firewall is to set a strict default state and slowly | |
| 36 | open up ports that you want to allow. This helps prevent anything malicious from | |
| 37 | slipping through the cracks. The following command prevents all incoming traffic | |
| 38 | (other than the rules we specify later), but you can also set this for outgoing | |
| 39 | connections, if necessary. | |
| 41 | 40 | |
| 42 | 41 | #+begin_src sh |
| 43 | 42 | sudo ufw default deny incoming |
| 44 | 43 | #+end_src |
| 45 | 44 | |
| 46 | You should also allow outgoing traffic if you want to allow the device | |
| 47 | to communicate back to you or other parties. For example, media servers | |
| 48 | like Plex need to be able to send out data related to streaming the | |
| 49 | media. | |
| 45 | You should also allow outgoing traffic if you want to allow the device to | |
| 46 | communicate back to you or other parties. For example, media servers like Plex | |
| 47 | need to be able to send out data related to streaming the media. | |
| 50 | 48 | |
| 51 | 49 | #+begin_src sh |
| 52 | 50 | sudo ufw default allow outgoing |
| @@ -54,23 +52,23 @@ sudo ufw default allow outgoing | ||
| 54 | 52 | |
| 55 | 53 | * Adding Port Rules |
| 56 | 54 | |
| 57 | Now that we've disabled all incoming traffic by default, we need to open | |
| 58 | up some ports (or else no traffic would be able to come in). If you need | |
| 59 | to be able to =ssh= into the machine, you'll need to open up port 22. | |
| 55 | Now that we've disabled all incoming traffic by default, we need to open up some | |
| 56 | ports (or else no traffic would be able to come in). If you need to be able to | |
| 57 | =ssh= into the machine, you'll need to open up port 22. | |
| 60 | 58 | |
| 61 | 59 | #+begin_src sh |
| 62 | 60 | sudo ufw allow 22 |
| 63 | 61 | #+end_src |
| 64 | 62 | |
| 65 | You can also issue more restrictive rules. The following rule will allow | |
| 66 | =ssh= connections only from machines on the local subnet. | |
| 63 | You can also issue more restrictive rules. The following rule will allow =ssh= | |
| 64 | (secure shell protocol) connections only from machines on the local subnet. | |
| 67 | 65 | |
| 68 | 66 | #+begin_src sh |
| 69 | 67 | sudo ufw allow proto tcp from 192.168.0.0/24 to any port 22 |
| 70 | 68 | #+end_src |
| 71 | 69 | |
| 72 | If you need to set a rule that isn't tcp, just append your connection | |
| 73 | type to the end of the rule. | |
| 70 | If you need to set a rule that isn't TCP (Transmission Control Protocol) just | |
| 71 | append your connection type to the end of the rule. | |
| 74 | 72 | |
| 75 | 73 | #+begin_src sh |
| 76 | 74 | sudo ufw allow 1900/udp |
| @@ -93,8 +91,7 @@ sudo reboot now | ||
| 93 | 91 | |
| 94 | 92 | * Checking Status |
| 95 | 93 | |
| 96 | Now that the firewall is enabled, let's check and see what the rules | |
| 97 | look like. | |
| 94 | Now that the firewall is enabled, let's check and see what the rules look like. | |
| 98 | 95 | |
| 99 | 96 | #+begin_src sh |
| 100 | 97 | sudo ufw status numbered |
| @@ -111,9 +108,9 @@ Status: active | ||
| 111 | 108 | |
| 112 | 109 | * Deleting Rules |
| 113 | 110 | |
| 114 | If you need to delete a rule, you need to know the number associated | |
| 115 | with that rule. Let's delete the first rule in the table above. You'll | |
| 116 | be asked to confirm the deletion as part of this process. | |
| 111 | If you need to delete a rule, you need to know the number associated with that | |
| 112 | rule. Let's delete the first rule in the table above. You'll be asked to confirm | |
| 113 | the deletion as part of this process. | |
| 117 | 114 | |
| 118 | 115 | #+begin_src sh |
| 119 | 116 | sudo ufw delete 1 |
| @@ -121,11 +118,10 @@ sudo ufw delete 1 | ||
| 121 | 118 | |
| 122 | 119 | * Managing App Rules |
| 123 | 120 | |
| 124 | Luckily, there's a convenient way for installed applications to create | |
| 125 | files that ufw can easily implement so that you don't have to search and | |
| 126 | find which ports your application requires. To see if your device has | |
| 127 | any applications with pre-installed ufw rules, execute the following | |
| 128 | command: | |
| 121 | Luckily, there's a convenient way for installed applications to create files | |
| 122 | that ufw can easily implement so that you don't have to search and find which | |
| 123 | ports your application requires. To see if your device has any applications with | |
| 124 | pre-installed UFW rules, execute the following command: | |
| 129 | 125 | |
| 130 | 126 | #+begin_src sh |
| 131 | 127 | sudo ufw app list |
| @@ -142,8 +138,8 @@ Available applications: | ||
| 142 | 138 | plexmediaserver-dlna |
| 143 | 139 | #+end_src |
| 144 | 140 | |
| 145 | If you want to get more information on a specific app rule, use the | |
| 146 | =info= command. | |
| 141 | If you want to get more information on a specific app rule, use the =info= | |
| 142 | command. | |
| 147 | 143 | |
| 148 | 144 | #+begin_src sh |
| 149 | 145 | sudo ufw app info plexmediaserver-dlna |
| @@ -161,8 +157,8 @@ Ports: | ||
| 161 | 157 | 32469/tcp |
| 162 | 158 | #+end_src |
| 163 | 159 | |
| 164 | You can add or delete app rules the same way that you'd add or delete | |
| 165 | specific port rules. | |
| 160 | You can add or delete app rules the same way that you'd add or delete specific | |
| 161 | port rules. | |
| 166 | 162 | |
| 167 | 163 | #+begin_src sh |
| 168 | 164 | sudo ufw allow plexmediaserver-dlna |
| @@ -174,12 +170,12 @@ sudo ufw delete RULE|NUM | ||
| 174 | 170 | |
| 175 | 171 | * Creating App Rules |
| 176 | 172 | |
| 177 | If you'd like to create you own app rule, you'll need to create a file | |
| 178 | in the =/etc/ufw/applications.d= directory. Within the file you create, | |
| 179 | you need to make sure the content is properly formatted. | |
| 173 | If you'd like to create you own app rule, you'll need to create a file in the | |
| 174 | =/etc/ufw/applications.d= directory. Within the file you create, you need to | |
| 175 | make sure the content is properly formatted. | |
| 180 | 176 | |
| 181 | For example, here are the contents my =plexmediaserver= file, which | |
| 182 | creates three distinct app rules for ufw: | |
| 177 | For example, here are the contents my =plexmediaserver= file, which creates | |
| 178 | three distinct app rules for ufw: | |
| 183 | 179 | |
| 184 | 180 | #+begin_src config |
| 185 | 181 | [plexmediaserver] |
| @@ -198,8 +194,8 @@ description=The Plex Media Server (with additional DLNA capability) | ||
| 198 | 194 | ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp |
| 199 | 195 | #+end_src |
| 200 | 196 | |
| 201 | So, if I wanted to create a custom app rule called "mycustomrule," I'd | |
| 202 | create a file and add my content like this: | |
| 197 | So, if I wanted to create a custom app rule called "mycustomrule," I'd create a | |
| 198 | file and add my content like this: | |
| 203 | 199 | |
| 204 | 200 | #+begin_src sh |
| 205 | 201 | sudo nano /etc/ufw/applications.d/mycustomrule |
content/blog/2021-02-19-macos.org +87 −96
| @@ -5,74 +5,69 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Diving into macOS |
| 7 | 7 | |
| 8 | After spending nearly 15 years working with Windows and 8 years on | |
| 9 | Linux, I have experienced macOS for the first time. By chance, my spouse | |
| 10 | happened to buy a new MacBook and gifted me their 2013 model. Of course, | |
| 11 | I still consider my Linux desktop to be my daily driver and keep Windows | |
| 12 | around for gaming needs, but over the past week I've found myself using | |
| 13 | the MacBook more and more for things that don't require gaming specs or | |
| 14 | advanced dev tools. | |
| 8 | After spending nearly 15 years working with Windows and 8 years on Linux, I have | |
| 9 | experienced macOS for the first time. By chance, my spouse happened to buy a new | |
| 10 | MacBook and gifted me their 2013 model. Of course, I still consider my Linux | |
| 11 | desktop to be my daily driver and keep Windows around for gaming needs, but over | |
| 12 | the past week I've found myself using the MacBook more and more for things that | |
| 13 | don't require gaming specs or advanced developer tools. | |
| 15 | 14 | |
| 16 | 15 | * Initial Thoughts |
| 17 | 16 | |
| 18 | Before I move on to the technical aspects of my set-up, I want to take | |
| 19 | some time and express my thoughts on the overall OS. | |
| 20 | ||
| 21 | As expected, the initial computer setup is a breeze with Mac's guided | |
| 22 | GUI installer. | |
| 23 | ||
| 24 | The desktop itself reminds me of GNOME more than anything else I've | |
| 25 | seen: even Pantheon from [[https://elementary.io/][ElementaryOS]], which | |
| 26 | people commonly refer to as the closest Linux distro to macOS. The | |
| 27 | desktop toolbar is great and far surpasses the utility of the GNOME | |
| 28 | toolbar due to the fact that the extensions and icons /actually work/. I | |
| 29 | launch macOS and immediately see my shortcuts for Tresorit, Bitwarden, | |
| 30 | and Mullvad pop up as the computer loads. | |
| 31 | ||
| 32 | Even further, the app dock is very useful and will be yet another | |
| 33 | familiarity for GNOME users. I know many people like panels instead of | |
| 34 | docks, but I've always found docks to have a more pleasing UI. However, | |
| 35 | I had to disable the "Show recent applications in Dock" preference; I | |
| 36 | can't stand items taking up precious screen space if I'm not currently | |
| 37 | using them. On that same note, it's taking me some time to get use to | |
| 38 | the fact that I have to manually quit an app or else it will still stay | |
| 39 | open/active in the dock, even if I've closed out all windows for that | |
| 40 | app (e.g. Firefox). | |
| 41 | ||
| 42 | Overall, I'm having a lot of fun and for users who spend a large | |
| 43 | majority of their time performing basic tasks like web browsing, | |
| 44 | writing, watching media, etc., macOS is a fantastic option. | |
| 45 | ||
| 46 | The rest of this post explains the technicalities of how I set up my CLI | |
| 47 | environment to make me feel more at-home, similar to the environments I | |
| 48 | set up on Fedora, Ubuntu, etc. | |
| 17 | Before I move on to the technical aspects of my set-up, I want to take some time | |
| 18 | and express my thoughts on the overall operating system (OS). | |
| 19 | ||
| 20 | As expected, the initial computer setup is a breeze with Mac's guided graphical | |
| 21 | user interface (GUI) installer. | |
| 22 | ||
| 23 | The desktop itself reminds me of GNOME more than anything else I've seen: even | |
| 24 | Pantheon from [[https://elementary.io/][ElementaryOS]], which people commonly refer to as the closest Linux | |
| 25 | distro to macOS. The desktop toolbar is great and far surpasses the utility of | |
| 26 | the GNOME toolbar due to the fact that the extensions and icons /actually work/. | |
| 27 | I launch macOS and immediately see my shortcuts for Tresorit, Bitwarden, and | |
| 28 | Mullvad pop up as the computer loads. | |
| 29 | ||
| 30 | Even further, the app dock is very useful and will be yet another familiarity | |
| 31 | for GNOME users. I know many people like panels instead of docks, but I've | |
| 32 | always found docks to have a more pleasing UI. However, I had to disable the | |
| 33 | "Show recent applications in Dock" preference; I can't stand items taking up | |
| 34 | precious screen space if I'm not currently using them. On that same note, it's | |
| 35 | taking me some time to get use to the fact that I have to manually quit an app | |
| 36 | or else it will still stay open/active in the dock, even if I've closed out all | |
| 37 | windows for that app (e.g. Firefox). | |
| 38 | ||
| 39 | Overall, I'm having a lot of fun and for users who spend a large majority of | |
| 40 | their time performing basic tasks like web browsing, writing, watching media, | |
| 41 | etc., macOS is a fantastic option. | |
| 42 | ||
| 43 | The rest of this post explains the technicalities of how I set up my command | |
| 44 | line interface (CLI) environment to make me feel more at-home, similar to the | |
| 45 | environments I set up on Fedora, Ubuntu, etc. | |
| 49 | 46 | |
| 50 | 47 | * Making it Feel Like Home |
| 51 | 48 | |
| 52 | If you're someone who uses Linux primarily, no doubt your first thought | |
| 53 | when booting macOS will be the same as mine was: "Where is the terminal | |
| 54 | and how do I set up my favorite utilities?" | |
| 49 | If you're someone who uses Linux primarily, no doubt your first thought when | |
| 50 | booting macOS will be the same as mine was: "Where is the terminal and how do I | |
| 51 | set up my favorite utilities?" | |
| 55 | 52 | |
| 56 | Luckily, macOS hasn't completely hidden away the development tools from | |
| 57 | the average user. You can easily find the Terminal app in the Launchpad | |
| 58 | area, but it's probably not what you're used to. I was surprised (and | |
| 59 | happy) to see that the default shell is =zsh=, the shell I use on all of | |
| 60 | my Linux distros. However, the commands are not the same - even the ones | |
| 61 | you may think are native to the shell. Commands like =dir= do not exist, | |
| 62 | so other native commands like =ls -la= or =pwd= are more useful here. | |
| 53 | Luckily, macOS hasn't completely hidden away the development tools from the | |
| 54 | average user. You can easily find the Terminal app in the Launchpad area, but | |
| 55 | it's probably not what you're used to. I was surprised (and happy) to see that | |
| 56 | the default shell is =zsh=, the shell I use on all of my Linux distros. However, | |
| 57 | the commands are not the same - even the ones you may think are native to the | |
| 58 | shell. Commands like =dir= do not exist, so other native commands like =ls -la= | |
| 59 | or =pwd= are more useful here. | |
| 63 | 60 | |
| 64 | With only a few minutes of installing and tweaking a few packages, I was | |
| 65 | able to recreate a terminal environment that I feel very comfortable | |
| 66 | using. See the image below for a preview of the iTerm2 app with a split | |
| 67 | view between my macOS desktop shell and an SSH session into my server. | |
| 61 | With only a few minutes of installing and tweaking a few packages, I was able to | |
| 62 | recreate a terminal environment that I feel very comfortable using. See the | |
| 63 | image below for a preview of the iTerm2 app with a split view between my macOS | |
| 64 | desktop shell and an SSH (secure shell protocol) session into my server. | |
| 68 | 65 | |
| 69 | 66 | * Xcode |
| 70 | 67 | |
| 71 | My first step was to search the web for any hints on how to get =zsh= | |
| 72 | back up to the state I like, with extensions, themes, etc. My first step | |
| 73 | was to install the CLI tools for | |
| 74 | [[https://developer.apple.com/xcode/][Xcode]], Apple's suite of | |
| 75 | development tools. | |
| 68 | My first step was to search the web for any hints on how to get =zsh= back up to | |
| 69 | the state I like, with extensions, themes, etc. My first step was to install the | |
| 70 | CLI tools for [[https://developer.apple.com/xcode/][Xcode]], Apple's suite of development tools. | |
| 76 | 71 | |
| 77 | 72 | #+begin_src sh |
| 78 | 73 | sudo xcode-select -r |
| @@ -84,25 +79,25 @@ sudo xcode-select --install | ||
| 84 | 79 | |
| 85 | 80 | * Homebrew |
| 86 | 81 | |
| 87 | Next up is to install [[https://brew.sh][Homebrew]], a nifty package | |
| 88 | manager for macOS. | |
| 82 | Next up is to install [[https://brew.sh][Homebrew]], a nifty package manager for macOS. | |
| 89 | 83 | |
| 90 | 84 | #+begin_src sh |
| 91 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| 85 | /bin/bash -c "$(curl -fsSL | |
| 86 | https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| 92 | 87 | #+end_src |
| 93 | 88 | |
| 94 | 89 | I ran into a permission error when installing Homebrew: |
| 95 | 90 | |
| 96 | 91 | #+begin_src sh |
| 97 | Error: Failed to link all completions, docs and manpages: | |
| 98 | Permission denied @ rb_file_s_symlink - (../../../Homebrew/completions/zsh/_brew, /usr/local/share/zsh/site-functions/_brew) | |
| 99 | Failed during: /usr/local/bin/brew update --force --quiet | |
| 92 | Error: Failed to link all completions, docs and manpages: Permission denied @ | |
| 93 | rb_file_s_symlink - (../../../Homebrew/completions/zsh/_brew, | |
| 94 | /usr/local/share/zsh/site-functions/_brew) Failed during: | |
| 95 | /usr/local/bin/brew update --force --quiet | |
| 100 | 96 | #+end_src |
| 101 | 97 | |
| 102 | I found that the following permission modification worked like a charm. | |
| 103 | However, I noted that some users online discussed the fact that this | |
| 104 | solution may not work if your system has multiple users who use | |
| 105 | Homebrew. | |
| 98 | I found that the following permission modification worked like a charm. However, | |
| 99 | I noted that some users online discussed the fact that this solution may not | |
| 100 | work if your system has multiple users who use Homebrew. | |
| 106 | 101 | |
| 107 | 102 | #+begin_src sh |
| 108 | 103 | sudo chown -R $(whoami) $(brew --prefix)/* |
| @@ -120,16 +115,16 @@ brew cleanup | ||
| 120 | 115 | |
| 121 | 116 | * iTerm2 |
| 122 | 117 | |
| 123 | Now that I've installed the basic utilities for development, I moved | |
| 124 | onto installing iTerm2, a much better terminal than the default. | |
| 118 | Now that I've installed the basic utilities for development, I moved onto | |
| 119 | installing iTerm2, a much better terminal than the default. | |
| 125 | 120 | |
| 126 | 121 | #+begin_src sh |
| 127 | 122 | brew install --cask iterm2 |
| 128 | 123 | #+end_src |
| 129 | 124 | |
| 130 | I also used the =Make iTerm2 Default Term= and | |
| 131 | =Install Shell Integration= options in the iTerm2 application menu to | |
| 132 | make sure I don't run into any issues later on with different terminals. | |
| 125 | I also used the =Make iTerm2 Default Term= and =Install Shell Integration= | |
| 126 | options in the iTerm2 application menu to make sure I don't run into any issues | |
| 127 | later on with different terminals. | |
| 133 | 128 | |
| 134 | 129 | We will also install =zsh= so we can use it in iTerm2. |
| 135 | 130 | |
| @@ -139,54 +134,50 @@ brew install zsh | ||
| 139 | 134 | |
| 140 | 135 | * Oh-My-Zsh |
| 141 | 136 | |
| 142 | I've shown the great aspects of [[https://ohmyz.sh][Oh My Zsh]] in other | |
| 143 | blog posts, so I'll skip over that speech for now. Simply install it and | |
| 144 | run an update. | |
| 137 | I've shown the great aspects of [[https://ohmyz.sh][Oh My Zsh]] in other blog posts, so I'll skip over | |
| 138 | that speech for now. Simply install it and run an update. | |
| 145 | 139 | |
| 146 | 140 | #+begin_src sh |
| 147 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" | |
| 141 | sh -c "$(curl -fsSL | |
| 142 | https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" | |
| 148 | 143 | #+end_src |
| 149 | 144 | |
| 150 | 145 | #+begin_src sh |
| 151 | 146 | omz update |
| 152 | 147 | #+end_src |
| 153 | 148 | |
| 154 | Finally, restart the iTerm2 application to ensure all changes go into | |
| 155 | effect. | |
| 149 | Finally, restart the iTerm2 application to ensure all changes go into effect. | |
| 156 | 150 | |
| 157 | 151 | * Oh-My-Zsh Themes |
| 158 | 152 | |
| 159 | Let's change the theme of the terminal to make it a little more | |
| 160 | friendly. | |
| 153 | Let's change the theme of the terminal to make it a little more friendly. | |
| 161 | 154 | |
| 162 | 155 | #+begin_src sh |
| 163 | 156 | open ~/.zshrc |
| 164 | 157 | #+end_src |
| 165 | 158 | |
| 166 | The third section of this file should contain a line like the code | |
| 167 | below. Change that theme to | |
| 168 | [[https://github.com/ohmyzsh/ohmyzsh/wiki/Themes][any theme you want]], | |
| 169 | save the file, and exit. | |
| 159 | The third section of this file should contain a line like the code below. Change | |
| 160 | that theme to [[https://github.com/ohmyzsh/ohmyzsh/wiki/Themes][any theme you want]], save the file, and exit. | |
| 170 | 161 | |
| 171 | 162 | #+begin_src sh |
| 172 | 163 | ZSH_THEME="af-magic" |
| 173 | 164 | #+end_src |
| 174 | 165 | |
| 175 | After changing the =.zshrc= file, you'll need to close your terminal and | |
| 176 | re-open it to see the changes. Optionally, just open a new tab if you're | |
| 177 | using iTerm2, and you'll see the new shell config. | |
| 166 | After changing the =.zshrc= file, you'll need to close your terminal and re-open | |
| 167 | it to see the changes. Optionally, just open a new tab if you're using iTerm2, | |
| 168 | and you'll see the new shell config. | |
| 178 | 169 | |
| 179 | 170 | * Oh-My-Zsh Plugins |
| 180 | 171 | |
| 181 | 172 | Of course, my customization of =zsh= would not be complete without |
| 182 | [[https://github.com/zsh-users/zsh-autosuggestions][zsh-autosuggestions]]. | |
| 183 | This will bring up commands you've run in the past as you type them. For | |
| 184 | example, if you've run =ssh user@192.168.1.99= before, the terminal will | |
| 185 | show this command as soon as you start typing it (e.g. =zsh u=), and you | |
| 186 | can hit the right arrow to autocomplete the command. | |
| 173 | [[https://github.com/zsh-users/zsh-autosuggestions][zsh-autosuggestions]]. This will bring up commands you've run in the past as you | |
| 174 | type them. For example, if you've run =ssh user@192.168.1.99= before, the | |
| 175 | terminal will show this command as soon as you start typing it (e.g. =zsh u=), | |
| 176 | and you can hit the right arrow to autocomplete the command. | |
| 187 | 177 | |
| 188 | 178 | #+begin_src sh |
| 189 | git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions | |
| 179 | git clone https://github.com/zsh-users/zsh-autosuggestions | |
| 180 | ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions | |
| 190 | 181 | #+end_src |
| 191 | 182 | |
| 192 | 183 | #+begin_src sh |
| @@ -198,6 +189,6 @@ open ~/.zshrc | ||
| 198 | 189 | plugins=(git zsh-autosuggestions) |
| 199 | 190 | #+end_src |
| 200 | 191 | |
| 201 | Remember: After changing the =.zshrc= file, you'll need to close your | |
| 202 | terminal and re-open it to see the changes. Optionally, just open a new | |
| 203 | tab if you're using iTerm2, and you'll see the new shell config. | |
| \ No newline at end of file | ||
| 192 | Remember: After changing the =.zshrc= file, you'll need to close your terminal | |
| 193 | and re-open it to see the changes. Optionally, just open a new tab if you're | |
| 194 | using iTerm2, and you'll see the new shell config. | |
content/blog/2021-03-19-clone-github-repos.org +27 −27
| @@ -5,14 +5,14 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Cloning from GitHub |
| 7 | 7 | |
| 8 | If you're like me and use a lot of different devices (and sometimes | |
| 9 | decide to just wipe your device and start with a new OS), you probably | |
| 10 | know the pain of cloning all your old code repositories down to your | |
| 11 | local file system. | |
| 8 | If you're like me and use a lot of different devices [and sometimes decide to | |
| 9 | just wipe your device and start with a new operating system (OS)], you probably know | |
| 10 | the pain of cloning all your old code repositories down to your local file | |
| 11 | system. | |
| 12 | 12 | |
| 13 | If you're using GitHub, you can easily clone all of your code back down | |
| 14 | in just seconds. First, create a bash script. I do so by opening a new | |
| 15 | file in =nano=, but you can use =gedit=, =vim=, or something else: | |
| 13 | If you're using GitHub, you can easily clone all of your code back down in just | |
| 14 | seconds. First, create a bash script. I do so by opening a new file in =nano=, | |
| 15 | but you can use =gedit=, =vim=, or something else: | |
| 16 | 16 | |
| 17 | 17 | #+begin_src sh |
| 18 | 18 | nano clone_github_repos.sh |
| @@ -44,12 +44,12 @@ Now you can run the script and should see the cloning process begin. | ||
| 44 | 44 | |
| 45 | 45 | * Cloning from Sourcehut |
| 46 | 46 | |
| 47 | I haven't fully figured out how to directly incorporate Sourcehut's | |
| 48 | GraphQL API into a bash script yet, so this one will take two steps. | |
| 47 | I haven't fully figured out how to directly incorporate Sourcehut's GraphQL | |
| 48 | application programming interface (API) into a bash script yet, so this one will | |
| 49 | take two steps. | |
| 49 | 50 | |
| 50 | First, log-in to Sourcehut and go to their | |
| 51 | [[https://git.sr.ht/graphql][GraphQL playground for Git]]. Next, paste | |
| 52 | the following query into the left box: | |
| 51 | First, log-in to Sourcehut and go to their [[https://git.sr.ht/graphql][GraphQL playground for Git]]. Next, | |
| 52 | paste the following query into the left box: | |
| 53 | 53 | |
| 54 | 54 | #+begin_src sh |
| 55 | 55 | query { |
| @@ -65,10 +65,10 @@ query { | ||
| 65 | 65 | } |
| 66 | 66 | #+end_src |
| 67 | 67 | |
| 68 | The output on the right side will give you an object of all your | |
| 69 | repositories. Just grab that text and remove all the characters such as | |
| 70 | quotation marks and curly brackets. You will need a single-line list of | |
| 71 | space-separated values for the next step. | |
| 68 | The output on the right side will give you an object of all your repositories. | |
| 69 | Just grab that text and remove all the characters such as quotation marks and | |
| 70 | curly brackets. You will need a single-line list of space-separated values for | |
| 71 | the next step. | |
| 72 | 72 | |
| 73 | 73 | Now let's create the bash script: |
| 74 | 74 | |
| @@ -76,12 +76,12 @@ Now let's create the bash script: | ||
| 76 | 76 | nano clone_sourcehut_repos.sh |
| 77 | 77 | #+end_src |
| 78 | 78 | |
| 79 | Next, paste the following bash script in with the list of repositories | |
| 80 | you obtained above and replace =your-username= with your username. | |
| 79 | Next, paste the following bash script in with the list of repositories you | |
| 80 | obtained above and replace =your-username= with your username. | |
| 81 | 81 | |
| 82 | Note that this uses the SSH-based Git cloning method | |
| 83 | (e.g. =git@git...=), so you'll need to ensure you have set up Sourcehut | |
| 84 | with your SSH key. | |
| 82 | Note that this uses the secure shell protocol (SSH)-based Git cloning method | |
| 83 | (e.g. =git@git...=), so you'll need to ensure you have set up Sourcehut with | |
| 84 | your SSH key. | |
| 85 | 85 | |
| 86 | 86 | #+begin_src sh |
| 87 | 87 | repos=(repo1 repo2 repo3) |
| @@ -108,17 +108,17 @@ Now you can run the script and should see the cloning process begin. | ||
| 108 | 108 | |
| 109 | 109 | * Moving Repositories to a New Host |
| 110 | 110 | |
| 111 | Now that you have all of your code repositories cloned to your local | |
| 112 | computer, you may want to change the remote host (e.g., moving from | |
| 113 | GitHub to GitLab). To do this, let's create another bash script: | |
| 111 | Now that you have all of your code repositories cloned to your local computer, | |
| 112 | you may want to change the remote host (e.g., moving from GitHub to GitLab). To | |
| 113 | do this, let's create another bash script: | |
| 114 | 114 | |
| 115 | 115 | #+begin_src sh |
| 116 | 116 | nano change_remote_urls.sh |
| 117 | 117 | #+end_src |
| 118 | 118 | |
| 119 | Past the following information and be sure to change the URL information | |
| 120 | to whichever host you are moving to. For this example, I am looping | |
| 121 | through all of my cloned GitHub directories and changing them to | |
| 119 | Past the following information and be sure to change the URL (uniform resource | |
| 120 | locator) information to whichever host you are moving to. For this example, I am | |
| 121 | looping through all of my cloned GitHub directories and changing them to | |
| 122 | 122 | Sourcehut (e.g. =<YOUR_NEW_REMOTE_URL>= -> =git@git.sr.ht:~myusername=). |
| 123 | 123 | |
| 124 | 124 | #+begin_src sh |
content/blog/2021-03-28-gemini-capsule.org +63 −73
| @@ -5,21 +5,17 @@ | ||
| 5 | 5 | |
| 6 | 6 | * What is Gemini? |
| 7 | 7 | |
| 8 | [[https://gemini.circumlunar.space/][Gemini]] is an internet protocol | |
| 9 | introduced in June 2019 as an alternative to HTTP(S) or Gopher. In | |
| 10 | layman's terms, it's an alternative way to browse sites (called | |
| 11 | capsules) that requires a special browser. Since Gemini is not | |
| 12 | standardized as an internet standard, normal web browsers won't be able | |
| 13 | to load a Gemini capsule. Instead, you'll need to use | |
| 14 | [[https://gemini.circumlunar.space/clients.html][a Gemini-specific | |
| 15 | browser]]. | |
| 16 | ||
| 17 | The content found within a Gemini page is called | |
| 18 | [[https://gemini.circumlunar.space/docs/cheatsheet.gmi][Gemtext]] and is | |
| 19 | /extremely/ basic (on purpose). Gemini only processes the text, no media | |
| 20 | content like images. However, you're able to style 3 levels of headings, | |
| 21 | regular text, links (which will display on their own line), quotes, and | |
| 22 | an unordered list. | |
| 8 | [[https://gemini.circumlunar.space/][Gemini]] is an internet protocol introduced in June 2019 as an alternative to the | |
| 9 | Hypertext Transfer Protocol (HTTP) or Gopher. In layman's terms, it's an | |
| 10 | alternative way to browse sites (called capsules) that requires a special | |
| 11 | browser. Since Gemini is not standardized as an internet standard, normal web | |
| 12 | browsers won't be able to load a Gemini capsule. Instead, you'll need to use [[https://gemini.circumlunar.space/clients.html][a | |
| 13 | Gemini-specific browser]]. | |
| 14 | ||
| 15 | The content found within a Gemini page is called [[https://gemini.circumlunar.space/docs/cheatsheet.gmi][Gemtext]] and is /extremely/ | |
| 16 | basic (on purpose). Gemini only processes the text, no media content like | |
| 17 | images. However, you're able to style 3 levels of headings, regular text, links | |
| 18 | (which will display on their own line), quotes, and an unordered list. | |
| 23 | 19 | |
| 24 | 20 | Here's a complete listing of valid Gemtext: |
| 25 | 21 | |
| @@ -44,78 +40,72 @@ My List: | ||
| 44 | 40 | |
| 45 | 41 | *** Free Option |
| 46 | 42 | |
| 47 | There are probably numerous websites that allow you to create your | |
| 48 | personal Gemini capsule, but I'm going to focus on the two sites that I | |
| 49 | have personally tested. The first option below, Midnight Pub, allows you | |
| 50 | to create/edit any Gemini files you want in your account. This is | |
| 51 | essentially a GUI option with a built-in text box for editing. The | |
| 52 | second option below, Sourcehut, allows you to use a Git repository and | |
| 53 | automatic build process to deploy your personal Gemini capsule every | |
| 54 | time you push a commit. | |
| 43 | There are probably numerous websites that allow you to create your personal | |
| 44 | Gemini capsule, but I'm going to focus on the two sites that I have personally | |
| 45 | tested. The first option below, Midnight Pub, allows you to create/edit any | |
| 46 | Gemini files you want in your account. This is essentially a graphical option | |
| 47 | with a built-in text box for editing. The second option below, Sourcehut, allows | |
| 48 | you to use a Git repository and automatic build process to deploy your personal | |
| 49 | Gemini capsule every time you push a commit. | |
| 55 | 50 | |
| 56 | 51 | ** Midnight Pub - Beginner Friendly |
| 57 | 52 | |
| 58 | [[https://midnight.pub/][Midnight Pub]] is a small, virtual community | |
| 59 | meant to reflect the atmosphere of wandering into a small alley pub. The | |
| 60 | site is built in Gemtext and has a server-side process to convert | |
| 61 | Gemtext to HTML if someone loads the site in an HTTP(S) browser. | |
| 53 | [[https://midnight.pub/][Midnight Pub]] is a small, virtual community meant to reflect the atmosphere of | |
| 54 | wandering into a small alley pub. The site is built in Gemtext and has a | |
| 55 | server-side process to convert Gemtext to HTML if someone loads the site in an | |
| 56 | HTTP(S) browser. | |
| 62 | 57 | |
| 63 | To create an account, you'll need to email the owner of the website to | |
| 64 | obtain a key. You can find their email on the Midnight Pub homepage. | |
| 65 | Once registered, head to [[https://midnight.pub/account][your account]] | |
| 66 | and select [[https://midnight.pub/site][manage site]]. This is the | |
| 67 | screen where you can upload or create any files to be displayed on the | |
| 68 | internet. | |
| 58 | To create an account, you'll need to email the owner of the website to obtain a | |
| 59 | key. You can find their email on the Midnight Pub homepage. Once registered, | |
| 60 | head to [[https://midnight.pub/account][your account]] and select [[https://midnight.pub/site][manage site]]. This is the screen where you can | |
| 61 | upload or create any files to be displayed on the internet. | |
| 69 | 62 | |
| 70 | For example, I've created both an HTML file and a Gemini file. Remember | |
| 71 | that Gemini is automatically converted to HTML on the Pub, so you don't | |
| 72 | need an HTML version. For example, I created an HTML version to add in | |
| 73 | some extra styling. | |
| 63 | For example, I've created both a Hypertext Markup Language (HTML) file and a | |
| 64 | Gemini file. Remember that Gemini is automatically converted to HTML on the Pub, | |
| 65 | so you don't need an HTML version. For example, I created an HTML version to add | |
| 66 | in some extra styling. | |
| 74 | 67 | |
| 75 | All you need to do is create a page like =index.gmi= and use your Gemini | |
| 76 | browser to head over to your-username.midnight.pub to see the result. | |
| 68 | All you need to do is create a page like =index.gmi= and use your Gemini browser | |
| 69 | to head over to your-username.midnight.pub to see the result. | |
| 77 | 70 | |
| 78 | That's all there is to it! Easy enough, right? Let's check out a more | |
| 79 | advanced version in the next section. | |
| 71 | That's all there is to it! Easy enough, right? Let's check out a more advanced | |
| 72 | version in the next section. | |
| 80 | 73 | |
| 81 | 74 | * Paid Option |
| 82 | 75 | |
| 83 | As of 2021, Sourcehut has decided to require users to have a paid | |
| 84 | account in order to utilize their automated build system. For now, paid | |
| 85 | accounts can be as low as $2/month. | |
| 76 | As of 2021, Sourcehut has decided to require users to have a paid account in | |
| 77 | order to utilize their automated build system. For now, paid accounts can be as | |
| 78 | low as $2/month. | |
| 86 | 79 | |
| 87 | 80 | ** Sourcehut |
| 88 | 81 | |
| 89 | [[https://sourcehut.org/][Sourcehut]] is a collection of software | |
| 90 | development tools, but mostly surrounds their hosted Git repository | |
| 91 | service. Simply put, it's a minimal and more private alternative to | |
| 92 | services like GitHub. | |
| 82 | [[https://sourcehut.org/][Sourcehut]] is a collection of software development tools, but mostly surrounds | |
| 83 | their hosted Git repository service. Simply put, it's a minimal and more private | |
| 84 | alternative to services like GitHub. | |
| 93 | 85 | |
| 94 | This walkthrough is more advanced and involves things like Git, SSH, the | |
| 95 | command line. If you don't think you know enough to do this, check out | |
| 96 | my walkthrough on creating a Gemini capsule for the Midnight Pub | |
| 97 | instead. | |
| 86 | This walkthrough is more advanced and involves things like Git, SSH, the command | |
| 87 | line. If you don't think you know enough to do this, check out my walkthrough on | |
| 88 | creating a Gemini capsule for the Midnight Pub instead. | |
| 98 | 89 | |
| 99 | The first thing you'll need to do is create an SSH key pair, if you | |
| 100 | don't already have one on your system. Once created, grab the contents | |
| 101 | of =id_rsa.pub= and add it to your Sourcehut account settings - this | |
| 102 | will allow you to push and pull code changes without using a | |
| 103 | username/password. | |
| 90 | The first thing you'll need to do is create an SSH key pair, if you don't | |
| 91 | already have one on your system. Once created, grab the contents of =id_rsa.pub= | |
| 92 | and add it to your Sourcehut account settings - this will allow you to push and | |
| 93 | pull code changes without using a username/password. | |
| 104 | 94 | |
| 105 | 95 | #+begin_src sh |
| 106 | 96 | ssh keygen |
| 107 | 97 | #+end_src |
| 108 | 98 | |
| 109 | Next up, let's create a repository with the proper name so that the | |
| 110 | Sourcehut build system will know we want them to host a website for us. | |
| 111 | Use the following format exactly: | |
| 99 | Next up, let's create a repository with the proper name so that the Sourcehut | |
| 100 | build system will know we want them to host a website for us. Use the following | |
| 101 | format exactly: | |
| 112 | 102 | |
| 113 | 103 | #+begin_src sh |
| 114 | 104 | mkdir your-username.srht.site && cd your-username.srht.site |
| 115 | 105 | #+end_src |
| 116 | 106 | |
| 117 | Now that we've created the repo, let's initialize Git and add the proper | |
| 118 | remote URL. | |
| 107 | Now that we've created the repo, let's initialize Git and add the proper remote | |
| 108 | URL. | |
| 119 | 109 | |
| 120 | 110 | #+begin_src sh |
| 121 | 111 | git init |
| @@ -125,14 +115,14 @@ git init | ||
| 125 | 115 | git remote add origin git@git.sr.ht:~your-username/your-username.srht.site |
| 126 | 116 | #+end_src |
| 127 | 117 | |
| 128 | Now that our repository is set up and configured, we will need to create | |
| 129 | at least two files: | |
| 118 | Now that our repository is set up and configured, we will need to create at | |
| 119 | least two files: | |
| 130 | 120 | |
| 131 | 121 | - =index.gmi= |
| 132 | 122 | - =.build.yml= |
| 133 | 123 | |
| 134 | For your =.build.yml= file, use the following content and be sure to | |
| 135 | update the =site= line with your username! | |
| 124 | For your =.build.yml= file, use the following content and be sure to update the | |
| 125 | =site= line with your username! | |
| 136 | 126 | |
| 137 | 127 | #+begin_src yaml |
| 138 | 128 | image: alpine/latest |
| @@ -147,11 +137,11 @@ tasks: | ||
| 147 | 137 | acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI |
| 148 | 138 | #+end_src |
| 149 | 139 | |
| 150 | For the =index.gmi= file, put whatever you want in there and save it. | |
| 151 | You could even just copy and paste the Gemtext cheatsheet. | |
| 140 | For the =index.gmi= file, put whatever you want in there and save it. You could | |
| 141 | even just copy and paste the Gemtext cheatsheet. | |
| 152 | 142 | |
| 153 | If you want to serve both HTML and Gemini files from this repository, | |
| 154 | just add a second command to the =upload= section: | |
| 143 | If you want to serve both HTML and Gemini files from this repository, just add a | |
| 144 | second command to the =upload= section: | |
| 155 | 145 | |
| 156 | 146 | #+begin_src yaml |
| 157 | 147 | - upload: | |
| @@ -165,9 +155,9 @@ Lastly, commit your changes and push them to the remote repo. | ||
| 165 | 155 | git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD |
| 166 | 156 | #+end_src |
| 167 | 157 | |
| 168 | If you've successfully created the files with the proper format, you'll | |
| 169 | see the terminal print a message that lets you know where the automatic | |
| 170 | build is taking place. For example, here's what the terminal tells me: | |
| 158 | If you've successfully created the files with the proper format, you'll see the | |
| 159 | terminal print a message that lets you know where the automatic build is taking | |
| 160 | place. For example, here's what the terminal tells me: | |
| 171 | 161 | |
| 172 | 162 | #+begin_src sh |
| 173 | 163 | remote: Build started: |
content/blog/2021-03-28-vaporwave-vs-outrun.org +62 −74
| @@ -5,15 +5,14 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Overview |
| 7 | 7 | |
| 8 | When it comes to an aesthetic that originated primarily online, there | |
| 9 | tends to be a lot of confusion around what falls into each specific | |
| 10 | genre. This post discusses Vaporwave and Outrun, which have become | |
| 11 | almost synonymous in the minds of those online who aren't hardcore into | |
| 12 | these genres of media. More specifically, Outrun is largely an unknown | |
| 13 | term while all aesthetics in these two genres are usually attributed to | |
| 14 | Vaporwave. For example, take a look at the image search results for | |
| 15 | Vaporwave: the results include *a lot* of Outrun-themed images. You'll | |
| 16 | find a similar trend almost everywhere. | |
| 8 | When it comes to an aesthetic that originated primarily online, there tends to | |
| 9 | be a lot of confusion around what falls into each specific genre. This post | |
| 10 | discusses Vaporwave and Outrun, which have become almost synonymous in the minds | |
| 11 | of those online who aren't hardcore into these genres of media. More | |
| 12 | specifically, Outrun is largely an unknown term while all aesthetics in these | |
| 13 | two genres are usually attributed to Vaporwave. For example, take a look at the | |
| 14 | image search results for Vaporwave: the results include *a lot* of Outrun-themed | |
| 15 | images. You'll find a similar trend almost everywhere. | |
| 17 | 16 | |
| 18 | 17 | #+caption: Vaporwave Search Results |
| 19 | 18 | [[https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/vaporwave-search-results.webp]] |
| @@ -23,102 +22,91 @@ find a similar trend almost everywhere. | ||
| 23 | 22 | #+caption: Macintosh Plus Album Cover |
| 24 | 23 | [[https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/macintosh-plus.webp]] |
| 25 | 24 | |
| 26 | Okay, so what is Vaporwave? I'm going to just copy-and-paste some | |
| 27 | general info from the Wikipedia article on | |
| 28 | [[https://en.wikipedia.org/wiki/Vaporwave][Vaporwave]], so that I'm not | |
| 29 | repeating everything you can already search for online: | |
| 25 | Okay, so what is Vaporwave? I'm going to just copy-and-paste some general info | |
| 26 | from the Wikipedia article on [[https://en.wikipedia.org/wiki/Vaporwave][Vaporwave]], so that I'm not repeating everything | |
| 27 | you can already search for online: | |
| 30 | 28 | |
| 31 | 29 | #+begin_quote |
| 32 | Vaporwave is a microgenre of electronic music, a visual art style, and | |
| 33 | an Internet meme that emerged in the early 2010s. It is defined partly | |
| 34 | by its slowed-down, chopped and screwed samples of smooth jazz, | |
| 35 | elevator, R&B, and lounge music from the 1980s and 1990s. The | |
| 36 | surrounding subculture is sometimes associated with an ambiguous or | |
| 37 | satirical take on consumer capitalism and pop culture, and tends to be | |
| 38 | characterized by a nostalgic or surrealist engagement with the popular | |
| 39 | entertainment, technology and advertising of previous decades. Visually, | |
| 40 | it incorporates early Internet imagery, late 1990s web design, glitch | |
| 41 | art, anime, 3D-rendered objects, and cyberpunk tropes in its cover | |
| 42 | artwork and music videos. | |
| 30 | Vaporwave is a microgenre of electronic music, a visual art style, and an | |
| 31 | Internet meme that emerged in the early 2010s. It is defined partly by its | |
| 32 | slowed-down, chopped and screwed samples of smooth jazz, elevator, R&B, and | |
| 33 | lounge music from the 1980s and 1990s. The surrounding subculture is sometimes | |
| 34 | associated with an ambiguous or satirical take on consumer capitalism and pop | |
| 35 | culture, and tends to be characterized by a nostalgic or surrealist engagement | |
| 36 | with the popular entertainment, technology and advertising of previous decades. | |
| 37 | Visually, it incorporates early Internet imagery, late 1990s web design, glitch | |
| 38 | art, anime, 3D-rendered objects, and cyberpunk tropes in its cover artwork and | |
| 39 | music videos. | |
| 43 | 40 | #+end_quote |
| 44 | 41 | |
| 45 | This is an excellent summary, and it helps address my point here: there | |
| 46 | are specific aspects that make Vaporwave unique: | |
| 42 | This is an excellent summary, and it helps address my point here: there are | |
| 43 | specific aspects that make Vaporwave unique: | |
| 47 | 44 | |
| 48 | 45 | ** Time Frame |
| 49 | 46 | |
| 50 | The time frame for references, logos, etc. focuses mostly on the 1990s | |
| 51 | in Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, | |
| 52 | tropical plants, classic marble sculptures, and many references from | |
| 53 | Japan's influence in the 90s. | |
| 47 | The time frame for references, logos, etc. focuses mostly on the 1990s in | |
| 48 | Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, tropical | |
| 49 | plants, classic marble sculptures, and many references from Japan's influence in | |
| 50 | the 90s. | |
| 54 | 51 | |
| 55 | 52 | ** Art |
| 56 | 53 | |
| 57 | The color scheme is generally a soft, light palette that uses pastel | |
| 58 | colors. The backdrop will often be in a light-pink or teal blue. | |
| 54 | The color scheme is generally a soft, light palette that uses pastel colors. The | |
| 55 | backdrop will often be in a light-pink or teal blue. | |
| 59 | 56 | |
| 60 | 57 | ** Music |
| 61 | 58 | |
| 62 | The musical genre of Vaporwave incorporates soft tunes, lounge music, | |
| 63 | and sound effects that will make the listener reminisce of the 90s. The | |
| 64 | sounds of the genre are generally slower-paced and calming. The major | |
| 65 | breakthrough artist for Vaporwave was | |
| 66 | [[https://en.wikipedia.org/wiki/Vektroid][Macintosh Plus]], who released | |
| 67 | the album | |
| 68 | [[https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete][Floral | |
| 69 | Shoppe]] in 2011. Another more recent example is the artist | |
| 70 | [[https://sadbert.bandcamp.com/][sadbert]], whose latest album | |
| 71 | incorporates the upbeat tones of the 1999 Dilbert TV series. | |
| 72 | ||
| 73 | Notice that Vaporwave doesn't include things like racing cars, | |
| 74 | futuristic technology, chrome, or the deep orange/purple color scheme. | |
| 75 | Vaporwave is a focus on the idyllic state of the world when technology | |
| 76 | was becoming common in households, a reality that we have already | |
| 77 | experienced. Focus on the most aesthetically-pleasing parts of that past | |
| 78 | is a large part of Vaporwave. | |
| 59 | The musical genre of Vaporwave incorporates soft tunes, lounge music, and sound | |
| 60 | effects that will make the listener reminisce of the 90s. The sounds of the | |
| 61 | genre are generally slower-paced and calming. The major breakthrough artist for | |
| 62 | Vaporwave was [[https://en.wikipedia.org/wiki/Vektroid][Macintosh Plus]], who released the album [[https://archive.org/details/MACINTOSHPLUS-FLORALSHOPPE_complete][Floral Shoppe]] in 2011. | |
| 63 | Another more recent example is the artist [[https://sadbert.bandcamp.com/][sadbert]], whose latest album | |
| 64 | incorporates the upbeat tones of the 1999 Dilbert television series. | |
| 65 | ||
| 66 | Notice that Vaporwave doesn't include things like racing cars, futuristic | |
| 67 | technology, chrome, or the deep orange/purple color scheme. Vaporwave is a focus | |
| 68 | on the idyllic state of the world when technology was becoming common in | |
| 69 | households, a reality that we have already experienced. Focus on the most | |
| 70 | aesthetically-pleasing parts of that past is a large part of Vaporwave. | |
| 79 | 71 | |
| 80 | 72 | * Outrun |
| 81 | 73 | |
| 82 | 74 | #+caption: Outrun |
| 83 | 75 | [[https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/outrun.webp]] |
| 84 | 76 | |
| 85 | Now, let's get to Outrun. This one is a little trickier since the genre | |
| 86 | has largely been lumped under the Vaporwave title for so long. However, | |
| 87 | it stems from the [[https://en.wikipedia.org/wiki/Synthwave][Synthwave]] | |
| 88 | music genre and is likely named after the 1986 racer game, | |
| 77 | Now, let's get to Outrun. This one is a little trickier since the genre has | |
| 78 | largely been lumped under the Vaporwave title for so long. However, it stems | |
| 79 | from the [[https://en.wikipedia.org/wiki/Synthwave][Synthwave]] music genre and is likely named after the 1986 racer game, | |
| 89 | 80 | [[https://en.wikipedia.org/wiki/Out_Run][Out Run]]. |
| 90 | 81 | |
| 91 | 82 | ** Time Frame |
| 92 | 83 | |
| 93 | Outrun can be thought of as a retro-futuristic aesthetic born from the | |
| 94 | 1980s. | |
| 84 | Outrun can be thought of as a retro-futuristic aesthetic born from the 1980s. | |
| 95 | 85 | |
| 96 | 86 | ** Art |
| 97 | 87 | |
| 98 | The color scheme uses a very dark color palette with the main colors | |
| 99 | being deep oranges, blues, and purples. Red edges are common around | |
| 100 | objects in Outrun art. The background of the Outrun aesthetic is almost | |
| 101 | always a neon grid like you'd expect to see in Tron or a 1980s arcade | |
| 102 | machine. | |
| 88 | The color scheme uses a very dark color palette with the main colors being deep | |
| 89 | oranges, blues, and purples. Red edges are common around objects in Outrun art. | |
| 90 | The background of the Outrun aesthetic is almost always a neon grid like you'd | |
| 91 | expect to see in Tron or a 1980s arcade machine. | |
| 103 | 92 | |
| 104 | Classic sports cars, chrome robots, computer generated graphics and | |
| 105 | fonts, and the occasional use of rain or palm trees can be found in | |
| 106 | Outrun art. | |
| 93 | Classic sports cars, chrome robots, computer generated graphics and fonts, and | |
| 94 | the occasional use of rain or palm trees can be found in Outrun art. | |
| 107 | 95 | |
| 108 | 96 | ** Music |
| 109 | 97 | |
| 110 | This aesthetic has a more aggressive and fast-paced style of music, | |
| 111 | which tends to match the subject of the art in this aesthetic. | |
| 98 | This aesthetic has a more aggressive and fast-paced style of music, which tends | |
| 99 | to match the subject of the art in this aesthetic. | |
| 112 | 100 | |
| 113 | Outrun enthusiasts love what people in the 1980s thought the future | |
| 114 | would look like. Take a look at a common video game discussed in Outrun | |
| 115 | circles, Far Cry 3: Blood Dragon: | |
| 101 | Outrun enthusiasts love what people in the 1980s thought the future would look | |
| 102 | like. Take a look at a common video game discussed in Outrun circles, Far Cry 3: | |
| 103 | Blood Dragon: | |
| 116 | 104 | |
| 117 | 105 | #+caption: Fry Cry 3: Blood Dragon |
| 118 | 106 | [[https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/far-cry.webp]] |
| 119 | 107 | |
| 120 | Another example that doesn't force the color scheme as hard as some | |
| 121 | online art does is Kung Fury: | |
| 108 | Another example that doesn't force the color scheme as hard as some online art | |
| 109 | does is Kung Fury: | |
| 122 | 110 | |
| 123 | 111 | #+caption: Kung Fury |
| 124 | 112 | [[https://img.cleberg.net/blog/20210328-vaporwave-vs-outrun/kung-fury.webp]] |
| @@ -128,7 +116,7 @@ online art does is Kung Fury: | ||
| 128 | 116 | |
| 129 | 117 | * Conclusion |
| 130 | 118 | |
| 131 | While Vaporwave and Outrun share similarities, they are two distinct | |
| 132 | aesthetics with many important distinctions. Someone who enjoys one may | |
| 133 | not necessarily enjoy the other, so it's important to make sure we | |
| 134 | properly describe the aesthetic we're looking for. | |
| 119 | While Vaporwave and Outrun share similarities, they are two distinct aesthetics | |
| 120 | with many important distinctions. Someone who enjoys one may not necessarily | |
| 121 | enjoy the other, so it's important to make sure we properly describe the | |
| 122 | aesthetic we're looking for. | |
content/blog/2021-03-30-vps-web-server.org +153 −178
| @@ -3,108 +3,93 @@ | ||
| 3 | 3 | #+description: Instructional outline for setting up and maintaining a VPS environment configured for secure and scalable web hosting applications. |
| 4 | 4 | #+slug: vps-web-server |
| 5 | 5 | |
| 6 | * Shared Hosting vs. VPS | |
| 7 | ||
| 8 | Choosing a place to host a website is one of the most confusing | |
| 9 | decisions for beginner web developers. Even for experienced web devs, | |
| 10 | choosing between different forms of web hosting can be a daunting | |
| 11 | choice. | |
| 12 | ||
| 13 | First, let's take a look at | |
| 14 | [[https://en.wikipedia.org/wiki/Shared_web_hosting_service][shared web | |
| 15 | hosting]]. Shared web hosting is a product where you are purchasing a | |
| 16 | small piece of a web server that is being shared between many websites. | |
| 17 | As a result, the cost of shared hosting is extremely low. You won't have | |
| 18 | access to the server itself, which means you can't install your own | |
| 19 | software on the server, such as Docker. Usually, you are simply allowed | |
| 20 | to connect your domains to the server, set up domain security, and other | |
| 21 | small utilities. | |
| 22 | ||
| 23 | In contrast, a | |
| 24 | [[https://en.wikipedia.org/wiki/Virtual_private_server][virtual private | |
| 25 | server]] (VPS) is a virtual machine that replicates the environment of | |
| 26 | having a dedicated server to yourself. You are able to control the | |
| 27 | virtual server's host names, base file system, package manager, etc. | |
| 28 | Another great upside of a VPS is that since it's virtual, the company | |
| 29 | providing the VPS can dynamically increase the disk size, RAM size, or | |
| 30 | number of CPUs at any time. However, the virtual server is still | |
| 31 | physically located on a server that is shared between multiple virtual | |
| 32 | servers. | |
| 33 | ||
| 34 | The choice between shared hosting and VPS mostly depends on your skill | |
| 35 | level with system administration. If you're comforting working on a | |
| 36 | server that is mostly left up to you (or you're willing to learn), then | |
| 37 | a VPS is usually a better option. However, shared hosting is a fantastic | |
| 38 | option for people who don't want to have to learn how to manage their | |
| 39 | server. | |
| 6 | * Shared Hosting vs. VPS (Virtual Private Server) | |
| 7 | ||
| 8 | Choosing a place to host a website is one of the most confusing decisions for | |
| 9 | beginner web developers. Even for experienced web devs, choosing between | |
| 10 | different forms of web hosting can be a daunting choice. | |
| 11 | ||
| 12 | First, let's take a look at [[https://en.wikipedia.org/wiki/Shared_web_hosting_service][shared web hosting]]. Shared web hosting is a product | |
| 13 | where you are purchasing a small piece of a web server that is being shared | |
| 14 | between many websites. As a result, the cost of shared hosting is extremely low. | |
| 15 | You won't have access to the server itself, which means you can't install your | |
| 16 | own software on the server, such as Docker. Usually, you are simply allowed to | |
| 17 | connect your domains to the server, set up domain security, and other small | |
| 18 | utilities. | |
| 19 | ||
| 20 | In contrast, a [[https://en.wikipedia.org/wiki/Virtual_private_server][virtual private server]] (VPS) is a virtual machine that replicates | |
| 21 | the environment of having a dedicated server to yourself. You are able to | |
| 22 | control the virtual server's host names, base file system, package manager, etc. | |
| 23 | Another great upside of a VPS is that since it's virtual, the company providing | |
| 24 | the VPS can dynamically increase the disk size, RAM size, or number of CPUs at | |
| 25 | any time. However, the virtual server is still physically located on a server | |
| 26 | that is shared between multiple virtual servers. | |
| 27 | ||
| 28 | The choice between shared hosting and VPS mostly depends on your skill level | |
| 29 | with system administration. If you're comforting working on a server that is | |
| 30 | mostly left up to you (or you're willing to learn), then a VPS is usually a | |
| 31 | better option. However, shared hosting is a fantastic option for people who | |
| 32 | don't want to have to learn how to manage their server. | |
| 40 | 33 | |
| 41 | 34 | * My Situation |
| 42 | 35 | |
| 43 | I had used shared hosting for approximately 5 years before trying my | |
| 44 | first VPS. I manage a homelab and have had success running a server and | |
| 45 | performing typical sysadmin duties, but I was still hesitant to get a | |
| 46 | VPS. One fear was that I always struggled to properly set up the | |
| 47 | networking part of a server - DNS and hostname configurations were not | |
| 48 | my friend. | |
| 49 | ||
| 50 | As a little bit of background, I originally used | |
| 51 | [[https://www.siteground.com][Siteground]] for my initially shared | |
| 52 | hosting and stayed on that platform for at least a year. However, the UI | |
| 53 | was clunky, and I didn't like how they handled certain technical | |
| 54 | aspects, so I switched to [[https://www.namecheap.com][Namecheap]]. | |
| 55 | Namecheap was great because it is the service I primarily use for | |
| 56 | purchasing domain names, which made it incredibly easy to link them to | |
| 57 | my hosting service. However, it was still mediocre shared hosting, and | |
| 58 | Namecheap is notorious for not letting you use | |
| 59 | [[https://letsencrypt.org][Let's Encrypt]] to obtain free SSL/TLS | |
| 60 | certificates; Namecheap wants to make you purchase certificates through | |
| 61 | their store. | |
| 62 | ||
| 63 | Finally, I settled down with [[https://www.iwebfusion.net][iWebFusion]] | |
| 64 | for about the last year of my shared hosting. This service was pretty | |
| 65 | great, came with free SSL/TLS, and I never had any complaints. | |
| 66 | ||
| 67 | However, I finally grew tired of not being able to install software on | |
| 68 | my own web server. I wanted to be able to try out things like | |
| 69 | [[https://postmill.xyz][Postmill]] or [[https://matrix.org][Matrix]]. | |
| 70 | This is possible with a VPS, so I decided to grab a new domain name to | |
| 71 | try it out. | |
| 36 | I had used shared hosting for approximately 5 years before trying my first VPS. | |
| 37 | I manage a homelab and have had success running a server and performing typical | |
| 38 | sysadmin duties, but I was still hesitant to get a VPS. One fear was that I | |
| 39 | always struggled to properly set up the networking part of a server - DNS and | |
| 40 | hostname configurations were not my friend. | |
| 41 | ||
| 42 | As a little bit of background, I originally used [[https://www.siteground.com][Siteground]] for my initially | |
| 43 | shared hosting and stayed on that platform for at least a year. However, the | |
| 44 | user interface (UI) was clunky, and I didn't like how they handled certain | |
| 45 | technical aspects, so I switched to [[https://www.namecheap.com][Namecheap]]. Namecheap was great because it is | |
| 46 | the service I primarily use for purchasing domain names, which made it | |
| 47 | incredibly easy to link them to my hosting service. However, it was still | |
| 48 | mediocre shared hosting, and Namecheap is notorious for not letting you use | |
| 49 | [[https://letsencrypt.org][Let's Encrypt]] to obtain free SSL (Secure Socket Layer)/TLS (Transport Layer | |
| 50 | Security) certificates; Namecheap wants to make you purchase certificates | |
| 51 | through their store. | |
| 52 | ||
| 53 | Finally, I settled down with [[https://www.iwebfusion.net][iWebFusion]] for about the last year of my shared | |
| 54 | hosting. This service was pretty great, came with free SSL/TLS, and I never had | |
| 55 | any complaints. | |
| 56 | ||
| 57 | However, I finally grew tired of not being able to install software on my own | |
| 58 | web server. I wanted to be able to try out things like [[https://postmill.xyz][Postmill]] or [[https://matrix.org][Matrix]]. This | |
| 59 | is possible with a VPS, so I decided to grab a new domain name to try it out. | |
| 72 | 60 | |
| 73 | 61 | * Getting Started: Buying a VPS |
| 74 | 62 | |
| 75 | The first step to moving over to a VPS is (you guessed it): finding a | |
| 76 | VPS provider. For my VPSs, I use [[https://1984hosting.com][1984]] and | |
| 77 | prefer their services much more than any alternative, due to their | |
| 78 | location (Iceland), their [[https://1984hosting.com/GDPR/][privacy | |
| 79 | policy]], their respect for GDPR, and the ability to remain anonymous if | |
| 80 | you pay in Bitcoin or Monero. | |
| 63 | The first step to moving over to a VPS is (you guessed it): finding a VPS | |
| 64 | provider. For my VPSs, I use [[https://1984hosting.com][1984]] and prefer their services much more than any | |
| 65 | alternative, due to their location (Iceland), their [[https://1984hosting.com/GDPR/][privacy policy]], their | |
| 66 | respect for GDPR, and the ability to remain anonymous if you pay in Bitcoin or | |
| 67 | Monero. | |
| 81 | 68 | |
| 82 | [[https://njal.la][Njalla]] is another good, privacy-oriented option for | |
| 83 | VPS services. | |
| 69 | [[https://njal.la][Njalla]] is another good, privacy-oriented option for VPS services. | |
| 84 | 70 | |
| 85 | You'll have to decide what specifications you want on your VPS. For me, | |
| 86 | I only build and deploy low-resource HTML, PHP, and Python websites. | |
| 87 | This means I can survive on the smallest VPS: 1 CPU, 1GB of RAM, and | |
| 88 | 25GB SSD for $5.00 per month. | |
| 71 | You'll have to decide what specifications you want on your VPS. For me, I only | |
| 72 | build and deploy low-resource HTML, PHP, and Python websites. This means I can | |
| 73 | survive on the smallest VPS: 1 CPU, 1GB of RAM, and 25GB SSD for $5.00 per | |
| 74 | month. | |
| 89 | 75 | |
| 90 | As noted above, the great thing about a VPS is you can request your | |
| 91 | provider to increase the resources at any time. | |
| 76 | As noted above, the great thing about a VPS is you can request your provider to | |
| 77 | increase the resources at any time. | |
| 92 | 78 | |
| 93 | 79 | * Configuring DNS Settings |
| 94 | 80 | |
| 95 | Okay, so now let's get into some actual work that has to be done to get | |
| 96 | content moved from a shared host to a VPS. At this point, I'm assuming | |
| 97 | you have a shared host with website content that you can still access, | |
| 98 | and you've purchased a new VPS and can SSH into that server. | |
| 81 | Okay, so now let's get into some actual work that has to be done to get content | |
| 82 | moved from a shared host to a VPS. At this point, I'm assuming you have a shared | |
| 83 | host with website content that you can still access, and you've purchased a new | |
| 84 | VPS and can SSH into that server. | |
| 99 | 85 | |
| 100 | The first change is minor, but it should be done immediately in order to | |
| 101 | get things moving: DNS settings. Go to wherever your DNS settings are | |
| 102 | handled. If your shared host also managed your DNS settings, you'll need | |
| 103 | to first move that DNS over to your new VPS provider. For me, I route my | |
| 104 | DNS through [[https://www.gandi.net][Gandi]]. | |
| 86 | The first change is minor, but it should be done immediately in order to get | |
| 87 | things moving: DNS settings. Go to wherever your DNS settings are handled. If | |
| 88 | your shared host also managed your DNS settings, you'll need to first move that | |
| 89 | DNS over to your new VPS provider. For me, I route my DNS through [[https://www.gandi.net][Gandi]]. | |
| 105 | 90 | |
| 106 | Once you know where your DNS settings are, go ahead and update the =A= | |
| 107 | records to match the public IP address of your VPS. For example: | |
| 91 | Once you know where your DNS settings are, go ahead and update the =A= records | |
| 92 | to match the public IP address of your VPS. For example: | |
| 108 | 93 | |
| 109 | 94 | #+begin_src txt |
| 110 | 95 | A example.com xxx.xxx.xxx.xxx |
| @@ -112,36 +97,35 @@ A subdomain xxx.xxx.xxx.xxx | ||
| 112 | 97 | CNAME www example.com. |
| 113 | 98 | #+end_src |
| 114 | 99 | |
| 115 | If you have any other records that require updates, such as MX or TXT | |
| 116 | records for a mail server, be sure to update those accordingly. | |
| 117 | Personally, I don't host my own mail server. I route all mail on my | |
| 118 | custom domains to [[https://www.migadu.com][Migadu]]. Hosting your own | |
| 119 | email server can become complex quickly and is not for beginners. | |
| 100 | If you have any other records that require updates, such as MX or TXT records | |
| 101 | for a mail server, be sure to update those accordingly. Personally, I don't host | |
| 102 | my own mail server. I route all mail on my custom domains to [[https://www.migadu.com][Migadu]]. Hosting | |
| 103 | your own email server can become complex quickly and is not for beginners. | |
| 120 | 104 | |
| 121 | DNS changes can take up to 48 hours to propagate, so be sure to give it | |
| 122 | some time before assuming you've made an error. | |
| 105 | DNS changes can take up to 48 hours to propagate, so be sure to give it some | |
| 106 | time before assuming you've made an error. | |
| 123 | 107 | |
| 124 | 108 | * Server Updates and Packages |
| 125 | 109 | |
| 126 | Now that the DNS settings have been changed, let's set up our server | |
| 127 | while we wait for the DNS to propagate. First up is to ssh into your | |
| 128 | server. If you've signed up with a service like DigitalOcean, you can | |
| 129 | add your SSH key to your account and to your VPS droplet so that you | |
| 130 | don't need a password in order to SSH. | |
| 110 | Now that the DNS settings have been changed, let's set up our server while we | |
| 111 | wait for the DNS to propagate. First up is to ssh into your server. If you've | |
| 112 | signed up with a service like DigitalOcean, you can add your SSH key to your | |
| 113 | account and to your VPS droplet so that you don't need a password in order to | |
| 114 | SSH. | |
| 131 | 115 | |
| 132 | 116 | #+begin_src sh |
| 133 | 117 | ssh root@xxx.xxx.xxx.xxx |
| 134 | 118 | #+end_src |
| 135 | 119 | |
| 136 | The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache | |
| 137 | web server. If you're working on a different operating system (OS) or | |
| 138 | want a different web server, such as Nginx, you'll have to use different | |
| 139 | commands to set it up. | |
| 120 | The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache web | |
| 121 | server. If you're working on a different operating system (OS) or want a | |
| 122 | different web server, such as Nginx, you'll have to use different commands to | |
| 123 | set it up. | |
| 140 | 124 | |
| 141 | 125 | First, let's update and upgrade our server. |
| 142 | 126 | |
| 143 | *NOTE:* Since we have logged in to the server as =root= for now, we | |
| 144 | don't need to use the =sudo= modifier before our commands. | |
| 127 | *NOTE:* Since we have logged in to the server as =root= for now, we don't need | |
| 128 | to use the =sudo= modifier before our commands. | |
| 145 | 129 | |
| 146 | 130 | #+begin_src sh |
| 147 | 131 | apt update && apt upgrade -y |
| @@ -149,11 +133,11 @@ apt update && apt upgrade -y | ||
| 149 | 133 | |
| 150 | 134 | * Create A User Account |
| 151 | 135 | |
| 152 | While being able to use =root= can be beneficial at times, you shouldn't | |
| 153 | use =root= unless you have to. | |
| 136 | While being able to use =root= can be beneficial at times, you shouldn't use | |
| 137 | =root= unless you have to. | |
| 154 | 138 | |
| 155 | So let's set up a new user in our system. The =-m= option below tells | |
| 156 | the OS to create a home directory for the new user. | |
| 139 | So let's set up a new user in our system. The =-m= option below tells the OS to | |
| 140 | create a home directory for the new user. | |
| 157 | 141 | |
| 158 | 142 | #+begin_src sh |
| 159 | 143 | adduser USERNAME |
| @@ -165,40 +149,40 @@ Now, create a password for that user. | ||
| 165 | 149 | passwd USERNAME |
| 166 | 150 | #+end_src |
| 167 | 151 | |
| 168 | Finally, add the user to the sudoers file, so they can perform | |
| 169 | priveleged commands. | |
| 152 | Finally, add the user to the sudoers file, so they can perform privileged | |
| 153 | commands. | |
| 170 | 154 | |
| 171 | 155 | #+begin_src sh |
| 172 | 156 | usermod -a -G sudo USERNAME |
| 173 | 157 | #+end_src |
| 174 | 158 | |
| 175 | If you are using SSH keys and not passwords, you'll need to copy your | |
| 176 | SSH key from your local machine to the VPS. If you haven't disabled | |
| 177 | password-based SSH yet, the easiest way to do this is =ssh-copy-id= from | |
| 178 | your local computer (not from the VPS): | |
| 159 | If you are using SSH (secure shell protocol) keys and not passwords, you'll need | |
| 160 | to copy your SSH key from your local machine to the VPS. If you haven't disabled | |
| 161 | password-based SSH yet, the easiest way to do this is =ssh-copy-id= from your | |
| 162 | local computer (not from the VPS): | |
| 179 | 163 | |
| 180 | 164 | #+begin_src sh |
| 181 | 165 | ssh-copy-id testuser@xxx.xxx.xxx.xxx |
| 182 | 166 | #+end_src |
| 183 | 167 | |
| 184 | If you've disabled password-based SSH, you'll need to manually copy your | |
| 185 | SSH key into the =~/.ssh/authorized_keys= file. | |
| 168 | If you've disabled password-based SSH, you'll need to manually copy your SSH key | |
| 169 | into the =~/.ssh/authorized_keys= file. | |
| 186 | 170 | |
| 187 | 171 | * Install Software |
| 188 | 172 | |
| 189 | Our goal here is to host a web server, so the next step is to install | |
| 190 | the Apache web server and any other packages we need. | |
| 173 | Our goal here is to host a web server, so the next step is to install the Apache | |
| 174 | web server and any other packages we need. | |
| 191 | 175 | |
| 192 | From this point on, I will be logged in as a user (not =root=) and will | |
| 193 | need to use the =sudo= modifier for most commands. | |
| 176 | From this point on, I will be logged in as a user (not =root=) and will need to | |
| 177 | use the =sudo= modifier for most commands. | |
| 194 | 178 | |
| 195 | 179 | #+begin_src sh |
| 196 | 180 | sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y |
| 197 | 181 | sudo apt install apache2 |
| 198 | 182 | #+end_src |
| 199 | 183 | |
| 200 | If you need other language support, such as PHP, you'll need to install | |
| 201 | that too. | |
| 184 | If you need other language support, such as PHP, you'll need to install that | |
| 185 | too. | |
| 202 | 186 | |
| 203 | 187 | #+begin_src sh |
| 204 | 188 | sudo apt install libapache2-mod-php php-dom |
| @@ -208,19 +192,18 @@ sudo systemctl restart apache2 | ||
| 208 | 192 | |
| 209 | 193 | * Website Files & Folders |
| 210 | 194 | |
| 211 | Next up is to create the directories for the domain(s) we want to be | |
| 212 | hosted on this web server. | |
| 195 | Next up is to create the directories for the domain(s) we want to be hosted on | |
| 196 | this web server. | |
| 213 | 197 | |
| 214 | 198 | #+begin_src sh |
| 215 | 199 | cd /var/www |
| 216 | 200 | sudo mkdir example.com |
| 217 | 201 | #+end_src |
| 218 | 202 | |
| 219 | We have a folder for =example.com= now, so let's add an =index.html= | |
| 220 | file and put it within a specific =public_html= folder. You don't need | |
| 221 | this =public_html= if you don't want it, but it helps with organizing | |
| 222 | items related to =example.com= that you don't want to publish to the | |
| 223 | internet. | |
| 203 | We have a folder for =example.com= now, so let's add an =index.html= file and | |
| 204 | put it within a specific =public_html= folder. You don't need this =public_html= | |
| 205 | if you don't want it, but it helps with organizing items related to | |
| 206 | =example.com= that you don't want to publish to the internet. | |
| 224 | 207 | |
| 225 | 208 | #+begin_src sh |
| 226 | 209 | cd example.com |
| @@ -228,8 +211,8 @@ sudo mkdir public_html && cd public_html | ||
| 228 | 211 | sudo nano index.html |
| 229 | 212 | #+end_src |
| 230 | 213 | |
| 231 | You can put anything you want in this =index.html= file. If you can't | |
| 232 | think of anything, paste this in there: | |
| 214 | You can put anything you want in this =index.html= file. If you can't think of | |
| 215 | anything, paste this in there: | |
| 233 | 216 | |
| 234 | 217 | #+begin_src html |
| 235 | 218 | <!DOCTYPE html> |
| @@ -245,9 +228,8 @@ think of anything, paste this in there: | ||
| 245 | 228 | </html> |
| 246 | 229 | #+end_src |
| 247 | 230 | |
| 248 | If you want something to be served at =example.com/page01/file.txt=, | |
| 249 | you'll have to create the =page01= directory under the =example.com= | |
| 250 | directory. For example: | |
| 231 | If you want something to be served at =example.com/page01/file.txt=, you'll have | |
| 232 | to create the =page01= directory under the =example.com= directory. For example: | |
| 251 | 233 | |
| 252 | 234 | #+begin_src sh |
| 253 | 235 | cd /var/www/example.com/public_html |
| @@ -257,9 +239,9 @@ sudo nano file.txt | ||
| 257 | 239 | |
| 258 | 240 | * Apache Configuration |
| 259 | 241 | |
| 260 | Now, let's set up the files that will tell the server where to find the | |
| 261 | files for =example.com=. We will copy the default configuration file and | |
| 262 | create our own. | |
| 242 | Now, let's set up the files that will tell the server where to find the files | |
| 243 | for =example.com=. We will copy the default configuration file and create our | |
| 244 | own. | |
| 263 | 245 | |
| 264 | 246 | #+begin_src sh |
| 265 | 247 | cd /etc/apache2/sites-available |
| @@ -267,9 +249,8 @@ sudo cp 000-default.conf example.com.conf | ||
| 267 | 249 | sudo nano example.com.conf |
| 268 | 250 | #+end_src |
| 269 | 251 | |
| 270 | This configuration file will have a few default lines, but you'll need | |
| 271 | to edit it to look similar to this (settings may change based on your | |
| 272 | personal needs): | |
| 252 | This configuration file will have a few default lines, but you'll need to edit | |
| 253 | it to look similar to this (settings may change based on your personal needs): | |
| 273 | 254 | |
| 274 | 255 | #+begin_src config |
| 275 | 256 | <VirtualHost *:80> |
| @@ -291,31 +272,30 @@ sudo a2dissite 000-default.conf | ||
| 291 | 272 | sudo systemctl reload apache2 |
| 292 | 273 | #+end_src |
| 293 | 274 | |
| 294 | You can always run a test to make sure no errors or warnings are found | |
| 295 | in your configuration files. | |
| 275 | You can always run a test to make sure no errors or warnings are found in your | |
| 276 | configuration files. | |
| 296 | 277 | |
| 297 | 278 | #+begin_src sh |
| 298 | 279 | sudo apache2ctl configtest |
| 299 | 280 | #+end_src |
| 300 | 281 | |
| 301 | Now, restart the web server entirely. After this, you should be able to | |
| 302 | browse to =http://example.com= and see the HTML content you provided | |
| 303 | earlier. Note that SSL/TLS has not been enabled yet, so you won't be | |
| 282 | Now, restart the web server entirely. After this, you should be able to browse | |
| 283 | to =http://example.com= and see the HTML (hypertext markup language) content you | |
| 284 | provided earlier. Note that SSL/TLS has not been enabled yet, so you won't be | |
| 304 | 285 | able to use the secure version yet (=https://example.com=). |
| 305 | 286 | |
| 306 | 287 | #+begin_src sh |
| 307 | 288 | sudo systemctl restart apache2 |
| 308 | 289 | #+end_src |
| 309 | 290 | |
| 310 | You can repeat this for as many websites as you need. Just create the | |
| 311 | domain folders in =/var/www/=, add the configuration file, enable the | |
| 312 | configuration, and restart =apache2=. | |
| 291 | You can repeat this for as many websites as you need. Just create the domain | |
| 292 | folders in =/var/www/=, add the configuration file, enable the configuration, | |
| 293 | and restart =apache2=. | |
| 313 | 294 | |
| 314 | 295 | * SSL/TLS Certificates: Serve Websites Over HTTPS |
| 315 | 296 | |
| 316 | In order to serve secure content, you'll need to obtain SSL/TLS | |
| 317 | certificates. Luckily, there's a free tool called | |
| 318 | [[https://certbot.eff.org][Certbot]] that helps us with the process. | |
| 297 | In order to serve secure content, you'll need to obtain SSL/TLS certificates. | |
| 298 | Luckily, there's a free tool called [[https://certbot.eff.org][Certbot]] that helps us with the process. | |
| 319 | 299 | |
| 320 | 300 | The first step is to install =snapd= and =core= for Ubuntu. |
| 321 | 301 | |
| @@ -340,10 +320,10 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot | ||
| 340 | 320 | |
| 341 | 321 | Finally, you can run =certbot= one of two ways: |
| 342 | 322 | |
| 343 | 1. run it and let it alter your Apache configuration files automatically | |
| 344 | to enable HTTPS redirects. | |
| 345 | 2. run it and only allow it to create certificates. You'll need to | |
| 346 | manually alter the config files to enable HTTPS redirects. | |
| 323 | 1. run it and let it alter your Apache configuration files automatically to | |
| 324 | enable HTTPS (Hypertext Transport Protocol) redirects. | |
| 325 | 2. run it and only allow it to create certificates. You'll need to manually | |
| 326 | alter the config files to enable HTTPS redirects. | |
| 347 | 327 | |
| 348 | 328 | Run certbot and allow automatic config changes: |
| 349 | 329 | |
| @@ -358,11 +338,10 @@ files: | ||
| 358 | 338 | sudo certbot certonly --apache |
| 359 | 339 | #+end_src |
| 360 | 340 | |
| 361 | The Certbot packages on your system come with a cron job or systemd | |
| 362 | timer that will renew your certificates automatically before they | |
| 363 | expire. You will not need to run Certbot again unless you change your | |
| 364 | configuration. You can test automatic renewal for your certificates by | |
| 365 | running this command: | |
| 341 | The Certbot packages on your system come with a =cron= job or =systemd= timer | |
| 342 | that will renew your certificates automatically before they expire. You will not | |
| 343 | need to run Certbot again unless you change your configuration. You can test | |
| 344 | automatic renewal for your certificates by running this command: | |
| 366 | 345 | |
| 367 | 346 | #+begin_src sh |
| 368 | 347 | sudo certbot renew --dry-run |
| @@ -373,13 +352,11 @@ Now, test your domains by going to =https://example.com=. | ||
| 373 | 352 | * Firewall Security |
| 374 | 353 | |
| 375 | 354 | To enable better security on your server, you'll need to enable a basic |
| 376 | firewall. For Ubuntu, we'll use | |
| 377 | [[../secure-your-network-with-the-uncomplicated-firewall/][the | |
| 378 | uncomplicated firewall]]. | |
| 355 | firewall. For Ubuntu, we'll use [[https://cleberg.net/blog/ufw.html][the uncomplicated firewall]]. | |
| 379 | 356 | |
| 380 | Now, add the following rules to the firewall allow SSH, Apache, and | |
| 381 | HTTP(S) connections. If you need to, you can enable different ports for | |
| 382 | specifics applications, SFTP, etc. | |
| 357 | Now, add the following rules to the firewall allow SSH, Apache, and HTTP(S) | |
| 358 | connections. If you need to, you can enable different ports for specific | |
| 359 | applications. | |
| 383 | 360 | |
| 384 | 361 | #+begin_src sh |
| 385 | 362 | sudo ufw default deny incoming |
| @@ -397,15 +374,13 @@ sudo ufw enable | ||
| 397 | 374 | |
| 398 | 375 | * Troubleshooting |
| 399 | 376 | |
| 400 | If you run into any issues during your VPS set-up, be sure to walk back | |
| 401 | through your actions and make sure you didn't miss any steps. | |
| 377 | If you run into any issues during your VPS set-up, be sure to walk back through | |
| 378 | your actions and make sure you didn't miss any steps. | |
| 402 | 379 | |
| 403 | Many websites have fantastic guides to setting up various web servers. | |
| 404 | This is one of the areas | |
| 405 | [[https://www.digitalocean.com/community/tutorials][where DigitalOcean | |
| 406 | shines]]. For simpler or more Linux-oriented questions, I suggest using | |
| 407 | [Linuxize] ([[https://linuxize.com]]). | |
| 380 | Many websites have fantastic guides to setting up various web servers. This is | |
| 381 | one of the areas [[https://www.digitalocean.com/community/tutorials][where DigitalOcean shines]]. For simpler or more Linux-oriented | |
| 382 | questions, I suggest using [Linuxize] ([[https://linuxize.com]]). | |
| 408 | 383 | |
| 409 | If you're getting certain errors (e.g. =500 Internal Server Error=) and | |
| 410 | need to debug locally, you can view the =access.log= and =error.log= | |
| 411 | files in the =/var/log/apache/= directory. | |
| 384 | If you're getting certain errors (e.g. =500 Internal Server Error=) and need to | |
| 385 | debug locally, you can view the =access.log= and =error.log= files in the | |
| 386 | =/var/log/apache/= directory. | |
content/blog/2021-04-17-gemini-server.org +33 −38
| @@ -5,28 +5,26 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Similar Article Available |
| 7 | 7 | |
| 8 | To read more about Gemini and ways to test out this new protocol without | |
| 9 | your own server, see my previous post | |
| 10 | [[../launching-a-gemini-capsule/][Launching a Gemini Capsule]]. | |
| 8 | To read more about Gemini and ways to test out this new protocol without your | |
| 9 | own server, see my previous post [[../launching-a-gemini-capsule/][Launching a Gemini Capsule]]. | |
| 11 | 10 | |
| 12 | 11 | * Preparation |
| 13 | 12 | |
| 14 | This guide assumes you have access to a server accessible to the world | |
| 15 | through a public IP address and that you own a domain name used for this | |
| 16 | Gemini capsule. | |
| 13 | This guide assumes you have access to a server accessible to the world through a | |
| 14 | public IP (internet protocol) address and that you own a domain name used for | |
| 15 | this Gemini capsule. | |
| 17 | 16 | |
| 18 | 17 | * Getting Started with Agate |
| 19 | 18 | |
| 20 | We are going to use [[https://github.com/mbrubeck/agate][Agate]] for | |
| 21 | this tutorial. This is a basic Gemini server written in Rust. It takes | |
| 22 | very little time and maintenance to get it running. | |
| 19 | We are going to use [[https://github.com/mbrubeck/agate][Agate]] for this tutorial. This is a basic Gemini server | |
| 20 | written in Rust. It takes very little time and maintenance to get it running. | |
| 23 | 21 | |
| 24 | 22 | * Install Dependencies |
| 25 | 23 | |
| 26 | First, you will need to install the Rust package for your system. On | |
| 27 | Ubuntu, use the following commands (remember to use =sudo= if you are | |
| 28 | not the root user). The Rust installation will give you options to | |
| 29 | customize the installation; I used the default installation options. | |
| 24 | First, you will need to install the Rust package for your system. On Ubuntu, use | |
| 25 | the following commands (remember to use =sudo= if you are not the root user). | |
| 26 | The Rust installation will give you options to customize the installation; I | |
| 27 | used the default installation options. | |
| 30 | 28 | |
| 31 | 29 | #+begin_src sh |
| 32 | 30 | sudo apt update && sudo apt upgrade -y |
| @@ -54,8 +52,8 @@ cargo install agate | ||
| 54 | 52 | |
| 55 | 53 | * Create Symlinks |
| 56 | 54 | |
| 57 | Once Cargo has finished installing all the required packages, symlink | |
| 58 | the executable to your $PATH. | |
| 55 | Once Cargo has finished installing all the required packages, create a symbolic | |
| 56 | link to the executable to your $PATH. | |
| 59 | 57 | |
| 60 | 58 | #+begin_src sh |
| 61 | 59 | sudo ln -s $HOME/.cargo/bin/agate /usr/local/bin/agate |
| @@ -63,8 +61,8 @@ sudo ln -s $HOME/.cargo/bin/agate /usr/local/bin/agate | ||
| 63 | 61 | |
| 64 | 62 | * Using Agate's Built-In Installation Tool |
| 65 | 63 | |
| 66 | If you're running Ubuntu or Debian, use the Debian installation script | |
| 67 | found in Agate's GitHub repository, under the =tools/debian= folder. | |
| 64 | If you're running Ubuntu or Debian, use the Debian installation script found in | |
| 65 | Agate's GitHub repository, under the =tools/debian= folder. | |
| 68 | 66 | |
| 69 | 67 | #+begin_src sh |
| 70 | 68 | git clone https://github.com/mbrubeck/agate |
| @@ -74,11 +72,11 @@ sudo ./install.sh | ||
| 74 | 72 | |
| 75 | 73 | * Configure the Gemini Service |
| 76 | 74 | |
| 77 | We have a little more to do, but since this script tries to immediately | |
| 78 | run the service, it will likely fail with an exit code. Let's add our | |
| 79 | finishing touches. Edit the following file and replace the hostname with | |
| 80 | your desired URL. You can also change the directory where content will | |
| 81 | be served. | |
| 75 | We have a little more to do, but since this script tries to immediately run the | |
| 76 | service, it will likely fail with an exit code. Let's add our finishing touches. | |
| 77 | Edit the following file and replace the hostname with your desired URL (uniform | |
| 78 | resource locator). You can also change the directory where content will be | |
| 79 | served. | |
| 82 | 80 | |
| 83 | 81 | #+begin_src sh |
| 84 | 82 | sudo nano /etc/systemd/system/gemini.service |
| @@ -97,8 +95,8 @@ WorkingDirectory=/var/gemini/ | ||
| 97 | 95 | ExecStart=agate --hostname gemini.example.com --lang en |
| 98 | 96 | #+end_src |
| 99 | 97 | |
| 100 | Since we've altered the systemd configuration files, we have to reload | |
| 101 | the daemon. Let's do that, restart our service, and check its status. | |
| 98 | Since we've altered the systemd configuration files, we have to reload the | |
| 99 | daemon. Let's do that, restart our service, and check its status. | |
| 102 | 100 | |
| 103 | 101 | #+begin_src sh |
| 104 | 102 | sudo systemctl daemon-reload |
| @@ -108,8 +106,8 @@ sudo systemctl status gemini.service | ||
| 108 | 106 | |
| 109 | 107 | * Fixing Systemd Errors |
| 110 | 108 | |
| 111 | If you're still getting errors, the installation process may not have | |
| 112 | properly enabled the gemini service. Fix it with the following commands. | |
| 109 | If you're still getting errors, the installation process may not have properly | |
| 110 | enabled the gemini service. Fix it with the following commands. | |
| 113 | 111 | |
| 114 | 112 | #+begin_src sh |
| 115 | 113 | sudo systemctl enable gemini.service |
| @@ -119,9 +117,9 @@ sudo systemctl status gemini.service | ||
| 119 | 117 | |
| 120 | 118 | * Firewall Rules |
| 121 | 119 | |
| 122 | Great! Our server is now functional and running. The first consideration | |
| 123 | now is that you need to be able to access port 1965 on the server. If | |
| 124 | you have a firewall enabled, you'll need to open that port up. | |
| 120 | Great! Our server is now functional and running. The first consideration now is | |
| 121 | that you need to be able to access port 1965 on the server. If you have a | |
| 122 | firewall enabled, you'll need to open that port up. | |
| 125 | 123 | |
| 126 | 124 | #+begin_src sh |
| 127 | 125 | sudo ufw allow 1965 |
| @@ -131,21 +129,18 @@ sudo ufw reload | ||
| 131 | 129 | * Creating Content |
| 132 | 130 | |
| 133 | 131 | Let's create the Gemini capsule. Note that wherever you set the |
| 134 | WorkingDirectory variable to earlier, Agate will expect you to put your | |
| 135 | Gemini capsule contents in a sub-folder called "content." So, I place my | |
| 136 | files in "/var/gmi/content." I'm going to create that folder now and put | |
| 137 | a file in there. | |
| 132 | =WorkingDirectory= variable to earlier, Agate will expect you to put your Gemini | |
| 133 | capsule contents in a sub-folder called =content=. So, I place my files in | |
| 134 | =/var/gmi/content=. I'm going to create that folder now and put a file in there. | |
| 138 | 135 | |
| 139 | 136 | #+begin_src sh |
| 140 | 137 | sudo mkdir /var/gemini/content |
| 141 | 138 | sudo nano /var/gemini/content/index.gmi |
| 142 | 139 | #+end_src |
| 143 | 140 | |
| 144 | You can put whatever you want in the "index.gmi" file, just make sure | |
| 145 | it's valid Gemtext. | |
| 141 | You can put whatever you want in the =index.gmi= file, just make sure it's valid | |
| 142 | Gemtext. | |
| 146 | 143 | |
| 147 | 144 | * The Results |
| 148 | 145 | |
| 149 | To view the results, you can use a Gemini browser, such as | |
| 150 | [[https://gmi.skyjake.fi/lagrange/][Lagrange]] or | |
| 151 | [[https://github.com/makeworld-the-better-one/amfora][amfora]]. | |
| 146 | To view the results, you can use a Gemini browser, such as [[https://gmi.skyjake.fi/lagrange/][Lagrange]] or [[https://github.com/makeworld-the-better-one/amfora][amfora]]. | |
content/blog/2021-04-23-php-comment-system.org +83 −94
| @@ -5,84 +5,79 @@ | ||
| 5 | 5 | |
| 6 | 6 | * The Terrible-ness of Commenting Systems |
| 7 | 7 | |
| 8 | The current state of affairs regarding interactive comment systems is, | |
| 9 | well, terrible. It is especially awful if you're a privacy conscious | |
| 10 | person who does not generally load third-party scripts or frames on the | |
| 11 | websites you visit. | |
| 8 | The current state of affairs regarding interactive comment systems is, well, | |
| 9 | terrible. It is especially awful if you're a privacy conscious person who does | |
| 10 | not generally load third-party scripts or frames on the websites you visit. | |
| 12 | 11 | |
| 13 | Even further, many comment systems are charging exorbitant fees for | |
| 14 | something that should be standard. | |
| 12 | Even further, many comment systems are charging exorbitant fees for something | |
| 13 | that should be standard. | |
| 15 | 14 | |
| 16 | 15 | Of course, there are some really terrible options: |
| 17 | 16 | |
| 18 | 17 | - Facebook Comments |
| 19 | 18 | - Discourse |
| 20 | 19 | |
| 21 | There are some options that are better but still use too many scripts, | |
| 22 | frames, or social integrations on your web page that could impact some | |
| 23 | users: | |
| 20 | There are some options that are better but still use too many scripts, frames, | |
| 21 | or social integrations on your web page that could impact some users: | |
| 24 | 22 | |
| 25 | 23 | - Disqus |
| 26 | 24 | - Isso |
| 27 | 25 | - Remark42 |
| 28 | 26 | |
| 29 | Lastly, I looked into a few unique ways of generating blog comments, | |
| 30 | such as using Twitter threads or GitHub issues to automatically post | |
| 31 | issues. However, these both rely on external third-party sites that I | |
| 32 | don't currently use. | |
| 27 | Lastly, I looked into a few unique ways of generating blog comments, such as | |
| 28 | using Twitter threads or GitHub issues to automatically post issues. However, | |
| 29 | these both rely on external third-party sites that I don't currently use. | |
| 33 | 30 | |
| 34 | 31 | * Stay Static with Server-Side Comments |
| 35 | 32 | |
| 36 | The main issue for my personal use-case is that my blog is completely, | |
| 37 | 100% static. I use PHP on the back-end but website visitors only see | |
| 38 | HTML and a single CSS file. No external javascript and no embedded | |
| 39 | frames. | |
| 33 | The main issue for my personal use-case is that my blog is completely, 100% | |
| 34 | static. I use PHP on the back-end but website visitors only see HTML (Hypertext | |
| 35 | Markup Language) and a single CSS (Cascading Style Sheets) file. No external | |
| 36 | JavaScript and no embedded frames. | |
| 40 | 37 | |
| 41 | So, how do we keep a site static and still allow users to interact with | |
| 42 | blog posts? The key actually pretty simple - I'm already using PHP, so | |
| 43 | why not rely on the classic HTML =<form>= and a PHP script to save the | |
| 44 | comments somewhere? As it turns out, this was a perfect solution for me. | |
| 38 | So, how do we keep a site static and still allow users to interact with blog | |
| 39 | posts? The key actually pretty simple - I'm already using PHP, so why not rely | |
| 40 | on the classic HTML =<form>= and a PHP script to save the comments somewhere? As | |
| 41 | it turns out, this was a perfect solution for me. | |
| 45 | 42 | |
| 46 | The second issue for my personal use-case is that I am trying to keep | |
| 47 | the contents of my website accessible over time, as described by | |
| 48 | [cite/t:@brandur], in his post entitled | |
| 49 | [[https://brandur.org/fragments/graceful-degradation-time][Blog with | |
| 50 | Markdown + Git, and degrade gracefully through time]] . | |
| 43 | The second issue for my personal use-case is that I am trying to keep the | |
| 44 | contents of my website accessible over time, as described by [cite/t:@brandur], | |
| 45 | in his post entitled [[https://brandur.org/fragments/graceful-degradation-time][Blog with Markdown + Git, and degrade gracefully through | |
| 46 | time]] . | |
| 51 | 47 | |
| 52 | This means I cannot rely on a database for comments, since I do not rely | |
| 53 | on a database for any other part of my websites. | |
| 48 | This means I cannot rely on a database for comments, since I do not rely on a | |
| 49 | database for any other part of my websites. | |
| 54 | 50 | |
| 55 | I blog in plain Markdown files, commit all articles to Git, and ensure | |
| 56 | that future readers will be able to see the source data long after I'm | |
| 57 | gone, or the website has gone offline. However, I still haven't | |
| 58 | committed any images served on my blog to Git, as I'm not entirely sold | |
| 59 | on Git LFS yet - for now, images can be found at | |
| 60 | [[https://img.cleberg.net][img.cleberg.net]]. | |
| 51 | I blog in plain Markdown files, commit all articles to Git, and ensure that | |
| 52 | future readers will be able to see the source data long after I'm gone, or the | |
| 53 | website has gone offline. However, I still haven't committed any images served | |
| 54 | on my blog to Git, as I'm not entirely sold on Git LFS (large file storage) | |
| 55 | yet - for now, images can be found at [[https://img.cleberg.net][img.cleberg.net]]. | |
| 61 | 56 | |
| 62 | Saving my comments back to the Git repository ensures that another | |
| 63 | aspect of my site will degrade gracefully. | |
| 57 | Saving my comments back to the Git repository ensures that another aspect of my | |
| 58 | site will degrade gracefully. | |
| 64 | 59 | |
| 65 | 60 | * Create a Comment Form |
| 66 | 61 | |
| 67 | Okay, let's get started. The first step is to create an HTML form that | |
| 68 | users can see and utilize to submit comments. This is fairly easy and | |
| 69 | can be changed depending on your personal preferences. | |
| 62 | Okay, let's get started. The first step is to create an HTML form that users can | |
| 63 | see and utilize to submit comments. This is fairly easy and can be changed | |
| 64 | depending on your personal preferences. | |
| 70 | 65 | |
| 71 | Take a look at the code block below for the form I currently use. Note | |
| 72 | that =<current-url>= is replaced automatically in PHP with the current | |
| 73 | post's URL, so that my PHP script used later will know which blog post | |
| 74 | the comment is related to. | |
| 66 | Take a look at the code block below for the form I currently use. Note that | |
| 67 | =<current-url>= is replaced automatically in PHP with the current post's URL | |
| 68 | (uniform resource locator), so that my PHP script used later will know which | |
| 69 | blog post the comment is related to. | |
| 75 | 70 | |
| 76 | 71 | The form contains the following structure: |
| 77 | 72 | |
| 78 | 1. =<form>= - This is the form and will determine which PHP script to | |
| 79 | send the comment to. | |
| 80 | 2. =<section hidden>= - This section is hidden from the user and is used | |
| 81 | to ensure that we know which blog post sent the comment. | |
| 82 | 3. =<section>= Display Name (Optional) - Used to accept a display name, | |
| 83 | if entered. | |
| 84 | 4. =<section>= Comment (Required) - Used to accept the user's full | |
| 85 | comment. Markdown is allowed. | |
| 73 | 1. =<form>= - This is the form and will determine which PHP script to send the | |
| 74 | comment to. | |
| 75 | 2. =<section hidden>= - This section is hidden from the user and is used to | |
| 76 | ensure that we know which blog post sent the comment. | |
| 77 | 3. =<section>= Display Name (Optional) - Used to accept a display name, if | |
| 78 | entered. | |
| 79 | 4. =<section>= Comment (Required) - Used to accept the user's full comment. | |
| 80 | Markdown is allowed. | |
| 86 | 81 | 5. =<button>= - A button to submit the form. |
| 87 | 82 | |
| 88 | 83 | #+begin_src html |
| @@ -129,25 +124,25 @@ The form contains the following structure: | ||
| 129 | 124 | |
| 130 | 125 | * Handle Comments via POST |
| 131 | 126 | |
| 132 | Now that we have a form and can submit comments, we need to create a PHP | |
| 133 | script so that the server can fetch the comment data and save it. Make | |
| 134 | sure your PHP script name matches the name you entered in the =action= | |
| 135 | field in your form. | |
| 127 | Now that we have a form and can submit comments, we need to create a PHP script | |
| 128 | so that the server can fetch the comment data and save it. Make sure your PHP | |
| 129 | script name matches the name you entered in the =action= field in your form. | |
| 136 | 130 | |
| 137 | See the code block below for the contents of my =comment.php= script. We | |
| 138 | perform the following tasks in this script: | |
| 131 | See the code block below for the contents of my =comment.php= script. We perform | |
| 132 | the following tasks in this script: | |
| 139 | 133 | |
| 140 | 134 | 1. Grab the POST data from the HTML form. |
| 141 | 135 | 2. Sanitize the comment data with =htmlentities=. |
| 142 | 136 | 3. Set the display name to =Anonymous= if it was left blank. |
| 143 | 137 | 4. Create a PHP object that combines all of this data. |
| 144 | 138 | 5. Check if our destination file =comments.json= exists. |
| 145 | 6. If so, convert the PHP object to JSON and save it to the file. | |
| 146 | 7. If the =comments.json= file does not exist, the script will exit with | |
| 147 | an error. You can alter this to ensure it creates the script, but my | |
| 148 | source code includes the file by default, so it will always exist. | |
| 149 | 8. Finally, send the user back to the =#comments= section of the blog | |
| 150 | post they just read. | |
| 139 | 6. If so, convert the PHP object to JSON (JavaScript Object Notation) and save | |
| 140 | it to the file. | |
| 141 | 7. If the =comments.json= file does not exist, the script will exit with an | |
| 142 | error. You can alter this to ensure it creates the script, but my source code | |
| 143 | includes the file by default, so it will always exist. | |
| 144 | 8. Finally, send the user back to the =#comments= section of the blog post they | |
| 145 | just read. | |
| 151 | 146 | |
| 152 | 147 | #+begin_src php |
| 153 | 148 | // Get the content sent from the comment form |
| @@ -186,9 +181,9 @@ if (file_exists($file_name)) { | ||
| 186 | 181 | header('Location: ' . $post_url . '#comments'); |
| 187 | 182 | #+end_src |
| 188 | 183 | |
| 189 | If you're using Apache, make sure the =www-data= user on your server has | |
| 190 | the correct permissions to your website directory or else it will not be | |
| 191 | able to write to =comments.json=. | |
| 184 | If you're using Apache, make sure the =www-data= user on your server has the | |
| 185 | correct permissions to your website directory or else it will not be able to | |
| 186 | write to =comments.json=. | |
| 192 | 187 | |
| 193 | 188 | #+begin_src sh |
| 194 | 189 | chgrp -R www-data /path/to/website/ |
| @@ -197,18 +192,15 @@ chmod -R g+w comments.json | ||
| 197 | 192 | |
| 198 | 193 | * Display User Comments |
| 199 | 194 | |
| 200 | Now that we can submit comments, and they are saved to the | |
| 201 | =comments.json= file, let's make sure we can show those comments in each | |
| 202 | blog post. | |
| 195 | Now that we can submit comments, and they are saved to the =comments.json= file, | |
| 196 | let's make sure we can show those comments in each blog post. | |
| 203 | 197 | |
| 204 | The code block below shows the function I use to decode my | |
| 205 | =comments.json= file, check if the comments apply to the current post, | |
| 206 | and then display them. | |
| 198 | The code block below shows the function I use to decode my =comments.json= file, | |
| 199 | check if the comments apply to the current post, and then display them. | |
| 207 | 200 | |
| 208 | This piece of code should *really* be inside a function (or at least in | |
| 209 | an organized PHP workflow). Don't just copy-and-paste and expect it to | |
| 210 | work. You need to at least supply a =$query= variable depending on the | |
| 211 | page visited. | |
| 201 | This piece of code should *really* be inside a function (or at least in an | |
| 202 | organized PHP workflow). Don't just copy-and-paste and expect it to work. You | |
| 203 | need to at least supply a =$query= variable depending on the page visited. | |
| 212 | 204 | |
| 213 | 205 | #+begin_src php |
| 214 | 206 | $query = 'your-blog-post.html'; |
| @@ -246,27 +238,24 @@ echo $comment_section; | ||
| 246 | 238 | |
| 247 | 239 | * Bonus: Create a 'Recent Comments' Page |
| 248 | 240 | |
| 249 | Finally, the last part of my current system is to create a Recent | |
| 250 | Comments page so that I can easily check-in on my blog and moderate any | |
| 251 | spam. As an alternative, you could use PHP's =mail()= function to email | |
| 252 | you for each blog comment. | |
| 241 | Finally, the last part of my current system is to create a Recent Comments page | |
| 242 | so that I can easily check-in on my blog and moderate any spam. As an | |
| 243 | alternative, you could use PHP's =mail()= function to email you for each blog | |
| 244 | comment. | |
| 253 | 245 | |
| 254 | The code to do this is literally the same code as the previous section, | |
| 255 | I just make sure it is printed when someone visits | |
| 256 | =https://example.com/comments/=. | |
| 246 | The code to do this is literally the same code as the previous section, I just | |
| 247 | make sure it is printed when someone visits =https://example.com/comments/=. | |
| 257 | 248 | |
| 258 | 249 | * Possible Enhancements |
| 259 | 250 | |
| 260 | This comment system is by no means a fully-developed system. I have | |
| 261 | noted a few possible enhancements here that I may implement in the | |
| 262 | future: | |
| 251 | This comment system is by no means a fully-developed system. I have noted a few | |
| 252 | possible enhancements here that I may implement in the future: | |
| 263 | 253 | |
| 264 | 254 | - Create a secure moderator page with user authentication at |
| 265 | =https://blog.example.com/mod/=. This page could have the option to | |
| 266 | edit or delete any comment found in =comments.json=. | |
| 267 | - Create a temporary file, such as =pending_comments.json=, that will | |
| 268 | store newly-submitted comments and won't display on blog posts until | |
| 269 | approved by a moderator. | |
| 270 | - Create a =/modlog/= page with a chronological log, showing which | |
| 271 | moderator approved which comments and why certain comments were | |
| 272 | rejected. | |
| 255 | =https://blog.example.com/mod/=. This page could have the option to edit or | |
| 256 | delete any comment found in =comments.json=. | |
| 257 | - Create a temporary file, such as =pending_comments.json=, that will store | |
| 258 | newly-submitted comments and won't display on blog posts until approved by a | |
| 259 | moderator. | |
| 260 | - Create a =/modlog/= page with a chronological log, showing which moderator | |
| 261 | approved which comments and why certain comments were rejected. | |
content/blog/2021-04-28-photography.org +39 −47
| @@ -6,66 +6,58 @@ | ||
| 6 | 6 | * Why Photography? |
| 7 | 7 | |
| 8 | 8 | I've often wondered why photography is as enticing as it is. You can see |
| 9 | billions of people around the world taking photographs every single | |
| 10 | moment of the day. New technology often boasts about their photographic | |
| 11 | capabilities, especially smartphones. I would even assume that we live | |
| 12 | in a world where there is never a moment in which a photograph is not | |
| 13 | being taken somewhere on Earth. | |
| 9 | billions of people around the world taking photographs every single moment of | |
| 10 | the day. New technology often boasts about their photographic capabilities, | |
| 11 | especially smartphones. I would even assume that we live in a world where there | |
| 12 | is never a moment in which a photograph is not being taken somewhere on Earth. | |
| 14 | 13 | |
| 15 | As for myself, I would simply say that I enjoy preserving a memory in | |
| 16 | physical (or digital) form. I've never had the best memory when it comes | |
| 17 | to recalling details of places and people gone by, so it helps to have a | |
| 18 | frame of reference lying around. | |
| 14 | As for myself, I would simply say that I enjoy preserving a memory in physical | |
| 15 | (or digital) form. I've never had the best memory when it comes to recalling | |
| 16 | details of places and people gone by, so it helps to have a frame of reference | |
| 17 | lying around. | |
| 19 | 18 | |
| 20 | Regardless of the reason, I think most people would agree that you | |
| 21 | simply cannot have too many hobbies. | |
| 19 | Regardless of the reason, I think most people would agree that you simply cannot | |
| 20 | have too many hobbies. | |
| 22 | 21 | |
| 23 | 22 | * Older Cameras |
| 24 | 23 | |
| 25 | I started playing around with the idea of photography when my family | |
| 26 | purchased a Fujifilm camera for family-specific events. I don't recall | |
| 27 | the specific model, but I do recall it was a point-and-shoot camera | |
| 28 | without an interchangeable lens. However, it was of great value to | |
| 29 | someone, like myself, who couldn't afford any other camera. I took about | |
| 30 | 10,000 shots with that camera over a 3-5 year span. Most notably, all of | |
| 31 | my trips to California were documented through this camera. | |
| 24 | I started playing around with the idea of photography when my family purchased a | |
| 25 | Fujifilm camera for family-specific events. I don't recall the specific model, | |
| 26 | but I do recall it was a point-and-shoot camera without an interchangeable lens. | |
| 27 | However, it was of great value to someone, like myself, who couldn't afford any | |
| 28 | other camera. I took about 10,000 shots with that camera over a 3-5 year span. | |
| 29 | Most notably, all of my trips to California were documented through this camera. | |
| 32 | 30 | |
| 33 | When possible, I would borrow my sister's camera, which is a Sony | |
| 34 | SLT-A58. This camera was great and allowed for some of my best early | |
| 35 | shots, especially those taken in Utah's and Nevada's parks. | |
| 31 | When possible, I would borrow my sister's camera, which is a Sony SLT-A58. This | |
| 32 | camera was great and allowed for some of my best early shots, especially those | |
| 33 | taken in Utah's and Nevada's parks. | |
| 36 | 34 | |
| 37 | 35 | * My Current Kit |
| 38 | 36 | |
| 39 | I've finally come to a point in my life where I have the disposable | |
| 40 | income to invest in a solid photography kit. I played around with the | |
| 41 | idea of a lot of different cameras, different types, new vs used, etc. | |
| 42 | Finally, I settled on the | |
| 43 | [[https://en.wikipedia.org/wiki/Sony_%CE%B17_III][Sony α7 III]]. This | |
| 44 | camera is mirror-less and uses a full-frame image sensor at 24 | |
| 45 | megapixels. I don't create large prints, and I am mostly focused on | |
| 46 | preserving memories in high quality for the next 5-10 years with this | |
| 47 | camera, so the specifications here are just perfect for me. | |
| 37 | I've finally come to a point in my life where I have the disposable income to | |
| 38 | invest in a solid photography kit. I played around with the idea of a lot of | |
| 39 | different cameras, different types, new vs used, etc. Finally, I settled on the | |
| 40 | [[https://en.wikipedia.org/wiki/Sony_%CE%B17_III][Sony α7 III]]. This camera is mirror-less and uses a full-frame image sensor at 24 | |
| 41 | megapixels. I don't create large prints, and I am mostly focused on preserving | |
| 42 | memories in high quality for the next 5-10 years with this camera, so the | |
| 43 | specifications here are just perfect for me. | |
| 48 | 44 | |
| 49 | 45 | For lenses, I decided to buy two lenses that could carry me through most |
| 50 | 46 | situations: |
| 51 | 47 | |
| 52 | - [[https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z][Vario-Tessar | |
| 53 | T** FE 24-70 mm F4 ZA OSS]] | |
| 54 | - [[https://www.tamron-usa.com/product/lenses/a047.html][Tamron 70-300mm | |
| 55 | f4.5-6.3 Di III RXD]] | |
| 48 | - [[https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z][Vario-Tessar T** FE 24-70 mm F4 ZA OSS]] | |
| 49 | - [[https://www.tamron-usa.com/product/lenses/a047.html][Tamron 70-300mm f4.5-6.3 Di III RXD]] | |
| 56 | 50 | |
| 57 | In addition, I grabbed a couple | |
| 58 | [[https://www.promaster.com/Product/6725][HGX Prime 67mm]] protection | |
| 59 | filters for the lenses. | |
| 51 | In addition, I grabbed a couple [[https://www.promaster.com/Product/6725][HGX Prime 67mm]] protection filters for the | |
| 52 | lenses. | |
| 60 | 53 | |
| 61 | As I delve further into photography and pick up more skills, I will most | |
| 62 | likely go back and grab a lens with a higher f-stop value, such as | |
| 63 | f/1.8. I toyed with the idea of grabbing a 50 mm at =f/1.8=, but decided | |
| 64 | to keep things in a reasonable price range instead. | |
| 54 | As I delve further into photography and pick up more skills, I will most likely | |
| 55 | go back and grab a lens with a higher f-stop value, such as f/1.8. I toyed with | |
| 56 | the idea of grabbing a 50 mm at =f/1.8=, but decided to keep things in a | |
| 57 | reasonable price range instead. | |
| 65 | 58 | |
| 66 | Finally, I made sure to buy a photography-specific backpack with a rain | |
| 67 | guard, and the zipper on the back panel, to protect the equipment while | |
| 68 | wearing the bag. If you've ever had to haul around a DSLR (or camera of | |
| 69 | similar heft) in a bag that only has a shoulder strap, you'll know the | |
| 70 | pain it can cause. Putting all my equipment in a backpack was an easy | |
| 71 | decision. | |
| 59 | Finally, I made sure to buy a photography-specific backpack with a rain guard, | |
| 60 | and the zipper on the back panel, to protect the equipment while wearing the | |
| 61 | bag. If you've ever had to haul around a DSLR (digital single-lens reflex) | |
| 62 | camera in a bag that only has a shoulder strap, you'll know the pain it can | |
| 63 | cause. Putting all my equipment in a backpack was an easy decision. | |
content/blog/2021-05-30-changing-git-authors.org +8 −8
| @@ -5,12 +5,12 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Changing Git Author/Email Based on Previously Committed Email |
| 7 | 7 | |
| 8 | Here's the dilemma: You've been committing changes to your git | |
| 9 | repository with an incorrect name or email (or multiple repositories), | |
| 10 | and now you want to fix it. Luckily, there's a semi-reliable way to fix | |
| 11 | that. While I have never experienced issues with this method, some | |
| 12 | people have warned that it can mess with historical hashes and integrity | |
| 13 | of commits, so use this method only if you're okay accepting that risk. | |
| 8 | Here's the dilemma: You've been committing changes to your Git repository with | |
| 9 | an incorrect name or email (or multiple repositories), and now you want to fix | |
| 10 | it. Luckily, there's a semi-reliable way to fix that. While I have never | |
| 11 | experienced issues with this method, some people have warned that it can mess | |
| 12 | with historical hashes and integrity of commits, so use this method only if | |
| 13 | you're okay accepting that risk. | |
| 14 | 14 | |
| 15 | 15 | Okay, let's create the bash script: |
| 16 | 16 | |
| @@ -18,8 +18,8 @@ Okay, let's create the bash script: | ||
| 18 | 18 | nano change_git_authors.sh |
| 19 | 19 | #+end_src |
| 20 | 20 | |
| 21 | The following information can be pasted directly into your bash script. | |
| 22 | The only changes you need to make are to the following variables: | |
| 21 | The following information can be pasted directly into your bash script. The only | |
| 22 | changes you need to make are to the following variables: | |
| 23 | 23 | |
| 24 | 24 | - =OLD_EMAIL= |
| 25 | 25 | - =CORRECT_NAME= |
content/blog/2021-07-15-delete-gitlab-repos.org +19 −22
| @@ -5,31 +5,29 @@ | ||
| 5 | 5 | |
| 6 | 6 | * Background |
| 7 | 7 | |
| 8 | Have you ever used GitLab to host your source code, moved to a different | |
| 9 | host, and wanted to delete everything from your GitLab account? Well, | |
| 10 | this post covers any scenario where you would want to delete all | |
| 11 | repositories from your GitLab account. | |
| 8 | Have you ever used GitLab to host your source code, moved to a different host, | |
| 9 | and wanted to delete everything from your GitLab account? Well, this post covers | |
| 10 | any scenario where you would want to delete all repositories from your GitLab | |
| 11 | account. | |
| 12 | 12 | |
| 13 | For me, I currently maintain around 30 repositories and don't like to | |
| 14 | manually delete them whenever I switch host. GitHub has a few different | |
| 15 | tools online to delete all repositories for you, but I have not found | |
| 16 | anything similar for GitLab, so I needed an alternative solution. | |
| 13 | For me, I currently maintain around 30 repositories and don't like to manually | |
| 14 | delete them whenever I switch host. GitHub has a few different tools online to | |
| 15 | delete all repositories for you, but I have not found anything similar for | |
| 16 | GitLab, so I needed an alternative solution. | |
| 17 | 17 | |
| 18 | 18 | * Use a Python Script |
| 19 | 19 | |
| 20 | 20 | ** Requirements |
| 21 | 21 | |
| 22 | Before we look at the script, make sure you know your GitLab username. | |
| 23 | Next, [[https://gitlab.com/-/profile/personal_access_tokens][create an | |
| 24 | authorization token]] so that the Python script can delete your | |
| 25 | repositories. Don't lose this token or else you'll need to create a new | |
| 26 | one. | |
| 22 | Before we look at the script, make sure you know your GitLab username. Next, | |
| 23 | [[https://gitlab.com/-/profile/personal_access_tokens][create an authorization token]] so that the Python script can delete your | |
| 24 | repositories. Don't lose this token or else you'll need to create a new one. | |
| 27 | 25 | |
| 28 | 26 | ** Create the Script |
| 29 | 27 | |
| 30 | To run a Python script, you must first create it. Open a terminal and | |
| 31 | enter the following commands in whichever directory you prefer to store | |
| 32 | the script. You can do the same things in a file manager if you prefer. | |
| 28 | To run a Python script, you must first create it. Open a terminal and enter the | |
| 29 | following commands in whichever directory you prefer to store the script. You | |
| 30 | can do the same things in a file manager if you prefer. | |
| 33 | 31 | |
| 34 | 32 | #+begin_src sh |
| 35 | 33 | mkdir delete-gitlab |
| @@ -101,13 +99,12 @@ if __name__ == "__main__": | ||
| 101 | 99 | main() |
| 102 | 100 | #+end_src |
| 103 | 101 | |
| 104 | Now that you have the proper information, replace ={user-id}= with your | |
| 105 | GitLab username and ={auth-token}= with the authorization token you | |
| 106 | created earlier. | |
| 102 | Now that you have the proper information, replace ={user-id}= with your GitLab | |
| 103 | username and ={auth-token}= with the authorization token you created earlier. | |
| 107 | 104 | |
| 108 | Finally, simply run the script and watch the output. You can also use | |
| 109 | PyCharm Community Edition to edit and run the Python script if you don't | |
| 110 | want to work in a terminal. | |
| 105 | Finally, simply run the script and watch the output. You can also use PyCharm | |
| 106 | Community Edition to edit and run the Python script if you don't want to work in | |
| 107 | a terminal. | |
| 111 | 108 | |
| 112 | 109 | #+begin_src sh |
| 113 | 110 | python3 main.py |
content/blog/2021-08-25-audit-sampling.org +98 −101
| @@ -6,44 +6,40 @@ | ||
| 6 | 6 | * Introduction |
| 7 | 7 | |
| 8 | 8 | For anyone who is familiar with internal auditing, external auditing, or |
| 9 | consulting, you will understand how tedious audit testing can become | |
| 10 | when you are required to test large swaths of data. When we cannot | |
| 11 | establish an automated means of testing an entire population, we | |
| 12 | generate samples to represent the population of data. This helps ensure | |
| 13 | we can have a small enough data pool to test and that our results still | |
| 14 | represent the population. | |
| 15 | ||
| 16 | However, sampling data within the world of audit still seems to confuse | |
| 17 | quite a lot of people. While some audit-focused tools have introduced | |
| 18 | sampling functionality (e.g. Wdesk), many audit departments and firms | |
| 19 | cannot use software like this due to certain constraints, such as the | |
| 20 | team's budget or knowledge. Here is where this article comes in: we're | |
| 21 | going to use [[https://www.python.org][Python]], a free and open-source | |
| 22 | programming language, to generate random samples from a dataset in order | |
| 23 | to suffice numerous audit situations. | |
| 9 | consulting, you will understand how tedious audit testing can become when you | |
| 10 | are required to test large swaths of data. When we cannot establish an automated | |
| 11 | means of testing an entire population, we generate samples to represent the | |
| 12 | population of data. This helps ensure we can have a small enough data pool to | |
| 13 | test and that our results still represent the population. | |
| 14 | ||
| 15 | However, sampling data within the world of audit still seems to confuse quite a | |
| 16 | lot of people. While some audit-focused tools have introduced sampling | |
| 17 | functionality (e.g. Wdesk), many audit departments and firms cannot use software | |
| 18 | like this due to certain constraints, such as the team's budget or knowledge. | |
| 19 | Here is where this article comes in: we're going to use [[https://www.python.org][Python]], a free and | |
| 20 | open-source programming language, to generate random samples from a dataset in | |
| 21 | order to suffice numerous audit situations. | |
| 24 | 22 | |
| 25 | 23 | * Audit Requirements for Sampling |
| 26 | 24 | |
| 27 | Before we get into the details of how to sample with Python, I want to | |
| 28 | make sure I discuss the different requirements that auditors may have of | |
| 29 | samples used within their projects. | |
| 25 | Before we get into the details of how to sample with Python, I want to make sure | |
| 26 | I discuss the different requirements that auditors may have of samples used | |
| 27 | within their projects. | |
| 30 | 28 | |
| 31 | 29 | ** Randomness |
| 32 | 30 | |
| 33 | First, let's discuss randomness. When testing out new technology to help | |
| 34 | assist with audit sampling, you need to understand exactly how your | |
| 35 | samples are being generated. For example, if the underlying function is | |
| 36 | just picking every 57th element from a list, that's not truly random; | |
| 37 | it's a systematic form of sampling. Luckily, since Python is | |
| 38 | open-source, we have access to its codebase. Through this blog post, I | |
| 39 | will be using the [[https://pandas.pydata.org][pandas]] module in order | |
| 40 | to generate the random samples. More specifically, I will be using the | |
| 41 | [[https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html][pandas.DataFrame.sample]] | |
| 42 | function provided by Pandas. | |
| 43 | ||
| 44 | Now that you know what you're using, you can always check out the code | |
| 45 | behind =pandas.DataFrame.sample=. This function does a lot of work, but | |
| 46 | we really only care about the following snippets of code: | |
| 31 | First, let's discuss randomness. When testing out new technology to help assist | |
| 32 | with audit sampling, you need to understand exactly how your samples are being | |
| 33 | generated. For example, if the underlying function is just picking every 57th | |
| 34 | element from a list, that's not truly random; it's a systematic form of | |
| 35 | sampling. Luckily, since Python is open-source, we have access to its codebase. | |
| 36 | Through this blog post, I will be using the [[https://pandas.pydata.org][pandas]] module in order to generate | |
| 37 | the random samples. More specifically, I will be using the | |
| 38 | [[https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html][pandas.DataFrame.sample]] function provided by Pandas. | |
| 39 | ||
| 40 | Now that you know what you're using, you can always check out the code behind | |
| 41 | =pandas.DataFrame.sample=. This function does a lot of work, but we really only | |
| 42 | care about the following snippets of code: | |
| 47 | 43 | |
| 48 | 44 | #+begin_src python |
| 49 | 45 | # Process random_state argument |
| @@ -59,61 +55,62 @@ result.index = ibase.default_index(len(result)) | ||
| 59 | 55 | return result |
| 60 | 56 | #+end_src |
| 61 | 57 | |
| 62 | The block of code above shows you that if you assign a =random_state= | |
| 63 | argument when you run the function, that will be used as a seed number | |
| 64 | in the random generation and will allow you to reproduce a sample, given | |
| 65 | that nothing else changes. This is critical to the posterity of audit | |
| 66 | work. After all, how can you say your audit process is adequately | |
| 67 | documented if the next person can't run the code and get the same | |
| 68 | sample? The final piece here on randomness is to look at the | |
| 69 | [[https://docs.python.org/3/library/random.html#random.choice][choice]] | |
| 70 | function used above. This is the crux of the generation and can also be | |
| 71 | examined for more detailed analysis on its reliability. As far as | |
| 72 | auditing goes, we will trust that these functions are mathematically | |
| 73 | random. | |
| 58 | The block of code above shows you that if you assign a =random_state= argument | |
| 59 | when you run the function, that will be used as a seed number in the random | |
| 60 | generation and will allow you to reproduce a sample, given that nothing else | |
| 61 | changes. This is critical to the posterity of audit work. After all, how can you | |
| 62 | say your audit process is adequately documented if the next person can't run the | |
| 63 | code and get the same sample? The final piece here on randomness is to look at | |
| 64 | the [[https://docs.python.org/3/library/random.html#random.choice][choice]] function used above. This is the crux of the generation and can also | |
| 65 | be examined for more detailed analysis on its reliability. As far as auditing | |
| 66 | goes, we will trust that these functions are mathematically random. | |
| 74 | 67 | |
| 75 | 68 | ** Sample Sizes |
| 76 | 69 | |
| 77 | As mentioned in the intro, sampling is only an effective method of | |
| 78 | auditing when it truly represents the entire population. While some | |
| 79 | audit departments or firms may consider certain judgmental sample sizes | |
| 80 | to be adequate, you may need to rely on statistically-significant | |
| 81 | confidence levels of sample testing at certain points. I will | |
| 82 | demonstrate both here. For statistically-significant confidence levels, | |
| 83 | most people will assume a 90% - 99% confidence level. In order to | |
| 84 | actually calculate the correct sample size, it is best to use | |
| 85 | statistical tools due to the tedious math work required. For example, | |
| 86 | for a population of 1000, and a 90% confidence level that no more than | |
| 87 | 5% of the items are nonconforming, you would sample 45 items. | |
| 88 | ||
| 89 | However, in my personal experience, many audit departments and firms do | |
| 90 | not use statistical sampling. Most people use a predetermined, often | |
| 91 | proprietary, table that will instruct auditors which sample sizes to | |
| 92 | choose. This allows for uniform testing and reduces overall workload. | |
| 93 | See the table below for a common implementation of sample sizes: | |
| 94 | ||
| 95 | Control Frequency Sample Size - High Risk Sample Size - Low Risk | |
| 96 | ||
| 97 | -------------- | |
| 98 | ||
| 99 | More Than Daily 40 25 Daily 40 25 Weekly 12 5 Monthly 5 3 Quarterly 2 2 | |
| 100 | Semi-Annually 1 1 Annually 1 1 Ad-hoc 1 1 | |
| 70 | As mentioned in the intro, sampling is only an effective method of auditing when | |
| 71 | it truly represents the entire population. While some audit departments or firms | |
| 72 | pmay consider certain judgmental sample sizes to be adequate, you may need to | |
| 73 | rely on statistically-significant confidence levels of sample testing at certain | |
| 74 | ||
| 75 | points. I will demonstrate both here. For statistically-significant confidence | |
| 76 | levels, most people will assume a 90% - 99% confidence level. In order to | |
| 77 | actually calculate the correct sample size, it is best to use statistical tools | |
| 78 | due to the tedious math work required. For example, for a population of 1000, | |
| 79 | and a 90% confidence level that no more than 5% of the items are nonconforming, | |
| 80 | you would sample 45 items. | |
| 81 | ||
| 82 | However, in my personal experience, many audit departments and firms do not use | |
| 83 | statistical sampling. Most people use a predetermined, often proprietary, table | |
| 84 | that will instruct auditors which sample sizes to choose. This allows for | |
| 85 | uniform testing and reduces overall workload. See the table below for a common | |
| 86 | implementation of sample sizes: | |
| 87 | ||
| 88 | | Control Frequency | Sample Size (High Risk) | Sample Size (Low Risk) | | |
| 89 | |-------------------+-------------------------+------------------------| | |
| 90 | | More Than Daily | 40 | 25 | | |
| 91 | | Daily | 40 | 25 | | |
| 92 | | Weekly | 12 | 5 | | |
| 93 | | Monthly | 5 | 3 | | |
| 94 | | Quarterly | 2 | 2 | | |
| 95 | | Semi-Annually | 1 | 1 | | |
| 96 | | Annually | 1 | 1 | | |
| 97 | | Ad-hoc | 1 | 1 | | |
| 101 | 98 | |
| 102 | 99 | *** Sampling with Python & Pandas |
| 103 | 100 | |
| 104 | In this section, I am going to cover a few basic audit situations that | |
| 105 | require sampling. While some situations may require more effort, the | |
| 106 | syntax, organization, and intellect used remain largely the same. If | |
| 107 | you've never used Python before, note that lines starting with a '=#=' | |
| 108 | symbol are called comments, and they will be skipped by Python. I highly | |
| 109 | recommend taking a quick tutorial online to understand the basics of | |
| 110 | Python if any of the code below is confusing to you. | |
| 101 | In this section, I am going to cover a few basic audit situations that require | |
| 102 | sampling. While some situations may require more effort, the syntax, | |
| 103 | organization, and intellect used remain largely the same. If you've never used | |
| 104 | Python before, note that lines starting with a '=#=' symbol are called comments, | |
| 105 | and they will be skipped by Python. I highly recommend taking a quick tutorial | |
| 106 | online to understand the basics of Python if any of the code below is confusing | |
| 107 | to you. | |
| 111 | 108 | |
| 112 | 109 | ** Simple Random Sample |
| 113 | 110 | |
| 114 | First, let's look at a simple, random sample. The code block below will | |
| 115 | import the =pandas= module, load a data file, sample the data, and | |
| 116 | export the sample to a file. | |
| 111 | First, let's look at a simple, random sample. The code block below will import | |
| 112 | the =pandas= module, load a data file, sample the data, and export the sample to | |
| 113 | a file. | |
| 117 | 114 | |
| 118 | 115 | #+begin_src python |
| 119 | 116 | # Import the Pandas module |
| @@ -137,8 +134,8 @@ sample.to_excel(file_output) | ||
| 137 | 134 | |
| 138 | 135 | ** Simple Random Sample: Using Multiple Input Files |
| 139 | 136 | |
| 140 | Now that we've created a simple sample, let's create a sample from | |
| 141 | multiple files. | |
| 137 | Now that we've created a simple sample, let's create a sample from multiple | |
| 138 | files. | |
| 142 | 139 | |
| 143 | 140 | #+begin_src python |
| 144 | 141 | # Import the Pandas module |
| @@ -171,9 +168,9 @@ sample.to_excel(file_output) | ||
| 171 | 168 | |
| 172 | 169 | ** Stratified Random Sample |
| 173 | 170 | |
| 174 | Well, what if you need to sample distinct parts of a single file? For | |
| 175 | example, let's write some code to separate our data by "Region" and | |
| 176 | sample those regions independently. | |
| 171 | Well, what if you need to sample distinct parts of a single file? For example, | |
| 172 | let's write some code to separate our data by "Region" and sample those regions | |
| 173 | independently. | |
| 177 | 174 | |
| 178 | 175 | #+begin_src python |
| 179 | 176 | # Import the Pandas module |
| @@ -205,10 +202,10 @@ sample.to_excel(file_output) | ||
| 205 | 202 | |
| 206 | 203 | ** Stratified Systematic Sample |
| 207 | 204 | |
| 208 | This next example is quite useful if you need audit coverage over a | |
| 209 | certain time period. This code will generate samples for each month in | |
| 210 | the data and combine them all together at the end. Obviously, this code | |
| 211 | can be modified to stratify by something other than months, if needed. | |
| 205 | This next example is quite useful if you need audit coverage over a certain time | |
| 206 | period. This code will generate samples for each month in the data and combine | |
| 207 | them all together at the end. Obviously, this code can be modified to stratify | |
| 208 | by something other than months, if needed. | |
| 212 | 209 | |
| 213 | 210 | #+begin_src python |
| 214 | 211 | # Import the Pandas module |
| @@ -254,17 +251,17 @@ sample.to_excel(file_output) | ||
| 254 | 251 | |
| 255 | 252 | *** Documenting the Results |
| 256 | 253 | |
| 257 | Once you've generated a proper sample, there are a few things left to do | |
| 258 | in order to properly ensure your process is reproducible. | |
| 259 | ||
| 260 | 1. Document the sample. Make sure the resulting file is readable and | |
| 261 | includes the documentation listed in the next bullet. | |
| 262 | 2. Include documentation around the data source, extraction techniques, | |
| 263 | any modifications made to the data, and be sure to include a copy of | |
| 264 | the script itself. | |
| 265 | 3. Whenever possible, perform a completeness and accuracy test to ensure | |
| 266 | your sample is coming from a complete and accurate population. To | |
| 267 | ensure completeness, compare the record count from the data source to | |
| 268 | the record count loaded into Python. To ensure accuracy, test a small | |
| 269 | sample against the source data (e.g., test 5 sales against the | |
| 270 | database to see if the details are accurate). | |
| 254 | Once you've generated a proper sample, there are a few things left to do in | |
| 255 | order to properly ensure your process is reproducible. | |
| 256 | ||
| 257 | 1. Document the sample. Make sure the resulting file is readable and includes | |
| 258 | the documentation listed in the next bullet. | |
| 259 | 2. Include documentation around the data source, extraction techniques, any | |
| 260 | modifications made to the data, and be sure to include a copy of the script | |
| 261 | itself. | |
| 262 | 3. Whenever possible, perform a completeness and accuracy test to ensure your | |
| 263 | sample is coming from a complete and accurate population. To ensure | |
| 264 | completeness, compare the record count from the data source to the record | |
| 265 | count loaded into Python. To ensure accuracy, test a small sample against the | |
| 266 | source data (e.g., test 5 sales against the database to see if the details | |
| 267 | are accurate). | |
content/blog/2021-10-09-apache-redirect.org +14 −17
| @@ -5,15 +5,13 @@ | ||
| 5 | 5 | |
| 6 | 6 | * The Problem |
| 7 | 7 | |
| 8 | After recently switching static site generators (SSG), my blog URLs | |
| 9 | changed with no option to preserve the classic =.html= extension at the | |
| 10 | end of my blog post URLs. | |
| 8 | After recently switching static site generators (SSG), my blog URLs (uniform | |
| 9 | resource locators) changed with no option to preserve the classic =.html= | |
| 10 | extension at the end of my blog post URLs. | |
| 11 | 11 | |
| 12 | I really disliked using my old SSG ([[https://jekyllrb.com][Jekyll]]) | |
| 13 | and prefer my new tool ([[https://www.getzola.org][Zola]]) much more, so | |
| 14 | I was determined to figure out a way to get the proper redirect set up | |
| 15 | so that people who find my posts online aren't constantly met by 404 | |
| 16 | errors. | |
| 12 | I really disliked using my old SSG ([[https://jekyllrb.com][Jekyll]]) and prefer my new tool ([[https://www.getzola.org][Zola]]) much | |
| 13 | more, so I was determined to figure out a way to get the proper redirect set up | |
| 14 | so that people who find my posts online aren't constantly met by 404 errors. | |
| 17 | 15 | |
| 18 | 16 | * The Solution |
| 19 | 17 | |
| @@ -21,11 +19,10 @@ To solve this problem, I really needed to solve two pieces: | ||
| 21 | 19 | |
| 22 | 20 | 1. Redirect all blog post URL requests from =/blog/some-post.html= to |
| 23 | 21 | =/blog/some-post/=. |
| 24 | 2. Ensure that no other =.html= files are redirected, such as | |
| 25 | =index.html=. | |
| 22 | 2. Ensure that no other =.html= files are redirected, such as =index.html=. | |
| 26 | 23 | |
| 27 | After /a lot/ of tweaking and testing, I believe I have finally found | |
| 28 | the solution. The solution is shown below. | |
| 24 | After /a lot/ of tweaking and testing, I believe I have finally found the | |
| 25 | solution. The solution is shown below. | |
| 29 | 26 | |
| 30 | 27 | #+begin_src conf |
| 31 | 28 | RewriteEngine On |
| @@ -38,8 +35,8 @@ following: | ||
| 38 | 35 | |
| 39 | 36 | 1. Turn on the RewriteEngine so that we can modify URLs. |
| 40 | 37 | 2. Ignore any =index.html= files from the rule we are about to specify. |
| 41 | 3. Find any =.html= files within the website directory and redirect it | |
| 42 | to exclude the file extension. | |
| 43 | 4. The final piece is adding the trailing slash (=/=) at the end of the | |
| 44 | URL - you'll notice that I don't have an Apache rule for that since | |
| 45 | Apache handles that automatically. | |
| 38 | 3. Find any =.html= files within the website directory and redirect it to | |
| 39 | exclude the file extension. | |
| 40 | 4. The final piece is adding the trailing slash (=/=) at the end of the URL - | |
| 41 | you'll notice that I don't have an Apache rule for that since Apache handles | |
| 42 | that automatically. | |
content/blog/2021-12-04-cisa.org +142 −156
| @@ -6,200 +6,186 @@ | ||
| 6 | 6 | * What is the CISA? |
| 7 | 7 | |
| 8 | 8 | For those of you lucky enough not to be knee-deep in the world of IT/IS |
| 9 | Auditing, [[https://www.isaca.org/credentialing/cisa][CISA]] stands for | |
| 10 | Certified Information Systems Auditor. This certification and exam are | |
| 11 | part of ISACA's suite of certifications. As I often explain it to people | |
| 12 | like my family, it basically means you're employed to use your knowledge | |
| 13 | of information systems, regulations, common threats, risks, etc. in | |
| 14 | order to assess an organization's current control of their risk. If a | |
| 15 | risk isn't controlled (and the company doesn't want to accept the risk), | |
| 16 | an IS auditor will suggest implementing a control to address that risk. | |
| 17 | ||
| 18 | Now, the CISA certification itself is, in my opinion, the main | |
| 19 | certification for this career. While certifications such as the CPA or | |
| 20 | CISSP are beneficial, nothing matches the power of the CISA for an IS | |
| 21 | auditor when it comes to getting hired, getting a raise/bonus, or | |
| 22 | earning respect in the field. | |
| 23 | ||
| 24 | However, to be honest, I am a skeptic of most certifications. I | |
| 25 | understand the value they hold in terms of how much you need to commit | |
| 26 | to studying or learning on the job, as well as the market value for | |
| 27 | certifications such as the CISA. But I also have known some very | |
| 28 | +incompetent+ /less than stellar/ auditors who have CPAs, CISAs, CIAs, | |
| 29 | etc. | |
| 30 | ||
| 31 | The same goes for most industries: if a person is good at studying, they | |
| 32 | can earn the certification. However, that knowledge means nothing unless | |
| 33 | you're actually able to use it in real life and perform as expected of a | |
| 34 | certification holder. The challenge comes when people are hired or | |
| 35 | connected strictly because of their certifications or resume; you need | |
| 36 | to see a person work before you can assume them having a CISA means | |
| 37 | they're better than someone without the CISA. | |
| 38 | ||
| 39 | Okay, rant over. Certifications are generally accepted as a measuring | |
| 40 | stick of commitment and quality of an employee, so I am accepting it | |
| 41 | too. | |
| 9 | Auditing, the [[https://www.isaca.org/credentialing/cisa][CISA]] (Certified Information Systems Auditor) certification and | |
| 10 | exam are part of ISACA's suite of certifications. As I often explain it to | |
| 11 | people like my family, it basically means you're employed to use your knowledge | |
| 12 | of information systems, regulations, common threats, risks, etc. in order to | |
| 13 | assess an organization's current control of their risk. If a risk isn't | |
| 14 | controlled (and the company doesn't want to accept the risk), an IS auditor will | |
| 15 | suggest implementing a control to address that risk. | |
| 16 | ||
| 17 | Now, the CISA certification itself is, in my opinion, the main certification for | |
| 18 | this career. While certifications such as the CPA (Certified Public Accountant) | |
| 19 | or CISSP (Certified Information Systems Security Professional) are beneficial, | |
| 20 | nothing matches the power of the CISA for an information systems (IS) auditor | |
| 21 | when it comes to getting hired, getting a raise/bonus, or earning respect in the | |
| 22 | field. | |
| 23 | ||
| 24 | However, to be honest, I am a skeptic of most certifications. I understand the | |
| 25 | value they hold in terms of how much you need to commit to studying or learning | |
| 26 | on the job, as well as the market value for certifications such as the CISA. But | |
| 27 | I also have known some very +incompetent+ /less than stellar/ auditors who have | |
| 28 | relevant certifications. | |
| 29 | ||
| 30 | The same goes for most industries: if a person is good at studying, they can | |
| 31 | earn the certification. However, that knowledge means nothing unless you're | |
| 32 | actually able to use it in real life and perform as expected of a certification | |
| 33 | holder. The challenge comes when people are hired or connected strictly because | |
| 34 | of their certifications or resume; you need to see a person work before you can | |
| 35 | assume them having a CISA means they're better than someone without the CISA. | |
| 36 | ||
| 37 | Okay, rant over. Certifications are generally accepted as a measuring stick of | |
| 38 | commitment and quality of an employee, so I am accepting it too. | |
| 42 | 39 | |
| 43 | 40 | * Exam Content |
| 44 | 41 | |
| 45 | The CISA is broken down into five sections, each weighted with a | |
| 46 | percentage of test questions that may appear. | |
| 42 | The CISA is broken down into five sections, each weighted with a percentage of | |
| 43 | test questions that may appear. | |
| 47 | 44 | |
| 48 | Since the exam contains 150 questions, here's how those sections break | |
| 49 | down: | |
| 45 | Since the exam contains 150 questions, here's how those sections break down: | |
| 50 | 46 | |
| 51 | | Exam Section | Percentage of Exam | Questions | | |
| 47 | | Exam Section | Percentage of Exam | Questions | | |
| 52 | 48 | |---------------+--------------------+-----------| |
| 53 | | 1 | 21% | 32 | | |
| 54 | | 2 | 17% | 26 | | |
| 55 | | 3 | 12% | 18 | | |
| 56 | | 4 | 23% | 34 | | |
| 57 | | 5 | 27% | 40 | | |
| 58 | | *Grand Total* | *100%* | *150* | | |
| 49 | | 1 | 21% | 32 | | |
| 50 | | 2 | 17% | 26 | | |
| 51 | | 3 | 12% | 18 | | |
| 52 | | 4 | 23% | 34 | | |
| 53 | | 5 | 27% | 40 | | |
| 54 | | *Grand Total* | *100%* | *150* | | |
| 59 | 55 | |
| 60 | 56 | * My Studying Habits |
| 61 | 57 | |
| 62 | This part is a little hard for me to break down into specific detail due | |
| 63 | to the craziness of the last year. While I officially purchased my | |
| 64 | studying materials in December 2020 and opened them to "start studying" | |
| 65 | in January 2021, I really wasn't able to study much due to the demands | |
| 66 | of my job and personal life. | |
| 58 | This part is a little hard for me to break down into specific detail due to the | |
| 59 | craziness of the last year. While I officially purchased my studying materials | |
| 60 | in December 2020 and opened them to "start studying" in January 2021, I really | |
| 61 | wasn't able to study much due to the demands of my job and personal life. | |
| 67 | 62 | |
| 68 | 63 | Let me approach this from a few different viewpoints. |
| 69 | 64 | |
| 70 | 65 | ** Study Materials |
| 71 | 66 | |
| 72 | Let's start by discussing the study materials I purchased. I'll be | |
| 73 | referring to #1 as the CRM and #2 as the QAE. | |
| 74 | ||
| 75 | 1. [[https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK][CISA | |
| 76 | Review Manual, 27th Edition | Print]] | |
| 77 | 2. [[https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK][CISA | |
| 78 | Review Questions, Answers & Explanations Manual, 12th Edition | | |
| 79 | Print]] | |
| 80 | ||
| 81 | The CRM is an excellent source of information and could honestly be used | |
| 82 | as a reference for most IS auditors as a learning reference during their | |
| 83 | daily audit responsibilities. However, it is *full* of information and | |
| 84 | can be overloading if you're not good at filtering out useless | |
| 85 | information while studying. | |
| 86 | ||
| 87 | The QAE is the real star of the show here. This book contains 1000 | |
| 88 | questions, separated by exam section, and a practice exam. My only | |
| 89 | complaint about the QAE is that each question is immediately followed | |
| 90 | with the correct answer and explanations below it, which means I had to | |
| 91 | use something to constantly cover the answers while I was studying. | |
| 92 | ||
| 93 | I didn't use the online database version of the QAE, but I've heard that | |
| 94 | it's easier to use than the printed book. However, it is more expensive | |
| 95 | ($299 database vs $129 book) which might be important if you're paying | |
| 96 | for materials yourself. | |
| 97 | ||
| 98 | In terms of question difficulty, I felt that the QAE was a good | |
| 99 | representation of the actual exam. I've seen a lot of people online say | |
| 100 | it wasn't accurate to the exam or that it was much easier/harder, but I | |
| 101 | disagree with all of those. The exam was fairly similar to the QAE, just | |
| 102 | focusing on whichever topics they chose for my version of the exam. | |
| 103 | ||
| 104 | If you understand the concepts, skim the CRM (and read in-depth on | |
| 105 | topics you struggle with), and use the QAE to continue practicing | |
| 106 | exam-like questions, you should be fine. I didn't use any online | |
| 107 | courses, videos, etc. - the ISACA materials are more than enough. | |
| 67 | Let's start by discussing the study materials I purchased. I'll be referring to | |
| 68 | #1 as the CRM (CISA Review Manual) and #2 as the QAE (Questions, Answers & | |
| 69 | Explanations). | |
| 70 | ||
| 71 | 1. [[https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK][CISA Review Manual, 27th Edition | Print]] | |
| 72 | 2. [[https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK][CISA Review Questions, Answers & Explanations Manual, 12th Edition | Print]] | |
| 73 | ||
| 74 | The CRM is an excellent source of information and could honestly be used as a | |
| 75 | reference for most IS auditors as a learning reference during their daily audit | |
| 76 | responsibilities. However, it is *full* of information and can be overloading if | |
| 77 | you're not good at filtering out useless information while studying. | |
| 78 | ||
| 79 | The QAE is the real star of the show here. This book contains 1000 questions, | |
| 80 | separated by exam section, and a practice exam. My only complaint about the QAE | |
| 81 | is that each question is immediately followed with the correct answer and | |
| 82 | explanations below it, which means I had to use something to constantly cover | |
| 83 | the answers while I was studying. | |
| 84 | ||
| 85 | I didn't use the online database version of the QAE, but I've heard that it's | |
| 86 | easier to use than the printed book. However, it is more expensive ($299 | |
| 87 | database vs $129 book) which might be important if you're paying for materials | |
| 88 | yourself. | |
| 89 | ||
| 90 | In terms of question difficulty, I felt that the QAE was a good representation | |
| 91 | of the actual exam. I've seen a lot of people online say it wasn't accurate to | |
| 92 | the exam or that it was much easier/harder, but I disagree with all of those. | |
| 93 | The exam was fairly similar to the QAE, just focusing on whichever topics they | |
| 94 | chose for my version of the exam. | |
| 95 | ||
| 96 | If you understand the concepts, skim the CRM (and read in-depth on topics you | |
| 97 | struggle with), and use the QAE to continue practicing exam-like questions, you | |
| 98 | should be fine. I didn't use any online courses, videos, etc. - the ISACA | |
| 99 | materials are more than enough. | |
| 108 | 100 | |
| 109 | 101 | ** Studying Process |
| 110 | 102 | |
| 111 | While I was able to briefly read through sections 1 and 2 in early 2021, | |
| 112 | I had to stop and take a break from February/March to September. I | |
| 113 | switched jobs in September, which allowed me a lot more free time to | |
| 114 | study. | |
| 103 | While I was able to briefly read through sections 1 and 2 in early 2021, I had | |
| 104 | to stop and take a break from February/March to September. I switched jobs in | |
| 105 | September, which allowed me a lot more free time to study. | |
| 115 | 106 | |
| 116 | In September, I studied sections 3-5, took notes, and did a quick review | |
| 117 | of the section topics. Once I felt comfortable with my notes, I took a | |
| 118 | practice exam from the QAE manual and scored 70% (105/150). | |
| 107 | In September, I studied sections 3-5, took notes, and did a quick review of the | |
| 108 | section topics. Once I felt comfortable with my notes, I took a practice exam | |
| 109 | from the QAE manual and scored 70% (105/150). | |
| 119 | 110 | |
| 120 | 111 | Here's a breakdown of my initial practice exam: |
| 121 | 112 | |
| 122 | | Exam Section | Incorrect | Correct | Grand Total | Percent | | |
| 113 | | Exam Section | Incorrect | Correct | Grand Total | Percent | | |
| 123 | 114 | |---------------+-----------+---------+-------------+---------| |
| 124 | | 1 | 8 | 25 | 33 | 76% | | |
| 125 | | 2 | 5 | 20 | 25 | 80% | | |
| 126 | | 3 | 6 | 12 | 18 | 67% | | |
| 127 | | 4 | 10 | 23 | 33 | 70% | | |
| 128 | | 5 | 16 | 25 | 41 | 61% | | |
| 129 | | *Grand Total* | *45* | *105* | *150* | *70%* | | |
| 115 | | 1 | 8 | 25 | 33 | 76% | | |
| 116 | | 2 | 5 | 20 | 25 | 80% | | |
| 117 | | 3 | 6 | 12 | 18 | 67% | | |
| 118 | | 4 | 10 | 23 | 33 | 70% | | |
| 119 | | 5 | 16 | 25 | 41 | 61% | | |
| 120 | | *Grand Total* | *45* | *105* | *150* | *70%* | | |
| 130 | 121 | |
| 131 | 122 | As I expected, my toughest sections were related to project management, |
| 132 | 123 | development, implementation, and security. |
| 133 | 124 | |
| 134 | This just leaves October and November. For these months, I tried to | |
| 135 | practice every few days, doing 10 questions for each section, until the | |
| 136 | exam. This came out to 13 practice sessions, ~140 questions per section, | |
| 137 | and ~700 questions total. | |
| 125 | This just leaves October and November. For these months, I tried to practice | |
| 126 | every few days, doing 10 questions for each section, until the exam. This came | |
| 127 | out to 13 practice sessions, ~140 questions per section, and ~700 questions | |
| 128 | total. | |
| 138 | 129 | |
| 139 | While some practice sessions were worse and some were better, the final | |
| 140 | results were similar to my practice exam results. As you can see below, | |
| 141 | my averages were slightly worse than my practice exam. However, I got in | |
| 142 | over 700 questions of practice and, most importantly, /I read through | |
| 143 | the explanations every time I answered incorrectly and learned from my | |
| 144 | mistakes/. | |
| 130 | While some practice sessions were worse and some were better, the final results | |
| 131 | were similar to my practice exam results. As you can see below, my averages were | |
| 132 | slightly worse than my practice exam. However, I got in over 700 questions of | |
| 133 | practice and, most importantly, /I read through the explanations every time I | |
| 134 | answered incorrectly and learned from my mistakes/. | |
| 145 | 135 | |
| 146 | | Exam Section | Incorrect | Correct | Grand Total | Percent | | |
| 136 | | Exam Section | Incorrect | Correct | Grand Total | Percent | | |
| 147 | 137 | |---------------+-----------+---------+-------------+---------| |
| 148 | | 1 | 33 | 108 | 141 | 77% | | |
| 149 | | 2 | 33 | 109 | 142 | 77% | | |
| 150 | | 3 | 55 | 89 | 144 | 62% | | |
| 151 | | 4 | 52 | 88 | 140 | 63% | | |
| 152 | | 5 | 55 | 85 | 140 | 61% | | |
| 153 | | *Grand Total* | *228* | *479* | *707* | *68%* | | |
| 138 | | 1 | 33 | 108 | 141 | 77% | | |
| 139 | | 2 | 33 | 109 | 142 | 77% | | |
| 140 | | 3 | 55 | 89 | 144 | 62% | | |
| 141 | | 4 | 52 | 88 | 140 | 63% | | |
| 142 | | 5 | 55 | 85 | 140 | 61% | | |
| 143 | | *Grand Total* | *228* | *479* | *707* | *68%* | | |
| 154 | 144 | |
| 155 | 145 | * Results |
| 156 | 146 | |
| 157 | Now, how do the practice scores reflect my actual results? After all, | |
| 158 | it's hard to tell how good a practice regimen is unless you see how it | |
| 159 | turns out. | |
| 147 | Now, how do the practice scores reflect my actual results? After all, it's hard | |
| 148 | to tell how good a practice regimen is unless you see how it turns out. | |
| 160 | 149 | |
| 161 | 150 | | Exam Section | Section Name | Score | |
| 162 | 151 | |--------------+------------------------------------------------------------------+-------| |
| 163 | | 1 | Information Systems Auditing Process | 678 | | |
| 164 | | 2 | Governance and Management of IT | 590 | | |
| 165 | | 3 | Information Systems Acquisition, Development, and Implementation | 721 | | |
| 166 | | 4 | Information Systems Operations and Business Resilience | 643 | | |
| 167 | | 5 | Protection of Information Assets | 511 | | |
| 168 | ||
| 169 | Now, in order to pass the CISA, you need at least 450 on a sliding scale | |
| 170 | of 200-800. Personally, I really have no clue what an average CISA score | |
| 171 | is. After a /very/ brief look online, I can see that the high end is | |
| 172 | usually in the low 700s. In addition, only about 50-60% of people pass | |
| 173 | the exam. | |
| 174 | ||
| 175 | Given this information, I feel great about my scores. 616 may not be | |
| 176 | phenomenal, and I wish I had done better on sections 2 & 5, but my | |
| 177 | practicing seems to have worked very well overall. | |
| 178 | ||
| 179 | However, the practice results do not conform to the actual results. | |
| 180 | Section 2 was one of my highest practice sections and was my | |
| 181 | second-lowest score in the exam. Conversely, section 3 was my | |
| 182 | second-lowest practice section and turned out to be my highest actual | |
| 183 | score! | |
| 184 | ||
| 185 | After reflecting, it is obvious that if you have any background on the | |
| 186 | CISA topics at all, the most important part of studying is doing | |
| 187 | practice questions. You really need to understand how to read the | |
| 188 | questions critically and pick the best answer. | |
| 152 | | 1 | Information Systems Auditing Process | 678 | | |
| 153 | | 2 | Governance and Management of IT | 590 | | |
| 154 | | 3 | Information Systems Acquisition, Development, and Implementation | 721 | | |
| 155 | | 4 | Information Systems Operations and Business Resilience | 643 | | |
| 156 | | 5 | Protection of Information Assets | 511 | | |
| 157 | ||
| 158 | Now, in order to pass the CISA, you need at least 450 on a sliding scale of | |
| 159 | 200-800. Personally, I really have no clue what an average CISA score is. After | |
| 160 | a /very/ brief look online, I can see that the high end is usually in the low | |
| 161 | 700s. In addition, only about 50-60% of people pass the exam. | |
| 162 | ||
| 163 | Given this information, I feel great about my scores. 616 may not be phenomenal, | |
| 164 | and I wish I had done better on sections 2 & 5, but my practicing seems to have | |
| 165 | worked very well overall. | |
| 166 | ||
| 167 | However, the practice results do not conform to the actual results. Section 2 | |
| 168 | was one of my highest practice sections and was my second-lowest score in the | |
| 169 | exam. Conversely, section 3 was my second-lowest practice section and turned out | |
| 170 | to be my highest actual score! | |
| 171 | ||
| 172 | After reflecting, it is obvious that if you have any background on the CISA | |
| 173 | topics at all, the most important part of studying is doing practice questions. | |
| 174 | You really need to understand how to read the questions critically and pick the | |
| 175 | best answer. | |
| 189 | 176 | |
| 190 | 177 | * Looking Forward |
| 191 | 178 | |
| 192 | I am extremely happy that I was finally able to pass the CISA. Looking | |
| 193 | to the future, I'm not sure what's next in terms of professional | |
| 194 | learning. My current company offers internal learning courses, so I will | |
| 195 | most likely focus on that if I need to gain more knowledge in certain | |
| 196 | areas. | |
| 197 | ||
| 198 | To be fair, even if you pass the CISA, it's hard to become an expert on | |
| 199 | any specific topic found within. My career may take me in a different | |
| 200 | direction, and I might need to focus more on security or networking | |
| 201 | certifications (or possibly building a better analysis/visualization | |
| 202 | portfolio if I want to go into data analysis/science). | |
| 179 | I am extremely happy that I was finally able to pass the CISA. Looking to the | |
| 180 | future, I'm not sure what's next in terms of professional learning. My current | |
| 181 | company offers internal learning courses, so I will most likely focus on that if | |
| 182 | I need to gain more knowledge in certain areas. | |
| 183 | ||
| 184 | To be fair, even if you pass the CISA, it's hard to become an expert on any | |
| 185 | specific topic found within. My career may take me in a different direction, and | |
| 186 | I might need to focus more on security or networking certifications (or possibly | |
| 187 | building a better analysis/visualization portfolio if I want to go into data | |
| 188 | analysis/science). | |
| 203 | 189 | |
| 204 | 190 | All I know is that I am content at the moment and extremely proud of my |
| 205 | 191 | accomplishment. |