earnest ma 1 year ago
parent 32ea0194ba
commit 9de2e8b6aa
Signed by: earnest ma
GPG Key ID: A343F43342EB6E2A
  1. 12
  2. 1
  3. 6
  4. 6
  5. 27
  6. 43
  7. 0
  8. 6
  9. 33
  10. 27
  11. 511
  12. 60
  13. 33
  14. 19
  15. 3
  16. 69
  17. 25
  18. 60
  19. 12
  20. 261
  21. 26
  22. 69
  23. 83
  24. 12
  25. 20
  26. 5
  27. 8
  28. 30
  29. 3
  30. 53
  31. 5
  32. 32
  33. 22
  34. 35
  35. 6
  36. 31
  37. 3
  38. 3
  39. 5
  40. 17
  41. 11
  42. 10
  43. 13
  44. 6
  45. 9
  46. 14
  47. 27
  48. 7
  49. 3
  50. 1
  51. 1
  52. 1
  53. 13
  54. BIN

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

@ -0,0 +1 @@
export PATH=node_modules/.bin:$PATH

.gitignore vendored

@ -0,0 +1,6 @@

@ -0,0 +1,6 @@
"[markdown]": {
"editor.wordWrap": "wordWrapColumn",
"editor.wordWrapColumn": 80

.vscode/tasks.json vendored

@ -0,0 +1,27 @@
"version": "2.0.0",
"tasks": [
"label": "Run watch",
"type": "shell",
"command": "hugo server",
"group": {
"kind": "build",
"isDefault": true
"problemMatcher": []
"label": "Make",
"type": "shell",
"command": "make",
"problemMatcher": []
"label": "Make lint",
"type": "shell",
"command": "make lint",
"problemMatcher": []

@ -0,0 +1,43 @@
earnest's public license (EMPL), v1.0.0
Copyright (c) 2020-2022 earnest ma <me@earne.link>
This license gives everyone as much permission to work with this software as
possible, while protecting contributors from liability.
In order to receive this license, you must agree to its rules. The rules of this
license are both obligations under that agreement and conditions to your
license. You must not do anything with this software that triggers a rule that
you cannot or will not follow.
Each contributor licenses you to do everything with this software that would
otherwise infringe that contributor's copyright in it.
- You may not use the software to accrue revenue without explicit permission
from the primary contributors.
- This software must be used for Good, not Evil, as determined by the primary
contributors to the software.
- No Law Enforcement, Military, Carceral Institutions, or Immigration
enforcement entities or individuals working in those areas may use the work or
products of the work, for any reason.
- You must ensure that everyone who gets a copy of any part of this software
from you, with or without changes, also gets the text of this license or a
link to <https://earnestma.com/projects/empl>.
If anyone notifies you in writing that you have not complied with Notices, you
can keep your license by taking all practical steps to comply within 30 days
after the notice. If you do not do so, your license ends immediately.
Each contributor licenses you to do everything with this software that would
otherwise infringe any patent claims they can license or become able to license.
No contributor can revoke this license.
**As far as the law allows, this software comes as is, without any warranty or
condition, and no contributor will be liable to anyone for any damages related
to this software or this license, under any kind of legal claim.**

@ -0,0 +1,6 @@
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true

@ -0,0 +1,33 @@
blockquote {
position: relative;
padding-left: 17px;
padding-left: 2ch;
overflow: hidden;
blockquote:after {
content: ">\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>";
white-space: pre;
position: absolute;
top: 0;
left: 0;
line-height: 20px;
h1:before {
content: "> ";
h2:before {
content: "## ";
h3:before {
content: "### ";
h4:before {
content: "#### ";
h5:before {
content: "##### ";
h6:before {
content: "###### ";

@ -0,0 +1,27 @@
// https://hugocodex.org/add-ons/new-window-fix
//open external links in a new window
function external_new_window() {
for (var c = document.getElementsByTagName("a"), a = 0; a < c.length; a++) {
var b = c[a];
if (b.getAttribute("href") && b.hostname !== location.hostname) {
b.target = "_blank";
b.rel = "noopener";
//open PDF links in a new window
function pdf_new_window() {
if (!document.getElementsByTagName) return false;
var links = document.getElementsByTagName("a");
for (var eleLink = 0; eleLink < links.length; eleLink++) {
if ((links[eleLink].href.indexOf('.pdf') !== -1) || (links[eleLink].href.indexOf('.doc') !== -1) || (links[eleLink].href.indexOf('.docx') !== -1)) {
links[eleLink].onclick =
function () {
return false;

@ -0,0 +1,511 @@
/* Set the global variables for everything. Change these to use your own fonts and colours. */
:root {
/* Set sans-serif & mono fonts */
/* Use monospace as determined by browser */
--sans-font: monospace;
--mono-font: monospace;
/* Body font size. By default, effectively 18.4px, based on 16px as 'root em' */
--base-fontsize: 1.20rem; /* changed */
/* Major third scale progression - see https://type-scale.com/ */
--header-scale: 1.25;
/* Line height is set to the "Golden ratio" for optimal legibility */
--line-height: 1.618;
/* Default (light) theme */
--bg: #fff;
--accent-bg: #f5f7ff;
--text: #212121;
--text-light: #585858;
--border: #d8dae1;
--accent: #0d47a1;
--accent-light: #90caf9;
--code: #d81b60;
--preformatted: #444;
--marked: #ffdd33;
--disabled: #efefef;
/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: #282828;
--accent-bg: #1d2021;
--text: #ebdbb2;
--text-light: #a89984;
--border: #665c54;
--accent: #d79921;
--accent-light: #fabd2f;
--code: #b16286;
--preformatted: #8ec07c;
--disabled: #1d2021;
video {
opacity: 0.6;
html {
/* Set the font globally */
font-family: var(--sans-font);
/* Make the body a nice central block */
body {
color: var(--text);
background: var(--bg);
font-size: var(--base-fontsize);
line-height: var(--line-height);
display: flex;
min-height: 100vh;
flex-direction: column;
flex: 1;
margin: 0 auto;
max-width: 55rem; /* increased width */
padding: 0 0.5rem;
overflow-x: hidden;
word-break: break-word;
overflow-wrap: break-word;
/* Make the header bg full width, but the content inline with body */
header {
background: var(--accent-bg);
border-bottom: 1px solid var(--border);
text-align: center;
padding: 2rem 0.5rem;
width: 100vw;
position: relative;
box-sizing: border-box;
left: 50%;
right: 50%;
margin-left: -50vw;
margin-right: -50vw;
/* Remove margins for header text */
header h1,
header p {
margin: 0;
/* Add a little padding to ensure spacing is correct between content and nav */
main {
padding-top: 1.5rem;
/* Fix line height when title wraps */
h3 {
line-height: 1.1;
/* Format navigation */
nav {
font-size: 1rem;
line-height: 2;
padding: 1rem 0;
nav a {
margin: 1rem 1rem 0 0;
border: 1px solid var(--border);
border-radius: 5px;
color: var(--text) !important;
display: inline-block;
padding: 0.1rem 1rem;
text-decoration: none;
transition: 0.4s;
nav a:hover {
color: var(--accent) !important;
border-color: var(--accent);
nav a.current:hover {
text-decoration: none;
footer {
margin-top: 4rem;
padding: 2rem 1rem 1.5rem 1rem;
color: var(--text-light);
font-size: 0.9rem;
text-align: center;
border-top: 1px solid var(--border);
/* Format headers */
h1 {
font-size: calc(
var(--base-fontsize) * var(--header-scale) * var(--header-scale) *
var(--header-scale) * var(--header-scale)
margin-top: calc(var(--line-height) * 1.5rem);
h2 {
font-size: calc(
var(--base-fontsize) * var(--header-scale) * var(--header-scale) *
margin-top: calc(var(--line-height) * 1.5rem);
h3 {
font-size: calc(
var(--base-fontsize) * var(--header-scale) * var(--header-scale)
margin-top: calc(var(--line-height) * 1.5rem);
h4 {
font-size: calc(var(--base-fontsize) * var(--header-scale));
margin-top: calc(var(--line-height) * 1.5rem);
h5 {
font-size: var(--base-fontsize);
margin-top: calc(var(--line-height) * 1.5rem);
h6 {
font-size: calc(var(--base-fontsize) / var(--header-scale));
margin-top: calc(var(--line-height) * 1.5rem);
/* Format links & buttons */
a:visited {
color: var(--accent);
a:hover {
text-decoration: none;
a button,
input[type="button"] {
font-family: var(--sans-font); /* added */
border: none;
border-radius: 5px;
background: var(--accent);
font-size: 1rem;
color: var(--bg);
padding: 0.7rem 0.9rem;
margin: 0.5rem 0;
transition: 0.4s;
a button[disabled],
select[disabled] {
cursor: default;
opacity: 0.5;
cursor: not-allowed;
select:disabled {
cursor: not-allowed;
background-color: var(--disabled);
input[type="range"] {
padding: 0;
/* Set the cursor to '?' while hovering over an abbreviation */
abbr {
cursor: help;
input[type="radio"]:enabled:hover {
opacity: 0.8;
cursor: pointer;
/* Format the expanding box */
details {
background: var(--accent-bg);
border: 1px solid var(--border);
border-radius: 5px;
margin-bottom: 1rem;
summary {
cursor: pointer;
font-weight: bold;
padding: 0.6rem 1rem;
details[open] {
padding: 0.6rem 1rem 0.75rem 1rem;
details[open] summary {
margin-bottom: 0.5rem;
padding: 0;
details[open] > *:last-child {
margin-bottom: 0;
/* Format tables */
table {
border-collapse: collapse;
width: 100%;
margin: 1.5rem 0;
th {
border: 1px solid var(--border);
text-align: left;
padding: 0.5rem;
th {
background: var(--accent-bg);
font-weight: bold;
tr:nth-child(even) {
/* Set every other cell slightly darker. Improves readability. */
background: var(--accent-bg);
table caption {
font-weight: bold;
margin-bottom: 0.5rem;
/* Lists */
ul {
padding-left: 3rem;
/* Format forms */
input {
font-size: inherit;
font-family: inherit;
padding: 0.5rem;
margin-bottom: 0.5rem;
color: var(--text);
background: var(--bg);
border: 1px solid var(--border);
border-radius: 5px;
box-shadow: none;
box-sizing: border-box;
width: 60%;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
/* Add arrow to */
select {
background-image: linear-gradient(45deg, transparent 49%, var(--text) 51%),
linear-gradient(135deg, var(--text) 51%, transparent 49%);
background-position: calc(100% - 20px), calc(100% - 15px);
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
select[multiple] {
background-image: none !important;
/* checkbox and radio button style */
input[type="radio"] {
vertical-align: bottom;
position: relative;
input[type="radio"] {
border-radius: 100%;
input[type="radio"]:checked {
background: var(--accent);
input[type="checkbox"]:checked::after {
/* Creates a rectangle with colored right and bottom borders which is rotated to look like a check mark */
content: " ";
width: 0.1em;
height: 0.25em;
border-radius: 0;
position: absolute;
top: 0.05em;
left: 0.18em;
background: transparent;
border-right: solid var(--bg) 0.08em;
border-bottom: solid var(--bg) 0.08em;
font-size: 1.8em;
transform: rotate(45deg);
input[type="radio"]:checked::after {
/* creates a colored circle for the checked radio button */
content: " ";
width: 0.25em;
height: 0.25em;
border-radius: 100%;
position: absolute;
top: 0.125em;
background: var(--bg);
left: 0.125em;
font-size: 32px;
/* Make the textarea wider than other inputs */
textarea {
width: 80%;
/* Makes input fields wider on smaller screens */
@media only screen and (max-width: 720px) {
input {
width: 100%;
/* Ensures the checkbox and radio inputs do not have a set width like other input fields */
input[type="radio"] {
width: auto;
/* do not show border around file selector button */
input[type="file"] {
border: 0;
/* Without this any HTML using <fieldset> shows ugly borders and has additional padding/margin. (Issue #3) */
fieldset {
border: 0;
padding: 0;
margin: 0;
/* Misc body elements */
hr {
color: var(--border);
border-top: 1px;
margin: 1rem auto;
mark {
padding: 2px 5px;
border-radius: 4px;
background: var(--marked);
main img,
main video {
max-width: 100%;
height: auto;
border-radius: 5px;
figure {
margin: 0;
figcaption {
font-size: 0.9rem;
color: var(--text-light);
text-align: center;
margin-bottom: 1rem;
blockquote {
margin: 2rem 0 2rem 2rem;
padding: 0.4rem 0.8rem;
/*border-left: 0.35rem solid var(--accent);*/
opacity: 0.8;
font-style: italic;
cite {
font-size: 0.9rem;
color: var(--text-light);
font-style: normal;
/* Use mono font for code like elements */
pre span,
samp {
font-size: 1.075rem;
font-family: var(--mono-font);
color: var(--code);
kbd {
color: var(--preformatted);
border: 1px solid var(--preformatted);
border-bottom: 3px solid var(--preformatted);
border-radius: 5px;
padding: 0.1rem;
pre {
padding: 1rem 1.4rem;
max-width: 100%;
overflow: auto;
overflow-x: auto;
color: var(--preformatted);
background: var(--accent-bg);
border: 1px solid var(--border);
border-radius: 5px;
/* Fix embedded code within pre */
pre code {
color: var(--preformatted);
background: none;
margin: 0;
padding: 0;

@ -0,0 +1,60 @@
baseURL = "https://staging.earnestma.com/"
languageCode = "en-ca"
title = "earnest ma"
enableGitInfo = true
copyrightYear = "2020-2021"
author = "earnest ma"
description = "earnest ma (earne)'s personal website and blog"
favicon = "/favicon.ico"
gitRepoURL = "https://git.earne.link/earnestma/site"
blog = "/:year/:month/:day/:slug"
books = "/books/:year/:month/:day/:slug"
identifier = "blog"
name = "Blog"
url = "/blog"
weight = 100
identifier = "about"
name = "About"
url = "/about"
weight = 200
identifier = "contact"
name = "Contact"
url = "/contact"
weight = 300
identifier = "feeds"
name = "Feeds"
url = "/feeds"
weight = 400
identifier = "top"
name = "Back to top"
url = "#"
weight = 100
identifier = "home"
name = "Home"
url = "/"
weight = 200
identifier = "feeds"
name = "Feeds"
url = "/feeds"
weight = 300
identifier = "sub-blogs"
name = "Sub-blogs"
url = "/#latest-posts"
weight = 300
unsafe = true

@ -0,0 +1,33 @@
title = "earnest's personal website"
# type = "page"
### Links
- Pleroma (main/public fediverse account): [@earnestma@pleroma.envs.net](https://pleroma.envs.net/earnestma)
- Mastodon (personal account): [@earne@mstdn.social](https://mstdn.social/@earne)
- Forges: [Personal Gitea server](https://git.earne.link/earnestma), [Sourcehut](https://sr.ht/~earnestma) *(in order of usage)*
- [GitHub](https://github.com/earnestma), [Codeberg](https://codeberg.org/earnestma), [GitLab](https://gitlab.com/earnestma)
- BookWyrm: [@earnestma@bookwyrm.social](https://bookwyrm.social/user/earnestma) ([Goodreads](https://www.goodreads.com/user/show/103641598-earnest) inactive)
- Instagram [@earnestma](https://www.instagram.com/earnestma/), [Pixelfed](https://pixey.org/earnestma)
- Livestreams ([info](/live)): [Twitch](https://www.twitch.tv/earnestma3)
- [YouTube](https://youtube.com/c/earnestma)
- [Spotify](https://open.spotify.com/user/5027gnyuq5pwub2sl9qltbr3n), [LastFM](https://www.last.fm/user/earnestma)
- [Steam](https://steamcommunity.com/id/earnestma/)
- [Ko-Fi](https://ko-fi.com/earnestma)
- Follow this blog via [RSS feeds](/feeds)!
{{< button "https://earne.org" "Digital garden" >}}
<h3 id="projects"><a href="/projects" style="text-decoration: none;">Projects</a></h3>
{{< partial "featuredprojects.html" >}}
<h3 id="latest-posts"><a href="/blog" style="text-decoration: none;">Latest posts</a></h3>
{{< partial "recentposts.html" >}}
{{< button "/blog" "Main blog" >}}
{{< button "/books" "Books blog" >}}
{{< button "/recipes" "Recipes list" >}}

@ -0,0 +1,19 @@
title = "About"
I'm earnest ma (`/nick earne`), pronouns [they/he](https://en.pronouns.page/@earne), 17.
Currently a Canadian high school student -- graduating this year! Interested in messing with computers and then wondering why things don't work.
I use and sometimes write about Linux + systems administration, FOSS, and productivity.
`shell scripts html css java python`
I run and maintain several services on earne.link, some of which you can register on.
Sometimes I [livestream](/live), and in my free time I enjoy reading and listening to music. You can find a ton of social links on the [homepage](/).
- [Contact me](/contact)
- {{< sponsor >}}
- [My Wikipedia user page](https://en.wikipedia.org/wiki/User:EarneM)

@ -0,0 +1,3 @@
title = "Blog"

@ -0,0 +1,69 @@
# Migrated from earnestma.xyz repo
title: "Mic Push-to-talk With AutoHotkey and SoundVolumeView"
date: 2021-02-10 23:06:31 -0500
#draft: false
#tags: ["autohotkey", "scripting"]
# - html
# - gemtext
# host: tech.lgbt
# user: earnestma
# id: 105710677971553309
categories: ["Windows", "Script"]
url: /2021/02/10-mic-push-to-talk-with-autohotkey-and-soundvolumeview
This is an [AutoHotkey](https://www.autohotkey.com/) script I set up to use with [NirSoft's SoundVolumeView](https://www.nirsoft.net/utils/sound_volume_view.html).
It uses the command-line from that to send mute/ unmute the microphone (through the system) whenever a key is held down. It's not perfect and there is a small delay, so improvements are definitely welcome. Anyways, here it is:
#SingleInstance, force
SendMode Input
ToolTip, Starting now...
RunWait, PowerShell "SoundVolumeView.exe /Mute 'Realtek(R) Audio\Device\Microphone\Capture'",, hide
SoundBeep, 200, 1000
launched := false
ToolTip, You should be muted
Sleep, 1000
if(not launched) {
RunWait, PowerShell "SoundVolumeView.exe /Unmute 'Realtek(R) Audio\Device\Microphone\Capture'",, hide
SoundBeep, 442
launched := true
` Up::
RunWait, PowerShell "SoundVolumeView.exe /Mute 'Realtek(R) Audio\Device\Microphone\Capture'",, hide
SoundBeep, 200
launched := false
RunWait, PowerShell "SoundVolumeView.exe /Unmute 'Realtek(R) Audio\Device\Microphone\Capture'",, hide
SoundBeep, 442, 1000
ToolTip, Unmuting and exiting
Sleep, 1000

@ -0,0 +1,25 @@
# Copy-pasted/ migrated from wordpress site
title = "Migrate Email with mbsync"
date = '2021-06-08'
categories = ["Tutorial"]
link = "https://aaronweb.net/blog/2014/11/migrating-mail-between-imap-servers-using-mbsync/"
url = "/2021/06/08-migrate-email-with-mbsync"
Just wanted to boost this blog post as it greatly helped me migrate emails from [Luke Smith’s emailwiz script](https://github.com/lukesmithxyz/emailwiz) to [Modoboa](https://modoboa.org/en/) (more on that in a future post).
> In package managers, mbsync is often installed through isync.
Here are some things mbsync complained about:
`UseIMAPS` is deprecated, I simply left it out and it worked ok.
For accounts with [subfolders](https://benswift.me/blog/2020/07/17/mbsync-v1-3-2-breaking-change/) (Archives, Archives/2020 etc.) I used:
MaildirStore me-local
Path ~/Mail/me
Inbox ~/Mail/me/INBOX
+SubFolders Verbatim

@ -0,0 +1,60 @@
# Migrated from earnestma.xyz repo
title: "My Email Workflow and Programs"
date: 2021-01-13 20:29:49 -0500
draft: false
#tags: ["email", "workflows"]
categories: ["None"]
url: /2021/01/13-my-email-workflow-programs
This has become more important since COVID-19 became a thing and I started working with more accounts. These are some of the tools, programs, and not-workflow that I use.
I self-host my personal email, setting it up with [Luke Smith's emailwiz script](https://github.com/lukesmithxyz/emailwiz) and modifying the config afterwards as needed. It was not difficult to import emails from Gmail/ Hotmail through Thunderbird. I have 2 main accounts that I use, one is listed and the one I usually give out and subscribe to mailing lists on, and a personal one. In the future, I may consider adding a "spam" address for signing up to random services or newsletters.
For newsletters/ random services, I make use of aliases. `+` seems to be common and as such may be detected and removed, so I use `-` instead.
For Postfix in /etc/postfix/main.cf: `recipient_delimiter = +-`
It's even possible to **send** mail from those addresses.
On top of these, I have additional external accounts (school, etc). Signing into webmails used to be ok, but not for checking multiple accounts at once (ex: Hotmail/ Outlook only lets you sign into one account at a time).
Sending [plain-text emails](https://useplaintext.email) has also become more important to me, with webmail sites that's often difficult to do. Same with GPG-signing/ encrypted emails.
The folder structure I use is pretty simple. Everything starts in the inbox, which I try to keep as small as possible. Newsletters are either immediately read, deleted, or placed in a "Later" folder. Regular email/ patches are replied to if needed, then archived or deleted. I keep a new Archives folder per year (Archives/2021). Lastly, I just have a folder for reference emails (reciepts, invoices...)
## Programs I use
### Thunderbird
Thunderbird is just a fantastic email client, and my main one. While it was a bit clunky to set up and get used to at first, it handles my needs and *multiple* email accounts great.
It also can do chat (IRC/ XMPP), Newsgroups (NNTP) and be an RSS reader.
[Instructions for setting up Thunderbird for plain text](https://useplaintext.email/#thunderbird). GPG is a little bit more complicated, since Thunderbird uses its own keychain. Since I use regualar GPG + Kleopatra (at least on Windows), I import my public keys from a Kleopatra export every once in a while, and whenever I update my secret keys.
#### Extensions
Useful extensions I use:
- *cloud - Easily "attach" large files using Nextcloud.
- Display Mail User Agent T
- DKIM Verifier
- ImportExportTools NG - At the end of each year I plan to backup my mail.
### K-9 Mail
The only good mail app for Android! Great for quickly reading and replying to email when on my phone when I can't from my computer. There has been no stable releases on the Play Store but there are regular beta versions that work pretty well that are available on F-Droid.
[Instructions for sending plain text mail](https://useplaintext.email/#k-9). GPG support can be added by installing the OpenKeychain app.
### aerc
https://aerc-mail.org/ - A pretty nice terminal email client. Easy to set up (unlike (neo)mutt), but doesn't build on Windows. Also no GPG support as far as I know yet. I am using it every once in a while and keeping a close eye at its development.
### Rainloop
What a good email webclient should be like! It even has GPG support, I have installed the Nextcloud app version. Useful in case I don't have my usual computer/ phone with me. [Instructions for sending plain text mail](https://useplaintext.email/#rainloop)

@ -0,0 +1,12 @@
# Copy-pasted/ migrated from wordpress site
title = "New domain earnestma.com"
date = '2021-11-28'
url = "/2021/11/28-new-domain-earnestma-com"
categories = ["Meta"]
lastmod = '2021-12-01 03:03'
Hi all! A short note that I am moving this site over to the https://earnestma.com domain (and any subdomains). Please update your feed/ links accordingly.
I will likely keep earnestma.xyz redirecting here until the domain expires in August of 2022.

@ -0,0 +1,261 @@
# Migrated from earnestma.xyz repo
title: "Selfhosting Gitea Installation and OAuth2 Settings for Nextcloud and Github"
description: "Installing and setting up Gitea on a Ubuntu 20.04 VPS. Also, setup OAuth2 authentication to Gitea with Nextcloud and Github."
date: 2020-11-05
# tags: ["gitea", "selfhosting"]
categories: ["Tutorial"]
url: /2020/11/05-selfhosting-gitea-installation-and-oauth2-settings-for-nextcloud-and-github/
**UPDATE**: Moved this from previous blog, updated links, and added Nginx config :)
This post will cover my process installing Gitea onto the Vultr VPS I've been using for the past months. I also moved the entire setup to another VPS with no issues. Both run Ubuntu 20.04 LTS.
I decided to go with Gitea[^1] as it was fairly lightweight and had most of the features I wanted/ needed.
I have most of my repositories on this, with mirrors on Github.
Because I *already* have a site running, I will be *reverse proxying Gitea* (from port 3000) to a *separate* subdomain (https://git.earne.link).
## Prerequisites.
- Nginx (Previously used Apache)
- MariaDB
- Certbot (Let's Encrypt SSL Certificates)
- git, gpg (`sudo apt install git gpg gnupg2`)
sudo apt update
sudo apt install nginx mariadb-server
# or sudo apt install apache2 mariadb-server
# secure your installation
sudo mysql_secure_installation
# SSL with Let's Encrypt
sudo apt install certbot python3-certbot-nginx # or python3-certbot-apache
## Configure DNS Settings
Set an address record from something like `git.example.com` to your server's public IP address.
## Configure the Reverse Proxy
### Using Nginx
In `/etc/nginx/sites-available/gitea.conf`
server {
server_name git.example.com;
location / {
proxy_pass http://localhost:3000;
### Using Apache
<VirtualHost *:80>
ServerName git.example.com
ProxyPreserveHost On
ProxyRequests off
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
For apache, you also need to enable some modules:
sudo a2enmod proxy proxy_http rewrite
sudo systemctl restart apache2.service
### Enable the site
sudo a2ensite gitea
Run `certbot`, let it redirect automatically from `http` to `https`.
## Create a user for gitea
sudo adduser --system --shell /bin/bash --gecos 'git' --group --disabled-password --home /home/git git
sudo mkdir /home/git/gitea
cd /home/git/gitea
## Download Gitea and the systemd service file
Get the latest download links for Gitea here: https://dl.gitea.io/gitea
sudo wget -O /bin/gitea https://dl.gitea.io/gitea/1.12.5/gitea-1.12.5-linux-amd64
sudo chmod +x /bin/gitea
sudo wget -O gitea.service https://github.com/go-gitea/gitea/raw/master/contrib/systemd/gitea.service
## Adjust the systemd service configuration file
Adjust `gitea.service` to your needs:
ExecStart=/bin/gitea web --config /home/git/gitea/custom/conf/app.ini
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/home/git/gitea
## Configure file/ folder directory and permissions
sudo mkdir -p /home/git/gitea/{custom,data,indexers,public,log}
sudo chmod 750 /home/git/gitea/{custom,data,indexers,public,log}
sudo mkdir /home/git/gitea-repositories
sudo chmod 750 /home/git/gitea-repositories
sudo chown git:git /home/git/gitea -R
## Enable Gitea through systemctl
sudo ln -s /home/git/gitea/gitea.service /lib/systemd/system/gitea.service
sudo systemctl daemon-reload
sudo systemctl enable gitea --now && sudo systemctl status gitea
## Gitea w/ Mariadb
sudo mariadb
CREATE USER 'gitea' IDENTIFIED BY 'YourPasswordHere';
Query OK, 0 rows affected (0.016 sec)
MariaDB [(none)]> CREATE DATABASE gitea CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
Query OK, 1 row affected (0.009 sec)
MariaDB [(none)]> GRANT ALL PRIVILEGES ON gitea.* TO 'gitea';
Query OK, 0 rows affected (0.002 sec)
Query OK, 0 rows affected (0.004 sec)
MariaDB [(none)]> exit
## Finish Install!
Head to `git.example.com/install`.
`MYSQL, charset uft8mb4`
Root URL (change to https://git.example.com/), Domain (git.example.com), configure SSH (you may want to disable it entirely), Port # (3000 is fine as we are reverse proxying it).
- Configure sending mail
## Swap File
Didn't have one, I needed a swap file because performance.
# Checks
free -m
sudo dd if=/dev/zero of=/swapfile count=1024 bs=1M # A 1GB Swap File (512 mb ram)
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo nvim /etc/fstab
Add this to the end of the file:
/swapfile none swap sw 0 0
## Editing the app.ini file (more configuration)
sudo su git
cd ~/gitea/custom/conf
nvim app.ini
## That's it!
My Gitea server is now running on https://git.earne.link
# Oauth2 Setup
Make signing into Gitea easier.
## Nextcloud
- Setup from Gitea: https://git.example.com/admin/auths/new
- Setup from Nextcloud: https://nextcloud.example.com/index.php/settings/admin/security -- OAuth 2.0 Clients
- Authentication Type: OAuth2
- Authentication Name: nextcloud
- OAuth2 Provider: Nextcloud
- Use **custom URL** instead of default.
URLs to use:
- https://nc.example.com/index.php/apps/oauth2/authorize (remove /index.php if you prettify URLs)
- https://nc.example.com/index.php/apps/oauth2/api/v1/token (remove /index.php if you prettify URLs)
- https://nc.example.com/ocs/v2.php/cloud/user?format=json
In Nextcloud, the redirection URL is: `https://git.example.com/user/oauth2/nextcloud/callback`
## Github
- Setup from Gitea: https://git.example.com/admin/auths/new
- Setup from Github: https://github.com/settings/applications/new
- Authentication Type: OAuth2
- Authentication Name: github
- OAuth2 Provider: Github
Callback URL: `https://git.example.com/user/oauth2/github/callback`
Thank you for reading!
[^1]: Gitea: https://gitea.io

@ -0,0 +1,26 @@
# Copy-pasted/ migrated from wordpress site
title = "Switching to WordPress"
date = '2021-07-27'
url = "/2021/07/27-switching-to-wordpress"
categories = ["Meta"]
**Update 2022-01:** Moved back to Hugo! <https://git.earne.link/earnestma/site>.
This site now uses WordPress! A few days ago, I migrated all of my blog posts and pages over from Hugo. It’s pretty weird to be going in what seems to be the *opposite* direction (more “bloat”), but I’m quite happy so far with it.
With that said, the RSS feed link is now located at https://earnestma.xyz/feed instead of `/blog/index.xml`. I’ve turned on a redirect, however, so this post shows up, but please update your feed readers if that’s how you read my blog 🙂
I am selfhosting it, and it runs ok on my VPS. Here are the plugins I am using:
- [NewStatPress](https://wordpress.org/plugins/newstatpress/) for some basic analytics/ stats
- [Options for Twenty Twenty-One](https://wordpress.org/plugins/options-for-twenty-twenty-one/), because to me it seems that some of the headings are wayyy to big by default, and I couldn’t find a way to easily change it except with this plugin
- [Public Post Preview](https://wordpress.org/plugins/public-post-preview/)
- [Redirection](https://wordpress.org/plugins/redirection/) to not break previous URLs that don’t exist anymore
- [Syntax-highlighting Code Block (with Server-side Rendering)](https://wordpress.org/plugins/syntax-highlighting-code-block/)
- [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/)
I was warned in multiple posts not to install too many plugins because of possible security and performance issues, so that is pretty much it.
I am using the default Twenty Twenty-One theme in my child theme, which has a git repository here: https://git.sr.ht/~earnestma/wordpress-custom. Currently it only adds a disclaimer at the top for old posts, removes the “powered by WordPress text” in the footer, and has a shortcode to list child pages.

@ -0,0 +1,69 @@
# Migrated from earnestma.xyz repo
title = "Uses, 2021 Edition"
date = '2021-12-06'
categories = ["Uses"]
url = "/2021/12/06-uses-2021-edition"
As 2021 wraps up, I thought I’d do an update on the various things I’ve been using. This year has been more heavy as I continue online learning and programming more. Oh, I also moved off Windows and did a tiny amount of distro-hopping during the summer! (Happy to interact with Windows only in a VM, pretty much for audio editing only)
I also selfhost or use hosted services for a few things, but I’ll list all of those [on my notes site instead](https://earne.org)
## Hardware
- Asus 15 F512D (AMD, 12GB RAM, 256GB SSD) with Fedora 34 Workstation and a random Logitech mouse
- This machine went through Windows, then Ubuntu, NixOS, Pop!_OS, then 2 installs of Fedora lol
- 2 spare laptops that don’t work very well
- LG Monitor
- iPad Air 4th generation (Space grey, 64GB) + Apple Pencil 2
- iPhone 11 (Purple, 128GB)
- Samsung Galaxy Active Smartwatch
- Works ok with iOS, I had an Android before, and if it weren’t for the price, I’d consider an Apple Watch next
- AudioTechnica AT-2005 microphone (mainly for podcast recording)
- 2018 Kindle (the battery is starting to go, so next year I may get the 2021 Paperwhite)
- MINISO bluetooth speaker that works fine, but don’t use that often
- Sony earphones
## Software
- Firefox, for web browsing
- Considering moving to Vivaldi
- Chrome for work
- [VSCodium](https://vscodium.com/) for most of my coding, sometimes Neovim
- GNOME Terminal with zsh (you can find my [dotfiles here](https://git.earne.link/earnestma/dotfiles))
- Email: [Thunderbird](https://www.thunderbird.net/en-US/)
- Music: [Spotify](https://www.spotify.com/)
- I used to use Navidrome and might take a look at it again/ other solutions in the future
- Chat: Discord, [Element](https://element.io/)
- Conferencing: Zoom
- Budgeting: [Buckets](https://www.budgetwithbuckets.com/)
- Office: Google {Docs, Sheets, Slides}, although I did set up a private [Cryptpad](https://cryptpad.fr/) (Nextcloud + ONLYOffice is a headache)
- File syncing: [Nextcloud](https://nextcloud.com/)*
- Livestreaming: OBS Studio
Again, a more complete list is [here](https://earne.org) if you’re interested.
## Mobile apps of note
- iPad apps
- Note-taking: Goodnotes
- Scores: Piascore
- Reddit client: Apollo
- Fediverse clients: Fedi, Metatext
- Livestreaming: Twitch or Streamlabs
- Podcast: Pocket Casts
## Final Thoughts
I do need to:
- Upgrade to Fedora 35
- The only thing I’m aware of is some GNOME extensions I use not supporting GNOME 41 yet
- Migrate two of my families laptops off Ubuntu 21.04
- I don’t feel comfortable with giving them 21.10 and the snaps situation
- Currently, I’m thinking of Fedora Workstation
- If someone has suggestions, please let me know 🙂
- Configure Restic? for backups, probably during Winter break
- Possibly find something better than Nextcloud for main cloud storage. I occasionally use Google Drive, but there’s no client for Linux; but I feel uncomfortable with both (Nextcloud is sometimes quite unreliable, and, well, Google…)
- Again, suggestions for anything are welcome!

@ -0,0 +1,83 @@
# Migrated from earnestma.xyz repo
title: "Using (Multiple) Emacs Daemons (Windows)"
date: 2020-12-30 22:46:02 -0500
draft: false
#tags: ["emacs"]
# host: tech.lgbt
# user: earnestma
# id: 105472762031053428
categories: ["Tutorial"]
url: /2020/12/30-using-multiple-emacs-daemons-windows
GNU Emacs' performance on Windows at times feels a bit sluggish/ slow. *It still randomly crashes sometimes when I use the menu bar but I haven't figured out why.* Of course, the daemon/ `server-mode` can be used, however, you can also run multiple daemon(s?)!
## Benefits
- Separation (if you have a clear separation between types of buffers/ things you have open)
- Emacs processes/ packages that frequently block input/ do not respond.
- *(on windows, if one daemon crashes I -could- quickly switch to another one lol)*
## SystemD
On my GNU/Linux laptop, this was easy: just create a user systemd file.
Make sure it starts after boot instead of after login: `sudo loginctl enable-linger $(whoami)`
In `~/.config/systemd/user/emacs@.service`:
Description=Emacs daemon
ExecStart=emacs --daemon=%i --chdir %h
ExecStop=emacsclient --server-file=hud --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))"
Starting and enabling daemon named `personal` and `work`: `systemctl enable --now emacs@personal.service --user` and `systemctl enable --now emacs@work.service --user`.
## Windows
On **Windows**, I struggled to find a way to launch the daemons on login - Task Scheduler didn't seem to work.
My solution was creating `start-emacs-daemons.bat` in `C:\Users\earne\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`:
runemacs --daemon=personal --chdir=%HOME%
runemacs --daemon=work --chdir=%HOME%
Make sure `runemacs.exe` (and all the other executables) are in your PATH, and set `%HOME%` to `C:\Users\YourUsername`. Then just click the file to start the daemons for the first time, although after this they should automatically launch on login.
## Aliases
I placed these in my `~/.bashrc` (I use Git Bash on windows and just regular bash on GNU/Linux, so this works fine)
## personal Emacs Daemon
alias pe="emacsclient --server-file=personal"
alias pew="emacsclient --server-file=personal --create-frame --no-wait"
alias pk="emacsclient --server-file=personal -e '(kill-emacs)'"
## work Emacs Daemon
alias we="emacsclient --server-file=work"
alias wew="emacsclient --server-file=work --create-frame --no-wait"
alias wk="emacsclient --server-file=work -e '(kill-emacs)'"
## More Reading
- https://tychoish.com/post/running-emacs/
- https://www.emacswiki.org/emacs/EmacsMsWindowsIntegration
Here are links to my [dotfiles](https://git.earne.link/earnestma/dotfiles) and ~~Emacs configuration~~.

@ -0,0 +1,12 @@
title = "Books"
#layout = "single"
I track books read on BookWyrm, however, to get better with writing I'm going to try and write *at least* a monthly summary post/review at the end of each month :)
<h3 id="books"><a href="https://bookwyrm.social/user/earnestma" style="text-decoration: none;">Here is my latest BookWyrm Activity</a></h3>
{{< partial "bsfeed.html" >}}
### Posts

@ -0,0 +1,20 @@
title = "Contact"
### Email
Emails are welcome! The address is `me` AT `earne` DOT `link`. I will do my best to get back to you within 2 days.
If you must use GPG, you can retrieve my key below or from the [OpenPGP Keyserver](https://keys.openpgp.org/search?q=80AE+985F+9B4E+3FB4+38E1+9299+6B36+1FA8+1C5F+B695). Please make sure I have a way of getting your public key!
- [GPG earnest-ma_0x42EB6E2A_public](/earnest-ma_0x42EB6E2A_public.asc)
- [Previous key](https://keys.openpgp.org/vks/v1/by-fingerprint/80AE985F9B4E3FB438E192996B361FA81C5FB695) (**don't use**)
You can pay me through e-Transfer (same email) or [PayPal](https://paypal.me/earnestma). {{< sponsor >}}
### Chat
- Matrix (preferred): [@earne:envs.net](https://matrix.to/#/@earne:envs.net)
- IRC: My nick is usually `earne` on libera.chat and tilde.chat
- I also have Discord/Signal

@ -0,0 +1,5 @@
type = "redirect"
slug = "discord"
redirect = "https://discord.gg/529hx4JJxW"

@ -0,0 +1,8 @@
title = "Feeds"
- This blog: [RSS](/blog/index.xml)
- Recipes: [RSS](/recipes/index.xml)
- Books: [RSS](/books/index.xml)
- *To follow a specific topic (tag/category/etc.), append `index.xml`*

@ -0,0 +1,30 @@
title = "Live"
I stream (usually to live record) at odd intervals for pretty random things. I currently use [Twitch](https://twitch.tv/EarnestMa3) for that, as it’s easier to stream on mobile (I think). The quality may not be so good, but please say hi if you follow/ watch!
<div id="twitch-embed"></div>
<script src="https://embed.twitch.tv/embed/v1.js"></script>
<!-- Create a Twitch.Embed object that will render within the "twitch-embed" element -->
<script type="text/javascript">
new Twitch.Embed("twitch-embed", {
width: 1000,
height: 500,
channel: "earnestma3",
## Archives
**EDIT: In the middle of moving channels. Links are outdated and should be updated soon.**