Compare commits
125 Commits
118ec6727c
...
renovate/s
Author | SHA1 | Date | |
---|---|---|---|
|
baf2bce206 | ||
|
223b7a9113 | ||
|
c200552255 | ||
|
8a27d7284f | ||
|
9be886267d | ||
|
8f1892115f | ||
|
d4971f0138 | ||
|
00875c94e4 | ||
|
43e110ee5b | ||
|
dff6b8921a | ||
|
8c3d1bdd5b | ||
|
1536ce8ed1 | ||
|
af833d173c | ||
|
3272b67283 | ||
|
4275a6adc4 | ||
|
1ff146f4aa | ||
|
54eb3fc904 | ||
|
842a7ef80a | ||
|
a2d6ebac07 | ||
|
c2fe588fe8 | ||
|
3bf6014537 | ||
|
8d898eb69a | ||
|
2475d2d67e | ||
|
9367f85f5f | ||
|
d839024d95 | ||
|
f9ee17986d | ||
|
953cf64989 | ||
|
c59415d6b3 | ||
|
f8d313309a | ||
|
190e0b2835 | ||
|
8b4902e3e2 | ||
|
824f145e2c | ||
|
7ea7031521 | ||
|
391d164ae9 | ||
|
1aeb6d20b6 | ||
|
0ee904d34f | ||
|
a24bf002ab | ||
|
9da895cd8a | ||
|
dc75012739 | ||
|
adf37e736e | ||
|
f76666c70d | ||
|
a49699a5d6 | ||
|
5d87003de0 | ||
|
37a27723f9 | ||
|
7202c2c37e | ||
|
ac454d75dc | ||
|
2902f5735b | ||
|
54de6a38c8 | ||
|
e89222a64e | ||
|
caac52cc74 | ||
|
f7af260779 | ||
|
eb1136bf90 | ||
|
379e9ce5ff | ||
|
ba0f6170af | ||
|
5880c0d9da | ||
|
8f0cec9739 | ||
|
a56eeeb528 | ||
|
b913e9b4a3 | ||
|
24ad44a9ec | ||
|
f4806ab344 | ||
|
fad71f3265 | ||
|
6a405662e9 | ||
|
c9bd65f2b9 | ||
|
d90d71b9c0 | ||
|
4b1cccc156 | ||
|
c12f2173db | ||
|
29a621a4c3 | ||
|
fdc27aad3a | ||
|
bb5e1f688b | ||
|
e2883bc1e8 | ||
|
413b06bb8a | ||
|
398cde5481 | ||
|
5e3b2d2dce | ||
|
51bd556992 | ||
|
b9926ba634 | ||
|
c7a2b2f4d2 | ||
|
604f3aaa4c | ||
|
a5a09666f5 | ||
|
21f72ae736 | ||
|
37c803f5c7 | ||
|
2cd866adfa | ||
|
19fe9f54d2 | ||
|
6738c889ad | ||
|
d23ef521dc | ||
|
95b7821199 | ||
|
bc76028dc0 | ||
|
a6d1d7aecd | ||
|
9b33229b72 | ||
|
3f549f7576 | ||
|
537c1b3d3b | ||
|
d06628d503 | ||
|
8af61db534 | ||
|
3b8e125d80 | ||
|
92b0f948be | ||
|
aa31beb01c | ||
|
028defa959 | ||
|
8683d699e1 | ||
|
58ebcc7de5 | ||
|
d2d24269ef | ||
|
92f44ed248 | ||
|
0da424dd19 | ||
|
789cae3baa | ||
|
66cff08323 | ||
|
c545a5a8c8 | ||
|
4d5ddf6d44 | ||
|
592b3d8d07 | ||
|
24d557bb21 | ||
|
18e98b4f5f | ||
|
946c2cf8d8 | ||
|
1b2e976dc9 | ||
|
bbf6a152e0 | ||
|
e7fc123bfe | ||
|
b058ab998f | ||
|
e5f3c5ae7e | ||
|
220c7af436 | ||
|
86d918f4e5 | ||
|
959b049552 | ||
|
1406dd036f | ||
|
3dc7cd1b5b | ||
|
feaf9c6be0 | ||
|
3c1f66efe7 | ||
|
91427fdcb5 | ||
|
6914e61259 | ||
|
83875f311c | ||
|
c97e2cbbc4 |
44
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Publish Hugo Site
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish Hugo Site
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
cache: "npm"
|
||||
# The action defaults to search for the dependency file (package-lock.json,
|
||||
# npm-shrinkwrap.json or yarn.lock) in the repository root, and uses its
|
||||
# hash as a part of the cache key.
|
||||
# https://github.com/actions/setup-node/blob/main/docs/advanced-usage.md#caching-packages-data
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
|
||||
- name: Setup Hugo
|
||||
uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: "0.120.3"
|
||||
extended: true
|
||||
|
||||
- run: npm ci
|
||||
- run: hugo --minify
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_branch: generated
|
121
.gitignore
vendored
@@ -1,2 +1,123 @@
|
||||
### Hugo ###
|
||||
/public/
|
||||
/resources/_gen/
|
||||
/assets/jsconfig.json
|
||||
hugo_stats.json
|
||||
.hugo_build.lock
|
||||
|
||||
.vscode
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
### Node Patch ###
|
||||
# Serverless Webpack directories
|
||||
.webpack/
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/hugo,node
|
||||
|
||||
public/
|
||||
|
||||
.obsidian/
|
||||
|
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "themes/hugo-video"]
|
||||
path = themes/hugo-video
|
||||
url = https://github.com/martignoni/hugo-video.git
|
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Dave Gallant
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
27
Makefile
@@ -1,27 +0,0 @@
|
||||
SHELL := bash
|
||||
.SHELLFLAGS := -eu -o pipefail -c
|
||||
.DELETE_ON_ERROR:
|
||||
MAKEFLAGS += --warn-undefined-variables
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
ifeq ($(origin .RECIPEPREFIX), undefined)
|
||||
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
|
||||
endif
|
||||
.RECIPEPREFIX = >
|
||||
|
||||
build:
|
||||
> rm -rf public/
|
||||
> hugo
|
||||
|
||||
## server: run server locally on port 1313 and open in a browser
|
||||
server:
|
||||
> hugo server --buildDrafts
|
||||
|
||||
## help: Print this help message
|
||||
help:
|
||||
> @echo
|
||||
> @echo "Usage:"
|
||||
> @echo
|
||||
> @sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /' | sort
|
||||
> @echo
|
||||
.PHONY: help
|
@@ -1,35 +1,10 @@
|
||||
---
|
||||
title: "{{ replace .TranslationBaseName "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
lastmod: {{ .Date }}
|
||||
title: "{{ humanize .Name | title }}"
|
||||
date: "{{ .Date }}"
|
||||
draft: true
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: []
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
comments: true
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
@@ -1,13 +0,0 @@
|
||||
.hanchor {
|
||||
visibility: hidden;
|
||||
color: silver;
|
||||
font-size: 100%;
|
||||
transition: 0.2s;
|
||||
padding-left: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h2:hover a, h3:hover a, h4:hover a {
|
||||
visibility: visible;
|
||||
text-decoration: none;
|
||||
}
|
129
config.yaml
@@ -1,71 +1,90 @@
|
||||
baseurl: /
|
||||
staticDir: static
|
||||
languageCode: en-us
|
||||
googleAnalytics: G-V8WJDERTX9
|
||||
baseURL: /
|
||||
copyright: Dave Gallant
|
||||
preserveTaxonomyNames: true
|
||||
pygmentsstyle: "monokai"
|
||||
pygmentscodefences: false
|
||||
pygmentscodefencesguesssyntax: true
|
||||
theme:
|
||||
- archie
|
||||
- hugo-video
|
||||
title: davegallant
|
||||
title: davegallant.ca
|
||||
enableGitInfo: true
|
||||
enableRobotsTXT: true
|
||||
paginate: 20
|
||||
|
||||
build:
|
||||
noJSConfigInAssets: true
|
||||
writeStats: true
|
||||
|
||||
params:
|
||||
mode: toggle
|
||||
useCDN: true
|
||||
subtitle: "A personal blog"
|
||||
mathjax: true
|
||||
katex: true
|
||||
author: Dave Gallant
|
||||
subtitle:
|
||||
description: "Dave Gallant is a software developer and a computer enthusiast."
|
||||
|
||||
favicon: https://davegallant.ca/favicon.ico
|
||||
logo:
|
||||
text: davegallant.ca
|
||||
url: /
|
||||
|
||||
customcss:
|
||||
- css/custom.css
|
||||
defaultTheme: "dark"
|
||||
|
||||
social:
|
||||
- name: Email
|
||||
icon: at-sign
|
||||
url: 'mailto:me@davegallant.ca'
|
||||
- name: LinkTree
|
||||
icon: compass
|
||||
url: 'https://linktr.ee/davegallant'
|
||||
- name: GitHub
|
||||
icon: github
|
||||
url: 'https://github.com/davegallant'
|
||||
- name: Mastodon
|
||||
icon: speaker
|
||||
url: https://mastodon.social/@davegallant
|
||||
- name: LinkedIn
|
||||
icon: linkedin
|
||||
url: https://www.linkedin.com/in/dave-gallant/
|
||||
comments:
|
||||
utterances:
|
||||
enable: true
|
||||
issueTerm: "pathname"
|
||||
github:
|
||||
username: davegallant
|
||||
repository: site
|
||||
|
||||
comments:
|
||||
utterances:
|
||||
enable: true
|
||||
issueTerm: "pathname"
|
||||
github:
|
||||
username: davegallant
|
||||
repository: davegallant.github.io
|
||||
prism:
|
||||
languages:
|
||||
- markup
|
||||
- css
|
||||
- clike
|
||||
- javascript
|
||||
- bash
|
||||
- csharp
|
||||
- hcl
|
||||
- ignore
|
||||
- json
|
||||
- markdown
|
||||
- powershell
|
||||
- toml
|
||||
- yaml
|
||||
plugins:
|
||||
- normalize-whitespace
|
||||
- toolbar
|
||||
- copy-to-clipboard
|
||||
- command-line
|
||||
|
||||
menu:
|
||||
main:
|
||||
- name: Home
|
||||
url: /
|
||||
weight: 1
|
||||
- name: All posts
|
||||
url: /post
|
||||
- name: Blog
|
||||
url: /blog
|
||||
weight: 2
|
||||
- name: RSS
|
||||
url: /index.xml
|
||||
weight: 3
|
||||
- name: Tags
|
||||
url: /tags
|
||||
weight: 4
|
||||
- name: About
|
||||
url: /about
|
||||
weight: 5
|
||||
|
||||
permalinks:
|
||||
post: '/blog/:year/:month/:day/:slug/'
|
||||
post: "/blog/:year/:month/:day/:slug/"
|
||||
|
||||
markup:
|
||||
goldmark:
|
||||
renderer:
|
||||
unsafe: true
|
||||
|
||||
module:
|
||||
imports:
|
||||
- path: custom-theme
|
||||
mounts:
|
||||
- source: node_modules/simple-icons/icons
|
||||
target: assets/simple-icons
|
||||
- source: assets
|
||||
target: assets
|
||||
- source: layouts
|
||||
target: layouts
|
||||
- source: static
|
||||
target: static
|
||||
- source: node_modules/prismjs
|
||||
target: assets/prismjs
|
||||
- source: node_modules/prism-themes/themes
|
||||
target: assets/prism-themes
|
||||
- source: node_modules/typeface-fira-code/files
|
||||
target: static/fonts
|
||||
- source: node_modules/typeface-roboto-slab/files
|
||||
target: static/fonts
|
||||
- source: node_modules/@tabler/icons/icons
|
||||
target: assets/tabler-icons
|
||||
|
27
content/_index.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Hello
|
||||
|
||||
👋 I'm a software tinkerer with a passion for infra, security, privacy, and self-hosting.
|
||||
|
||||
This is a space where I document my learnings and share them with others. I hope you find something useful here. Continuous improvement is what motivates me to keep learning.
|
||||
|
||||
I choose to host this site, alongside other tools, rather than relying exclusively on larger platforms because I believe in the open web. Interoperability is often not a consideration for popular platforms today and I find that concerning.
|
||||
|
||||
My blog can be found [here](./blog).
|
||||
|
||||
## Connect
|
||||
|
||||
If you would like to connect with me:
|
||||
|
||||
- [Email](mailto:davegallant@proton.me)
|
||||
- [LinkedIn](https://www.linkedin.com/in/dave-gallant)
|
||||
- [Cal.com](https://cal.com/davegallant)
|
||||
- [Mastodon](https://mastodon.social/@davegallant)
|
||||
- [GitHub](https://github.com/davegallant)
|
||||
- [RSS Feed](https://davegallant.ca/index.xml)
|
||||
- [gitea.snake-cloud.ts.net](https://gitea.snake-cloud.ts.net/explore/repos)
|
||||
|
||||
## Credits
|
||||
|
||||
- The site is generated with [hugo](https://gohugo.io/)
|
||||
- The theme is a modified version of [hugo-theme-gruvbox](https://github.com/schnerring/hugo-theme-gruvbox)
|
||||
- The comments system is powered by [utterances](https://github.com/utterance/utterances)
|
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: About
|
||||
weight: -210
|
||||
disable_comments: true
|
||||
---
|
||||
|
||||
I'm a software engineer with a passion for open-source, infrastructure, tooling and security.
|
5
content/blog/_index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Blog
|
||||
---
|
||||
|
||||
Subscribe via [RSS](https://davegallant.ca/index.xml).
|
95
content/blog/amazon-ebs-csi-driver-terraform/index.md
Normal file
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "Amazon EBS CSI driver with terraform"
|
||||
date: "2024-04-07T15:20:23-04:00"
|
||||
draft: false
|
||||
comments: true
|
||||
toc: false
|
||||
author: "Dave Gallant"
|
||||
tags: ['aws', 'eks', 'ebs', 'aws-ebs-csi-driver', 'oidc', 'efs', 'aws-efs-csi-driver']
|
||||
---
|
||||
|
||||
I recently configured the Amazon EBS CSI driver and found the setup with terraform to be more effort than expected. I wanted to avoid third-party modules and keep it as simple as possible, while remaining least privilege.
|
||||
|
||||
> UPDATE: This approach can also be used for the aws-efs-csi-driver
|
||||
|
||||
<!--more-->
|
||||
|
||||
The [Amazon EBS CSI driver docs](https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html) mention that the following are needed:
|
||||
|
||||
- an existing EKS cluster
|
||||
- IAM role (that allows communication to the EC2 API)
|
||||
- EKS add-on (aws-ebs-csi-driver)
|
||||
- OIDC provider
|
||||
|
||||
This sounded simple enough but I was unable to find a "grab-and-go" terraform example that followed the recommendations in the docs. I saw some suggestions about attaching an `AmazonEBSCSIDriverPolicy` policy to the node groups but did not think this was the best idea since this would allow many pods to potentially have access to the EC2 API.
|
||||
|
||||
After a few minutes of LLM prompting, I was unimpressed with the results. I began to piece together the config myself, and after some trial and error, this is the terraform that I came up with:
|
||||
|
||||
```hcl
|
||||
|
||||
# TLS needed for the thumbprint
|
||||
provider "tls" {}
|
||||
|
||||
data "tls_certificate" "oidc" {
|
||||
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
|
||||
}
|
||||
|
||||
# EKS addon
|
||||
resource "aws_eks_addon" "ebs_csi_driver" {
|
||||
cluster_name = aws_eks_cluster.main.name
|
||||
addon_name = "aws-ebs-csi-driver"
|
||||
addon_version = "v1.29.1-eksbuild.1"
|
||||
service_account_role_arn = aws_iam_role.ebs_csi_driver.arn
|
||||
}
|
||||
|
||||
# AWS Identity and Access Management (IAM) OpenID Connect (OIDC) provider
|
||||
|
||||
resource "aws_iam_openid_connect_provider" "eks" {
|
||||
url = aws_eks_cluster.main.identity.0.oidc.0.issuer
|
||||
client_id_list = ["sts.amazonaws.com"]
|
||||
thumbprint_list = [data.tls_certificate.oidc.certificates[0].sha1_fingerprint]
|
||||
}
|
||||
|
||||
# IAM
|
||||
resource "aws_iam_role" "ebs_csi_driver" {
|
||||
name = "ebs-csi-driver"
|
||||
assume_role_policy = data.aws_iam_policy_document.ebs_csi_driver_assume_role.json
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "ebs_csi_driver_assume_role" {
|
||||
statement {
|
||||
effect = "Allow"
|
||||
|
||||
principals {
|
||||
type = "Federated"
|
||||
identifiers = [aws_iam_openid_connect_provider.eks.arn]
|
||||
}
|
||||
|
||||
actions = [
|
||||
"sts:AssumeRoleWithWebIdentity",
|
||||
]
|
||||
|
||||
condition {
|
||||
test = "StringEquals"
|
||||
variable = "${aws_iam_openid_connect_provider.eks.url}:aud"
|
||||
values = ["sts.amazonaws.com"]
|
||||
}
|
||||
|
||||
condition {
|
||||
test = "StringEquals"
|
||||
variable = "${aws_iam_openid_connect_provider.eks.url}:sub"
|
||||
values = ["system:serviceaccount:kube-system:ebs-csi-controller-sa"]
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "AmazonEBSCSIDriverPolicy" {
|
||||
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
|
||||
role = aws_iam_role.ebs_csi_driver.name
|
||||
}
|
||||
```
|
||||
|
||||
The above configuration follows the docs, binding an IAM role to the service account `kube-system/ebs-csi-controller-sa` using an OpenID connect provider.
|
||||
|
||||
After applying the changes above, I deployed [the sample application](https://docs.aws.amazon.com/eks/latest/userguide/ebs-sample-app.html) and noticed that the persistent volume claims were bound to EBS volumes.
|
@@ -2,8 +2,7 @@
|
||||
title: "AppGate SDP on Arch Linux"
|
||||
date: 2020-03-16T22:00:15-04:00
|
||||
draft: false
|
||||
keywords: ['linux', 'vpn']
|
||||
description: ""
|
||||
comments: true
|
||||
tags: ['linux', 'vpn', 'python']
|
||||
author: "Dave Gallant"
|
||||
---
|
@@ -1,39 +1,13 @@
|
||||
---
|
||||
title: "Automatically Rotating AWS Access Keys"
|
||||
title: "Automatically rotating AWS access keys"
|
||||
date: 2021-09-17T12:48:33-04:00
|
||||
lastmod: 2021-09-17T12:48:33-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
comments: true
|
||||
tags: ['aws', 'python', 'security', 'aws-vault']
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
Rotating credentials is a security best practice. This morning, I read a question about automatically rotating AWS Access Keys without having to go through the hassle of navigating the AWS console. There are some existing solutions already, but I decided to write a [script](https://gist.github.com/davegallant/2c042686a78684a657fe99e20fa7a924#file-aws_access_key_rotator-py) since it was incredibly simple. The script could be packed up as a systemd/launchd service to continually rotate access keys in the background.
|
||||
|
||||
In the longer term, migrating my local workflows to [aws-vault](https://github.com/99designs/aws-vault) seems like a more secure solution. This would mean that credentials (even temporary session credentials) never have to be written in plaintext to disk (i.e. where [AWS suggests](https://docs.aws.amazon.com/sdkref/latest/guide/file-location.html)). Any existing applications, such as terraform, could be have their credentials passed to them from aws-vault, which retrieves them from the OS's secure keystore. There is even a [rotate command](https://github.com/99designs/aws-vault/blob/master/USAGE.md#rotating-credentials) included.
|
@@ -1,40 +1,16 @@
|
||||
---
|
||||
title: "Backing Up Gmail With Synology"
|
||||
title: "Backing up gmail with Synology"
|
||||
date: 2022-03-13T18:49:10-04:00
|
||||
lastmod: 2022-03-13T18:49:10-04:00
|
||||
comments: true
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ['degoogle', 'synology', 'gmail', 'backup', 'ransomware']
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
tags: ["synology", "gmail", "backup", "ransomware"]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
I've used gmail since the beta launched touting a whopping 1GB of storage. I thought this was a massive leap in email technology at the time. I was lucky enough to get an invite fairly quickly. Not suprisingly, I have many years of emails, attachments, and photos. I certainly do not want to lose the content of many of these emails. Despite the redundancy of the data that Google secures, I still feel better retaining a copy of this data on my own physical machines.
|
||||
|
||||
I've used gmail since the beta launched touting a whopping 1GB of storage. I thought this was a massive leap in email technology at the time. I was lucky enough to get an invite fairly quickly. Not suprisingly, I have many years of emails, attachments, and photos. I certainly do not want to lose the content of many of these emails. Despite the redundancy of the data that Google secures, I still feel better retaining a copy of this data on my own physical machines.
|
||||
<!--more-->
|
||||
|
||||
The thought of completely de-googling has crossed my mind on occassion. Convenience, coupled with my admiration for Google engineering, has prevented me from doing so thus far. Though, I may end up doing so at some point in the future.
|
||||
|
||||
@@ -42,7 +18,7 @@ The thought of completely de-googling has crossed my mind on occassion. Convenie
|
||||
|
||||
Synology products are reasonably priced for what you get (essentially a cloud-in-a-box) and there is very little maintenance required. I've recently been in interested in syncing and snapshotting my personal data. I've setup [Synology's Cloud Sync](https://www.synology.com/en-ca/dsm/feature/cloud_sync) and keep copies of most of my cloud data.
|
||||
|
||||
I've used tools such as [gmvault](http://www.gmvault.org) with success in the past. Setting this up on a cron seems like a viable option. However, I don't really need a lot of the features it offers and do not plan to restore this data to another account.
|
||||
I've used tools such as [gmvault](http://www.gmvault.org) with success in the past. Setting this up on a cron seems like a viable option. However, I don't really need a lot of the features it offers and do not plan to restore this data to another account.
|
||||
|
||||
Synology's MailPlus seems to be a good candidate for backing up this data. By enabling POP3 fetching, it's possible to fetch all existing emails, as well as periodically fetch all new emails. If a disaster ever did occur, having these emails would be beneficial, as they are an extension of my memory bank.
|
||||
|
||||
@@ -62,7 +38,7 @@ After this, mail started coming in.
|
||||
|
||||

|
||||
|
||||
After fetching 19 years worth of emails, I tried searching for some emails. It only took a few seconds to search through ~50K emails, which is a relief if I ever did have to search for something important.
|
||||
After fetching 19 years worth of emails, I tried searching for some emails. It only took a few seconds to search through ~50K emails, which is a relief if I ever did have to search for something important.
|
||||
|
||||
## Securing Synology
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
43
content/blog/opting-out-of-haveibeenpwned/index.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: "Opting out of haveibeenpwned"
|
||||
date: "2025-02-16T21:15:07-05:00"
|
||||
draft: false
|
||||
comments: true
|
||||
toc: false
|
||||
author: "Dave Gallant"
|
||||
tags:
|
||||
[
|
||||
"breach",
|
||||
"darkweb",
|
||||
"haveibeenpwned",
|
||||
"hibp",
|
||||
"passwords",
|
||||
"privacy",
|
||||
]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
Data breaches are a concern for anyone trying to live a life of relative privacy. Last month, PowerSchool informed its customers that [hackers stole data of 62 million students](https://www.bleepingcomputer.com/news/security/powerschool-hacker-claims-they-stole-data-of-62-million-students/). This may not have impacted you, but unless you have been practicing [Extreme Privacy](https://inteltechniques.com/book7.html) techniques for decades, you likely have been impacted by a data breach in the past.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Understanding Data Breaches
|
||||
|
||||
Data breaches occur when unauthorized individuals gain access to sensitive information (names, addresses, emails, phone numbers among other details). If the breach is substantial enough, the raw data is likely to make it into the hands of data brokers that will collect, aggregate, and sell the information on the [dark web](https://en.wikipedia.org/wiki/Dark_web).
|
||||
|
||||
## Check if you have been impacted
|
||||
|
||||
There are a number of services that can be used to check if you have been impacted by a data breach, including [Mozilla monitor](https://monitor.mozilla.org), [Google Dark web report](https://myactivity.google.com/dark-web-report/dashboard), and [haveibeenpwned.com](https://haveibeenpwned.com/). Some password managers offer features that compare your credentials against known breaches. These services can also be configured to send you notifications when a breach occurs. It is a good idea to become aware of these breaches as soon as you can, so that you can protect yourself from malicious behaviour such as phishing.
|
||||
|
||||
If you have been an email or phone number for any length of time, there is a high probability that some of your data has been exposed. You can easily check by querying [haveibeenpwned.com](https://haveibeenpwned.com/). Many of the tools that offer breach detection, query the haveibeenpwned database. Although I believe this is service is a public good, it also opens the door for anyone who may be looking to gain more information about your present and past usages of various websites and services.
|
||||
|
||||
## Opting out
|
||||
|
||||
If you have an identity that you'd like to protect, I'd suggest [opting out of public searchability](https://haveibeenpwned.com/OptOut/). This of course does not undo the data breach that happened, but does it make it more challenging for someone to quickly search for an impacted email address. Even after opting out, you can still [subscribe to breach notifications](https://haveibeenpwned.com/NotifyMe), as long as you can validate that you have access to the email in question.
|
||||
|
||||
There are other websites that offer similar style lookups, but many of them are either paywalled or require account registration.
|
||||
|
||||
## Email aliases
|
||||
|
||||
A more proactive method of reducing the likelihood of future exposures is to use an email aliasing service such as [Firefox Relay](https://relay.firefox.com), [DuckDuckGo Email Protection](https://duckduckgo.com/email/), or if you use Proton Mail, [hide-my-email aliases](https://proton.me/support/addresses-and-aliases#hide). This will allow you sign up for services using an alias instead of revealing your email address. The service then forwards all emails to your real address that you configure when setting up the alias.
|
||||
|
@@ -3,40 +3,16 @@ title: "Replacing docker with podman on macOS (and Linux)"
|
||||
date: 2021-10-11T10:43:35-04:00
|
||||
lastmod: 2021-10-11T10:43:35-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ['docker', 'podman', 'containers']
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
comments: true
|
||||
tags: ["docker", "podman", "containers"]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
|
||||
There are a number of reasons why you might want to replace docker, especially on macOS. The following feature bundled in Docker Desktop might have motivated you enough to consider replacing docker:
|
||||
|
||||
{{< tweet 1388586550682861568 >}}
|
||||
<!--more-->
|
||||
|
||||
{{< tweet user="moyix" id="1388586550682861568" >}}
|
||||
|
||||
Docker has been one of the larger influencers in the container world, helping to standardize the [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/main/spec.md). For many developers, containers have become synonymous with terms like `docker` and `Dockerfile` (a file containing build instructions for a container image). Docker has certainly made it very convenient to build and run containers, but it is not the only solution for doing so.
|
||||
|
||||
@@ -85,7 +61,7 @@ Copying config sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8
|
||||
Writing manifest to image destination
|
||||
Storing signatures
|
||||
14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
|
||||
````
|
||||
```
|
||||
|
||||
> If you're having an issue pulling images, you may need to remove `~/.docker/config.json` or remove the set of auths in the configuration as mentioned [here](https://stackoverflow.com/a/69121873/1191286).
|
||||
|
||||
@@ -118,7 +94,7 @@ alias docker=podman
|
||||
|
||||
### podman-compose
|
||||
|
||||
You may be wondering: what about docker-compose? Well, there *claims* to be a drop-in replacement for it: [podman-compose](https://github.com/containers/podman-compose).
|
||||
You may be wondering: what about docker-compose? Well, there _claims_ to be a drop-in replacement for it: [podman-compose](https://github.com/containers/podman-compose).
|
||||
|
||||
```sh
|
||||
pip3 install --user podman-compose
|
||||
@@ -168,5 +144,4 @@ One caveat to mention is that there isn't an official graphical user interface f
|
||||
|
||||
> Update: After further usage, bind mounts do not seem to work out of the box when the client and host are on different machines. A rather involved solution using [sshfs](https://en.wikipedia.org/wiki/SSHFS) was shared [here](https://github.com/containers/podman/issues/8016#issuecomment-920015800).
|
||||
|
||||
|
||||
I had been experimenting with Podman on Linux before writing this, but after listening to this [podcast episode](https://kubernetespodcast.com/episode/164-podman/), I was inspired to give Podman a try on macOS.
|
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: "Replicating TrueNAS datasets to sftpgo over Tailscale"
|
||||
date: "2025-04-17T22:03:33-04:00"
|
||||
draft: false
|
||||
comments: true
|
||||
toc: false
|
||||
author: "Dave Gallant"
|
||||
tags:
|
||||
[
|
||||
"tailscale",
|
||||
"truenas",
|
||||
"sftpgo",
|
||||
]
|
||||
---
|
||||
|
||||
I've recently spun up an instance of TrueNAS SCALE after salvaging a couple hard drives from a past computer build and decided I could use additional network storage for various backups such as Proxmox VMs and home directory backups.
|
||||
|
||||
<!--more-->
|
||||
|
||||
The only app I've needed to install has been Tailscale which has enabled me to access the TrueNAS Web UI from anywhere. I've setup a few datasets and NFS shares to store various backups and the rest of the periodic backups have routinely been working without a hitch. Since my homelab is becoming more of a vital piece of infrastructure for my daily needs, I wanted to ensure that these datasets had [Cloud Sync Tasks](https://www.truenas.com/docs/scale/scaletutorials/dataprotection/cloudsynctasks/) setup for offsite backups. These encrypted backups are mostly being stored in places such as Google Drive and other blob storage providers.
|
||||
|
||||
More recently, to reduce cloud costs, I've setup some a small node at another physical location and installed both Tailscale and [sftpgo](https://github.com/drakkan/sftpgo) on it to facilitate offsite backups. After setting up the infrastructure and adding a Cloud Sync Task in TrueNAS SCALE to replicate these backups offsite to sftpgo, I noticed that Tailscale's Magic DNS was not working, nor was the Tailscale IPv4 address.
|
||||
|
||||
After reading the [Tailscale docs](https://tailscale.com/kb/1483/truenas#route-non-tailnet-traffic-through-truenas) , it became clear that the **Userspace** box had to be unchecked in the Tailscale app settings. This is because the Tailscale app is running within a docker container on the TrueNAS SCALE VM. After unchecking the **Userspace** box, I was able to verify that the Backup Credentials created for sftpgo worked when specifying the host as a Tailscale IPv4 address. This was probably good enough since the IP won't change unless the node is re-registered.
|
||||
|
||||
~~To get MagicDNS working, I went to Network > Global Configuration and set "Nameserver 1" to **100.100.100.100**. After this, I was able to specify the FQDN in the Backup Credentials and the Cloud Sync Tasks started.~~
|
||||
|
||||
This method of adding MagicDNS can lead to issues with DNS when updating the tailscale application in TrueNAS, so I ended using the Tailscale IP directly.
|
||||
|
||||
|
@@ -3,37 +3,11 @@ title: "Running K3s in LXC on Proxmox"
|
||||
date: 2021-11-14T10:07:03-05:00
|
||||
lastmod: 2021-11-14T10:07:03-05:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ["k3s", "proxmox", "lxc"]
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
comments: true
|
||||
tags: ["k3s", "proxmox", "lxc", "self-hosted"]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
It has been a while since I've actively used Kubernetes and wanted to explore the evolution of tools such as [Helm](https://helm.sh) and [Tekton](https://tekton.dev). I decided to deploy [K3s](https://k3s.io), since I've had success with deploying it on resource-contrained Raspberry Pis in the past. I thought that this time it'd be convenient to have K3s running in a LXC container on Proxmox. This would allow for easy snapshotting of the entire Kubernetes deployment. LXC containers also provide an efficient way to use a machine's resources.
|
||||
|
||||
## What is K3s?
|
||||
@@ -48,9 +22,9 @@ This [gist](https://gist.github.com/triangletodd/02f595cd4c0dc9aac5f7763ca226418
|
||||
|
||||
There is an issue on Kubernetes regarding swap [here](https://github.com/kubernetes/kubernetes/issues/53533). There claims to be support for swap in 1.22, but for now let's disable it:
|
||||
|
||||
```
|
||||
sysctl vm.swappiness=0
|
||||
swapoff -a
|
||||
```shell
|
||||
sudo sysctl vm.swappiness=0
|
||||
sudo swapoff -a
|
||||
```
|
||||
|
||||
It might be worth experimenting with swap enabled in the future to see how that might affect performance.
|
||||
@@ -59,7 +33,7 @@ It might be worth experimenting with swap enabled in the future to see how that
|
||||
|
||||
To avoid IP Forwarding issues with Traefik, run the following on the host:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
sudo sysctl net.ipv4.ip_forward=1
|
||||
sudo sysctl net.ipv6.conf.all.forwarding=1
|
||||
sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
|
||||
@@ -81,7 +55,7 @@ Now back on the host run `pct list` to determine what VMID it was given.
|
||||
|
||||
Open `/etc/pve/lxc/$VMID.conf` and append:
|
||||
|
||||
```sh
|
||||
```
|
||||
lxc.apparmor.profile: unconfined
|
||||
lxc.cap.drop:
|
||||
lxc.mount.auto: "proc:rw sys:rw"
|
||||
@@ -92,6 +66,7 @@ All of the above configurations are described in the [manpages](https://linuxcon
|
||||
Notice that `cgroup2` is used since Proxmox VE 7.0 has switched to a [pure cgroupv2 environment](https://pve.proxmox.com/pve-docs/chapter-pct.html#pct_cgroup).
|
||||
|
||||
Thankfully cgroup v2 support has been supported in k3s with these contributions:
|
||||
|
||||
- https://github.com/k3s-io/k3s/pull/2584
|
||||
- https://github.com/k3s-io/k3s/pull/2844
|
||||
|
||||
@@ -99,7 +74,7 @@ Thankfully cgroup v2 support has been supported in k3s with these contributions:
|
||||
|
||||
From within the container, run:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
echo '#!/bin/sh -e
|
||||
ln -s /dev/console /dev/kmsg
|
||||
mount --make-rshared /' > /etc/rc.local
|
||||
@@ -113,7 +88,7 @@ One of the simplest ways to install K3s on a remote host is to use [k3sup](https
|
||||
Ensure that you supply a valid `CONTAINER_IP` and choose the `k3s-version` you prefer.
|
||||
As of 2021/11, it is still defaulting to the 1.19 channel, so I overrode it to 1.22 for cgroup v2 support. See the published releases [here](https://github.com/k3s-io/k3s/releases).
|
||||
|
||||
```sh
|
||||
```shell
|
||||
ssh-copy-id root@$CONTAINER_IP
|
||||
k3sup install --ip $CONTAINER_IP --user root --k3s-version v1.22.3+k3s1
|
||||
```
|
||||
@@ -124,7 +99,6 @@ If all goes well, you should see a path to the `kubeconfig` generated. I moved t
|
||||
|
||||
Installing K3s in LXC on Proxmox works with a few tweaks to the default configuration. I later followed the Tekton's [Getting Started](https://tekton.dev/docs/getting-started/) guide and was able to deploy it in a few commands.
|
||||
|
||||
|
||||
```console
|
||||
$ kubectl get all --namespace tekton-pipelines
|
||||
NAME READY STATUS RESTARTS AGE
|
After Width: | Height: | Size: 34 KiB |
@@ -1,40 +1,18 @@
|
||||
---
|
||||
title: "Setting Up Gitea Actions With Tailscale"
|
||||
title: "Setting up Gitea Actions with Tailscale"
|
||||
date: 2023-12-10T17:22:11-05:00
|
||||
comments: true
|
||||
lastmod: 2023-12-10T17:22:11-05:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ["gitea", "gitea actions", "github actions", "tailscale"]
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
tags: ["gitea", "gitea actions", "github actions", "tailscale", "self-hosted"]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
In this post I'll go through the process of setting up Gitea Actions and [Tailscale](https://tailscale.com/), unlocking a simple and secure way to automate workflows.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## What is Gitea?
|
||||
|
||||
[Gitea](https://about.gitea.com/) is a lightweight and fast git server that has much of the same look and feel as github. I have been using it in my homelab to mirror repositories hosted on other platforms such as github and gitlab. These mirrors take advantage of the decentralized nature of git by serving as "backups". One of the main reasons I hadn't been using it more often was due to the lack of integrated CI/CD. This is no longer the case.
|
||||
@@ -45,23 +23,24 @@ In this post I'll go through the process of setting up Gitea Actions and [Tailsc
|
||||
|
||||
So what are they? If you've ever used GitHub Actions (and if you're reading this, I imagine you have), these will look familiar. Gitea Actions essentially enable the ability to run github workflows on gitea. Workflows between gitea and github are not completely interopable, but a lot of the same workflow syntax is already compatible on gitea. You can find a documented list of [unsupported workflows syntax](https://docs.gitea.com/usage/actions/comparison#unsupported-workflows-syntax).
|
||||
|
||||
Actions work by using a [custom fork](https://gitea.com/gitea/act) of [nekos/act](https://github.com/nektos/act). Workflows run in a new container for every job. If you specify an action such as 'actions/checkout@v3', it defaults to downloading the scripts from github.com. To avoid internet egress, you could always clone the required actions to your local gitea instance.
|
||||
Actions work by using a [custom fork](https://gitea.com/gitea/act) of [nekos/act](https://github.com/nektos/act). Workflows run in a new container for every job. If you specify an action such as `actions/checkout@v4`, it defaults to downloading the scripts from github.com. To avoid internet egress, you could always clone the required actions to your local gitea instance.
|
||||
|
||||
Actions (gitea's implementation) has me excited because it makes spinning up a network-isolated environment for workflow automation incredibly simple.
|
||||
|
||||
## Integration with Tailscale
|
||||
|
||||
So how does Tailscale help here? Well, more recently I've been exposing my self-hosted services through a combination of traefik and the tailscale (through the tailscale-traefik proxy integration described [here](https://traefik.io/blog/exploring-the-tailscale-traefik-proxy-integration/)). This allows for a nice looking dns name (i.e. gitea.my-tailnet-name.ts.net) and automatic tls certificate management. I can also share this tailscale node securely with other tailscale users without configuring any firewall rules on my router.
|
||||
> **2024-02-10**: I had originally written this post to include [Tailscale-Traefik Proxy Integration](https://traefik.io/blog/exploring-the-tailscale-traefik-proxy-integration/), but have since removed it in favour of Tailscale Serve after learning from this [example](https://github.com/tailscale-dev/docker-guide-code-examples). This simplifies the setup and reduces the number of moving parts.
|
||||
|
||||
So how does Tailscale help here? Well, more recently I've been exposing my self-hosted services using Tailscale [Serve](https://tailscale.com/kb/1312/serve). This allows for a nice looking dns name (i.e. gitea.my-tailnet-name.ts.net), automatic tls certificate management, and optionally allowing the address to be publically accessible (by using [Funnel](https://tailscale.com/kb/1223/funnel)).
|
||||
|
||||
## Deploying Gitea, Traefik, and Tailscale
|
||||
|
||||
In my case, the following is already set up:
|
||||
|
||||
- [docker-compose is installed](https://docs.docker.com/compose/install/linux/)
|
||||
- [tailscale is installed on the gitea host](https://tailscale.com/kb/1017/install/)
|
||||
- [tailscale magic dns is enabled](https://tailscale.com/kb/1081/magicdns/)
|
||||
|
||||
My preferred approach to deploying code in a homelab environment is with docker compose. I have deployed this in a [proxmox lxc container](https://pve.proxmox.com/wiki/Linux_Container) based on debian with a hostname `gitea`. This could be deployed in any environment and with any hostname (as long you updated the tailscale machine name to your preferred subdomain for magic dns).
|
||||
My preferred approach to deploying code in a homelab environment is with docker compose. I have deployed this in a LXC on Proxmox. You could run this on a virtual machine or a physical host as well.
|
||||
|
||||
The `docker-compose.yaml` file looks like:
|
||||
|
||||
@@ -71,6 +50,7 @@ services:
|
||||
gitea:
|
||||
image: gitea/gitea:1.21.1
|
||||
container_name: gitea
|
||||
network_mode: service:ts-gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
@@ -84,67 +64,62 @@ services:
|
||||
- ./data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
traefik:
|
||||
image: traefik:v3.0.0-beta4
|
||||
container_name: traefik
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
ts-gitea:
|
||||
image: tailscale/tailscale:v1.58
|
||||
container_name: ts-gitea
|
||||
hostname: gitea
|
||||
environment:
|
||||
- TS_AUTHKEY=<FILL THIS IN>
|
||||
- TS_SERVE_CONFIG=/config/gitea.json
|
||||
- TS_STATE_DIR=/var/lib/tailscale
|
||||
volumes:
|
||||
- ./traefik/data/traefik.yaml:/traefik.yaml:ro
|
||||
- ./traefik/data/dynamic.yaml:/dynamic.yaml:ro
|
||||
- /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
|
||||
- ${PWD}/state:/var/lib/tailscale
|
||||
- ${PWD}/config:/config
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
cap_add:
|
||||
- net_admin
|
||||
- sys_module
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
`traefik/data/traefik.yaml`:
|
||||
Note that you must specify a `TS_AUTHKEY` in the `ts-gitea` service. You can generate an auth key [here](https://login.tailscale.com/admin/settings/keys).
|
||||
|
||||
`config/gitea.json`:
|
||||
|
||||
```yaml
|
||||
entryPoints:
|
||||
https:
|
||||
address: ":443"
|
||||
providers:
|
||||
file:
|
||||
filename: dynamic.yaml
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
tailscale: {}
|
||||
log:
|
||||
level: INFO
|
||||
{
|
||||
"TCP": { "443": { "HTTPS": true } },
|
||||
"Web":
|
||||
{
|
||||
"${TS_CERT_DOMAIN}:443":
|
||||
{ "Handlers": { "/": { "Proxy": "http://127.0.0.1:3000" } } },
|
||||
},
|
||||
"AllowFunnel": { "${TS_CERT_DOMAIN}:443": false }
|
||||
}
|
||||
```
|
||||
|
||||
and finally `traefik/data/dynamic/dynamic.yaml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
routers:
|
||||
gitea:
|
||||
rule: Host(`gitea.my-tailnet-name.ts.net`)
|
||||
entrypoints:
|
||||
- "https"
|
||||
service: gitea
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
services:
|
||||
gitea:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://gitea:3000"
|
||||
```
|
||||
|
||||
Something to consider is whether or not you want to use ssh with git. One method to get this to work with containers is to use [ssh container passthrough](https://docs.gitea.com/installation/install-with-docker#ssh-container-passthrough). I decided to keep it simple and not use ssh, since communicating over https is perfectly fine for my use case.
|
||||
|
||||
After adding the above configuration, running `docker compose up -d` should be enough to get an instance up and running. It will be accessible at [https://gitea.my-tailnet-name.ts.net](https://gitea.my-tailnet-name.ts.net) from within the tailnet.
|
||||
|
||||
## Connecting a Runner
|
||||
Something to consider is whether or not you want to use ssh with git. One method to get this to work with containers is to use [ssh container passthrough](https://docs.gitea.com/installation/install-with-docker#ssh-container-passthrough). I decided to keep it simple and not use ssh, since communicating over https is perfectly fine for my use case.
|
||||
|
||||
I installed the runner by [following the docs](https://docs.gitea.com/usage/actions/quickstart#set-up-runner). I opted for installing it on a separate host (another lxc container) as recommended in the docs. I used the systemd unit file to ensure that the runner comes back online after system reboots. I installed tailscale on this act runner as well, so that it can have the same "networking privileges" as the main instance.
|
||||
## Theming
|
||||
|
||||
After registering this runner and starting the daemon, it appeared in `/admin/actions/runners`:
|
||||
I discovered some themes for gitea [here](https://git.sainnhe.dev/sainnhe/gitea-themes).
|
||||
|
||||

|
||||
I added the theme by copying [theme-palenight.css](https://git.sainnhe.dev/sainnhe/gitea-themes/raw/branch/master/dist/theme-palenight.css) into `./data/gitea/public/assets/css`. I then added the following to `environment` in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
- GITEA__ui__DEFAULT_THEME=palenight
|
||||
- GITEA__ui__THEMES=palenight
|
||||
```
|
||||
|
||||
After restarting the gitea instance, the default theme was applied.
|
||||
|
||||
## Connecting runners
|
||||
|
||||
I installed the runner by [following the docs](https://docs.gitea.com/usage/actions/quickstart#set-up-runner). I opted for installing it on a separate host as recommended in the docs. I used the systemd unit file to ensure that the runner comes back online after system reboots. I installed tailscale on the gitea runner as well, so that it can be part of the same tailnet as the main instance.
|
||||
|
||||
After registering this runner and starting the daemon, the runner appeared in `/admin/actions/runners`. I added two other runners to help with parallelization.
|
||||
|
||||
## Running a workflow
|
||||
|
||||
@@ -155,7 +130,7 @@ After this, I wanted to make sure that some of my existing workflows could be mi
|
||||
The following workflow uses a matrix to run a job for several of my hosts using ansible playbooks that will do various tasks such as patching os updates and updating container images.
|
||||
|
||||
```yaml
|
||||
name: Run ansible playbooks
|
||||
name: Run ansible
|
||||
on:
|
||||
push:
|
||||
schedule:
|
||||
@@ -164,23 +139,9 @@ on:
|
||||
jobs:
|
||||
run-ansible-playbook:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
host:
|
||||
- changedetection
|
||||
- grafana
|
||||
- homer
|
||||
- invidious
|
||||
- jackett
|
||||
- ladder
|
||||
- miniflux
|
||||
- plex
|
||||
- qbittorrent
|
||||
- tailscale-exit-node
|
||||
- uptime-kuma
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install ansible
|
||||
run: |
|
||||
apt update && apt install ansible -y
|
||||
@@ -189,22 +150,38 @@ jobs:
|
||||
with:
|
||||
playbook: playbooks/main.yml
|
||||
requirements: requirements.yml
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY}}
|
||||
options: |
|
||||
--inventory inventory
|
||||
--limit ${{ matrix.host }}
|
||||
- name: Send failure notification
|
||||
uses: dawidd6/action-send-mail@v3
|
||||
if: always() && failure()
|
||||
with:
|
||||
server_address: smtp.gmail.com
|
||||
server_port: 465
|
||||
secure: true
|
||||
username: myuser
|
||||
password: ${{ secrets.MAIL_PASSWORD }}
|
||||
subject: ansible runbook failed
|
||||
to: me@davegallant.ca
|
||||
from: RFD Notify
|
||||
body: |
|
||||
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}
|
||||
```
|
||||
|
||||
And voilà:
|
||||
|
||||
{{< video src="gitea-runner" >}}
|
||||

|
||||
|
||||
You may be wondering how the gitea runner is allowed to connect to the other hosts using ansible? Well, the nodes are in the same tailnet and have [tailscale ssh](https://tailscale.com/tailscale-ssh) enabled.
|
||||
|
||||
## Areas for improvement
|
||||
|
||||
One enhancement that I would like to see is the ability to send notifications on workflow failures. Currently, this [doesn't seem possible](https://github.com/go-gitea/gitea/issues/23725).
|
||||
One enhancement that I would like to see is the ability to send notifications on workflow failures. Currently, this [doesn't seem possible](https://github.com/go-gitea/gitea/issues/23725) without adding logic to each workflow.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Gitea Actions are fast and the resource footprint is minimal. My gitea instance is currently using around 250mb of memory and a small fraction of a single cpu core (and the runner is using a similar amount of resources). This is impressive since many alternatives tend to require substantionally more resources (ahem, gitlab). It likely helps that the codebase is largely written in go.
|
||||
Gitea Actions are fast and the resource footprint is minimal. My gitea instance is currently using around 250mb of memory and a small fraction of a single cpu core (and the runner is using a similar amount of resources). This is impressive since many alternatives tend to require substantially more resources. It likely helps that the codebase is largely written in go.
|
||||
|
||||
By combining gitea with the networking marvel that is tailscale, running workflows becomes simple and fun. Whether you are working on a team or working alone, this setup ensures that your workflows are securely accessible from anywhere with an internet connection.
|
||||
|
||||
Check out my gitea instance exposed via Funnel [here](https://gitea.snake-cloud.ts.net).
|
83
content/blog/using-a-realtek-nic-with-opnsense/index.md
Normal file
@@ -0,0 +1,83 @@
|
||||
---
|
||||
title: "Using a Realtek NIC with OPNsense"
|
||||
date: "2025-04-21T17:17:46-04:00"
|
||||
draft: false
|
||||
comments: true
|
||||
toc: false
|
||||
author: "Dave Gallant"
|
||||
tags:
|
||||
[
|
||||
linux,
|
||||
freebsd,
|
||||
opnsense,
|
||||
pfsense,
|
||||
proxmox,
|
||||
realtek,
|
||||
nic,
|
||||
]
|
||||
---
|
||||
|
||||
For the past few years, I've been running pfSense (and more recently OPNsense) in a virtual machine within Proxmox. This has been running fine with a single onboard Intel NIC. A few months ago, I upgraded to a machine that has a CPU that supports hardware-accelerated transcoding, has more SATA ports, and has more PCI slots for future expansion. With the goal of having a dedicated NIC for WAN, I bought an inexpensive 1Gbps PCIe NIC (TG-3468) despite reading about some of the concerns around Realtek NICs (sluggish performance, driver instability, and in some cases system crashes).
|
||||
|
||||
I've been running a Realtek NICs reliably on Linux and Windows desktops, so I figured I could make it work without too much effort, but it turns out Realtek NICs really can be problematic when it comes to FreeBSD-based routers, and commonly documented workarounds did not solve my problems.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Environment
|
||||
|
||||
My environment consists of:
|
||||
|
||||
- Proxmox 8.4
|
||||
- OPNsense 25.1 (QEMU VM)
|
||||
- Ethernet controller: Intel Corporation Ethernet Connection (5) I219-LM
|
||||
- Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
|
||||
|
||||
# Goal
|
||||
|
||||
The goal is to upgrade the OPNsense router from a single NIC to two NICs. The NICs are responsible for:
|
||||
|
||||
1. **LAN**: the internal network for computers, phones, cameras, printers, etc (NIC 1)
|
||||
2. **WAN**: the connection from the ISP (NIC 2)
|
||||
|
||||
Having two separate physical interfaces for LAN and WAN creates clear, physical separation between the trusted internal network and the untrusted external network at the hardware level. This also should improve performance and throughput since the same physical connection is no longer shared between LAN and WAN.
|
||||
|
||||
## Device Passthrough
|
||||
|
||||
For maximum performance and reduced hypervisor overhead, passing through a physical NIC for WAN directly to the VM seemed to make the most sense, so I passed it through to the OPNsense VM.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
I added the PCI device and restarted the OPNsense VM and re-configured the WAN in OPNsense to use this device.
|
||||
|
||||
I received the WAN IP and everything appeared to be working. I ran a few speed tests and noticed that the download speeds were much lower than normal from all of my devices. I checked my instance of [speedtest-tracker](https://docs.speedtest-tracker.dev) noticed that the download speeds were significantly slower than historical records:
|
||||
|
||||

|
||||
|
||||
These speeds tests were going through Mullvad, which occasionally is inconsistent, but the results remained consistently lower than the previous configuration.
|
||||
|
||||
I reverted the WAN back to the original NIC, and the download speeds returned to more average results immediately so it became obvious that something was not right with this setup.
|
||||
|
||||
### Realtek drivers
|
||||
|
||||
I did some web searching / LLM prompting and discovered that some people have had improved results after installing the OPNsense plugin **os-realtek-re**.
|
||||
|
||||
After installing the plugin and ensuring the kernel module was loaded at boot by following the post-install instructions, the throughput was still signicantly slower than before adding a second NIC.
|
||||
|
||||
I was starting to think that there might be a problem with the hardware and began the process to return it to the vendor.
|
||||
|
||||
## Virtualized NIC with a Linux bridge
|
||||
|
||||
As one last shot, I created Linux Bridge in the Proxmox GUI with the Realtek NIC and passed it through to the OPNsense VM:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
I re-configured the WAN interface in OPNsense to use the newly added network device, and the download and upload speeds returned to the typical speeds. Another added benefit to this setup is that it bypasses the need for installing Realtek FreeBSD drivers on the OPNsense VM, since the network device is virtual and managed on the Proxmox host (debian-based).
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
Although I am not sure why passing through a Realtek NIC to an OPNsense VM causes so much degradation in throughput, I am glad that there is a workaround. If I get ahold of another NIC, I would be interested in trying to reproduce the issue.
|
After Width: | Height: | Size: 96 KiB |
BIN
content/blog/using-a-realtek-nic-with-opnsense/linux-bridge.png
Normal file
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 116 KiB |
@@ -1,55 +1,31 @@
|
||||
---
|
||||
title: "Using AKS and SOCKS to connect to a Private Azure DB"
|
||||
title: "Using AKS and SOCKS to connect to a private Azure DB"
|
||||
date: 2023-05-22T16:31:29-04:00
|
||||
lastmod: 2023-05-22T16:31:29-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
comments: true
|
||||
tags:
|
||||
[
|
||||
"azure",
|
||||
"database",
|
||||
"proxy",
|
||||
"socks",
|
||||
"aks",
|
||||
"k8s",
|
||||
"aws",
|
||||
"azure",
|
||||
"bastion",
|
||||
"eks",
|
||||
"cloud-sql-proxy",
|
||||
"database",
|
||||
"eks",
|
||||
"k8s",
|
||||
"kubectl-plugin-socks5-proxy",
|
||||
"proxy",
|
||||
"socat",
|
||||
"socks",
|
||||
]
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
I ran into a roadblock recently where I wanted to conveniently connect to a managed postgres database within Azure that was not running on public subnets. And by conveniently, I mean that I'd rather not have to spin up an ephemeral virtual machine running in the same network and proxy the connection, and I'd like to use a local client (preferably with a GUI). After several web searches, it became evident that Azure does not readily provide much tooling to support this.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## The Problem
|
||||
|
||||
I ran into a roadblock recently where I wanted to be able to conveniently connect to a managed postgres database within Azure that was not running on public subnets. And by conveniently, I mean that I'd rather not have to spin up an ephemeral virtual machine running in the same network and proxy the connection, and I'd like to use a local client (preferably with a GUI). After several web searches, it became evident that Azure does not readily provide much tooling to support this.
|
||||
|
||||
## Go Public?
|
||||
|
||||
Should the database be migrated to public subnets? Ideally not, since it is good practice to host internal infrastructure in restricted subnets.
|
||||
@@ -70,6 +46,10 @@ Because this adds cost (and complexity), it does not seem like a desirable optio
|
||||
|
||||
## SOCKS
|
||||
|
||||
> **2023-12-13:**
|
||||
> An alternative to using a socks proxy is [socat](http://www.dest-unreach.org/socat/). This would allow you to relay tcp connections to a pod running in k8s, and then port-forward them to your localhost.
|
||||
> If this sounds more appealing, install [krew-net-forward](https://github.com/antitree/krew-net-forward/tree/master) and then run "kubectl net-forward -i mydb.postgres.database.azure.com -p 5432 -l 5432" to access the database through "localhost:5432"
|
||||
|
||||
[SOCKS](https://en.wikipedia.org/wiki/SOCKS) is a protocol that enables a way to proxy connections by exchanging network packets between the client and the server. There are many implementations and many readily available container images that can run a SOCKS server.
|
||||
|
||||
It's possible to use this sort of proxy to connect to a private DB, but is it any simpler than using a virtual machine as a jumphost? It wasn't until I stumbled upon [kubectl-plugin-socks5-proxy](https://github.com/yokawasa/kubectl-plugin-socks5-proxy) that I was convinced that using SOCKS could be made simple.
|
||||
@@ -101,4 +81,6 @@ If these stars align, than this solution might work as a stopgap for accessing a
|
||||
|
||||
It would be nice if Azure provided tooling similar to cloud-sql-proxy, so that using private databases would be more of a convenient experience.
|
||||
|
||||
One other thing to note is that some clients (such as [dbeaver](https://dbeaver.io/)) [do not provide DNS resolution over SOCKS](https://github.com/dbeaver/dbeaver/issues/872). So in this case, you won't be able to use DNS as if you were inside the cluster, but instead have to rely on knowing private ip addresses.
|
||||
~~One other thing to note is that some clients (such as [dbeaver](https://dbeaver.io/)) [do not provide DNS resolution over SOCKS](https://github.com/dbeaver/dbeaver/issues/872). So in this case, you won't be able to use DNS as if you were inside the cluster, but instead have to rely on knowing private ip addresses.~~
|
||||
|
||||
> **2025-01-16:**: DNS over SOCKS now works with the latest dbeaver client.
|
@@ -1,49 +1,33 @@
|
||||
---
|
||||
title: "Virtualizing My Router With pfSense"
|
||||
title: "Virtualizing my router with pfSense"
|
||||
date: 2022-04-02T18:50:09-04:00
|
||||
lastmod: 2022-04-02T18:50:09-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ['pfsense', 'router', 'openwrt', 'router-on-a-stick', 'proxmox', 'vlan']
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
comments: true
|
||||
tags:
|
||||
[
|
||||
"pfsense",
|
||||
"router",
|
||||
"openwrt",
|
||||
"router-on-a-stick",
|
||||
"proxmox",
|
||||
"vlan",
|
||||
"self-hosted",
|
||||
]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
<!--more-->
|
||||
|
||||
## The problem
|
||||
|
||||
My aging router has been running [OpenWrt](https://en.wikipedia.org/wiki/OpenWrt) for years and for the most part has been quite reliable. OpenWrt is an open-source project used on embedded devices to route network traffic. It supports many different configurations and there exists a [large index of packages](https://openwrt.org/packages/index/start). Ever since I've connected some standalone wireless access points, I've had less of a need for an off-the-shelf all-in-one wireless router combo. I've also recently been experiencing instability with my router (likely the result of a combination of configuration tweaking and firmware updating). OpenWrt has served me well, but it is time to move on!
|
||||
|
||||
<!--more-->
|
||||
|
||||
## pfSense
|
||||
|
||||
I figured this would be a good opportunity to try [pfSense](https://en.wikipedia.org/wiki/PfSense). I've heard nothing but positive things about pfSense and the fact it's been around since 2004, based on FreeBSD, and written in PHP gave me the impression that it would be relatively stable (and I'd expect nothing less because it has an important job to do!). pfSense can be run on many different machines, and there are even some [officially supported appliances](https://www.netgate.com/appliances). Since I already have a machine running Proxmox, why not just run it in a VM? It'd allow for automatic snapshotting of the machine. There is a good [video](https://www.youtube.com/watch?v=hdoBQNI_Ab8) on this by Techno Tim. Tim has a lot of good videos, and this one is about virtualizing pfSense.
|
||||
|
||||
## Router on a stick
|
||||
|
||||
I had initially made the assumption that in order to build a router, you would need more than a single NIC (or a dual-port NIC) in order to support both WAN and LAN. This is simply [not the case](https://en.wikipedia.org/wiki/Router_on_a_stick), because VLANs are awesome! In order to create a router, all you need is a single port NIC and a network switch that supports VLANs (also marketed as a managed switch). I picked up the Netgear GS308E because it has both a sufficient amount of ports for my needs, and it supports VLANs. It also has a nice sturdy metal frame which was a pleasant surprise.
|
||||
I had initially made the assumption that in order to build a router, you would need more than a single NIC (or a dual-port NIC) in order to support both WAN and LAN. This is simply [not the case](https://en.wikipedia.org/wiki/Router_on_a_stick), because VLANs are awesome! In order to create a router, all you need is a single port NIC and a network switch that supports VLANs (also marketed as a managed switch). I picked up the Netgear GS308E because it has both a sufficient amount of ports for my needs, and it supports VLANs. It also has a nice sturdy metal frame which was a pleasant surprise.
|
||||
|
||||
After setting up this Netgear switch, it shoud be possible to access the web interface at [http://192.168.0.239](http://192.168.0.239). It may be at a different address. To find the address, try checking your DHCP leases in your router interface (if you plugged it into an existing router). I realized I was unable to access this interface because I was on a different subnet, so I set my machine's address to `192.168.0.22` in order to temporarily setup this switch. I assigned a static ip address to the switch (in `System > Switch Information`) so that it was in the same subnet as the rest of my network.
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 935 KiB After Width: | Height: | Size: 935 KiB |
@@ -1,40 +1,25 @@
|
||||
---
|
||||
title: "Watching YouTube in Private"
|
||||
title: "Watching YouTube in private"
|
||||
date: 2022-12-10T21:46:55-05:00
|
||||
lastmod: 2022-12-10T21:46:55-05:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ["invidious", "degoogle", "youtube", "yewtu.be", "tailscale", "privacy"]
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
comments: true
|
||||
tags:
|
||||
[
|
||||
"invidious",
|
||||
"youtube",
|
||||
"yewtu.be",
|
||||
"tailscale",
|
||||
"privacy",
|
||||
"self-hosted",
|
||||
]
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
I recently stumbled upon [yewtu.be](https://yewtu.be) and found it intriguing. It not only allows you to watch YouTube without _being on YouTube_, but it also allows you to create an account and subscribe to channels without a Google account. What sort of wizardry is going on under the hood? It turns out that it's a hosted instance of [invidious](https://invidious.io/).
|
||||
|
||||
<!--more-->
|
||||
|
||||

|
||||
|
||||
The layout is simple, and **JavaScript is not required**.
|
||||
@@ -47,13 +32,13 @@ A few days ago, yewtu.be went down briefly, and that motivated me enough to self
|
||||
|
||||
The quickest way to get invidious up is with docker-compose as mentioned in the [docs](https://docs.invidious.io/installation/).
|
||||
|
||||
I made a few modifications (such as pinning the container's tag), and ended up with:
|
||||
I made a few modifications, and ended up with:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
invidious:
|
||||
image: quay.io/invidious/invidious:5160d8bae39dc5cc5d51abee90571a03c08d0f2b
|
||||
image: quay.io/invidious/invidious
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "0.0.0.0:3000:3000"
|
||||
@@ -98,10 +83,32 @@ After invidious was up and running, I installed [Tailscale](https://tailscale.co
|
||||
|
||||
I figured it would be nice to redirect existing YouTube links that others send me, so that I could seamlessly watch the videos using invidious.
|
||||
|
||||
I went looking for a way to redirect paths at the browser level. I found the lightweight proxy [requestly](https://requestly.io/), which can be used to modify http requests in my browser. I created the following rules:
|
||||
I went looking for a way to redirect paths at the browser level. I found [Redirector](https://github.com/einaregilsson/Redirector), which can be used to modify http requests in the browser. I created the following redirect (exported as json):
|
||||
|
||||

|
||||
```json
|
||||
{
|
||||
"redirects": [
|
||||
{
|
||||
"description": "youtube to invidious",
|
||||
"exampleUrl": "https://www.youtube.com/watch?v=-lz30by8-sU",
|
||||
"exampleResult": "http://invidious:3000/watch?v=-lz30by8-sU",
|
||||
"error": null,
|
||||
"includePattern": "https://*youtube.com/*",
|
||||
"excludePattern": "",
|
||||
"patternDesc": "Any youtube video should redirect to invidious",
|
||||
"redirectUrl": "http://invidious:3000/$2",
|
||||
"patternType": "W",
|
||||
"processMatches": "noProcessing",
|
||||
"disabled": false,
|
||||
"grouped": false,
|
||||
"appliesTo": [
|
||||
"main_frame"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Now the link https://www.youtube.com/watch?v=-lz30by8-sU will redirect to [http://invidious:3000/watch?v=-lz30by8-sU](http://invidious:3000/watch?v=-lz30by8-sU)
|
||||
Now the link <https://www.youtube.com/watch?v=-lz30by8-sU> will redirect to [http://invidious:3000/watch?v=-lz30by8-sU](http://invidious:3000/watch?v=-lz30by8-sU)
|
||||
|
||||
I'm still looking for ways to improve this invidious setup. There doesn't appear to be a way to stream in 4K yet.
|
@@ -1,26 +1,27 @@
|
||||
---
|
||||
title: "What To Do With A Homelab"
|
||||
title: "What to do with a homelab"
|
||||
date: 2021-09-06T01:12:54-04:00
|
||||
lastmod: 2021-09-06T01:12:54-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
tags: ['tailscale', 'homelab', 'netdata', 'jellyfin', 'plex', 'pihole', 'virtualization', 'adguard', 'grafana']
|
||||
comments: true
|
||||
author: "Dave Gallant"
|
||||
tags: ["self-hosted", "proxmox", "tailscale"]
|
||||
---
|
||||
|
||||
A homelab can be an inexpensive way to host a multitude of internal/external services and learn *a lot* in the process.
|
||||
A homelab can be an inexpensive way to host a multitude of internal/external services and learn _a lot_ in the process.
|
||||
|
||||
<!--more-->
|
||||
Do you want host your own Media server? Ad blocker? Web server?
|
||||
|
||||
Do you want host your own media server? ad blocker? reverse proxy?
|
||||
Are you interested in learning more about Linux? Virtualization? Networking? Security?
|
||||
Building a homelab can be an entertaining playground to enhance your computer skills.
|
||||
A homelab can be a playground to enhance your computer skills, without worrying about breaking anything important.
|
||||
|
||||
One of the best parts about building a homelab is that it doesn't have to be a large investment in terms of hardware. One of the simplest ways to build a homelab is out of a [refurbished computer](https://ca.refurb.io/products/hp-800-g1-usff-intel-core-i5-4570s-16gb-ram-512gb-ssd-wifi-windows-10-pro?variant=33049503825943).
|
||||
Having multiple machines/nodes provides the advantage of increased redundancy, but starting out with a single node is enough to reap many of the benefits of having a homelab.
|
||||
|
||||
## Virtualization
|
||||
|
||||
Virtualizing your hardware is an organized way of dividing up your machine's resources. This can be done with something such as a *Virtual Machine* or something lighter like a container using *LXC* or *runC*.
|
||||
Virtualizing your hardware is an organized way of dividing up your machine's resources. This can be done with something such as a _Virtual Machine_ or something lighter like a container using _LXC_ or _runC_.
|
||||
Containers have much less overhead in terms of boot time and storage allocation. This [Stack Overflow answer](https://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-virtual-machine) sums it up nicely.
|
||||
|
||||

|
||||
@@ -29,20 +30,23 @@ A hypervisor such as [Proxmox](https://www.proxmox.com/en/proxmox-ve/get-started
|
||||
|
||||
## Services
|
||||
|
||||
So what are some useful services to deploy?
|
||||
Here is a list of some useful services to consider:
|
||||
|
||||
- [Jellyfin](https://jellyfin.org/) or [Plex](https://www.plex.tv/) - basically a self-hosted Netflix that can be used to stream from multiple devices, and the best part is that you manage the content! Unlike Plex, Jellyfin is open source and can be found [here](https://github.com/jellyfin/jellyfin).
|
||||
- [changedetection](https://github.com/dgtlmoon/changedetection.io) - is a self-hosted equivalent to something like [visualping.io](https://visualping.io/) that will notify you when a webpage changes and keep track of the diffs
|
||||
- [Adguard](https://github.com/AdguardTeam/AdGuardHome) or [Pihole](https://pi-hole.net/) - can block a list of known trackers for all clients on your local network. I've used pihole for a long time, but have recently switched to Adguard since the UI is more modern and it has the ability to toggle on/off a pre-defined list of services, including Netflix (this is useful if you have stealthy young kids). Either of these will speed up your internet experience, simply because you won't need to download all of the extra tracking bloat.
|
||||
- [Gitea](https://gitea.io/) - A lightweight git server. I use this to mirror git repos from GitHub, GitLab, etc.
|
||||
- [Homer](https://github.com/bastienwirtz/homer) - A customizable landing page for services you need to access (including the ability to quickly search).
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma) - A fancy tool for monitoring the uptime of services.
|
||||
- [Jellyfin](https://jellyfin.org/) or [Plex](https://www.plex.tv/) - a common gateway to self-hosting that enables a "self-hosted Netflix" experience that puts you in control of the content (guaranteed to make your partner and kids happy)
|
||||
- [changedetection](https://github.com/dgtlmoon/changedetection.io) - is a self-hosted equivalent to something like [visualping.io](https://visualping.io/) that can notify you when a webpage changes and keep track of the diffs
|
||||
- [Adguard](https://github.com/AdguardTeam/AdGuardHome) or [Pihole](https://pi-hole.net/) - can block a list of known trackers for all clients on your local network with the added benefit of speeding up web page load times
|
||||
- [gitea](https://gitea.io/) - A lightweight git server that can be used to mirror git repos and host private content
|
||||
- [miniflux](https://github.com/miniflux/v2) - a minimalist RSS reader
|
||||
- [gethomepage](https://github.com/gethomepage/homepage) - A customizable landing page for quick access to services with many supported widgets that can query APIs and display information
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma) - A tool for monitoring the uptime of services, with notification support
|
||||
- [Speedtest Tracker](https://github.com/alexjustesen/speedtest-tracker) - a way to monitor the performance of your internet connection and/or vpn connection
|
||||
- [Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF) - a self-hosted PDF manipulation tool that will keep your data private
|
||||
|
||||
There is a large number of services you can self-host, including your own applications that you might be developing. [awesome-self-hosted](https://github.com/awesome-selfhosted/awesome-selfhosted) provides a curated list of services that might be of interest to you.
|
||||
There is a large number of services you can self-host, including your own applications that you might be developing. Homelabbing allows you to have control over your data and services, and gives you the opportunity to be a software, network, and infrastructure engineer all at once.
|
||||
|
||||
## VPN
|
||||
|
||||
You could certainly setup and manage your own VPN by using something like [OpenVPN](https://openvpn.net/community-downloads/), but there is also something else you can try: [tailscale](https://tailscale.com/). It is a very quick way to create fully-encrypted connections between clients. With its [MagicDNS](https://tailscale.com/kb/1081/magicdns/), your can reference the names of machines like `homer` rather than using an IP address. By using this mesh-like VPN, you can easily create a secure tunnel to your homelab from anywhere.
|
||||
[Tailscale](https://tailscale.com/) is a quick way to create a flat network for all of your services. With its [MagicDNS](https://tailscale.com/kb/1081/magicdns/), your can reference the names of machines like `changedetection` rather than using an IP address, or managing DNS yourself. By using this mesh-like VPN, you can easily create a secure tunnel to your homelab from anywhere.
|
||||
|
||||
## Monitoring
|
||||
|
||||
@@ -59,3 +63,5 @@ As mentioned above, [Uptime Kuma](https://github.com/louislam/uptime-kuma) is a
|
||||
## In Summary
|
||||
|
||||
Building out a homelab can be a rewarding experience and it doesn't require buying a rack full of expensive servers to get a significant amount of utility. There are many services that you can run that require very minimal setup, making it possible to get a server up and running in a short period of time, with monitoring, and that can be securely connected to remotely.
|
||||
|
||||
If you're looking for a steady stream of ideas for your homelab, check out [selfhosted.show](https://selfhosted.show/).
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
BIN
content/blog/what-to-do-with-a-homelab/proxmox.png
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
content/blog/what-to-do-with-a-homelab/uptime-kuma.png
Normal file
After Width: | Height: | Size: 41 KiB |
@@ -1,39 +1,15 @@
|
||||
---
|
||||
title: "Why I Threw Out My Dotfiles"
|
||||
title: "Why I threw out my dotfiles"
|
||||
date: 2021-09-08T00:42:33-04:00
|
||||
lastmod: 2021-09-08T00:42:33-04:00
|
||||
draft: false
|
||||
keywords: []
|
||||
description: ""
|
||||
comments: true
|
||||
tags: ['nix', 'dotfiles', 'home-manager']
|
||||
categories: []
|
||||
author: ""
|
||||
|
||||
# You can also close(false) or open(true) something for this content.
|
||||
# P.S. comment can only be closed
|
||||
comment: false
|
||||
toc: false
|
||||
autoCollapseToc: false
|
||||
postMetaInFooter: false
|
||||
hiddenFromHomePage: false
|
||||
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
|
||||
contentCopyright: false
|
||||
reward: false
|
||||
mathjax: false
|
||||
mathjaxEnableSingleDollar: false
|
||||
|
||||
flowchartDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
sequenceDiagrams:
|
||||
enable: false
|
||||
options: ""
|
||||
|
||||
author: "Dave Gallant"
|
||||
---
|
||||
Over the years I have collected a number of dotfiles that I have shared across both Linux and macOS machines (`~/.zshrc`, `~/.config/git/config`, `~/.config/tmux/tmux.conf`, etc). I have tried several different ways to manage them, including [bare git repos](https://www.atlassian.com/git/tutorials/dotfiles) and utilities such as [GNU Stow](https://www.gnu.org/software/stow/). These solutions work well enough, but I have since found what I would consider a much better solution for organizing user configuration: [home-manager](https://github.com/nix-community/home-manager).
|
||||
|
||||
<!--more-->
|
||||
Over the years I have collected a number of dotfiles that I have shared across both Linux and macOS machines (`~/.zshrc`, `~/.config/git/config`, `~/.config/tmux/tmux.conf`, etc). I have tried several different ways to manage them, including [bare git repos](https://www.atlassian.com/git/tutorials/dotfiles) and utilities such as [GNU Stow](https://www.gnu.org/software/stow/). These solutions work well enough, but I have since found what I would consider a much better solution for organizing user configuration: [home-manager](https://github.com/nix-community/home-manager).
|
||||
|
||||
## What is home-manager?
|
||||
|
||||
@@ -206,3 +182,5 @@ In ways, home-manager can be seen as a gateway to the nix ecosystem. If you have
|
||||
## Wrapping up
|
||||
|
||||
The title of this post is slightly misleading, since it's possible to retain some of your dotfiles and have them intermingle with home-manager by including them alongside nix. The idea of defining user configuration using nix can provide a clean way to maintain your configuration, and allow it to be portable across platforms. Is it worth the effort to migrate away from shell scripts and dotfiles? I'd say so.
|
||||
|
||||
You can find my nix config [here](https://github.com/davegallant/nix-config).
|
@@ -1,9 +0,0 @@
|
||||
---
|
||||
type: page
|
||||
layout: search
|
||||
outputs:
|
||||
- html
|
||||
- json
|
||||
---
|
||||
|
||||
test
|
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 157 KiB |
Before Width: | Height: | Size: 117 KiB |
10
justfile
Normal file
@@ -0,0 +1,10 @@
|
||||
build: clean
|
||||
npm ci
|
||||
hugo --minify
|
||||
|
||||
clean:
|
||||
rm -rf public/
|
||||
|
||||
server: clean
|
||||
npm ci
|
||||
hugo server --buildDrafts
|
@@ -1,8 +1,19 @@
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://storage.ko-fi.com/cdn/widget/Widget_2.js"
|
||||
></script>
|
||||
<script type="text/javascript">
|
||||
kofiwidget2.init("Buy me a coffee", "#32344a", "F1F2S4LWI");
|
||||
kofiwidget2.draw();
|
||||
</script>
|
||||
|
||||
{{- $config := .Site.Params.comments -}}
|
||||
|
||||
{{- $utterancesEnabled := $config.utterances.enable -}}
|
||||
|
||||
{{- if and ( $utterancesEnabled ) ( not .Params.disable_comments) -}}
|
||||
{{- if $utterancesEnabled -}}
|
||||
<br>
|
||||
<br>
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'>
|
19
layouts/partials/comments/utterances.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{{- $scriptSrc := "https://utteranc.es/client.js" -}} {{- $issueTerm :=
|
||||
.Page.Site.Params.comments.utterances.issueTerm -}} {{- $label :=
|
||||
.Page.Site.Params.comments.utterances.label -}} {{- $username :=
|
||||
.Page.Site.Params.comments.utterances.github.username -}} {{- $repository :=
|
||||
.Page.Site.Params.comments.utterances.github.repository -}}
|
||||
|
||||
<script>
|
||||
// load comments
|
||||
let theme = "dark-blue";
|
||||
let script = document.createElement("script");
|
||||
script.src = "https://utteranc.es/client.js";
|
||||
script.setAttribute("repo", '{{ print $username "/" $repository }}');
|
||||
script.setAttribute("issue-term", "{{ $issueTerm }}");
|
||||
script.setAttribute("theme", theme);
|
||||
script.setAttribute("crossorigin", "anonymous");
|
||||
script.setAttribute("async", "");
|
||||
document.querySelector("div.comments").innerHTML = "";
|
||||
document.querySelector("div.comments").appendChild(script);
|
||||
</script>
|
9
layouts/partials/footer_end.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!-- Cloudflare Web Analytics -->
|
||||
<script
|
||||
defer
|
||||
src="https://static.cloudflareinsights.com/beacon.min.js"
|
||||
data-cf-beacon='{"token": "b96799f53f9940dca6f660e6052ba009"}'
|
||||
></script>
|
||||
<!-- End Cloudflare Web Analytics -->
|
||||
|
||||
{{ template "_internal/google_analytics.html" . }}
|
2
layouts/partials/head/head_end.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<!-- Umami Analytics -->
|
||||
<script defer src="https://umami.snake-cloud.ts.net/script.js" data-website-id="e8adafba-b892-4dad-a139-2bd61fe5fab9"></script>
|
6785
package-lock.json
generated
Normal file
35
package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@tabler/icons": "^2.44.0",
|
||||
"flexsearch": "^0.7.31",
|
||||
"normalize.css": "^8.0.1",
|
||||
"prism-themes": "^1.9.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"simple-icons": "^10.4.0",
|
||||
"typeface-fira-code": "^1.1.13",
|
||||
"typeface-roboto-slab": "^1.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^5.0.0",
|
||||
"cssnano": "^6.0.2",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.1",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^15.2.0",
|
||||
"markdownlint-cli": "^0.38.0",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"postcss-custom-media": "^10.0.2",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-nesting": "^12.0.2",
|
||||
"postcss-preset-env": "^9.3.0",
|
||||
"postcss-url": "^10.1.3",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-go-template": "^0.0.15",
|
||||
"stylelint": "^16.0.2",
|
||||
"stylelint-prettier": "^5.0.0"
|
||||
},
|
||||
"name": "davegallant.github.io",
|
||||
"version": "0.1.0"
|
||||
}
|
@@ -1 +0,0 @@
|
||||
davegallant.ca
|
@@ -1,141 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>About - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="I’m a software engineer with a passion for open-source, infrastructure, tooling and security." />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="About" />
|
||||
<meta property="og:description" content="I’m a software engineer with a passion for open-source, infrastructure, tooling and security." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/about/" /><meta property="article:section" content="" />
|
||||
|
||||
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="About"/>
|
||||
<meta name="twitter:description" content="I’m a software engineer with a passion for open-source, infrastructure, tooling and security."/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">About</h1>
|
||||
<div class="meta">Posted on Jan 1, 0001</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>I’m a software engineer with a passion for open-source, infrastructure, tooling and security.</p>
|
||||
</section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,269 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>AppGate SDP on Arch Linux - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux." />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="AppGate SDP on Arch Linux" />
|
||||
<meta property="og:description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2020/03/16/appgate-sdp-on-arch-linux/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2020-03-16T22:00:15-04:00" />
|
||||
<meta property="article:modified_time" content="2020-03-16T22:00:15-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="AppGate SDP on Arch Linux"/>
|
||||
<meta name="twitter:description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux."/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">AppGate SDP on Arch Linux</h1>
|
||||
<div class="meta">Posted on Mar 16, 2020</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP <code>4.3.2</code> working on Arch Linux.</p>
|
||||
<p>Depending on the AppGate SDP Server that is running, you may require a client that is more recent than the latest package on <a href="https://aur.archlinux.org/packages/appgate-sdp/">AUR</a>.
|
||||
As of right now, the latest AUR is <code>4.2.2-1</code>.</p>
|
||||
<p>These steps highlight how to get it working with <code>Python3.8</code> by making a 1 line modification to AppGate source code.</p>
|
||||
<h1 id="packaging">Packaging</h1>
|
||||
<p>We already know the community package is currently out of date, so let’s clone it:</p>
|
||||
<pre><code class="language-shell">git clone https://aur.archlinux.org/appgate-sdp.git
|
||||
cd appgate-sdp
|
||||
</code></pre>
|
||||
<p>You’ll likely notice that the version is not what we want, so let’s modify the <code>PKGBUILD</code> to the following:</p>
|
||||
<pre><code class="language-shell"># Maintainer: Pawel Mosakowski <pawel at mosakowski dot net>
|
||||
pkgname=appgate-sdp
|
||||
conflicts=('appgate-sdp-headless')
|
||||
pkgver=4.3.2
|
||||
_download_pkgver=4.3
|
||||
pkgrel=1
|
||||
epoch=
|
||||
pkgdesc="Software Defined Perimeter - GUI client"
|
||||
arch=('x86_64')
|
||||
url="https://www.cyxtera.com/essential-defense/appgate-sdp/support"
|
||||
license=('custom')
|
||||
# dependecies calculated by namcap
|
||||
depends=('gconf' 'libsecret' 'gtk3' 'python' 'nss' 'libxss' 'nodejs' 'dnsmasq')
|
||||
source=("https://sdpdownloads.cyxtera.com/AppGate-SDP-${_download_pkgver}/clients/${pkgname}_${pkgver}_amd64.deb"
|
||||
"appgatedriver.service")
|
||||
options=(staticlibs)
|
||||
prepare() {
|
||||
tar -xf data.tar.xz
|
||||
}
|
||||
package() {
|
||||
cp -dpr "${srcdir}"/{etc,lib,opt,usr} "${pkgdir}"
|
||||
mv -v "$pkgdir/lib/systemd/system" "$pkgdir/usr/lib/systemd/"
|
||||
rm -vrf "$pkgdir/lib"
|
||||
cp -v "$srcdir/appgatedriver.service" "$pkgdir/usr/lib/systemd/system/appgatedriver.service"
|
||||
mkdir -vp "$pkgdir/usr/share/licenses/appgate-sdp"
|
||||
cp -v "$pkgdir/usr/share/doc/appgate/copyright" "$pkgdir/usr/share/licenses/appgate-sdp"
|
||||
cp -v "$pkgdir/usr/share/doc/appgate/LICENSE.github" "$pkgdir/usr/share/licenses/appgate-sdp"
|
||||
cp -v "$pkgdir/usr/share/doc/appgate/LICENSES.chromium.html.bz2" "$pkgdir/usr/share/licenses/appgate-sdp"
|
||||
}
|
||||
md5sums=('17101aac7623c06d5fbb95f50cf3dbdc'
|
||||
'002644116e20b2d79fdb36b7677ab4cf')
|
||||
|
||||
</code></pre>
|
||||
<p>Let’s first make sure we have some dependencies. If you do not have <a href="https://github.com/Jguer/yay">yay</a>, check it out.</p>
|
||||
<pre><code class="language-shell">yay -S dnsmasq gconf
|
||||
</code></pre>
|
||||
<p>Now, let’s install it:</p>
|
||||
<pre><code class="language-shell">makepkg -si
|
||||
</code></pre>
|
||||
<h1 id="running-the-client">Running the client</h1>
|
||||
<p>Ok, let’s run the client by executing <code>appgate</code>.</p>
|
||||
<p>It complains about not being able to connect.</p>
|
||||
<p>Easy fix:</p>
|
||||
<pre><code class="language-shell">sudo systemctl start appgatedriver.service
|
||||
</code></pre>
|
||||
<p>Now we should be connected… but DNS is not working?</p>
|
||||
<h1 id="fixing-the-dns">Fixing the DNS</h1>
|
||||
<p>Running <code>resolvectl</code> should display that something is not right.</p>
|
||||
<p>Why is the DNS not being set by appgate?</p>
|
||||
<pre><code class="language-shell">$ head -3 /opt/appgate/linux/set_dns
|
||||
#!/usr/bin/env python3
|
||||
'''
|
||||
This is used to set and unset the DNS.
|
||||
</code></pre>
|
||||
<p>It seems like python3 is required for the DNS setting to happen.
|
||||
Let’s try to run it.</p>
|
||||
<pre><code class="language-shell">$ sudo /opt/appgate/linux/set_dns
|
||||
/opt/appgate/linux/set_dns:88: SyntaxWarning: "is" with a literal. Did you mean "=="?
|
||||
servers = [( socket.AF_INET if x.version is 4 else socket.AF_INET6, map(int, x.packed)) for x in servers]
|
||||
Traceback (most recent call last):
|
||||
File "/opt/appgate/linux/set_dns", line 30, in <module>
|
||||
import dbus
|
||||
ModuleNotFoundError: No module named 'dbus'
|
||||
</code></pre>
|
||||
<p>Ok, let’s install it:</p>
|
||||
<pre><code class="language-shell">$ sudo python3.8 -m pip install dbus-python
|
||||
</code></pre>
|
||||
<p>Will it work now? Not yet. There’s another issue:</p>
|
||||
<pre><code class="language-shell">$ sudo /opt/appgate/linux/set_dns
|
||||
/opt/appgate/linux/set_dns:88: SyntaxWarning: "is" with a literal. Did you mean "=="?
|
||||
servers = [( socket.AF_INET if x.version is 4 else socket.AF_INET6, map(int, x.packed)) for x in servers]
|
||||
module 'platform' has no attribute 'linux_distribution'
|
||||
</code></pre>
|
||||
<p>This is a breaking change in Python3.8.</p>
|
||||
<p>So what is calling <code>platform.linux_distribution</code>?</p>
|
||||
<p>Let’s search for it:</p>
|
||||
<pre><code class="language-shell">$ sudo grep -r 'linux_distribution' /opt/appgate/linux/
|
||||
/opt/appgate/linux/nm.py: if platform.linux_distribution()[0] != 'Fedora':
|
||||
</code></pre>
|
||||
<p>Aha! So this is in the local AppGate source code. This should be an easy fix. Let’s just replace this line with:</p>
|
||||
<pre><code class="language-python">if True: # Since we are not using Fedora :)
|
||||
</code></pre>
|
||||
<h1 id="wrapping-up">Wrapping up</h1>
|
||||
<p>It turns out there are <a href="https://docs.python.org/3.7/library/platform.html#platform.linux_distribution">breaking changes</a> in Python3.8.</p>
|
||||
<p>The docs say <code>Deprecated since version 3.5, will be removed in version 3.8: See alternative like the distro package.</code></p>
|
||||
<p>I suppose this highlights one of the caveats of relying upon the system’s python, rather than having an isolated, dedicated environment for all dependencies.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/linux">linux</a></li>
|
||||
|
||||
<li><a href="/tags/vpn">vpn</a></li>
|
||||
|
||||
<li><a href="/tags/python">python</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,217 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>What To Do With A Homelab - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process." />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="What To Do With A Homelab" />
|
||||
<meta property="og:description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2021/09/06/what-to-do-with-a-homelab/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-06T01:12:54-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-06T01:12:54-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="What To Do With A Homelab"/>
|
||||
<meta name="twitter:description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process."/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">What To Do With A Homelab</h1>
|
||||
<div class="meta">Posted on Sep 6, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>A homelab can be an inexpensive way to host a multitude of internal/external services and learn <em>a lot</em> in the process.</p>
|
||||
<p>Do you want host your own Media server? Ad blocker? Web server?
|
||||
Are you interested in learning more about Linux? Virtualization? Networking? Security?
|
||||
Building a homelab can be an entertaining playground to enhance your computer skills.</p>
|
||||
<p>One of the best parts about building a homelab is that it doesn’t have to be a large investment in terms of hardware. One of the simplest ways to build a homelab is out of a <a href="https://ca.refurb.io/products/hp-800-g1-usff-intel-core-i5-4570s-16gb-ram-512gb-ssd-wifi-windows-10-pro?variant=33049503825943">refurbished computer</a>.
|
||||
Having multiple machines/nodes provides the advantage of increased redundancy, but starting out with a single node is enough to reap many of the benefits of having a homelab.</p>
|
||||
<h2 id="virtualization">Virtualization<a href="#virtualization" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Virtualizing your hardware is an organized way of dividing up your machine’s resources. This can be done with something such as a <em>Virtual Machine</em> or something lighter like a container using <em>LXC</em> or <em>runC</em>.
|
||||
Containers have much less overhead in terms of boot time and storage allocation. This <a href="https://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-virtual-machine">Stack Overflow answer</a> sums it up nicely.</p>
|
||||
<p><img src="proxmox.png" alt="image"></p>
|
||||
<p>A hypervisor such as <a href="https://www.proxmox.com/en/proxmox-ve/get-started">Proxmox</a> can be installed in minutes on a new machine. It provides a web interface and a straight-forward way to spin up new VMs and containers. Even if your plan is to run mostly docker containers, Proxmox can be a useful abstraction for managing VMs, disks and running scheduled backups. You can even run docker within an LXC container by enabling nested virtualization. You’ll want to ensure that VT-d and VT-x are enabled in the BIOS if you decide to install a hypervisor to manage your virtualization.</p>
|
||||
<h2 id="services">Services<a href="#services" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>So what are some useful services to deploy?</p>
|
||||
<ul>
|
||||
<li><a href="https://jellyfin.org/">Jellyfin</a> or <a href="https://www.plex.tv/">Plex</a> - basically a self-hosted Netflix that can be used to stream from multiple devices, and the best part is that you manage the content! Unlike Plex, Jellyfin is open source and can be found <a href="https://github.com/jellyfin/jellyfin">here</a>.</li>
|
||||
<li><a href="https://github.com/dgtlmoon/changedetection.io">changedetection</a> - is a self-hosted equivalent to something like <a href="https://visualping.io/">visualping.io</a> that will notify you when a webpage changes and keep track of the diffs</li>
|
||||
<li><a href="https://github.com/AdguardTeam/AdGuardHome">Adguard</a> or <a href="https://pi-hole.net/">Pihole</a> - can block a list of known trackers for all clients on your local network. I’ve used pihole for a long time, but have recently switched to Adguard since the UI is more modern and it has the ability to toggle on/off a pre-defined list of services, including Netflix (this is useful if you have stealthy young kids). Either of these will speed up your internet experience, simply because you won’t need to download all of the extra tracking bloat.</li>
|
||||
<li><a href="https://gitea.io/">Gitea</a> - A lightweight git server. I use this to mirror git repos from GitHub, GitLab, etc.</li>
|
||||
<li><a href="https://github.com/bastienwirtz/homer">Homer</a> - A customizable landing page for services you need to access (including the ability to quickly search).</li>
|
||||
<li><a href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> - A fancy tool for monitoring the uptime of services.</li>
|
||||
</ul>
|
||||
<p>There is a large number of services you can self-host, including your own applications that you might be developing. <a href="https://github.com/awesome-selfhosted/awesome-selfhosted">awesome-self-hosted</a> provides a curated list of services that might be of interest to you.</p>
|
||||
<h2 id="vpn">VPN<a href="#vpn" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>You could certainly setup and manage your own VPN by using something like <a href="https://openvpn.net/community-downloads/">OpenVPN</a>, but there is also something else you can try: <a href="https://tailscale.com/">tailscale</a>. It is a very quick way to create fully-encrypted connections between clients. With its <a href="https://tailscale.com/kb/1081/magicdns/">MagicDNS</a>, your can reference the names of machines like <code>homer</code> rather than using an IP address. By using this mesh-like VPN, you can easily create a secure tunnel to your homelab from anywhere.</p>
|
||||
<h2 id="monitoring">Monitoring<a href="#monitoring" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p><img src="netdata.png" alt="dashboard"></p>
|
||||
<p>Monitoring can become an important aspect of your homelab after it starts to become something that is relied upon. One of the simplest ways to setup some monitoring is using <a href="https://www.netdata.cloud/">netdata</a>. It can be installed on individual containers, VMs, and also a hypervisor (such as Proxmox). All of the monitoring works out of the box by detecting disks, memory, network interfaces, etc.</p>
|
||||
<p>Additionally, agents installed on different machines can all be centrally viewed in netdata, and it can alert you when some of your infrastructure is down or in a degraded state. Adding additional nodes to netdata is as simple as a 1-line shell command.</p>
|
||||
<p>As mentioned above, <a href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> is a convenient way to track uptime and monitor the availability of your services.</p>
|
||||
<p><img src="uptime-kuma.png" alt="uptime-kuma"></p>
|
||||
<h2 id="in-summary">In Summary<a href="#in-summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Building out a homelab can be a rewarding experience and it doesn’t require buying a rack full of expensive servers to get a significant amount of utility. There are many services that you can run that require very minimal setup, making it possible to get a server up and running in a short period of time, with monitoring, and that can be securely connected to remotely.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/tailscale">tailscale</a></li>
|
||||
|
||||
<li><a href="/tags/homelab">homelab</a></li>
|
||||
|
||||
<li><a href="/tags/netdata">netdata</a></li>
|
||||
|
||||
<li><a href="/tags/jellyfin">jellyfin</a></li>
|
||||
|
||||
<li><a href="/tags/plex">plex</a></li>
|
||||
|
||||
<li><a href="/tags/pihole">pihole</a></li>
|
||||
|
||||
<li><a href="/tags/virtualization">virtualization</a></li>
|
||||
|
||||
<li><a href="/tags/adguard">adguard</a></li>
|
||||
|
||||
<li><a href="/tags/grafana">grafana</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 157 KiB |
Before Width: | Height: | Size: 117 KiB |
@@ -1,313 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Why I Threw Out My Dotfiles - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Why I Threw Out My Dotfiles" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2021/09/08/why-i-threw-out-my-dotfiles/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-08T00:42:33-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-08T00:42:33-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Why I Threw Out My Dotfiles"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Why I Threw Out My Dotfiles</h1>
|
||||
<div class="meta">Posted on Sep 8, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>Over the years I have collected a number of dotfiles that I have shared across both Linux and macOS machines (<code>~/.zshrc</code>, <code>~/.config/git/config</code>, <code>~/.config/tmux/tmux.conf</code>, etc). I have tried several different ways to manage them, including <a href="https://www.atlassian.com/git/tutorials/dotfiles">bare git repos</a> and utilities such as <a href="https://www.gnu.org/software/stow/">GNU Stow</a>. These solutions work well enough, but I have since found what I would consider a much better solution for organizing user configuration: <a href="https://github.com/nix-community/home-manager">home-manager</a>.</p>
|
||||
<h2 id="what-is-home-manager">What is home-manager?<a href="#what-is-home-manager" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Before understanding home-manager, it is worth briefly discussing what nix is. <a href="https://nixos.org/">nix</a> is a package manager that originally spawned from a <a href="https://edolstra.github.io/pubs/phd-thesis.pdf">PhD thesis</a>. Unlike other package managers, it uses symbolic links to keep track of the currently installed packages, keeping around the old ones in case you may want to rollback.</p>
|
||||
<p>For example, I have used nix to install the package <a href="https://search.nixos.org/packages?channel=unstable&show=bind&from=0&size=50&sort=relevance&type=packages&query=bind">bind</a> which includes <code>dig</code>. You can see that it is available on multiple platforms. The absolute path of <code>dig</code> can be found by running:</p>
|
||||
<pre><code class="language-console">$ ls -lh $(which dig)
|
||||
lrwxr-xr-x 73 root 31 Dec 1969 /run/current-system/sw/bin/dig -> /nix/store/0r4qdyprljd3dki57jn6c6a8dh2rbg9g-bind-9.16.16-dnsutils/bin/dig
|
||||
</code></pre>
|
||||
<p>Notice that there is a hash included in the file path? This is a nix store path and is computed by the nix package manager. This <a href="https://nixos.org/guides/nix-pills/nix-store-paths.html">nix pill</a> does a good job explaining how this hash is computed. All of the nix pills are worth a read, if you are interested in learning more about nix itself. However, using home-manager does not require extensive knowledge of nix.</p>
|
||||
<p>Part of the nix ecosystem includes <a href="https://github.com/NixOS/nixpkgs">nixpkgs</a>. Many popular tools can be found already packaged in this repository. As you can see with these <a href="https://repology.org/repositories/statistics/total">stats</a>, there is a large number of existing packages that are being maintained by the community. Contributing a new package is easy, and anyone can do it!</p>
|
||||
<p>home-manager leverages the nix package manager (and nixpkgs), as well the nix language so that you can declaratively define your system configuration. I store my <a href="https://github.com/davegallant/nix-config">nix-config</a> in git so that I can keep track of my packages and configurations, and retain a clean and informative git commit history so that I can understand what changed and why.</p>
|
||||
<h2 id="setting-up-home-manager">Setting up home-manager<a href="#setting-up-home-manager" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<blockquote>
|
||||
<p>⚠️ If you run this on your main machine, make sure you backup your configuration files first. home-manager is pretty good about not overwriting existing configuration, but it is better to have a backup! Alternatively, you could test this out on a VM or cloud instance.</p>
|
||||
</blockquote>
|
||||
<p>The first thing you should do is <a href="https://nixos.org/guides/install-nix.html">install nix</a>:</p>
|
||||
<pre><code class="language-shell">curl -L https://nixos.org/nix/install | sh
|
||||
</code></pre>
|
||||
<p>It’s generally not a good idea to curl and execute files from the internet (without verifying integrity), so you might want to download the install script first and take a look before executing it!</p>
|
||||
<p>Open up a new shell in your terminal and running <code>nix</code> <em>should</em> work. If not, run <code>. ~/.nix-profile/etc/profile.d/nix.sh</code></p>
|
||||
<p>Now, <a href="https://github.com/nix-community/home-manager#installation">install home-manager</a>:</p>
|
||||
<pre><code class="language-shell">nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
|
||||
nix-channel --update
|
||||
nix-shell '<home-manager>' -A install
|
||||
</code></pre>
|
||||
<p>You should see a wave of <code>/nix/store/*</code> paths being displayed on your screen.</p>
|
||||
<p>Now, to start off with a basic configuration, open up <code>~/.config/nixpkgs/home.nix</code> in the editor of your choice and paste this in (you will want to change <code>userName</code> and <code>homeDirectory</code>):</p>
|
||||
<pre><code class="language-nix">{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
home = {
|
||||
username = "dave";
|
||||
homeDirectory = "/home/dave";
|
||||
stateVersion = "21.11";
|
||||
packages = with pkgs; [
|
||||
bind
|
||||
exa
|
||||
fd
|
||||
ripgrep
|
||||
];
|
||||
};
|
||||
|
||||
programs = {
|
||||
|
||||
git = {
|
||||
enable = true;
|
||||
aliases = {
|
||||
aa = "add -A .";
|
||||
br = "branch";
|
||||
c = "commit -S";
|
||||
ca = "commit -S --amend";
|
||||
cb = "checkout -b";
|
||||
co = "checkout";
|
||||
d = "diff";
|
||||
l =
|
||||
"log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
|
||||
};
|
||||
|
||||
delta = {
|
||||
enable = true;
|
||||
|
||||
options = {
|
||||
features = "line-numbers decorations";
|
||||
whitespace-error-style = "22 reverse";
|
||||
plus-style = "green bold ul '#198214'";
|
||||
decorations = {
|
||||
commit-decoration-style = "bold yellow box ul";
|
||||
file-style = "bold yellow ul";
|
||||
file-decoration-style = "none";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = {
|
||||
push = { default = "current"; };
|
||||
pull = { rebase = true; };
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
starship = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
|
||||
settings = {
|
||||
add_newline = false;
|
||||
scan_timeout = 10;
|
||||
};
|
||||
};
|
||||
|
||||
zsh = {
|
||||
enable = true;
|
||||
enableAutosuggestions = true;
|
||||
enableSyntaxHighlighting = true;
|
||||
history.size = 1000000;
|
||||
|
||||
localVariables = {
|
||||
CASE_SENSITIVE = "true";
|
||||
DISABLE_UNTRACKED_FILES_DIRTY = "true";
|
||||
RPROMPT = ""; # override because macOS defaults to filepath
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE = "fg=#838383,underline";
|
||||
ZSH_DISABLE_COMPFIX = "true";
|
||||
};
|
||||
|
||||
initExtra = ''
|
||||
export PAGER=less
|
||||
'';
|
||||
|
||||
shellAliases = {
|
||||
".." = "cd ..";
|
||||
grep = "rg --smart-case";
|
||||
ls = "exa -la --git";
|
||||
};
|
||||
|
||||
"oh-my-zsh" = {
|
||||
enable = true;
|
||||
plugins = [
|
||||
"gitfast"
|
||||
"last-working-dir"
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
</code></pre>
|
||||
<p>Save the file and run:</p>
|
||||
<pre><code>home-manager switch
|
||||
</code></pre>
|
||||
<p>You should see another wave of <code>/nix/store/*</code> paths. The new configuration should now be active.</p>
|
||||
<p>If you run <code>zsh</code>, you should see that you have <a href="https://starship.rs/">starship</a> and access to several other utils such as <code>rg</code>, <code>fd</code>, and <code>exa</code>.</p>
|
||||
<p>This basic configuration above is also defining your <code>~/.config/git/config</code> and <code>.zshrc</code>. If you already have either of these files, home-manager will complain about them already existing.</p>
|
||||
<p>If you run <code>cat ~/.zshrc</code>, you will see the way these configuration files are generated.</p>
|
||||
<p>You can extend this configuration for programs such as (neo)vim, emacs, alacritty, ssh, etc. To see other programs, take a look at <a href="https://github.com/nix-community/home-manager/tree/master/modules/programs">home-manager/modules/programs</a>.</p>
|
||||
<h2 id="gateway-to-nix">Gateway To Nix<a href="#gateway-to-nix" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>In ways, home-manager can be seen as a gateway to the nix ecosystem. If you have enjoyed the way you can declare user configuration with home-manager, you may be interested in expanding your configuration to include other system dependencies and configuration. For example, in Linux you can define your entire system’s configuration (including the kernel, kernel modules, networking, filesystems, etc) in nix. For macOS, there is <a href="https://github.com/LnL7/nix-darwin">nix-darwin</a> that includes nix modules for configuring launchd, dock, and other preferences and services. You may also want to check out <a href="https://nixos.wiki/wiki/Flakes">Nix Flakes</a>: a more recent feature that allows you declare dependencies, and have them automatically pinned and hashed in <code>flake.lock</code>, similar to that of many modern package managers.</p>
|
||||
<h2 id="wrapping-up">Wrapping up<a href="#wrapping-up" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>The title of this post is slightly misleading, since it’s possible to retain some of your dotfiles and have them intermingle with home-manager by including them alongside nix. The idea of defining user configuration using nix can provide a clean way to maintain your configuration, and allow it to be portable across platforms. Is it worth the effort to migrate away from shell scripts and dotfiles? I’d say so.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/nix">nix</a></li>
|
||||
|
||||
<li><a href="/tags/dotfiles">dotfiles</a></li>
|
||||
|
||||
<li><a href="/tags/home-manager">home-manager</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,177 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Automatically Rotating AWS Access Keys - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Automatically Rotating AWS Access Keys" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2021/09/17/automatically-rotating-aws-access-keys/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-17T12:48:33-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-17T12:48:33-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Automatically Rotating AWS Access Keys"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Automatically Rotating AWS Access Keys</h1>
|
||||
<div class="meta">Posted on Sep 17, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>Rotating credentials is a security best practice. This morning, I read a question about automatically rotating AWS Access Keys without having to go through the hassle of navigating the AWS console. There are some existing solutions already, but I decided to write a <a href="https://gist.github.com/davegallant/2c042686a78684a657fe99e20fa7a924#file-aws_access_key_rotator-py">script</a> since it was incredibly simple. The script could be packed up as a systemd/launchd service to continually rotate access keys in the background.</p>
|
||||
<p>In the longer term, migrating my local workflows to <a href="https://github.com/99designs/aws-vault">aws-vault</a> seems like a more secure solution. This would mean that credentials (even temporary session credentials) never have to be written in plaintext to disk (i.e. where <a href="https://docs.aws.amazon.com/sdkref/latest/guide/file-location.html">AWS suggests</a>). Any existing applications, such as terraform, could be have their credentials passed to them from aws-vault, which retrieves them from the OS’s secure keystore. There is even a <a href="https://github.com/99designs/aws-vault/blob/master/USAGE.md#rotating-credentials">rotate command</a> included.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/aws">aws</a></li>
|
||||
|
||||
<li><a href="/tags/python">python</a></li>
|
||||
|
||||
<li><a href="/tags/security">security</a></li>
|
||||
|
||||
<li><a href="/tags/aws-vault">aws-vault</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,264 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Replacing docker with podman on macOS (and Linux) - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Replacing docker with podman on macOS (and Linux)" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2021/10/11/replacing-docker-with-podman-on-macos-and-linux/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-10-11T10:43:35-04:00" />
|
||||
<meta property="article:modified_time" content="2021-10-11T10:43:35-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Replacing docker with podman on macOS (and Linux)"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Replacing docker with podman on macOS (and Linux)</h1>
|
||||
<div class="meta">Posted on Oct 11, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>There are a number of reasons why you might want to replace docker, especially on macOS. The following feature bundled in Docker Desktop might have motivated you enough to consider replacing docker:</p>
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">...ignoring Docker updates is a paid feature now?? <a href="https://t.co/ZxKW3b9LQM">pic.twitter.com/ZxKW3b9LQM</a></p>— Brendan Dolan-Gavitt (@moyix) <a href="https://twitter.com/moyix/status/1388586550682861568?ref_src=twsrc%5Etfw">May 1, 2021</a></blockquote>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
|
||||
<p>Docker has been one of the larger influencers in the container world, helping to standardize the <a href="https://github.com/opencontainers/image-spec/blob/main/spec.md">OCI Image Format Specification</a>. For many developers, containers have become synonymous with terms like <code>docker</code> and <code>Dockerfile</code> (a file containing build instructions for a container image). Docker has certainly made it very convenient to build and run containers, but it is not the only solution for doing so.</p>
|
||||
<p>This post briefly describes my experience swapping out docker for podman on macOS.</p>
|
||||
<h3 id="what-is-a-container">What is a container?<a href="#what-is-a-container" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>A container is a standard unit of software that packages up all application dependencies within it. Multiple containers can be run on a host machine all sharing the same kernel as the host. Linux namespaces help provide an isolated view of the system, including mnt, pid, net, ipc, uid, cgroup, and time. There is an <a href="https://www.youtube.com/watch?v=sK5i-N34im8">in-depth video</a> that discusses what containers are made from, and <a href="https://youtu.be/sK5i-N34im8?t=2468">near the end</a> there is a demonstration on how to build your own containers from the command line.</p>
|
||||
<p>By easily allowing the necessary dependencies to live alongside the application code, containers make the “works on my machine” problem less of a problem.</p>
|
||||
<h3 id="benefits-of-podman">Benefits of Podman<a href="#benefits-of-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>One of the most interesting features of Podman is that it is daemonless. There isn’t a process running on your system managing your containers. In contrast, the docker client is reliant upon the docker daemon (often running as root) to be able to build and run containers.</p>
|
||||
<p>Podman is rootless by default. It is now possible to <a href="https://docs.docker.com/engine/security/rootless/">run the docker daemon rootless</a> as well, but it’s still not the default behaviour.</p>
|
||||
<p>I’ve also observed that so far my 2019 16" Macbook Pro hasn’t sounded like a jet engine, although I haven’t performed any disk-intensive operations yet.</p>
|
||||
<h3 id="installing-podman">Installing Podman<a href="#installing-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Running Podman on macOS is more involved than on Linux, because the podman-machine must run Linux inside of a virtual machine. Fortunately, the installation is made simple with <a href="https://formulae.brew.sh/formula/podman">brew</a> (read <a href="https://podman.io/getting-started/installation#linux-distributions">this</a> if you’re installing Podman on Linux):</p>
|
||||
<pre><code class="language-sh">brew install podman
|
||||
</code></pre>
|
||||
<p>The podman-machine must be started:</p>
|
||||
<pre><code class="language-sh"># This is not necessary on Linux
|
||||
podman machine init
|
||||
podman machine start
|
||||
</code></pre>
|
||||
<h3 id="running-a-container">Running a container<a href="#running-a-container" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Let’s try to pull an image:</p>
|
||||
<pre><code class="language-console">$ podman pull alpine
|
||||
Trying to pull docker.io/library/alpine:latest...
|
||||
Getting image source signatures
|
||||
Copying blob sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e
|
||||
Copying config sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
|
||||
Writing manifest to image destination
|
||||
Storing signatures
|
||||
14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>If you’re having an issue pulling images, you may need to remove <code>~/.docker/config.json</code> or remove the set of auths in the configuration as mentioned <a href="https://stackoverflow.com/a/69121873/1191286">here</a>.</p>
|
||||
</blockquote>
|
||||
<p>and then run and exec into the container:</p>
|
||||
<pre><code class="language-console">$ podman run --rm -ti alpine
|
||||
Error: error preparing container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b for attach: error configuring network namespace for container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b: error adding pod unruffled_bohr_unruffled_bohr to CNI network "podman": unexpected end of JSON input
|
||||
</code></pre>
|
||||
<p>What does this error mean? A bit of searching lead to <a href="https://github.com/containers/podman/issues/11837">this github issue</a>.</p>
|
||||
<p>Until the fix is released, a workaround is to just specify a port (even when it’s not needed):</p>
|
||||
<pre><code class="language-sh">podman run -p 4242 --rm -ti alpine
|
||||
</code></pre>
|
||||
<p>If you’re reading this from the future, there is a good chance specifying a port won’t be needed.</p>
|
||||
<p>Another example of running a container with Podman can be found in the <a href="https://jellyfin.org/docs/general/administration/installing.html#podman">Jellyfin Documentation</a>.</p>
|
||||
<h3 id="aliasing-docker-with-podman">Aliasing docker with podman<a href="#aliasing-docker-with-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Force of habit (or other scripts) may have you calling <code>docker</code>. To work around this:</p>
|
||||
<pre><code class="language-sh">alias docker=podman
|
||||
</code></pre>
|
||||
<h3 id="podman-compose">podman-compose<a href="#podman-compose" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>You may be wondering: what about docker-compose? Well, there <em>claims</em> to be a drop-in replacement for it: <a href="https://github.com/containers/podman-compose">podman-compose</a>.</p>
|
||||
<pre><code class="language-sh">pip3 install --user podman-compose
|
||||
</code></pre>
|
||||
<p>Now let’s create a <code>docker-compose.yml</code> file to test:</p>
|
||||
<pre><code class="language-sh">cat << EOF >> docker-compose.yml
|
||||
version: '2'
|
||||
services:
|
||||
hello_world:
|
||||
image: ubuntu
|
||||
command: [/bin/echo, 'Hello world']
|
||||
EOF
|
||||
</code></pre>
|
||||
<p>Now run:</p>
|
||||
<pre><code class="language-console">$ podman-compose up
|
||||
podman pod create --name=davegallant.github.io --share net
|
||||
40d61dc6e95216c07d2b21cea6dcb30205bfcaf1260501fe652f05bddf7e595e
|
||||
0
|
||||
podman create --name=davegallant.github.io_hello_world_1 --pod=davegallant.github.io -l io.podman.compose.config-hash=123 -l io.podman.compose.project=davegallant.github.io -l io.podman.compose.version=0.0.1 -l com.docker.compose.container-number=1 -l com.docker.compose.service=hello_world --add-host hello_world:127.0.0.1 --add-host davegallant.github.io_hello_world_1:127.0.0.1 ubuntu /bin/echo Hello world
|
||||
Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
|
||||
Trying to pull docker.io/library/ubuntu:latest...
|
||||
Getting image source signatures
|
||||
Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
|
||||
Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
|
||||
Copying config sha256:597ce1600cf4ac5f449b66e75e840657bb53864434d6bd82f00b172544c32ee2
|
||||
Writing manifest to image destination
|
||||
Storing signatures
|
||||
1a68b2fed3fdf2037b7aef16d770f22929eec1d799219ce30541df7876918576
|
||||
0
|
||||
podman start -a davegallant.github.io_hello_world_1
|
||||
Hello world
|
||||
</code></pre>
|
||||
<p>This should more or less provide the same results you would come to expect with docker. The README does clearly state that podman-compose is under development.</p>
|
||||
<h3 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Installing Podman on macOS was not seamless, but it was manageable well within 30 minutes. I would recommend giving Podman a try to anyone who is unhappy with experiencing forced docker updates, or who is interested in using a more modern technology for running containers.</p>
|
||||
<p>One caveat to mention is that there isn’t an official graphical user interface for Podman, but there is an <a href="https://github.com/containers/podman/issues/11494">open issue</a> considering one. If you rely heavily on Docker Desktop’s UI, you may not be as interested in using podman yet.</p>
|
||||
<blockquote>
|
||||
<p>Update: After further usage, bind mounts do not seem to work out of the box when the client and host are on different machines. A rather involved solution using <a href="https://en.wikipedia.org/wiki/SSHFS">sshfs</a> was shared <a href="https://github.com/containers/podman/issues/8016#issuecomment-920015800">here</a>.</p>
|
||||
</blockquote>
|
||||
<p>I had been experimenting with Podman on Linux before writing this, but after listening to this <a href="https://kubernetespodcast.com/episode/164-podman/">podcast episode</a>, I was inspired to give Podman a try on macOS.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/docker">docker</a></li>
|
||||
|
||||
<li><a href="/tags/podman">podman</a></li>
|
||||
|
||||
<li><a href="/tags/containers">containers</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,258 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Running K3s in LXC on Proxmox - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Running K3s in LXC on Proxmox" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2021/11/14/running-k3s-in-lxc-on-proxmox/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-11-14T10:07:03-05:00" />
|
||||
<meta property="article:modified_time" content="2021-11-14T10:07:03-05:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Running K3s in LXC on Proxmox"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Running K3s in LXC on Proxmox</h1>
|
||||
<div class="meta">Posted on Nov 14, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>It has been a while since I’ve actively used Kubernetes and wanted to explore the evolution of tools such as <a href="https://helm.sh">Helm</a> and <a href="https://tekton.dev">Tekton</a>. I decided to deploy <a href="https://k3s.io">K3s</a>, since I’ve had success with deploying it on resource-contrained Raspberry Pis in the past. I thought that this time it’d be convenient to have K3s running in a LXC container on Proxmox. This would allow for easy snapshotting of the entire Kubernetes deployment. LXC containers also provide an efficient way to use a machine’s resources.</p>
|
||||
<h2 id="what-is-k3s">What is K3s?<a href="#what-is-k3s" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>K3s is a Kubernetes distro that advertises itself as a lightweight binary with a much smaller memory-footprint than traditional k8s. K3s is not a fork of k8s as it seeks to remain as close to upstream as it possibly can.</p>
|
||||
<h2 id="configure-proxmox">Configure Proxmox<a href="#configure-proxmox" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>This <a href="https://gist.github.com/triangletodd/02f595cd4c0dc9aac5f7763ca2264185">gist</a> contains snippets and discussion on how to deploy K3s in LXC on Proxmox. It mentions that <code>bridge-nf-call-iptables</code> should be loaded, but I did not understand the benefit of doing this.</p>
|
||||
<h2 id="disable-swap">Disable swap<a href="#disable-swap" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>There is an issue on Kubernetes regarding swap <a href="https://github.com/kubernetes/kubernetes/issues/53533">here</a>. There claims to be support for swap in 1.22, but for now let’s disable it:</p>
|
||||
<pre><code>sysctl vm.swappiness=0
|
||||
swapoff -a
|
||||
</code></pre>
|
||||
<p>It might be worth experimenting with swap enabled in the future to see how that might affect performance.</p>
|
||||
<h3 id="enable-ip-forwarding">Enable IP Forwarding<a href="#enable-ip-forwarding" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>To avoid IP Forwarding issues with Traefik, run the following on the host:</p>
|
||||
<pre><code class="language-sh">sudo sysctl net.ipv4.ip_forward=1
|
||||
sudo sysctl net.ipv6.conf.all.forwarding=1
|
||||
sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
|
||||
sudo sed -i 's/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/g' /etc/sysctl.conf
|
||||
</code></pre>
|
||||
<h2 id="create-lxc-container">Create LXC container<a href="#create-lxc-container" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Create an LXC container in the Proxmox interface as you normally would. Remember to:</p>
|
||||
<ul>
|
||||
<li>Uncheck <code>unprivileged container</code></li>
|
||||
<li>Use a LXC template (I chose a debian 11 template downloaded with <a href="https://pve.proxmox.com/wiki/Linux_Container#Create_container">pveam</a>)</li>
|
||||
<li>In memory, set swap to 0</li>
|
||||
<li>Create and start the container</li>
|
||||
</ul>
|
||||
<h3 id="modify-container-config">Modify container config<a href="#modify-container-config" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Now back on the host run <code>pct list</code> to determine what VMID it was given.</p>
|
||||
<p>Open <code>/etc/pve/lxc/$VMID.conf</code> and append:</p>
|
||||
<pre><code class="language-sh">lxc.apparmor.profile: unconfined
|
||||
lxc.cap.drop:
|
||||
lxc.mount.auto: "proc:rw sys:rw"
|
||||
lxc.cgroup2.devices.allow: c 10:200 rwm
|
||||
</code></pre>
|
||||
<p>All of the above configurations are described in the <a href="https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html">manpages</a>.
|
||||
Notice that <code>cgroup2</code> is used since Proxmox VE 7.0 has switched to a <a href="https://pve.proxmox.com/pve-docs/chapter-pct.html#pct_cgroup">pure cgroupv2 environment</a>.</p>
|
||||
<p>Thankfully cgroup v2 support has been supported in k3s with these contributions:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/k3s-io/k3s/pull/2584">https://github.com/k3s-io/k3s/pull/2584</a></li>
|
||||
<li><a href="https://github.com/k3s-io/k3s/pull/2844">https://github.com/k3s-io/k3s/pull/2844</a></li>
|
||||
</ul>
|
||||
<h2 id="enable-shared-host-mounts">Enable shared host mounts<a href="#enable-shared-host-mounts" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>From within the container, run:</p>
|
||||
<pre><code class="language-sh">echo '#!/bin/sh -e
|
||||
ln -s /dev/console /dev/kmsg
|
||||
mount --make-rshared /' > /etc/rc.local
|
||||
chmod +x /etc/rc.local
|
||||
reboot
|
||||
</code></pre>
|
||||
<h2 id="install-k3s">Install K3s<a href="#install-k3s" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>One of the simplest ways to install K3s on a remote host is to use <a href="https://github.com/alexellis/k3sup">k3sup</a>.
|
||||
Ensure that you supply a valid <code>CONTAINER_IP</code> and choose the <code>k3s-version</code> you prefer.
|
||||
As of 2021/11, it is still defaulting to the 1.19 channel, so I overrode it to 1.22 for cgroup v2 support. See the published releases <a href="https://github.com/k3s-io/k3s/releases">here</a>.</p>
|
||||
<pre><code class="language-sh">ssh-copy-id root@$CONTAINER_IP
|
||||
k3sup install --ip $CONTAINER_IP --user root --k3s-version v1.22.3+k3s1
|
||||
</code></pre>
|
||||
<p>If all goes well, you should see a path to the <code>kubeconfig</code> generated. I moved this into <code>~/.kube/config</code> so that kubectl would read this by default.</p>
|
||||
<h2 id="wrapping-up">Wrapping up<a href="#wrapping-up" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Installing K3s in LXC on Proxmox works with a few tweaks to the default configuration. I later followed the Tekton’s <a href="https://tekton.dev/docs/getting-started/">Getting Started</a> guide and was able to deploy it in a few commands.</p>
|
||||
<pre><code class="language-console">$ kubectl get all --namespace tekton-pipelines
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
pod/tekton-pipelines-webhook-8566ff9b6b-6rnh8 1/1 Running 1 (50m ago) 12h
|
||||
pod/tekton-dashboard-6bf858f977-qt4hr 1/1 Running 1 (50m ago) 11h
|
||||
pod/tekton-pipelines-controller-69fd7498d8-f57m4 1/1 Running 1 (50m ago) 12h
|
||||
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
service/tekton-pipelines-controller ClusterIP 10.43.44.245 <none> 9090/TCP,8080/TCP 12h
|
||||
service/tekton-pipelines-webhook ClusterIP 10.43.183.242 <none> 9090/TCP,8008/TCP,443/TCP,8080/TCP 12h
|
||||
service/tekton-dashboard ClusterIP 10.43.87.97 <none> 9097/TCP 11h
|
||||
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
deployment.apps/tekton-pipelines-webhook 1/1 1 1 12h
|
||||
deployment.apps/tekton-dashboard 1/1 1 1 11h
|
||||
deployment.apps/tekton-pipelines-controller 1/1 1 1 12h
|
||||
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
replicaset.apps/tekton-pipelines-webhook-8566ff9b6b 1 1 1 12h
|
||||
replicaset.apps/tekton-dashboard-6bf858f977 1 1 1 11h
|
||||
replicaset.apps/tekton-pipelines-controller-69fd7498d8 1 1 1 12h
|
||||
|
||||
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
|
||||
horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook Deployment/tekton-pipelines-webhook 9%/100% 1 5 1 12h
|
||||
</code></pre>
|
||||
<p>I made sure to install Tailscale in the container so that I can easily access K3s from anywhere.</p>
|
||||
<p>If I’m feeling adventurous, I might experiment with <a href="https://rancher.com/docs/k3s/latest/en/advanced/#running-k3s-with-rootless-mode-experimental">K3s rootless</a>.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/k3s">k3s</a></li>
|
||||
|
||||
<li><a href="/tags/proxmox">proxmox</a></li>
|
||||
|
||||
<li><a href="/tags/lxc">lxc</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,197 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Backing Up Gmail With Synology - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Backing Up Gmail With Synology" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2022/03/13/backing-up-gmail-with-synology/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-03-13T18:49:10-04:00" />
|
||||
<meta property="article:modified_time" content="2022-03-13T18:49:10-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Backing Up Gmail With Synology"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Backing Up Gmail With Synology</h1>
|
||||
<div class="meta">Posted on Mar 13, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>I’ve used gmail since the beta launched touting a whopping 1GB of storage. I thought this was a massive leap in email technology at the time. I was lucky enough to get an invite fairly quickly. Not suprisingly, I have many years of emails, attachments, and photos. I certainly do not want to lose the content of many of these emails. Despite the redundancy of the data that Google secures, I still feel better retaining a copy of this data on my own physical machines.</p>
|
||||
<p>The thought of completely de-googling has crossed my mind on occassion. Convenience, coupled with my admiration for Google engineering, has prevented me from doing so thus far. Though, I may end up doing so at some point in the future.</p>
|
||||
<h2 id="synology-mailplus-server">Synology MailPlus Server<a href="#synology-mailplus-server" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Synology products are reasonably priced for what you get (essentially a cloud-in-a-box) and there is very little maintenance required. I’ve recently been in interested in syncing and snapshotting my personal data. I’ve setup <a href="https://www.synology.com/en-ca/dsm/feature/cloud_sync">Synology’s Cloud Sync</a> and keep copies of most of my cloud data.</p>
|
||||
<p>I’ve used tools such as <a href="http://www.gmvault.org">gmvault</a> with success in the past. Setting this up on a cron seems like a viable option. However, I don’t really need a lot of the features it offers and do not plan to restore this data to another account.</p>
|
||||
<p>Synology’s MailPlus seems to be a good candidate for backing up this data. By enabling POP3 fetching, it’s possible to fetch all existing emails, as well as periodically fetch all new emails. If a disaster ever did occur, having these emails would be beneficial, as they are an extension of my memory bank.</p>
|
||||
<p>Installing MailPlus can be done from the Package Center:</p>
|
||||
<p><img src="install-mailplus-server.png" alt="image"></p>
|
||||
<p>Next, I went into <strong>Synology MailPlus Server</strong> and on the left, clicked on <strong>Account</strong> and ensured my user was marked as active.</p>
|
||||
<p>Afterwords, I followed <a href="https://kb.synology.com/en-in/DSM/tutorial/How_should_I_receive_external_email_messages_via_MailPlus">these instructions</a> in order to start backing up emails.</p>
|
||||
<p>When entering the POP3 credentials, I created an <a href="https://myaccount.google.com/apppasswords">app password</a> solely for authenticating to POP3 from the Synology device. This is required because I have 2-Step verification enabled on my account. There doesn’t seem to be a more secure way to access POP3 at the moment. It does seem like app password access is limited in scope (when MFA is enabled). These app passwords can’t be used to login to the main Google account.</p>
|
||||
<p>I made sure to set the <code>Fetch Range</code> to <code>All</code> in order to get all emails from the beginning of time.</p>
|
||||
<p>After this, mail started coming in.</p>
|
||||
<p><img src="mail-plus-incoming-mail.png" alt="image"></p>
|
||||
<p>After fetching 19 years worth of emails, I tried searching for some emails. It only took a few seconds to search through ~50K emails, which is a relief if I ever did have to search for something important.</p>
|
||||
<h2 id="securing-synology">Securing Synology<a href="#securing-synology" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Since Synology devices are not hermetically sealed, it’s best to secure them by <a href="https://kb.synology.com/en-us/DSM/tutorial/How_to_add_extra_security_to_your_Synology_NAS#x_anchor_id8">enabling MFA</a> to help prevent being the <a href="https://www.bleepingcomputer.com/news/security/qlocker-ransomware-returns-to-target-qnap-nas-devices-worldwide/">victim of ransomware</a>. It is also wise to backup your system settings and volumes to the cloud using a tool such as <a href="https://www.synology.com/en-ca/dsm/feature/hyper_backup">Hyper Backup</a>.
|
||||
Encrypting your shared volumes should also be done, since unfortunately <a href="https://community.synology.com/enu/forum/12/post/144665">DSM does not support full disk encryption</a>.</p>
|
||||
<h2 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Having backups of various forms of cloud data is a good investment, especially in <a href="https://en.wikipedia.org/wiki/2022_Ukraine_cyberattacks">times of war</a>. I certainly feel more at ease for having backed up my emails.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/degoogle">degoogle</a></li>
|
||||
|
||||
<li><a href="/tags/synology">synology</a></li>
|
||||
|
||||
<li><a href="/tags/gmail">gmail</a></li>
|
||||
|
||||
<li><a href="/tags/backup">backup</a></li>
|
||||
|
||||
<li><a href="/tags/ransomware">ransomware</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 52 KiB |
@@ -1,217 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Virtualizing My Router With pfSense - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Virtualizing My Router With pfSense" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2022/04/02/virtualizing-my-router-with-pfsense/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-04-02T18:50:09-04:00" />
|
||||
<meta property="article:modified_time" content="2022-04-02T18:50:09-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Virtualizing My Router With pfSense"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Virtualizing My Router With pfSense</h1>
|
||||
<div class="meta">Posted on Apr 2, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><h2 id="the-problem">The problem<a href="#the-problem" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>My aging router has been running <a href="https://en.wikipedia.org/wiki/OpenWrt">OpenWrt</a> for years and for the most part has been quite reliable. OpenWrt is an open-source project used on embedded devices to route network traffic. It supports many different configurations and there exists a <a href="https://openwrt.org/packages/index/start">large index of packages</a>. Ever since I’ve connected some standalone wireless access points, I’ve had less of a need for an off-the-shelf all-in-one wireless router combo. I’ve also recently been experiencing instability with my router (likely the result of a combination of configuration tweaking and firmware updating). OpenWrt has served me well, but it is time to move on!</p>
|
||||
<h2 id="pfsense">pfSense<a href="#pfsense" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I figured this would be a good opportunity to try <a href="https://en.wikipedia.org/wiki/PfSense">pfSense</a>. I’ve heard nothing but positive things about pfSense and the fact it’s been around since 2004, based on FreeBSD, and written in PHP gave me the impression that it would be relatively stable (and I’d expect nothing less because it has an important job to do!). pfSense can be run on many different machines, and there are even some <a href="https://www.netgate.com/appliances">officially supported appliances</a>. Since I already have a machine running Proxmox, why not just run it in a VM? It’d allow for automatic snapshotting of the machine. There is a good <a href="https://www.youtube.com/watch?v=hdoBQNI_Ab8">video</a> on this by Techno Tim. Tim has a lot of good videos, and this one is about virtualizing pfSense.</p>
|
||||
<h2 id="router-on-a-stick">Router on a stick<a href="#router-on-a-stick" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I had initially made the assumption that in order to build a router, you would need more than a single NIC (or a dual-port NIC) in order to support both WAN and LAN. This is simply <a href="https://en.wikipedia.org/wiki/Router_on_a_stick">not the case</a>, because VLANs are awesome! In order to create a router, all you need is a single port NIC and a network switch that supports VLANs (also marketed as a managed switch). I picked up the Netgear GS308E because it has both a sufficient amount of ports for my needs, and it supports VLANs. It also has a nice sturdy metal frame which was a pleasant surprise.</p>
|
||||
<p>After setting up this Netgear switch, it shoud be possible to access the web interface at <a href="http://192.168.0.239">http://192.168.0.239</a>. It may be at a different address. To find the address, try checking your DHCP leases in your router interface (if you plugged it into an existing router). I realized I was unable to access this interface because I was on a different subnet, so I set my machine’s address to <code>192.168.0.22</code> in order to temporarily setup this switch. I assigned a static ip address to the switch (in <code>System > Switch Information</code>) so that it was in the same subnet as the rest of my network.</p>
|
||||
<p>The web interface is nothing spectactular, but it allows for managing VLANs.</p>
|
||||
<p>The following configuration will:</p>
|
||||
<ul>
|
||||
<li>assign port 1 to be the LAN (connected to the Proxmox machine)</li>
|
||||
<li>assign port 8 to be the WAN (connected to my ISP’s modem)</li>
|
||||
</ul>
|
||||
<p>In the switch’s web interface, I went to <code>VLAN</code> and then <code>802.1Q</code>, and then clicked on <code>VLAN Configuration</code>. I configured the ports to look like this:</p>
|
||||
<p><img src="netgear-vlan-configuration.png" alt="vlan-config"></p>
|
||||
<p>Note that the <code>VLAN Identifier Setting</code> has been setup already with two VLANs (1 and 10). More VLANs can be created (i.e. to isolate IoT devices), but 2 VLANs is all we need for the initial setup of a router.</p>
|
||||
<p>To replicate the above configuration, add a new VLAN ID 10 (1 should exist by default).</p>
|
||||
<p>Next, go into <code>VLAN Membership</code> and configure VLAN 1’s port membership to be the following:</p>
|
||||
<p><img src="netgear-vlan-membership-1.png" alt="vlan-membership-1"></p>
|
||||
<p>and then configure VLAN 10’s port membership to be the following:</p>
|
||||
<p><img src="netgear-vlan-membership-10.png" alt="vlan-membership-10"></p>
|
||||
<p>Now, go into <code>Port PVID</code> and ensure that port 8 is set to PVID 10.</p>
|
||||
<p><img src="netgear-port-pvid.png" alt="vlan-port-pvid"></p>
|
||||
<p>This above configuration will dedicate two of the eight ports to WAN and LAN. This will allow the internet to flow into the pfSense from the modem.</p>
|
||||
<h2 id="setting-up-pfsense">Setting up pfSense<a href="#setting-up-pfsense" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>pfSense is fairly easy to setup. Just <a href="https://www.pfsense.org/download/">download the latest ISO</a> and boot up the virtual machine.
|
||||
When setting up the machine, I mostly went with all of the defaults. Configuration can be changed later in the web interface, which is quite a bit simpler.</p>
|
||||
<p>Since VLANs are going to be leveraged, when you go to <code>Assign Interfaces</code>, VLANs should be setup now like the following:</p>
|
||||
<ul>
|
||||
<li><code>WAN</code> should be <code>vtnet0.10</code></li>
|
||||
<li><code>LAN</code> should be <code>vtnet0</code></li>
|
||||
</ul>
|
||||
<p>After going through the rest of the installation, if everything is connected correctly it should display both WAN and LAN addresses.</p>
|
||||
<p>If all goes well, the web interface should be running at <a href="https://192.168.1.1">https://192.168.1.1</a>.</p>
|
||||
<p><img src="pfsense-dashboard.png" alt="pfsense-dashboard"></p>
|
||||
<p>And this is where the fun begins. There are many tutorials and blogs about how to setup pfSense and various services and packages that can be installed. I’ve already installed <a href="https://docs.netgate.com/pfsense/en/latest/packages/pfblocker.html">pfBlocker-NG</a>.</p>
|
||||
<h2 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>It is fairly simple to setup a router with pfSense from within a virtual machine. A physical dedicated routing machine is not necessary and often does not perform as well as software running on faster and more reliable hardware. So far, pfSense has been running for over a week without a single hiccup. pfSense is a mature piece of software that is incredibly powerful and flexible. To avoid some of the instability I had experienced with OpenWrt, I enabled <a href="https://docs.netgate.com/pfsense/en/latest/backup/autoconfigbackup.html">AutoConfigBackup</a>, which is capable of automatically backing up configuration upon every change. I plan to explore and experiment with more services and configuration in the future, so the ability to track all of these changes gives me the peace of mind that experimentation is safe.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/pfsense">pfsense</a></li>
|
||||
|
||||
<li><a href="/tags/router">router</a></li>
|
||||
|
||||
<li><a href="/tags/openwrt">openwrt</a></li>
|
||||
|
||||
<li><a href="/tags/router-on-a-stick">router-on-a-stick</a></li>
|
||||
|
||||
<li><a href="/tags/proxmox">proxmox</a></li>
|
||||
|
||||
<li><a href="/tags/vlan">vlan</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 935 KiB |
@@ -1,235 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Watching YouTube in Private - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Watching YouTube in Private" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2022/12/10/watching-youtube-in-private/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-12-10T21:46:55-05:00" />
|
||||
<meta property="article:modified_time" content="2022-12-10T21:46:55-05:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Watching YouTube in Private"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Watching YouTube in Private</h1>
|
||||
<div class="meta">Posted on Dec 10, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>I recently stumbled upon <a href="https://yewtu.be">yewtu.be</a> and found it intriguing. It not only allows you to watch YouTube without <em>being on YouTube</em>, but it also allows you to create an account and subscribe to channels without a Google account. What sort of wizardry is going on under the hood? It turns out that it’s a hosted instance of <a href="https://invidious.io/">invidious</a>.</p>
|
||||
<p><img src="computerphile.png" alt="image"></p>
|
||||
<p>The layout is simple, and <strong>JavaScript is not required</strong>.</p>
|
||||
<p>I started using <a href="https://yewtu.be">yewtu.be</a> as my primary client for watching videos. I subscribe to several YouTube channels and I prefer the interface invidiuous provides due to its simplicity. It’s also nice to be in control of my search and watch history.</p>
|
||||
<p>A few days ago, yewtu.be went down briefly, and that motivated me enough to self-host invidious. There are several other hosted instances listed <a href="https://docs.invidious.io/instances/">here</a>, but being able to easily backup my own instance (including subscriptions and watch history) is more compelling in my case.</p>
|
||||
<h3 id="hosting-invidious">Hosting invidious<a href="#hosting-invidious" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>The quickest way to get invidious up is with docker-compose as mentioned in the <a href="https://docs.invidious.io/installation/">docs</a>.</p>
|
||||
<p>I made a few modifications (such as pinning the container’s tag), and ended up with:</p>
|
||||
<pre><code class="language-yaml">version: "3"
|
||||
services:
|
||||
invidious:
|
||||
image: quay.io/invidious/invidious:5160d8bae39dc5cc5d51abee90571a03c08d0f2b
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "0.0.0.0:3000:3000"
|
||||
environment:
|
||||
INVIDIOUS_CONFIG: |
|
||||
db:
|
||||
dbname: invidious
|
||||
user: kemal
|
||||
password: kemal
|
||||
host: invidious-db
|
||||
port: 5432
|
||||
check_tables: true
|
||||
healthcheck:
|
||||
test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 2
|
||||
depends_on:
|
||||
- invidious-db
|
||||
|
||||
invidious-db:
|
||||
image: docker.io/library/postgres:14
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgresdata:/var/lib/postgresql/data
|
||||
- ./config/sql:/config/sql
|
||||
- ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
|
||||
environment:
|
||||
POSTGRES_DB: invidious
|
||||
POSTGRES_USER: kemal
|
||||
POSTGRES_PASSWORD: kemal
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
|
||||
|
||||
volumes:
|
||||
postgresdata:
|
||||
</code></pre>
|
||||
<p>After invidious was up and running, I installed <a href="https://tailscale.com/">Tailscale</a> on it to leverage its MagicDNS, and I’m now able to access this instance from anywhere at <a href="http://invidious:3000/feed/subscriptions">http://invidious:3000/feed/subscriptions</a>.</p>
|
||||
<h3 id="redirecting-youtube-links">Redirecting YouTube links<a href="#redirecting-youtube-links" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>I figured it would be nice to redirect existing YouTube links that others send me, so that I could seamlessly watch the videos using invidious.</p>
|
||||
<p>I went looking for a way to redirect paths at the browser level. I found the lightweight proxy <a href="https://requestly.io/">requestly</a>, which can be used to modify http requests in my browser. I created the following rules:</p>
|
||||
<p><img src="requestly-rules.png" alt="requestly"></p>
|
||||
<p>Now the link <a href="https://www.youtube.com/watch?v=-lz30by8-sU">https://www.youtube.com/watch?v=-lz30by8-sU</a> will redirect to <a href="http://invidious:3000/watch?v=-lz30by8-sU">http://invidious:3000/watch?v=-lz30by8-sU</a></p>
|
||||
<p>I’m still looking for ways to improve this invidious setup. There doesn’t appear to be a way to stream in 4K yet.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/invidious">invidious</a></li>
|
||||
|
||||
<li><a href="/tags/degoogle">degoogle</a></li>
|
||||
|
||||
<li><a href="/tags/youtube">youtube</a></li>
|
||||
|
||||
<li><a href="/tags/yewtu.be">yewtu.be</a></li>
|
||||
|
||||
<li><a href="/tags/tailscale">tailscale</a></li>
|
||||
|
||||
<li><a href="/tags/privacy">privacy</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 86 KiB |
@@ -1,223 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Using AKS and SOCKS to connect to a Private Azure DB - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Using AKS and SOCKS to connect to a Private Azure DB" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2023/05/22/using-aks-and-socks-to-connect-to-a-private-azure-db/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2023-05-22T16:31:29-04:00" />
|
||||
<meta property="article:modified_time" content="2023-05-22T16:31:29-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Using AKS and SOCKS to connect to a Private Azure DB"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Using AKS and SOCKS to connect to a Private Azure DB</h1>
|
||||
<div class="meta">Posted on May 22, 2023</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><h2 id="the-problem">The Problem<a href="#the-problem" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I ran into a roadblock recently where I wanted to be able to conveniently connect to a managed postgres database within Azure that was not running on public subnets. And by conveniently, I mean that I’d rather not have to spin up an ephemeral virtual machine running in the same network and proxy the connection, and I’d like to use a local client (preferably with a GUI). After several web searches, it became evident that Azure does not readily provide much tooling to support this.</p>
|
||||
<h2 id="go-public">Go Public?<a href="#go-public" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Should the database be migrated to public subnets? Ideally not, since it is good practice to host internal infrastructure in restricted subnets.</p>
|
||||
<h2 id="how-do-others-handle-this">How do others handle this?<a href="#how-do-others-handle-this" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>With GCP, connecting to a private db instance from any machine can be achieved with <a href="https://github.com/GoogleCloudPlatform/cloud-sql-proxy">cloud-sql-proxy</a>. This works by proxying requests from your machine to the SQL database instance in the cloud, while the authentication is handled by GCP’s IAM.</p>
|
||||
<p>So what about Azure? Is there any solution that is as elegant as cloud-sql-proxy?</p>
|
||||
<h2 id="a-bastion">A Bastion<a href="#a-bastion" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Similar to what <a href="https://aws.amazon.com/blogs/database/securely-connect-to-an-amazon-rds-or-amazon-ec2-database-instance-remotely-with-your-preferred-gui/">AWS has recommended</a>, perhaps a bastion is the way forward?</p>
|
||||
<p>Azure has a fully-managed service called <a href="https://azure.microsoft.com/en-ca/products/azure-bastion">Azure Bastion</a> that provides secure access to virtual machines that do not have public IPs. This looks interesting, but unfortunately it <a href="https://azure.microsoft.com/en-ca/pricing/details/azure-bastion/#pricing">costs money</a> and requires an additional virtual machine.</p>
|
||||
<p>Because this adds cost (and complexity), it does not seem like a desirable option in its current state. If it provided a more seamless connection to the database, it would be more appealing.</p>
|
||||
<h2 id="socks">SOCKS<a href="#socks" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p><a href="https://en.wikipedia.org/wiki/SOCKS">SOCKS</a> is a protocol that enables a way to proxy connections by exchanging network packets between the client and the server. There are many implementations and many readily available container images that can run a SOCKS server.</p>
|
||||
<p>It’s possible to use this sort of proxy to connect to a private DB, but is it any simpler than using a virtual machine as a jumphost? It wasn’t until I stumbled upon <a href="https://github.com/yokawasa/kubectl-plugin-socks5-proxy">kubectl-plugin-socks5-proxy</a> that I was convinced that using SOCKS could be made simple.</p>
|
||||
<p>So how does it work? By installing the kubectl plugin and then running <code>kubectl socks5-proxy</code>, a SOCKS proxy server is spun up in a pod and then opens up port-forwarding session using kubectl.</p>
|
||||
<p>As you can see below, this k8s plugin is wrapped up nicely:</p>
|
||||
<pre><code class="language-console">$ kubectl socks5-proxy
|
||||
using: namespace=default
|
||||
using: port=1080
|
||||
using: name=davegallant-proxy
|
||||
using: image=serjs/go-socks5-proxy
|
||||
Creating SOCKS5 Proxy (Pod)...
|
||||
pod/davegallant-proxy created
|
||||
</code></pre>
|
||||
<p>With the above proxy connection open, it is possible to access both the DNS and private IPs accessible within the k8s cluster. In this case, I am able to access the private database, since there is network connectivity between the k8s cluster and the database.</p>
|
||||
<h2 id="caveats-and-conclusion">Caveats and Conclusion<a href="#caveats-and-conclusion" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>The above outlined solution makes some assumptions:</p>
|
||||
<ul>
|
||||
<li>there is a k8s cluster</li>
|
||||
<li>the k8s cluster has network connectivity to the desired private database</li>
|
||||
</ul>
|
||||
<p>If these stars align, than this solution might work as a stopgap for accessing a private Azure DB (and I’m assuming this could work similarly on AWS).</p>
|
||||
<p>It would be nice if Azure provided tooling similar to cloud-sql-proxy, so that using private databases would be more of a convenient experience.</p>
|
||||
<p>One other thing to note is that some clients (such as <a href="https://dbeaver.io/">dbeaver</a>) <a href="https://github.com/dbeaver/dbeaver/issues/872">do not provide DNS resolution over SOCKS</a>. So in this case, you won’t be able to use DNS as if you were inside the cluster, but instead have to rely on knowing private ip addresses.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/azure">azure</a></li>
|
||||
|
||||
<li><a href="/tags/database">database</a></li>
|
||||
|
||||
<li><a href="/tags/proxy">proxy</a></li>
|
||||
|
||||
<li><a href="/tags/socks">socks</a></li>
|
||||
|
||||
<li><a href="/tags/aks">aks</a></li>
|
||||
|
||||
<li><a href="/tags/k8s">k8s</a></li>
|
||||
|
||||
<li><a href="/tags/aws">aws</a></li>
|
||||
|
||||
<li><a href="/tags/bastion">bastion</a></li>
|
||||
|
||||
<li><a href="/tags/eks">eks</a></li>
|
||||
|
||||
<li><a href="/tags/cloud-sql-proxy">cloud-sql-proxy</a></li>
|
||||
|
||||
<li><a href="/tags/kubectl-plugin-socks5-proxy">kubectl-plugin-socks5-proxy</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,314 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Setting Up Gitea Actions With Tailscale - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Setting Up Gitea Actions With Tailscale" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/blog/2023/12/10/setting-up-gitea-actions-with-tailscale/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2023-12-10T17:22:11-05:00" />
|
||||
<meta property="article:modified_time" content="2023-12-10T17:22:11-05:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Setting Up Gitea Actions With Tailscale"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Setting Up Gitea Actions With Tailscale</h1>
|
||||
<div class="meta">Posted on Dec 10, 2023</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>In this post I’ll go through the process of setting up Gitea Actions and <a href="https://tailscale.com/">Tailscale</a>, unlocking a simple and secure way to automate workflows.</p>
|
||||
<h2 id="what-is-gitea">What is Gitea?<a href="#what-is-gitea" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p><a href="https://about.gitea.com/">Gitea</a> is a lightweight and fast git server that has much of the same look and feel as github. I have been using it in my homelab to mirror repositories hosted on other platforms such as github and gitlab. These mirrors take advantage of the decentralized nature of git by serving as “backups”. One of the main reasons I hadn’t been using it more often was due to the lack of integrated CI/CD. This is no longer the case.</p>
|
||||
<h2 id="gitea-actions">Gitea Actions<a href="#gitea-actions" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p><a href="https://docs.gitea.com/usage/actions/overview">Gitea Actions</a> have made it into the <a href="https://blog.gitea.com/release-of-1.19.0/">1.19.0 release</a>. This feature had been in an experimental state up until <a href="https://blog.gitea.com/release-of-1.21.0/">1.21.0</a> and is now enabled by default 🎉.</p>
|
||||
<p>So what are they? If you’ve ever used GitHub Actions (and if you’re reading this, I imagine you have), these will look familiar. Gitea Actions essentially enable the ability to run github workflows on gitea. Workflows between gitea and github are not completely interopable, but a lot of the same workflow syntax is already compatible on gitea. You can find a documented list of <a href="https://docs.gitea.com/usage/actions/comparison#unsupported-workflows-syntax">unsupported workflows syntax</a>.</p>
|
||||
<p>Actions work by using a <a href="https://gitea.com/gitea/act">custom fork</a> of <a href="https://github.com/nektos/act">nekos/act</a>. Workflows run in a new container for every job. If you specify an action such as ‘actions/checkout@v3’, it defaults to downloading the scripts from github.com. To avoid internet egress, you could always clone the required actions to your local gitea instance.</p>
|
||||
<p>Actions (gitea’s implementation) has me excited because it makes spinning up a network-isolated environment for workflow automation incredibly simple.</p>
|
||||
<h2 id="integration-with-tailscale">Integration with Tailscale<a href="#integration-with-tailscale" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>So how does Tailscale help here? Well, more recently I’ve been exposing my self-hosted services through a combination of traefik and the tailscale (through the tailscale-traefik proxy integration described <a href="https://traefik.io/blog/exploring-the-tailscale-traefik-proxy-integration/">here</a>). This allows for a nice looking dns name (i.e. gitea.my-tailnet-name.ts.net) and automatic tls certificate management. I can also share this tailscale node securely with other tailscale users without configuring any firewall rules on my router.</p>
|
||||
<h2 id="deploying-gitea-traefik-and-tailscale">Deploying Gitea, Traefik, and Tailscale<a href="#deploying-gitea-traefik-and-tailscale" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>In my case, the following is already set up:</p>
|
||||
<ul>
|
||||
<li><a href="https://docs.docker.com/compose/install/linux/">docker-compose is installed</a></li>
|
||||
<li><a href="https://tailscale.com/kb/1017/install/">tailscale is installed on the gitea host</a></li>
|
||||
<li><a href="https://tailscale.com/kb/1081/magicdns/">tailscale magic dns is enabled</a></li>
|
||||
</ul>
|
||||
<p>My preferred approach to deploying code in a homelab environment is with docker compose. I have deployed this in a <a href="https://pve.proxmox.com/wiki/Linux_Container">proxmox lxc container</a> based on debian with a hostname <code>gitea</code>. This could be deployed in any environment and with any hostname (as long you updated the tailscale machine name to your preferred subdomain for magic dns).</p>
|
||||
<p>The <code>docker-compose.yaml</code> file looks like:</p>
|
||||
<pre><code class="language-yaml">version: "3.7"
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:1.21.1
|
||||
container_name: gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
|
||||
- GITEA__server__DOMAIN=gitea.my-tailnet-name.ts.net
|
||||
- GITEA__server__ROOT_URL=https://gitea.my-tailnet-name.ts.net
|
||||
- GITEA__server__HTTP_ADDR=0.0.0.0
|
||||
- GITEA__server__LFS_JWT_SECRET=my-secret-jwt
|
||||
restart: always
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
traefik:
|
||||
image: traefik:v3.0.0-beta4
|
||||
container_name: traefik
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- ./traefik/data/traefik.yaml:/traefik.yaml:ro
|
||||
- ./traefik/data/dynamic.yaml:/dynamic.yaml:ro
|
||||
- /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
|
||||
</code></pre>
|
||||
<p><code>traefik/data/traefik.yaml</code>:</p>
|
||||
<pre><code class="language-yaml">entryPoints:
|
||||
https:
|
||||
address: ":443"
|
||||
providers:
|
||||
file:
|
||||
filename: dynamic.yaml
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
tailscale: {}
|
||||
log:
|
||||
level: INFO
|
||||
</code></pre>
|
||||
<p>and finally <code>traefik/data/dynamic/dynamic.yaml</code>:</p>
|
||||
<pre><code class="language-yaml">http:
|
||||
routers:
|
||||
gitea:
|
||||
rule: Host(`gitea.my-tailnet-name.ts.net`)
|
||||
entrypoints:
|
||||
- "https"
|
||||
service: gitea
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
services:
|
||||
gitea:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://gitea:3000"
|
||||
</code></pre>
|
||||
<p>Something to consider is whether or not you want to use ssh with git. One method to get this to work with containers is to use <a href="https://docs.gitea.com/installation/install-with-docker#ssh-container-passthrough">ssh container passthrough</a>. I decided to keep it simple and not use ssh, since communicating over https is perfectly fine for my use case.</p>
|
||||
<p>After adding the above configuration, running <code>docker compose up -d</code> should be enough to get an instance up and running. It will be accessible at <a href="https://gitea.my-tailnet-name.ts.net">https://gitea.my-tailnet-name.ts.net</a> from within the tailnet.</p>
|
||||
<h2 id="connecting-a-runner">Connecting a Runner<a href="#connecting-a-runner" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I installed the runner by <a href="https://docs.gitea.com/usage/actions/quickstart#set-up-runner">following the docs</a>. I opted for installing it on a separate host (another lxc container) as recommended in the docs. I used the systemd unit file to ensure that the runner comes back online after system reboots. I installed tailscale on this act runner as well, so that it can have the same “networking privileges” as the main instance.</p>
|
||||
<p>After registering this runner and starting the daemon, it appeared in <code>/admin/actions/runners</code>:</p>
|
||||
<p><img src="gitea-runners.png" alt="image"></p>
|
||||
<h2 id="running-a-workflow">Running a workflow<a href="#running-a-workflow" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Now it’s time start running some automation. I used the <a href="https://docs.gitea.com/usage/actions/quickstart#use-actions">demo workflow</a> as a starting point to verify that the runner is executing workflows.</p>
|
||||
<p>After this, I wanted to make sure that some of my existing workflows could be migrated over.</p>
|
||||
<p>The following workflow uses a matrix to run a job for several of my hosts using ansible playbooks that will do various tasks such as patching os updates and updating container images.</p>
|
||||
<pre><code class="language-yaml">name: Run ansible playbooks
|
||||
on:
|
||||
push:
|
||||
schedule:
|
||||
- cron: "0 */12 * * *"
|
||||
|
||||
jobs:
|
||||
run-ansible-playbook:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
host:
|
||||
- changedetection
|
||||
- grafana
|
||||
- homer
|
||||
- invidious
|
||||
- jackett
|
||||
- ladder
|
||||
- miniflux
|
||||
- plex
|
||||
- qbittorrent
|
||||
- tailscale-exit-node
|
||||
- uptime-kuma
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install ansible
|
||||
run: |
|
||||
apt update && apt install ansible -y
|
||||
- name: Run playbook
|
||||
uses: dawidd6/action-ansible-playbook@v2
|
||||
with:
|
||||
playbook: playbooks/main.yml
|
||||
requirements: requirements.yml
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY}}
|
||||
options: |
|
||||
--inventory inventory
|
||||
--limit ${{ matrix.host }}
|
||||
</code></pre>
|
||||
<p>And voilà:</p>
|
||||
<video controls preload="auto" width="100%" poster="/blog/2023/12/10/setting-up-gitea-actions-with-tailscale/gitea-runners.png" playsinline class="html-video">
|
||||
<source src="/blog/2023/12/10/setting-up-gitea-actions-with-tailscale/gitea-runner.webm" type="video/webm">
|
||||
<span>Your browser doesn't support embedded videos, but don't worry, you can <a href="/blog/2023/12/10/setting-up-gitea-actions-with-tailscale/gitea-runner.webm">download it</a> and watch it with your favorite video player!</span>
|
||||
</video>
|
||||
<h2 id="areas-for-improvement">Areas for improvement<a href="#areas-for-improvement" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>One enhancement that I would like to see is the ability to send notifications on workflow failures. Currently, this <a href="https://github.com/go-gitea/gitea/issues/23725">doesn’t seem possible</a>.</p>
|
||||
<h2 id="conclusion">Conclusion<a href="#conclusion" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Gitea Actions are fast and the resource footprint is minimal. My gitea instance is currently using around 250mb of memory and a small fraction of a single cpu core (and the runner is using a similar amount of resources). This is impressive since many alternatives tend to require substantionally more resources (ahem, gitlab). It likely helps that the codebase is largely written in go.</p>
|
||||
<p>By combining gitea with the networking marvel that is tailscale, running workflows becomes simple and fun. Whether you are working on a team or working alone, this setup ensures that your workflows are securely accessible from anywhere with an internet connection.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/gitea">gitea</a></li>
|
||||
|
||||
<li><a href="/tags/gitea-actions">gitea actions</a></li>
|
||||
|
||||
<li><a href="/tags/github-actions">github actions</a></li>
|
||||
|
||||
<li><a href="/tags/tailscale">tailscale</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,158 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Categories - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<link rel="alternate" type="application/rss+xml" href="/categories/index.xml" title="davegallant" />
|
||||
<meta property="og:title" content="Categories" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="/categories/" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Categories"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.0e5aa3b634b92d61bafebfd908290cc7a034e4d50e6a0c59ce50044560179c4e.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.b11f422ffce8151207bad84653d44cb512043f9efe93a0a049f836b9cc32b34a.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/index.xml">RSS</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<h1 class="page-title">All tags</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="tag-cloud">
|
||||
<ul class="tags">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments'><script>
|
||||
|
||||
var getTheme = window.localStorage && window.localStorage.getItem("theme-storage");
|
||||
getTheme = getTheme == null ? 'light' : getTheme;
|
||||
|
||||
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
|
||||
let s = document.createElement('script');
|
||||
s.src = 'https://utteranc.es/client.js';
|
||||
s.setAttribute('repo', 'davegallant\/davegallant.github.io');
|
||||
s.setAttribute('issue-term', 'pathname');
|
||||
s.setAttribute('theme', theme);
|
||||
s.setAttribute('crossorigin', 'anonymous');
|
||||
s.setAttribute('async', '');
|
||||
document.querySelector('div.comments').innerHTML = '';
|
||||
document.querySelector('div.comments').appendChild(s);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="mailto:me@davegallant.ca" rel="me" title="Email"><i data-feather="at-sign"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://linktr.ee/davegallant" rel="me" title="LinkTree"><i data-feather="compass"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://mastodon.social/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V8WJDERTX9"></script>
|
||||
<script>
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-V8WJDERTX9', { 'anonymize_ip': false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>Categories on davegallant</title>
|
||||
<link>/categories/</link>
|
||||
<description>Recent content in Categories on davegallant</description>
|
||||
<generator>Hugo -- gohugo.io</generator>
|
||||
<language>en-us</language>
|
||||
<copyright>Dave Gallant</copyright><atom:link href="/categories/index.xml" rel="self" type="application/rss+xml" />
|
||||
</channel>
|
||||
</rss>
|
@@ -1,13 +0,0 @@
|
||||
.hanchor {
|
||||
visibility: hidden;
|
||||
color: silver;
|
||||
font-size: 100%;
|
||||
transition: 0.2s;
|
||||
padding-left: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h2:hover a, h3:hover a, h4:hover a {
|
||||
visibility: visible;
|
||||
text-decoration: none;
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
body {
|
||||
color: white;
|
||||
background-color: #202124;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: blue;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: rgb(212, 240, 32);
|
||||
color: #000000;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 3px dotted blue;
|
||||
}
|
||||
code {
|
||||
background-color: rgb(184, 189, 190);
|
||||
color: black;
|
||||
text-decoration: bold;
|
||||
padding: 0em 0.1em;
|
||||
}
|
||||
pre {
|
||||
background-color: #272822;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
blockquote {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #ddd;
|
||||
}
|
||||
h1::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "# ";
|
||||
}
|
||||
h2::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "## ";
|
||||
}
|
||||
h3::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "### ";
|
||||
}
|
||||
h4::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "#### ";
|
||||
}
|
||||
h5::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "##### ";
|
||||
}
|
||||
h6::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "###### ";
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
color: inherit;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-description a {
|
||||
color: #ddd;
|
||||
}
|
||||
.site-description a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tags a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
}
|
||||
.tags a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-title a {
|
||||
color: white;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.header nav,
|
||||
.footer {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #333;
|
||||
}
|
||||
.soc:hover {
|
||||
color: black;
|
||||
}
|
||||
.draft-label {
|
||||
color: var(--darkMaincolor);
|
||||
background-color: blue;
|
||||
}
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: rgb(118, 137, 118);
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
@@ -1,334 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: #a15bc2;
|
||||
--bordercl: #a15bc2;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor: #a15bc2;
|
||||
--darkMaincolor: #a15bc2;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 18px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
background-color: #f8f8f8;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #eef35c;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Roboto Light', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0em .0.1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: var(--maincolor);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,330 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs >
|
||||
<font id="FiraSans" horiz-adv-x="558" ><font-face
|
||||
font-family="Fira Sans"
|
||||
units-per-em="1000"
|
||||
panose-1="2 11 5 3 5 0 0 2 0 4"
|
||||
ascent="935"
|
||||
descent="-265"
|
||||
alphabetic="0" />
|
||||
<glyph unicode=" " glyph-name="space" horiz-adv-x="265" />
|
||||
<glyph unicode="!" glyph-name="exclam" horiz-adv-x="241" d="M170 689L160 230H79L68 689H170ZM150 127T170 107T190 58Q190 29 170 9T120 -12Q91 -12 71 8T51 58Q51 87 71 107T120 127Q150 127 170 107Z" />
|
||||
<glyph unicode=""" glyph-name="quotedbl" horiz-adv-x="399" d="M75 427L60 689H159L144 427H75ZM255 427L240 689H339L324 427H255Z" />
|
||||
<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="518" d="M503 447H427L399 232H466V163H389L368 0H290L311 163H157L136 0H58L79 163H15V232H89L117 447H52V517H126L146 669H224L204 517H358L378 669H456L436 517H503V447ZM321 232L349 447H195L167 232H321Z" />
|
||||
<glyph unicode="$" glyph-name="dollar" horiz-adv-x="531" d="M491 110T443 58T310 -8V-155H230V-11Q107 -5 25 75L79 134Q151 64 251 64Q314 64 354 95T395 183Q395 216 383 238T339 277T250 312Q147 344 100 387T52 505Q52 575 101 622T230 678V824H310V677Q358
|
||||
672 396 654T470 602L417 544Q383 576 347 590T267 604Q214 604 181 580T147 509Q147 480 159 461T202 425T293 389Q356 370 398 347T465 285T491 186Q491 110 443 58Z" />
|
||||
<glyph unicode="%" glyph-name="percent" horiz-adv-x="826" d="M613 711L677 669L214 -31L150 11L613 711ZM279 679T324 633T370 510Q370 433 325 387T207 341Q136 341 91 387T45 510Q45 587 90 633T207 679Q279 679 324 633ZM163 617T145 587T126 510Q126 464
|
||||
144 434T207 403Q288 403 288 510Q288 556 270 586T207 617Q163 617 145 587ZM691 326T736 280T781 157Q781 80 736 34T619 -12Q547 -12 502 34T456 157Q456 234 501 280T619 326Q691 326 736 280ZM575 263T557 234T538 157Q538 111 556 81T619 50Q700 50 700 157Q700
|
||||
203 682 233T619 263Q575 263 557 234Z" />
|
||||
<glyph unicode="&" glyph-name="ampersand" horiz-adv-x="729" d="M356 701T397 682T462 627T485 549Q485 490 448 448T344 366L520 200Q560 281 580 369L666 344Q631 228 577 147L689 42L623 -12L526 82Q483 35 429 12T305 -12Q239 -12 189 11T110 76T81
|
||||
175Q81 237 116 283T220 374Q170 422 147 460T123 546Q123 614 170 657T302 701Q356 701 397 682ZM261 633T237 609T213 547Q213 511 232 483T292 415Q343 446 369 476T395 544Q395 586 370 609T303 633Q261 633 237 609ZM223 291T199 257T175 178Q175 123 213
|
||||
92T315 61Q362 61 400 79T473 133L273 324Q223 291 199 257Z" />
|
||||
<glyph unicode="'" glyph-name="quotesingle" horiz-adv-x="219" d="M75 427L60 689H159L144 427H75Z" />
|
||||
<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="324" d="M284 805Q232 728 202 668T154 530T136 350Q136 248 153 171T201 33T284 -105L226 -145Q160 -51 125 9T65 154T40 350Q40 461 64 545T124 690T226 845L284 805Z" />
|
||||
<glyph unicode=")" glyph-name="parenright" horiz-adv-x="324" d="M164 751T199 691T259 546T284 350Q284 239 260 155T200 10T98 -145L40 -105Q92 -29 122 32T170 171T188 350Q188 453 171 530T123 667T40 805L98 845Q164 751 199 691Z" />
|
||||
<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="439" d="M419 561L266 528L370 412L298 359L219 493L141 359L69 411L172 528L20 561L47 643L189 582L174 739H264L249 581L391 644L419 561Z" />
|
||||
<glyph unicode="+" glyph-name="plus" horiz-adv-x="499" d="M291 519V369H437V293H291V144H207V293H62V369H207V519H291Z" />
|
||||
<glyph unicode="," glyph-name="comma" horiz-adv-x="240" d="M149 127T169 107T189 58Q189 27 171 -13L104 -166H38L78 0Q65 10 58 25T50 58Q50 87 70 107T119 127Q149 127 169 107Z" />
|
||||
<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="403" d="M60 274V352H343V274H60Z" />
|
||||
<glyph unicode="." glyph-name="period" horiz-adv-x="240" d="M149 127T169 107T189 58Q189 29 169 9T119 -12Q90 -12 70 8T50 58Q50 87 70 107T119 127Q149 127 169 107Z" />
|
||||
<glyph unicode="/" glyph-name="slash" horiz-adv-x="520" d="M337 807L415 789L184 -104L105 -85L337 807Z" />
|
||||
<glyph unicode="0" glyph-name="zero" d="M390 679T446 591T503 334Q503 166 447 77T279 -12Q168 -12 112 77T55 334Q55 502 111 590T279 679Q390 679 446 591ZM214 606T183 542T151 334Q151 190 182 126T279 61Q343 61 375 125T407 334Q407 477 375 541T279 606Q214
|
||||
606 183 542Z" />
|
||||
<glyph unicode="1" glyph-name="one" horiz-adv-x="433" d="M323 669V0H231V571L75 476L35 541L242 669H323Z" />
|
||||
<glyph unicode="2" glyph-name="two" horiz-adv-x="495" d="M288 679T333 655T404 590T429 496Q429 435 402 379T317 258T144 77H445L434 0H39V73Q173 212 229 276T309 389T333 492Q333 544 303 573T223 603Q182 603 151 586T85 530L25 578Q66 629 116 654T228
|
||||
679Q288 679 333 655Z" />
|
||||
<glyph unicode="3" glyph-name="three" horiz-adv-x="499" d="M287 679T331 656T399 594T423 509Q423 448 388 409T293 355Q360 349 402 307T444 193Q444 135 416 88T336 15T216 -12Q155 -12 104 10T15 78L70 129Q103 95 137 79T213 63Q276 63 312 98T348 194Q348
|
||||
260 314 287T215 314H165L176 385H210Q262 385 296 416T331 503Q331 550 301 577T220 605Q181 605 149 591T82 545L34 600Q119 679 225 679Q287 679 331 656Z" />
|
||||
<glyph unicode="4" glyph-name="four" horiz-adv-x="532" d="M502 238V165H415V0H326V165H40V231L241 679L318 647L137 238H327L335 418H415V238H502Z" />
|
||||
<glyph unicode="5" glyph-name="five" horiz-adv-x="501" d="M420 597H159V400Q210 426 266 426Q352 426 404 370T456 214Q456 148 427 97T346 17T224 -12Q163 -12 115 9T26 73L80 126Q112 94 146 79T223 63Q287 63 323 103T360 216Q360 289 327 322T238 355Q212
|
||||
355 190 350T143 332H71V669H433L420 597Z" />
|
||||
<glyph unicode="6" glyph-name="six" horiz-adv-x="533" d="M359 440T401 416T468 344T493 227Q493 156 465 102T388 18T280 -12Q163 -12 109 74T55 314Q55 423 85 505T173 633T308 679Q384 679 446 638L410 577Q363 606 307 606Q235 606 193 537T147 352Q209
|
||||
440 308 440Q359 440 401 416ZM338 61T369 105T400 224Q400 367 292 367Q248 367 211 343T148 275Q151 165 182 113T280 61Q338 61 369 105Z" />
|
||||
<glyph unicode="7" glyph-name="seven" horiz-adv-x="444" d="M414 669V600L164 -10L80 18L321 594H25V669H414Z" />
|
||||
<glyph unicode="8" glyph-name="eight" horiz-adv-x="551" d="M506 302T506 179Q506 124 477 81T394 13T274 -12Q206 -12 154 12T74 79T45 177Q45 239 78 281T177 351Q124 378 99 416T73 507Q73 561 101 600T176 659T276 679Q328 679 374 660T450 603T479 510Q479
|
||||
460 451 424T365 359Q506 302 506 179ZM224 610T194 583T163 506Q163 458 192 433T287 387L304 381Q349 407 369 436T389 507Q389 554 360 582T276 610Q224 610 194 583ZM337 61T373 93T410 178Q410 214 396 238T351 281T264 319L239 328Q189 304 165 268T141 177Q141
|
||||
122 177 92T275 61Q337 61 373 93Z" />
|
||||
<glyph unicode="9" glyph-name="nine" horiz-adv-x="525" d="M365 679T420 610T475 419Q475 282 438 199T325 66T119 -22L98 47Q232 85 303 150T380 323Q357 287 318 265T230 243Q178 243 136 269T70 344T45 458Q45 526 74 576T151 652T259 679Q365 679 420 610ZM328
|
||||
315T382 398Q384 509 355 557T261 606Q202 606 170 567T138 456Q138 386 168 351T249 315Q328 315 382 398Z" />
|
||||
<glyph unicode=":" glyph-name="colon" horiz-adv-x="240" d="M149 127T169 107T189 58Q189 29 169 9T119 -12Q90 -12 70 8T50 58Q50 87 70 107T119 127Q149 127 169 107ZM149 495T169 475T189 426Q189 397 169 377T119 356Q90 356 70 376T50 426Q50 455 70 475T119
|
||||
495Q149 495 169 475Z" />
|
||||
<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="240" d="M149 127T169 107T189 58Q189 27 171 -13L104 -166H38L78 0Q65 10 58 25T50 58Q50 87 70 107T119 127Q149 127 169 107ZM149 495T169 475T189 426Q189 397 169 377T119 356Q90 356 70 376T50 426Q50
|
||||
455 70 475T119 495Q149 495 169 475Z" />
|
||||
<glyph unicode="<" glyph-name="less" horiz-adv-x="500" d="M417 551L450 475L123 333L450 189L417 115L50 286V380L417 551Z" />
|
||||
<glyph unicode="=" glyph-name="equal" horiz-adv-x="500" d="M62 389V466H438V389H62ZM62 452V529H438V452H62Z" />
|
||||
<glyph unicode=">" glyph-name="greater" horiz-adv-x="500" d="M83 551L450 380V286L83 115L50 189L377 333L50 475L83 551Z" />
|
||||
<glyph unicode="?" glyph-name="question" horiz-adv-x="459" d="M298 701T341 680T407 622T429 545Q429 506 416 479T383 434T332 394Q290 365 269 341T248 275V230H157V280Q157 323 171 353T206 401T259 442Q297 467 315 487T333 539Q333 580 306 602T232 625Q152
|
||||
625 93 553L30 602Q114 701 238 701Q298 701 341 680ZM235 127T255 107T275 58Q275 29 255 9T205 -12Q176 -12 156 8T136 58Q136 87 156 107T205 127Q235 127 255 107Z" />
|
||||
<glyph unicode="@" glyph-name="at" horiz-adv-x="1020" d="M660 701T756 648T901 504T950 307Q950 177 900 93T753 9Q697 9 666 40T625 112Q606 68 571 40T481 11Q401 11 355 71T308 231Q308 357 368 424T526 492Q568 492 605 483T683 452V193Q683 131 700 106T751
|
||||
80Q857 80 857 305Q857 402 819 474T707 585T526 625Q416 625 334 576T207 439T163 240Q163 129 205 44T330 -89T526 -137Q621 -137 718 -103L743 -174Q687 -194 638 -203T525 -213Q391 -213 288 -158T128 1T70 240Q70 370 127 475T289 640T526 701Q660 701 756
|
||||
648ZM567 78T600 164V411Q567 426 529 426Q398 426 398 231Q398 156 422 117T492 78Q567 78 600 164Z" />
|
||||
<glyph unicode="A" glyph-name="A" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250Z" />
|
||||
<glyph unicode="B" glyph-name="B" horiz-adv-x="608" d="M475 352T519 314T563 196Q563 0 290 0H100V689H263Q394 689 463 646T533 515Q533 455 496 415T404 364Q475 352 519 314ZM195 614V397H299Q359 397 397 426T436 508Q436 568 396 591T273 614H195ZM374
|
||||
76T418 101T463 196Q463 264 420 294T308 324H195V76H290Q374 76 418 101Z" />
|
||||
<glyph unicode="C" glyph-name="C" horiz-adv-x="560" d="M403 701T445 685T532 633L480 572Q417 623 347 623Q261 623 209 557T156 345Q156 203 208 136T346 68Q390 68 423 83T493 125L540 65Q508 32 458 10T343 -12Q259 -12 194 29T92 151T55 345Q55 458 93
|
||||
538T196 660T341 701Q403 701 445 685Z" />
|
||||
<glyph unicode="D" glyph-name="D" horiz-adv-x="644" d="M400 689T494 617T589 348Q589 157 495 79T265 0H100V689H244Q400 689 494 617ZM195 613V75H272Q368 75 428 134T488 348Q488 457 457 515T378 593T265 613H195Z" />
|
||||
<glyph unicode="E" glyph-name="E" horiz-adv-x="535" d="M473 689L462 613H195V388H427V312H195V76H481V0H100V689H473Z" />
|
||||
<glyph unicode="F" glyph-name="F" horiz-adv-x="491" d="M100 0V689H466L455 613H195V378H420V303H195V0H100Z" />
|
||||
<glyph unicode="G" glyph-name="G" horiz-adv-x="631" d="M419 701T466 683T561 625L505 567Q468 597 434 610T354 623Q301 623 257 595T184 504T156 345Q156 200 203 133T344 66Q420 66 475 97V305H353L342 382H569V49Q462 -12 344 -12Q208 -12 132 79T55 345Q55
|
||||
457 95 537T204 659T354 701Q419 701 466 683Z" />
|
||||
<glyph unicode="H" glyph-name="H" horiz-adv-x="680" d="M485 0V323H195V0H100V689H195V401H485V689H580V0H485Z" />
|
||||
<glyph unicode="I" glyph-name="I" horiz-adv-x="295" d="M195 689V0H100V689H195Z" />
|
||||
<glyph unicode="J" glyph-name="J" horiz-adv-x="305" d="M210 96Q210 -6 166 -57T30 -137L5 -68Q51 -50 74 -29T106 22T115 100V689H210V96Z" />
|
||||
<glyph unicode="K" glyph-name="K" horiz-adv-x="589" d="M195 689V0H100V689H195ZM570 689L309 374L589 0H472L200 368L462 689H570Z" />
|
||||
<glyph unicode="L" glyph-name="L" horiz-adv-x="498" d="M195 689V83H478L467 0H100V689H195Z" />
|
||||
<glyph unicode="M" glyph-name="M" horiz-adv-x="778" d="M716 0H624L600 311Q585 494 583 592L434 78H345L188 593Q188 468 175 304L152 0H62L119 689H247L392 188L530 689H659L716 0Z" />
|
||||
<glyph unicode="N" glyph-name="N" horiz-adv-x="683" d="M583 0H456L176 585Q182 516 185 458T189 316V0H100V689H224L507 103Q504 129 499 194T494 313V689H583V0Z" />
|
||||
<glyph unicode="O" glyph-name="O" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200 206 133T346 66Q536
|
||||
66 536 344Q536 623 346 623Q256 623 206 555Z" />
|
||||
<glyph unicode="P" glyph-name="P" horiz-adv-x="581" d="M409 689T479 636T549 476Q549 363 476 308T282 253H195V0H100V689H281Q409 689 479 636ZM361 328T404 360T448 475Q448 549 405 582T280 615H195V328H278Q361 328 404 360Z" />
|
||||
<glyph unicode="Q" glyph-name="Q" horiz-adv-x="691" d="M534 39T579 23T666 -23L604 -103Q544 -50 490 -30T344 -10Q258 -10 193 30T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660T600 538T637 344Q637 223 597 152T479 39Q534 39 579 23ZM156
|
||||
200T206 133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555T156 343Q156 200 206 133Z" />
|
||||
<glyph unicode="R" glyph-name="R" horiz-adv-x="605" d="M302 292H195V0H100V689H281Q410 689 476 640T543 494Q543 422 506 377T394 309L580 0H467L302 292ZM291 365Q366 365 404 395T442 494Q442 558 404 586T280 615H195V365H291Z" />
|
||||
<glyph unicode="S" glyph-name="S" horiz-adv-x="545" d="M339 701T388 682T483 621L431 563Q392 594 355 608T274 623Q220 623 185 598T150 525Q150 495 162 475T206 437T301 401Q366 381 409 358T478 295T505 192Q505 132 476 86T391 14T259 -12Q116 -12 25
|
||||
77L77 135Q119 101 162 84T258 66Q322 66 364 97T406 189Q406 223 393 245T349 286T257 322Q151 354 102 399T53 521Q53 573 80 614T157 678T270 701Q339 701 388 682Z" />
|
||||
<glyph unicode="T" glyph-name="T" horiz-adv-x="517" d="M507 689L497 608H306V0H211V608H15V689H507Z" />
|
||||
<glyph unicode="U" glyph-name="U" horiz-adv-x="662" d="M572 221Q572 152 544 100T461 18T330 -12Q215 -12 153 51T90 221V689H185V228Q185 148 221 108T330 68Q404 68 440 107T476 228V689H572V221Z" />
|
||||
<glyph unicode="V" glyph-name="V" horiz-adv-x="556" d="M550 689L330 0H228L6 689H108L281 103L454 689H550Z" />
|
||||
<glyph unicode="W" glyph-name="W" horiz-adv-x="826" d="M801 689L661 0H539L412 577L284 0H165L25 689H118L229 83L362 689H463L599 83L714 689H801Z" />
|
||||
<glyph unicode="X" glyph-name="X" horiz-adv-x="540" d="M325 372L535 0H427L268 305L107 0H5L212 367L23 689H131L270 430L410 689H512L325 372Z" />
|
||||
<glyph unicode="Y" glyph-name="Y" horiz-adv-x="550" d="M545 689L323 265V0H227V264L5 689H110L278 348L446 689H545Z" />
|
||||
<glyph unicode="Z" glyph-name="Z" horiz-adv-x="522" d="M477 689V612L136 81H477L466 0H30V76L374 609H66V689H477Z" />
|
||||
<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="322" d="M272 816V739H152V-40H272V-116H65V816H272Z" />
|
||||
<glyph unicode="\" glyph-name="backslash" horiz-adv-x="520" d="M183 807L415 -85L336 -104L105 789L183 807Z" />
|
||||
<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="322" d="M257 816V-116H50V-40H170V739H50V816H257Z" />
|
||||
<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="540" d="M311 840L500 527H402L269 760L137 527H40L229 840H311Z" />
|
||||
<glyph unicode="_" glyph-name="underscore" horiz-adv-x="520" d="M17 -142V-63H503V-142H17Z" />
|
||||
<glyph unicode="`" glyph-name="grave" horiz-adv-x="300" d="M71 801L270 687L242 638L30 724L71 801Z" />
|
||||
<glyph unicode="a" glyph-name="a" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539 265 539Q358
|
||||
539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139Z" />
|
||||
<glyph unicode="b" glyph-name="b" horiz-adv-x="594" d="M426 539T479 467T532 264Q532 182 507 120T435 23T325 -12Q242 -12 185 58L176 0H95V739L187 750V461Q244 539 336 539Q426 539 479 467ZM364 61T398 110T433 264Q433 371 401 418T310 466Q240 466 187
|
||||
384V132Q208 99 238 80T303 61Q364 61 398 110Z" />
|
||||
<glyph unicode="c" glyph-name="c" horiz-adv-x="478" d="M334 539T373 526T448 482L404 424Q376 444 350 453T291 463Q227 463 192 412T156 261Q156 161 191 114T291 66Q322 66 348 75T406 106L448 46Q376 -12 287 -12Q180 -12 119 60T57 259Q57 343 85 406T164
|
||||
504T287 539Q334 539 373 526Z" />
|
||||
<glyph unicode="d" glyph-name="d" horiz-adv-x="598" d="M503 739V0H422L413 73Q387 33 348 11T261 -12Q167 -12 115 62T62 261Q62 342 87 405T159 503T269 539Q350 539 411 474V750L503 739ZM323 61T353 80T411 139V397Q385 431 356 448T289 466Q228 466 195
|
||||
415T161 263Q161 161 192 111T281 61Q323 61 353 80Z" />
|
||||
<glyph unicode="e" glyph-name="e" horiz-adv-x="545" d="M493 256T491 232H155Q161 145 199 104T297 63Q335 63 367 74T434 109L474 54Q390 -12 290 -12Q180 -12 119 60T57 258Q57 340 83 403T159 503T276 539Q381 539 437 470T493 279Q493 256 491 232ZM402
|
||||
306Q402 384 371 425T278 466Q165 466 155 300H402V306Z" />
|
||||
<glyph unicode="f" glyph-name="f" horiz-adv-x="335" d="M232 676T214 658T196 600V527H324L314 456H196V0H104V456H10V527H104V599Q104 667 147 708T269 750Q305 750 333 744T395 723L366 656Q321 676 274 676Q232 676 214 658Z" />
|
||||
<glyph unicode="g" glyph-name="g" horiz-adv-x="520" d="M520 503Q490 493 454 490T366 487Q459 445 459 354Q459 275 405 225T258 175Q222 175 191 185Q179 177 172 164T165 136Q165 93 234 93H318Q371 93 412 74T475 22T498 -53Q498 -130 435 -171T251 -213Q166
|
||||
-213 117 -196T46 -143T25 -53H108Q108 -85 120 -103T163 -131T251 -141Q334 -141 369 -121T405 -59Q405 -22 377 -3T299 16H216Q149 16 115 44T80 116Q80 142 95 166T138 209Q92 233 71 268T49 355Q49 408 75 450T148 515T252 539Q314 538 356 543T425 558T493
|
||||
586L520 503ZM200 473T172 441T143 355Q143 301 172 269T254 236Q308 236 336 267T365 356Q365 473 252 473Q200 473 172 441Z" />
|
||||
<glyph unicode="h" glyph-name="h" horiz-adv-x="586" d="M415 539T455 496T496 378V0H404V365Q404 421 383 444T320 467Q279 467 247 443T187 375V0H95V738L187 748V454Q249 539 343 539Q415 539 455 496Z" />
|
||||
<glyph unicode="i" glyph-name="i" horiz-adv-x="282" d="M187 527V0H95V527H187ZM169 780T187 762T205 717Q205 690 187 673T140 655Q112 655 94 672T76 717Q76 744 94 762T140 780Q169 780 187 762Z" />
|
||||
<glyph unicode="j" glyph-name="j" horiz-adv-x="280" d="M185 32Q185 -41 167 -85T115 -156T18 -212L-9 -145Q30 -127 51 -110T82 -61T93 26V527H185V32ZM168 780T186 762T204 717Q204 690 186 673T139 655Q111 655 93 672T75 717Q75 744 93 762T139 780Q168
|
||||
780 186 762Z" />
|
||||
<glyph unicode="k" glyph-name="k" horiz-adv-x="512" d="M187 750V0H95V739L187 750ZM490 527L296 294L512 0H402L193 288L387 527H490Z" />
|
||||
<glyph unicode="l" glyph-name="l" horiz-adv-x="293" d="M149 -12T120 18T90 104V739L182 750V106Q182 84 189 74T215 64Q234 64 249 70L273 6Q240 -12 200 -12Q149 -12 120 18Z" />
|
||||
<glyph unicode="m" glyph-name="m" horiz-adv-x="857" d="M689 539T728 496T767 378V0H675V365Q675 467 601 467Q562 467 535 445T477 374V0H385V365Q385 467 311 467Q271 467 244 444T187 374V0H95V527H174L182 450Q241 539 334 539Q383 539 417 514T467 444Q498
|
||||
490 535 514T624 539Q689 539 728 496Z" />
|
||||
<glyph unicode="n" glyph-name="n" horiz-adv-x="586" d="M415 539T455 496T496 378V0H404V365Q404 421 383 444T321 467Q279 467 247 443T187 374V0H95V527H174L182 449Q210 491 251 515T343 539Q415 539 455 496Z" />
|
||||
<glyph unicode="o" glyph-name="o" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428 465 293 465Q156
|
||||
465 156 263Z" />
|
||||
<glyph unicode="p" glyph-name="p" horiz-adv-x="594" d="M438 539T485 467T532 264Q532 140 478 64T325 -12Q237 -12 187 48V-202L95 -213V527H174L181 456Q210 496 251 517T337 539Q438 539 485 467ZM433 63T433 264Q433 466 314 466Q275 466 243 443T187 384V127Q207
|
||||
96 237 80T303 63Q433 63 433 264Z" />
|
||||
<glyph unicode="q" glyph-name="q" horiz-adv-x="598" d="M503 527V-213L411 -202V70Q385 31 347 10T261 -12Q167 -12 115 62T62 261Q62 342 87 405T159 503T269 539Q353 539 417 468L424 527H503ZM323 61T353 80T411 139V397Q385 431 356 448T289 466Q228 466
|
||||
195 415T161 263Q161 161 192 111T281 61Q323 61 353 80Z" />
|
||||
<glyph unicode="r" glyph-name="r" horiz-adv-x="386" d="M352 539T376 533L359 443Q335 449 313 449Q264 449 234 413T187 301V0H95V527H174L183 420Q204 479 240 509T324 539Q352 539 376 533Z" />
|
||||
<glyph unicode="s" glyph-name="s" horiz-adv-x="467" d="M292 539T335 524T417 479L378 421Q342 444 310 455T241 466Q196 466 170 448T144 397Q144 365 168 347T257 312Q345 290 388 252T432 148Q432 70 372 29T224 -12Q104 -12 25 57L74 113Q141 62 222 62Q274
|
||||
62 304 83T335 142Q335 169 324 185T286 214T207 241Q123 263 86 300T48 394Q48 435 72 468T140 520T238 539Q292 539 335 524Z" />
|
||||
<glyph unicode="t" glyph-name="t" horiz-adv-x="361" d="M361 24Q309 -12 243 -12Q176 -12 139 26T101 138V456H9V527H101V646L193 657V527H318L308 456H193V142Q193 101 207 83T256 64Q287 64 326 85L361 24Z" />
|
||||
<glyph unicode="u" glyph-name="u" horiz-adv-x="582" d="M487 0H408L401 82Q371 33 332 11T237 -12Q168 -12 129 30T90 149V527H182V159Q182 105 201 83T263 60Q340 60 395 151V527H487V0Z" />
|
||||
<glyph unicode="v" glyph-name="v" horiz-adv-x="492" d="M482 527L303 0H192L10 527H110L248 82L385 527H482Z" />
|
||||
<glyph unicode="w" glyph-name="w" horiz-adv-x="717" d="M697 527L577 0H452L360 444L265 0H143L20 527H112L207 64L311 527H414L513 64L609 527H697Z" />
|
||||
<glyph unicode="x" glyph-name="x" horiz-adv-x="485" d="M297 282L480 0H369L240 223L109 0H5L189 278L26 527H134L244 334L355 527H459L297 282Z" />
|
||||
<glyph unicode="y" glyph-name="y" horiz-adv-x="492" d="M306 -3Q275 -95 220 -148T61 -213L51 -141Q103 -132 134 -115T183 -72T218 0H187L10 527H108L249 67L387 527H482L306 -3Z" />
|
||||
<glyph unicode="z" glyph-name="z" horiz-adv-x="437" d="M404 527V457L129 77H407L396 0H25V69L299 449H48V527H404Z" />
|
||||
<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="322" d="M277 765Q226 765 204 750T182 697V458Q182 407 164 385T107 349Q147 335 164 314T182 242V3Q182 -34 204 -49T277 -65V-136Q177 -136 136 -102T95 13V235Q95 277 80 294T25 311V387Q64 387 79
|
||||
405T95 465V687Q95 767 136 801T277 836V765Z" />
|
||||
<glyph unicode="|" glyph-name="bar" horiz-adv-x="403" d="M243 807V-102H160V807H243Z" />
|
||||
<glyph unicode="}" glyph-name="braceright" horiz-adv-x="322" d="M145 836T186 802T227 687V465Q227 423 242 405T297 387V311Q258 311 243 294T227 235V13Q227 -67 186 -101T45 -136V-65Q96 -65 118 -50T140 3V242Q140 293 157 314T215 349Q176 362 158 384T140
|
||||
458V697Q140 734 118 749T45 765V836Q145 836 186 802Z" />
|
||||
<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="488" d="M290 250T269 259T217 288Q199 300 187 306T163 312Q124 312 91 258L35 287Q85 384 172 384Q200 384 221 375T270 348Q290 335 302 329T328 323Q349 323 367 336T398 371L453 341Q406 250 319
|
||||
250Q290 250 269 259Z" />
|
||||
<glyph unicode=" " glyph-name="uni00A0" horiz-adv-x="265" />
|
||||
<glyph unicode="¡" glyph-name="exclamdown" horiz-adv-x="241" d="M150 495T170 475T190 425Q190 396 170 376T121 356Q91 356 71 376T51 425Q51 454 71 474T121 495Q150 495 170 475ZM162 247L173 -202H71L81 247H162Z" />
|
||||
<glyph unicode="¢" glyph-name="cent" horiz-adv-x="478" d="M448 46Q392 1 329 -9V-154H249V-9Q159 3 108 73T57 259Q57 374 108 448T250 536V684H329V536Q394 527 448 482L404 424Q376 444 350 453T291 463Q227 463 192 412T156 261Q156 161 191 114T291
|
||||
66Q322 66 348 75T406 106L448 46Z" />
|
||||
<glyph unicode="£" glyph-name="sterling" horiz-adv-x="520" d="M213 153T200 125T152 77H472L461 0H40V73Q75 86 92 100T115 138T122 205V322H56V382H122V493Q122 576 172 627T311 679Q366 679 410 659T490 596L430 550Q406 578 379 591T315 604Q266 604
|
||||
240 576T213 494V382H421V322H213V204Q213 153 200 125Z" />
|
||||
<glyph unicode="¤" glyph-name="currency" horiz-adv-x="560" d="M492 272T455 218L531 143L476 88L398 164Q345 132 278 132Q212 132 160 167L82 88L29 143L107 221Q71 274 71 341Q71 406 106 460L29 540L84 595L162 515Q211 549 278 549Q347 549 399 516L478
|
||||
595L531 540L455 463Q492 411 492 341Q492 272 455 218ZM341 205T372 241T404 342Q404 407 373 443T281 479Q222 479 191 443T159 342Q159 277 190 241T281 205Q341 205 372 241Z" />
|
||||
<glyph unicode="¥" glyph-name="yen" horiz-adv-x="536" d="M531 669L340 346H453V284H315V194H453V133H315V0H221V133H82V194H221V284H82V346H196L5 669H107L271 374L434 669H531Z" />
|
||||
<glyph unicode="¦" glyph-name="brokenbar" horiz-adv-x="403" d="M243 807V443H160V807H243ZM243 262V-102H160V262H243Z" />
|
||||
<glyph unicode="§" glyph-name="section" horiz-adv-x="533" d="M441 136T441 75Q441 8 387 -31T246 -71Q149 -71 78 -21L113 40Q143 20 175 11T249 1Q293 1 321 18T349 66Q349 90 339 105T304 133T225 163Q142 190 106 222T70 311Q70 347 90 378T147 432Q120
|
||||
450 107 474T94 533Q94 600 146 638T281 677Q378 677 452 623L417 565Q384 586 352 596T280 606Q235 606 210 589T185 540Q185 516 194 501T230 471T307 440Q390 412 426 379T463 293Q463 224 387 173Q441 136 441 75ZM159 287T178 269T254 233Q297 219 333 203Q353
|
||||
221 364 241T375 280Q375 304 366 319T335 347T267 376Q232 389 200 403Q181 384 170 363T159 323Q159 287 178 269Z" />
|
||||
<glyph unicode="¨" glyph-name="dieresis" horiz-adv-x="385" d="M112 768T128 752T145 711Q145 687 129 671T88 654Q63 654 47 670T30 711Q30 735 46 751T88 768Q112 768 128 752ZM322 768T338 752T355 711Q355 687 339 671T297 654Q273 654 257 670T240
|
||||
711Q240 735 256 751T297 768Q322 768 338 752Z" />
|
||||
<glyph unicode="©" glyph-name="copyright" horiz-adv-x="810" d="M492 748T563 708T676 596T718 434Q718 344 677 273T564 161T406 121Q320 121 248 161T134 272T92 434Q92 524 134 595T248 707T406 748Q492 748 563 708ZM334 696T277 663T186 570T153 434Q153
|
||||
358 186 299T276 207T406 174Q477 174 534 207T625 299T658 434Q658 510 625 570T535 663T406 696Q334 696 277 663ZM444 625T471 615T525 585L490 538Q452 565 412 565Q371 565 346 533T321 435Q321 372 345 340T412 308Q437 308 456 315T496 339L528 291Q476
|
||||
245 409 245Q335 245 290 295T245 435Q245 495 267 538T326 603T408 625Q444 625 471 615Z" />
|
||||
<glyph unicode="ª" glyph-name="ordfeminine" horiz-adv-x="500" d="M313 525V549Q313 588 293 604T230 620Q181 620 117 599L95 661Q173 689 245 689Q402 689 402 554V384Q402 361 410 350T435 333L416 272Q381 276 360 289T327 331Q306 301 274 286T201
|
||||
271Q138 271 102 304T65 393Q65 457 114 491T255 525H313ZM280 337T313 390V470H265Q159 470 159 398Q159 369 176 353T224 337Q280 337 313 390ZM71 77H447V0H71V77Z" />
|
||||
<glyph unicode="«" glyph-name="guillemotleft" horiz-adv-x="575" d="M230 535L285 497L150 287L285 77L230 39L55 255V318L230 535ZM465 535L520 497L385 287L520 77L465 39L290 255V318L465 535Z" />
|
||||
<glyph unicode="¬" glyph-name="logicalnot" horiz-adv-x="500" d="M438 361V141H355V284H62V361H438Z" />
|
||||
<glyph unicode="­" glyph-name="uni00AD" horiz-adv-x="403" d="M60 274V352H343V274H60Z" />
|
||||
<glyph unicode="®" glyph-name="registered" horiz-adv-x="641" d="M390 750T448 716T540 622T574 493Q574 423 541 365T449 272T319 238Q250 238 192 272T101 364T67 493Q67 563 100 622T192 715T319 750Q390 750 448 716ZM377 287T422 313T493 387T519
|
||||
493Q519 552 494 599T423 674T319 701Q263 701 218 674T148 600T122 493Q122 434 147 387T218 314T319 287Q377 287 422 313ZM428 522T410 503T363 474L437 359H370L309 465H285V359H228V635H306Q428 635 428 551Q428 522 410 503ZM285 509H315Q369 509 369 551Q369
|
||||
572 356 581T313 591H285V509Z" />
|
||||
<glyph unicode="¯" glyph-name="overscore" horiz-adv-x="333" d="M303 667H30V736H303V667Z" />
|
||||
<glyph unicode="°" glyph-name="degree" horiz-adv-x="523" d="M176 381T139 400T78 455T55 541Q55 590 78 626T138 682T219 701Q262 701 299 682T360 626T383 540Q383 491 360 455T300 400T219 381Q176 381 139 400ZM256 443T281 468T306 540Q306 587 281
|
||||
612T219 638Q182 638 157 613T132 541Q132 494 157 469T219 443Q256 443 281 468Z" />
|
||||
<glyph unicode="±" glyph-name="plusminus" horiz-adv-x="500" d="M62 0V77H438V0H62ZM292 542V392H438V316H292V167H208V316H63V392H208V542H292Z" />
|
||||
<glyph unicode="²" glyph-name="uni00B2" horiz-adv-x="400" d="M259 746T296 712T334 626Q334 592 318 561T264 489T155 384H344L336 322H67V380Q151 461 187 499T238 565T254 620Q254 650 236 667T189 684Q163 684 144 674T104 640L55 678Q110 746 195
|
||||
746Q259 746 296 712Z" />
|
||||
<glyph unicode="³" glyph-name="uni00B3" horiz-adv-x="400" d="M261 746T297 716T334 641Q334 603 311 578T248 543Q292 539 320 513T348 441Q348 386 306 350T191 313Q104 313 52 373L97 415Q135 374 187 374Q224 374 245 393T267 445Q267 481 247 496T187
|
||||
512H153L162 568H185Q217 568 237 584T257 631Q257 657 239 672T191 687Q166 687 145 678T103 650L63 694Q121 746 197 746Q261 746 297 716Z" />
|
||||
<glyph unicode="´" glyph-name="acute" horiz-adv-x="300" d="M229 801L270 724L58 638L30 687L229 801Z" />
|
||||
<glyph unicode="µ" glyph-name="uni00B5" horiz-adv-x="588" d="M487 80T513 0L427 -12Q416 14 412 33T403 85V86Q379 44 344 16T265 -12Q230 -12 208 -1T169 38Q178 10 182 -20T186 -96V-202L95 -213V527H187V156Q187 67 266 67Q346 67 395 163V527H487V180Q487
|
||||
80 513 0Z" />
|
||||
<glyph unicode="¶" glyph-name="paragraph" horiz-adv-x="734" d="M594 689V-202L511 -215V616H397V-202L314 -215V282Q201 288 146 343T90 486Q90 583 156 636T336 689H594Z" />
|
||||
<glyph unicode="·" glyph-name="middot" horiz-adv-x="240" d="M149 380T169 360T189 311Q189 282 169 262T119 241Q90 241 70 261T50 311Q50 340 70 360T119 380Q149 380 169 360Z" />
|
||||
<glyph unicode="¸" glyph-name="cedilla" horiz-adv-x="275" d="M152 -56Q200 -60 222 -83T245 -141Q245 -189 210 -215T121 -241Q93 -241 69 -235T30 -217L55 -165Q85 -181 118 -181Q141 -181 154 -172T168 -141Q168 -120 147 -110T79 -99L93 16H152V-56Z" />
|
||||
<glyph unicode="¹" glyph-name="uni00B9" horiz-adv-x="400" d="M274 739V322H197V660L99 603L65 656L205 739H274Z" />
|
||||
<glyph unicode="º" glyph-name="ordmasculine" horiz-adv-x="500" d="M343 689T393 634T444 480Q444 385 393 328T250 271Q158 271 107 327T56 480Q56 575 108 632T251 689Q343 689 393 634ZM151 620T151 480Q151 340 250 340Q349 340 349 480Q349 552 325
|
||||
586T251 620Q151 620 151 480ZM62 0V77H438V0H62Z" />
|
||||
<glyph unicode="»" glyph-name="guillemotright" horiz-adv-x="566" d="M110 535L285 318V255L110 39L55 77L190 287L55 497L110 535ZM336 535L511 318V255L336 39L281 77L416 287L281 497L336 535Z" />
|
||||
<glyph unicode="¼" glyph-name="onequarter" horiz-adv-x="932" d="M274 689V272H197V610L99 553L65 606L205 689H274ZM640 750L699 721L293 -78L233 -49L640 750ZM889 156V96H836V0H760V96H574V150L702 424L768 399L655 156H761L768 261H836V156H889Z" />
|
||||
<glyph unicode="½" glyph-name="onehalf" horiz-adv-x="932" d="M274 689V272H197V610L99 553L65 606L205 689H274ZM640 750L699 721L293 -78L233 -49L640 750ZM791 424T828 390T866 304Q866 270 850 239T796 167T687 62H876L868 0H599V58Q683 139 719 177T770
|
||||
243T786 298Q786 328 768 345T721 362Q695 362 676 352T636 318L587 356Q642 424 727 424Q791 424 828 390Z" />
|
||||
<glyph unicode="¾" glyph-name="threequarters" horiz-adv-x="932" d="M261 696T297 666T334 591Q334 553 311 528T248 493Q292 489 320 463T348 391Q348 336 306 300T191 263Q104 263 52 323L97 365Q135 324 187 324Q224 324 245 343T267 395Q267 431 247
|
||||
446T187 462H153L162 518H185Q217 518 237 534T257 581Q257 607 239 622T191 637Q166 637 145 628T103 600L63 644Q121 696 197 696Q261 696 297 666ZM640 750L699 721L293 -78L233 -49L640 750ZM889 156V96H836V0H760V96H574V150L702 424L768 399L655 156H761L768
|
||||
261H836V156H889Z" />
|
||||
<glyph unicode="¿" glyph-name="questiondown" horiz-adv-x="459" d="M224 356T204 376T184 425Q184 454 204 474T254 495Q283 495 303 475T323 425Q323 396 303 376T254 356Q224 356 204 376ZM161 -215T118 -194T52 -136T30 -59Q30 -19 43 8T77 53T129 92Q170
|
||||
120 190 143T211 206V247H302V201Q302 159 288 130T254 84T201 44Q163 20 145 0T126 -53Q126 -94 153 -116T227 -139Q307 -139 366 -67L429 -116Q345 -215 221 -215Q161 -215 118 -194Z" />
|
||||
<glyph unicode="À" glyph-name="Agrave" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM196 911L397 804L373 755L157 834L196 911Z" />
|
||||
<glyph unicode="Á" glyph-name="Aacute" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM367 911L407 834L191 755L167 804L367 911Z" />
|
||||
<glyph unicode="Â" glyph-name="Acircumflex" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM160 759L120 804L256 914H317L452 804L413 759L286 840L160 759Z" />
|
||||
<glyph unicode="Ã" glyph-name="Atilde" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM326 782T311 789T276 809Q261 820 251 825T229 830Q213 830 201 819T176 784L120 812Q139 852 166 876T229
|
||||
900Q250 900 265 893T299 872Q302 870 311 864T329 855T345 852Q360 852 372 862T398 896L454 868Q435 826 407 804T345 782Q326 782 311 789Z" />
|
||||
<glyph unicode="Ä" glyph-name="Adieresis" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM206 894T222 878T239 837Q239 813 223 797T182 780Q157 780 141 796T124 837Q124 861 140 877T182 894Q206
|
||||
894 222 878ZM416 894T432 878T449 837Q449 813 433 797T391 780Q367 780 351 796T334 837Q334 861 350 877T391 894Q416 894 432 878Z" />
|
||||
<glyph unicode="Å" glyph-name="Aring" horiz-adv-x="573" d="M467 0L415 173H154L102 0H6L227 689H347L567 0H467ZM177 250H392L285 610L177 250ZM337 962T369 932T401 856Q401 811 369 781T287 750Q237 750 205 780T173 856Q173 901 205 931T287 962Q337
|
||||
962 369 932ZM262 912T248 897T234 856Q234 830 248 815T287 800Q311 800 325 815T340 856Q340 882 326 897T287 912Q262 912 248 897Z" />
|
||||
<glyph unicode="Æ" glyph-name="AE" horiz-adv-x="816" d="M535 76H762V0H458L418 173H150L85 0H-12L262 689H721L710 613H401L457 387H712V311H476L535 76ZM179 250H400L316 613L179 250Z" />
|
||||
<glyph unicode="Ç" glyph-name="Ccedilla" horiz-adv-x="560" d="M512 36T471 16T376 -10V-56Q424 -60 446 -83T469 -141Q469 -189 434 -215T345 -241Q317 -241 293 -235T254 -217L279 -165Q309 -181 342 -181Q365 -181 378 -172T392 -141Q392 -120 371 -110T303
|
||||
-99L314 -11Q237 -4 179 39T88 160T55 345Q55 458 93 538T196 660T341 701Q403 701 445 685T532 633L480 572Q417 623 347 623Q261 623 209 557T156 345Q156 203 208 136T346 68Q390 68 423 83T493 125L540 65Q512 36 471 16Z" />
|
||||
<glyph unicode="È" glyph-name="Egrave" horiz-adv-x="535" d="M473 689L462 613H195V388H427V312H195V76H481V0H100V689H473ZM199 911L400 804L376 755L160 834L199 911Z" />
|
||||
<glyph unicode="É" glyph-name="Eacute" horiz-adv-x="535" d="M473 689L462 613H195V388H427V312H195V76H481V0H100V689H473ZM370 911L410 834L194 755L170 804L370 911Z" />
|
||||
<glyph unicode="Ê" glyph-name="Ecircumflex" horiz-adv-x="535" d="M473 689L462 613H195V388H427V312H195V76H481V0H100V689H473ZM163 759L123 804L259 914H320L455 804L416 759L289 840L163 759Z" />
|
||||
<glyph unicode="Ë" glyph-name="Edieresis" horiz-adv-x="535" d="M473 689L462 613H195V388H427V312H195V76H481V0H100V689H473ZM209 894T225 878T242 837Q242 813 226 797T185 780Q160 780 144 796T127 837Q127 861 143 877T185 894Q209 894 225 878ZM419
|
||||
894T435 878T452 837Q452 813 436 797T394 780Q370 780 354 796T337 837Q337 861 353 877T394 894Q419 894 435 878Z" />
|
||||
<glyph unicode="Ì" glyph-name="Igrave" horiz-adv-x="295" d="M195 689V0H100V689H195ZM56 911L257 804L233 755L17 834L56 911Z" />
|
||||
<glyph unicode="Í" glyph-name="Iacute" horiz-adv-x="295" d="M195 689V0H100V689H195ZM227 911L267 834L51 755L27 804L227 911Z" />
|
||||
<glyph unicode="Î" glyph-name="Icircumflex" horiz-adv-x="295" d="M195 689V0H100V689H195ZM20 759L-20 804L116 914H177L312 804L273 759L146 840L20 759Z" />
|
||||
<glyph unicode="Ï" glyph-name="Idieresis" horiz-adv-x="295" d="M195 689V0H100V689H195ZM66 894T82 878T99 837Q99 813 83 797T42 780Q17 780 1 796T-16 837Q-16 861 0 877T42 894Q66 894 82 878ZM276 894T292 878T309 837Q309 813 293 797T251 780Q227
|
||||
780 211 796T194 837Q194 861 210 877T251 894Q276 894 292 878Z" />
|
||||
<glyph unicode="Ð" glyph-name="Eth" horiz-adv-x="656" d="M412 689T506 617T601 348Q601 157 507 79T277 0H112V318H20V388H112V689H256Q412 689 506 617ZM380 75T440 134T500 348Q500 457 469 515T390 593T277 613H207V388H364V318H207V75H284Q380 75 440 134Z" />
|
||||
<glyph unicode="Ñ" glyph-name="Ntilde" horiz-adv-x="683" d="M583 0H456L176 585Q182 516 185 458T189 316V0H100V689H224L507 103Q504 129 499 194T494 313V689H583V0ZM392 782T377 789T342 809Q327 820 317 825T295 830Q279 830 267 819T242 784L186
|
||||
812Q205 852 232 876T295 900Q316 900 331 893T365 872Q368 870 377 864T395 855T411 852Q426 852 438 862T464 896L520 868Q501 826 473 804T411 782Q392 782 377 789Z" />
|
||||
<glyph unicode="Ò" glyph-name="Ograve" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200 206
|
||||
133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555ZM255 911L456 804L432 755L216 834L255 911Z" />
|
||||
<glyph unicode="Ó" glyph-name="Oacute" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200 206
|
||||
133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555ZM426 911L466 834L250 755L226 804L426 911Z" />
|
||||
<glyph unicode="Ô" glyph-name="Ocircumflex" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200
|
||||
206 133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555ZM219 759L179 804L315 914H376L511 804L472 759L345 840L219 759Z" />
|
||||
<glyph unicode="Õ" glyph-name="Otilde" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200 206
|
||||
133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555ZM385 782T370 789T335 809Q320 820 310 825T288 830Q272 830 260 819T235 784L179 812Q198 852 225 876T288 900Q309 900 324 893T358 872Q361 870 370 864T388 855T404 852Q419 852 431 862T457 896L513
|
||||
868Q494 826 466 804T404 782Q385 782 370 789Z" />
|
||||
<glyph unicode="Ö" glyph-name="Odieresis" horiz-adv-x="692" d="M433 701T498 660T600 538T637 344Q637 232 601 152T499 30T346 -12Q259 -12 194 29T92 150T55 343Q55 454 91 535T194 658T346 701Q433 701 498 660ZM256 623T206 555T156 343Q156 200 206
|
||||
133T346 66Q536 66 536 344Q536 623 346 623Q256 623 206 555ZM265 894T281 878T298 837Q298 813 282 797T241 780Q216 780 200 796T183 837Q183 861 199 877T241 894Q265 894 281 878ZM475 894T491 878T508 837Q508 813 492 797T450 780Q426 780 410 796T393 837Q393
|
||||
861 409 877T450 894Q475 894 491 878Z" />
|
||||
<glyph unicode="×" glyph-name="multiply" horiz-adv-x="500" d="M372 486L428 429L308 309L428 185L372 129L252 253L128 129L72 185L192 305L72 429L128 486L248 361L372 486Z" />
|
||||
<glyph unicode="Ø" glyph-name="Oslash" horiz-adv-x="692" d="M558 628T597 546T637 344Q637 232 601 152T499 30T346 -12Q310 -12 279 -5L244 -127L165 -106L205 22Q134 62 95 143T55 343Q55 454 91 535T194 658T346 701Q383 701 412 694L449 819L528 798L486
|
||||
667Q558 628 597 546ZM256 623T206 555T156 343Q156 158 238 97L396 618Q369 623 346 623Q256 623 206 555ZM536 66T536 344Q536 443 515 504T452 594L296 71Q321 66 346 66Q536 66 536 344Z" />
|
||||
<glyph unicode="Ù" glyph-name="Ugrave" horiz-adv-x="662" d="M572 221Q572 152 544 100T461 18T330 -12Q215 -12 153 51T90 221V689H185V228Q185 148 221 108T330 68Q404 68 440 107T476 228V689H572V221ZM240 911L441 804L417 755L201 834L240 911Z" />
|
||||
<glyph unicode="Ú" glyph-name="Uacute" horiz-adv-x="662" d="M572 221Q572 152 544 100T461 18T330 -12Q215 -12 153 51T90 221V689H185V228Q185 148 221 108T330 68Q404 68 440 107T476 228V689H572V221ZM411 911L451 834L235 755L211 804L411 911Z" />
|
||||
<glyph unicode="Û" glyph-name="Ucircumflex" horiz-adv-x="662" d="M572 221Q572 152 544 100T461 18T330 -12Q215 -12 153 51T90 221V689H185V228Q185 148 221 108T330 68Q404 68 440 107T476 228V689H572V221ZM204 759L164 804L300 914H361L496 804L457
|
||||
759L330 840L204 759Z" />
|
||||
<glyph unicode="Ü" glyph-name="Udieresis" horiz-adv-x="662" d="M572 221Q572 152 544 100T461 18T330 -12Q215 -12 153 51T90 221V689H185V228Q185 148 221 108T330 68Q404 68 440 107T476 228V689H572V221ZM250 894T266 878T283 837Q283 813 267 797T226
|
||||
780Q201 780 185 796T168 837Q168 861 184 877T226 894Q250 894 266 878ZM460 894T476 878T493 837Q493 813 477 797T435 780Q411 780 395 796T378 837Q378 861 394 877T435 894Q460 894 476 878Z" />
|
||||
<glyph unicode="Ý" glyph-name="Yacute" horiz-adv-x="550" d="M545 689L323 265V0H227V264L5 689H110L278 348L446 689H545ZM355 911L395 834L179 755L155 804L355 911Z" />
|
||||
<glyph unicode="Þ" glyph-name="Thorn" horiz-adv-x="581" d="M409 571T479 517T549 354Q549 238 476 183T282 127H195V0H100V689H195V571H281Q409 571 479 517ZM362 202T405 235T448 353Q448 430 405 463T280 497H195V202H278Q362 202 405 235Z" />
|
||||
<glyph unicode="ß" glyph-name="germandbls" horiz-adv-x="593" d="M351 750T391 731T454 680T476 607Q476 566 459 542T410 492Q386 472 376 459T365 427Q365 404 382 387T434 346Q472 320 495 299T536 244T553 162Q553 110 529 71T463 10T375 -12Q316 -12
|
||||
273 11L300 75Q326 62 366 62Q408 62 433 88T459 163Q459 208 436 236T366 297Q323 328 301 354T278 420Q278 453 292 472T335 515Q362 537 375 555T388 602Q388 639 362 658T295 678Q187 678 187 539V0H95V539Q95 639 147 694T296 750Q351 750 391 731Z" />
|
||||
<glyph unicode="à" glyph-name="agrave" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539 265
|
||||
539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM192 801L391 687L363 638L151 724L192 801Z" />
|
||||
<glyph unicode="á" glyph-name="aacute" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539 265
|
||||
539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM340 801L381 724L169 638L141 687L340 801Z" />
|
||||
<glyph unicode="â" glyph-name="acircumflex" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539
|
||||
265 539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM134 634L95 679L230 792H291L427 679L387 634L261 718L134 634Z" />
|
||||
<glyph unicode="ã" glyph-name="atilde" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539 265
|
||||
539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM300 656T285 663T250 683Q235 694 225 699T203 704Q187 704 175 693T150 658L94 686Q113 726 140 750T203 774Q224 774 239 767T273
|
||||
746Q276 744 285 738T303 729T319 726Q334 726 346 736T372 770L428 742Q409 700 381 678T319 656Q300 656 285 663Z" />
|
||||
<glyph unicode="ä" glyph-name="adieresis" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539
|
||||
265 539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM180 768T196 752T213 711Q213 687 197 671T156 654Q131 654 115 670T98 711Q98 735 114 751T156 768Q180 768 196 752ZM390
|
||||
768T406 752T423 711Q423 687 407 671T365 654Q341 654 325 670T308 711Q308 735 324 751T365 768Q390 768 406 752Z" />
|
||||
<glyph unicode="å" glyph-name="aring" horiz-adv-x="544" d="M450 91T461 76T494 52L473 -12Q432 -7 407 11T370 67Q317 -12 213 -12Q135 -12 90 32T45 147Q45 231 105 276T277 321H358V360Q358 416 331 440T248 464Q190 464 106 436L83 503Q181 539 265
|
||||
539Q358 539 404 494T450 364V123Q450 91 461 76ZM313 57T358 139V260H289Q143 260 143 152Q143 105 166 81T234 57Q313 57 358 139ZM311 836T343 806T375 730Q375 685 343 655T261 624Q211 624 179 654T147 730Q147 775 179 805T261 836Q311 836 343 806ZM236
|
||||
786T222 771T208 730Q208 704 222 689T261 674Q285 674 299 689T314 730Q314 756 300 771T261 786Q236 786 222 771Z" />
|
||||
<glyph unicode="æ" glyph-name="ae" horiz-adv-x="849" d="M797 256T795 232H459Q465 145 503 104T601 63Q639 63 671 74T738 109L778 54Q694 -12 594 -12Q531 -12 483 13T404 85Q368 33 323 11T216 -12Q137 -12 91 32T45 147Q45 231 107 276T280 321H361V360Q361
|
||||
416 334 440T251 464Q193 464 109 436L86 503Q184 539 268 539Q382 539 425 455Q482 539 584 539Q686 539 741 470T797 279Q797 256 795 232ZM706 306Q706 384 675 425T582 466Q469 466 459 300H706V306ZM279 57T312 79T376 149Q361 197 361 257V260H292Q146 260
|
||||
146 152Q146 105 169 81T237 57Q279 57 312 79Z" />
|
||||
<glyph unicode="ç" glyph-name="ccedilla" horiz-adv-x="478" d="M385 -5T308 -11V-56Q356 -60 378 -83T401 -141Q401 -189 366 -215T277 -241Q249 -241 225 -235T186 -217L211 -165Q241 -181 274 -181Q297 -181 310 -172T324 -141Q324 -120 303 -110T235
|
||||
-99L246 -9Q157 5 107 75T57 259Q57 343 85 406T164 504T287 539Q334 539 373 526T448 482L404 424Q376 444 350 453T291 463Q227 463 192 412T156 261Q156 161 191 114T291 66Q322 66 348 75T406 106L448 46Q385 -5 308 -11Z" />
|
||||
<glyph unicode="è" glyph-name="egrave" horiz-adv-x="545" d="M493 256T491 232H155Q161 145 199 104T297 63Q335 63 367 74T434 109L474 54Q390 -12 290 -12Q180 -12 119 60T57 258Q57 340 83 403T159 503T276 539Q381 539 437 470T493 279Q493 256 491
|
||||
232ZM402 306Q402 384 371 425T278 466Q165 466 155 300H402V306ZM210 801L409 687L381 638L169 724L210 801Z" />
|
||||
<glyph unicode="é" glyph-name="eacute" horiz-adv-x="545" d="M493 256T491 232H155Q161 145 199 104T297 63Q335 63 367 74T434 109L474 54Q390 -12 290 -12Q180 -12 119 60T57 258Q57 340 83 403T159 503T276 539Q381 539 437 470T493 279Q493 256 491
|
||||
232ZM402 306Q402 384 371 425T278 466Q165 466 155 300H402V306ZM358 801L399 724L187 638L159 687L358 801Z" />
|
||||
<glyph unicode="ê" glyph-name="ecircumflex" horiz-adv-x="545" d="M493 256T491 232H155Q161 145 199 104T297 63Q335 63 367 74T434 109L474 54Q390 -12 290 -12Q180 -12 119 60T57 258Q57 340 83 403T159 503T276 539Q381 539 437 470T493 279Q493 256
|
||||
491 232ZM402 306Q402 384 371 425T278 466Q165 466 155 300H402V306ZM152 634L113 679L248 792H309L445 679L405 634L279 718L152 634Z" />
|
||||
<glyph unicode="ë" glyph-name="edieresis" horiz-adv-x="545" d="M493 256T491 232H155Q161 145 199 104T297 63Q335 63 367 74T434 109L474 54Q390 -12 290 -12Q180 -12 119 60T57 258Q57 340 83 403T159 503T276 539Q381 539 437 470T493 279Q493 256
|
||||
491 232ZM402 306Q402 384 371 425T278 466Q165 466 155 300H402V306ZM198 768T214 752T231 711Q231 687 215 671T174 654Q149 654 133 670T116 711Q116 735 132 751T174 768Q198 768 214 752ZM408 768T424 752T441 711Q441 687 425 671T383 654Q359 654 343 670T326
|
||||
711Q326 735 342 751T383 768Q408 768 424 752Z" />
|
||||
<glyph unicode="ì" glyph-name="igrave" horiz-adv-x="282" d="M187 527V0H95V527H187ZM72 801L271 687L243 638L31 724L72 801Z" />
|
||||
<glyph unicode="í" glyph-name="iacute" horiz-adv-x="282" d="M187 527V0H95V527H187ZM220 801L261 724L49 638L21 687L220 801Z" />
|
||||
<glyph unicode="î" glyph-name="icircumflex" horiz-adv-x="282" d="M187 527V0H95V527H187ZM14 634L-25 679L110 792H171L307 679L267 634L141 718L14 634Z" />
|
||||
<glyph unicode="ï" glyph-name="idieresis" horiz-adv-x="282" d="M187 527V0H95V527H187ZM60 768T76 752T93 711Q93 687 77 671T36 654Q11 654 -5 670T-22 711Q-22 735 -6 751T36 768Q60 768 76 752ZM270 768T286 752T303 711Q303 687 287 671T245 654Q221
|
||||
654 205 670T188 711Q188 735 204 751T245 768Q270 768 286 752Z" />
|
||||
<glyph unicode="ð" glyph-name="eth" horiz-adv-x="570" d="M432 596T470 501T508 265Q508 182 479 120T398 23T278 -12Q216 -12 166 17T86 102T57 235Q57 297 79 352T147 441T258 475Q349 475 405 408Q393 471 365 519T286 607L214 537L151 569L225 644Q173
|
||||
668 112 680L132 750Q217 733 281 702L351 776L405 729L342 664Q432 596 470 501ZM340 61T377 114T415 266Q415 287 413 325Q387 364 353 383T272 403Q151 403 151 239Q151 153 185 107T277 61Q340 61 377 114Z" />
|
||||
<glyph unicode="ñ" glyph-name="ntilde" horiz-adv-x="586" d="M415 539T455 496T496 378V0H404V365Q404 421 383 444T321 467Q279 467 247 443T187 374V0H95V527H174L182 449Q210 491 251 515T343 539Q415 539 455 496ZM337 656T322 663T287 683Q272 694
|
||||
262 699T240 704Q224 704 212 693T187 658L131 686Q150 726 177 750T240 774Q261 774 276 767T310 746Q313 744 322 738T340 729T356 726Q371 726 383 736T409 770L465 742Q446 700 418 678T356 656Q337 656 322 663Z" />
|
||||
<glyph unicode="ò" glyph-name="ograve" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428 465
|
||||
293 465Q156 465 156 263ZM223 801L422 687L394 638L182 724L223 801Z" />
|
||||
<glyph unicode="ó" glyph-name="oacute" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428 465
|
||||
293 465Q156 465 156 263ZM371 801L412 724L200 638L172 687L371 801Z" />
|
||||
<glyph unicode="ô" glyph-name="ocircumflex" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428
|
||||
465 293 465Q156 465 156 263ZM165 634L126 679L261 792H322L458 679L418 634L292 718L165 634Z" />
|
||||
<glyph unicode="õ" glyph-name="otilde" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428 465
|
||||
293 465Q156 465 156 263ZM331 656T316 663T281 683Q266 694 256 699T234 704Q218 704 206 693T181 658L125 686Q144 726 171 750T234 774Q255 774 270 767T304 746Q307 744 316 738T334 729T350 726Q365 726 377 736T403 770L459 742Q440 700 412 678T350 656Q331
|
||||
656 316 663Z" />
|
||||
<glyph unicode="ö" glyph-name="odieresis" horiz-adv-x="584" d="M404 539T465 465T527 264Q527 182 499 120T418 23T292 -12Q181 -12 119 62T57 263Q57 345 85 407T166 504T293 539Q404 539 465 465ZM156 465T156 263Q156 62 292 62Q428 62 428 264Q428
|
||||
465 293 465Q156 465 156 263ZM211 768T227 752T244 711Q244 687 228 671T187 654Q162 654 146 670T129 711Q129 735 145 751T187 768Q211 768 227 752ZM421 768T437 752T454 711Q454 687 438 671T396 654Q372 654 356 670T339 711Q339 735 355 751T396 768Q421
|
||||
768 437 752Z" />
|
||||
<glyph unicode="÷" glyph-name="divide" horiz-adv-x="500" d="M280 174T300 154T320 105Q320 76 300 56T250 35Q221 35 201 55T181 105Q181 134 201 154T250 174Q280 174 300 154ZM280 631T300 611T320 562Q320 533 300 513T250 492Q221 492 201 512T181
|
||||
562Q181 591 201 611T250 631Q280 631 300 611ZM62 294V371H438V294H62Z" />
|
||||
<glyph unicode="ø" glyph-name="oslash" horiz-adv-x="584" d="M470 475T498 413T527 264Q527 182 499 120T418 23T292 -12Q268 -12 241 -7L202 -130L127 -108L169 19Q115 52 86 115T57 263Q57 345 85 407T166 504T293 539Q317 539 344 534L383 656L458 634L416
|
||||
508Q470 475 498 413ZM156 465T156 263Q156 134 204 89L328 462Q311 465 293 465Q156 465 156 263ZM428 62T428 264Q428 331 417 373T381 437L258 65Q273 62 292 62Q428 62 428 264Z" />
|
||||
<glyph unicode="ù" glyph-name="ugrave" horiz-adv-x="582" d="M487 0H408L401 82Q371 33 332 11T237 -12Q168 -12 129 30T90 149V527H182V159Q182 105 201 83T263 60Q340 60 395 151V527H487V0ZM220 801L419 687L391 638L179 724L220 801Z" />
|
||||
<glyph unicode="ú" glyph-name="uacute" horiz-adv-x="582" d="M487 0H408L401 82Q371 33 332 11T237 -12Q168 -12 129 30T90 149V527H182V159Q182 105 201 83T263 60Q340 60 395 151V527H487V0ZM368 801L409 724L197 638L169 687L368 801Z" />
|
||||
<glyph unicode="û" glyph-name="ucircumflex" horiz-adv-x="582" d="M487 0H408L401 82Q371 33 332 11T237 -12Q168 -12 129 30T90 149V527H182V159Q182 105 201 83T263 60Q340 60 395 151V527H487V0ZM162 634L123 679L258 792H319L455 679L415 634L289 718L162
|
||||
634Z" />
|
||||
<glyph unicode="ü" glyph-name="udieresis" horiz-adv-x="582" d="M487 0H408L401 82Q371 33 332 11T237 -12Q168 -12 129 30T90 149V527H182V159Q182 105 201 83T263 60Q340 60 395 151V527H487V0ZM208 768T224 752T241 711Q241 687 225 671T184 654Q159
|
||||
654 143 670T126 711Q126 735 142 751T184 768Q208 768 224 752ZM418 768T434 752T451 711Q451 687 435 671T393 654Q369 654 353 670T336 711Q336 735 352 751T393 768Q418 768 434 752Z" />
|
||||
<glyph unicode="ý" glyph-name="yacute" horiz-adv-x="492" d="M306 -3Q275 -95 220 -148T61 -213L51 -141Q103 -132 134 -115T183 -72T218 0H187L10 527H108L249 67L387 527H482L306 -3ZM325 801L366 724L154 638L126 687L325 801Z" />
|
||||
<glyph unicode="þ" glyph-name="thorn" horiz-adv-x="594" d="M438 539T485 467T532 264Q532 140 478 64T325 -12Q237 -12 187 48V-198L95 -213V739L187 750V463Q215 500 254 519T337 539Q438 539 485 467ZM433 63T433 264Q433 466 314 466Q275 466 243 443T187
|
||||
384V127Q207 96 237 80T303 63Q433 63 433 264Z" />
|
||||
<glyph unicode="ÿ" glyph-name="ydieresis" horiz-adv-x="492" d="M306 -3Q275 -95 220 -148T61 -213L51 -141Q103 -132 134 -115T183 -72T218 0H187L10 527H108L249 67L387 527H482L306 -3ZM165 768T181 752T198 711Q198 687 182 671T141 654Q116 654 100
|
||||
670T83 711Q83 735 99 751T141 768Q165 768 181 752ZM375 768T391 752T408 711Q408 687 392 671T350 654Q326 654 310 670T293 711Q293 735 309 751T350 768Q375 768 391 752Z" />
|
||||
<glyph unicode="–" glyph-name="endash" horiz-adv-x="520" d="M32 274V352H488V274H32Z" />
|
||||
<glyph unicode="—" glyph-name="emdash" horiz-adv-x="790" d="M32 274V352H758V274H32Z" />
|
||||
<glyph unicode="‘" glyph-name="quoteleft" horiz-adv-x="228" d="M82 490T63 508T44 553Q44 565 47 577T61 611L128 753H188L148 603Q174 583 174 553Q174 527 155 509T109 490Q82 490 63 508Z" />
|
||||
<glyph unicode="’" glyph-name="quoteright" horiz-adv-x="228" d="M146 753T165 735T184 690Q184 678 181 666T167 632L100 490H40L80 640Q54 660 54 690Q54 716 73 734T119 753Q146 753 165 735Z" />
|
||||
<glyph unicode="‚" glyph-name="quotesinglbase" horiz-adv-x="228" d="M146 107T165 89T184 44Q184 32 181 20T167 -14L100 -156H40L80 -6Q54 14 54 44Q54 70 73 88T119 107Q146 107 165 89Z" />
|
||||
<glyph unicode="“" glyph-name="quotedblleft" horiz-adv-x="406" d="M82 490T63 508T44 553Q44 565 47 577T61 611L128 753H188L148 603Q174 583 174 553Q174 527 155 509T109 490Q82 490 63 508ZM260 490T241 508T222 553Q222 565 225 577T239 611L306
|
||||
753H366L326 603Q352 583 352 553Q352 527 333 509T287 490Q260 490 241 508Z" />
|
||||
<glyph unicode="”" glyph-name="quotedblright" horiz-adv-x="406" d="M146 753T165 735T184 690Q184 678 181 666T167 632L100 490H40L80 640Q54 660 54 690Q54 716 73 734T119 753Q146 753 165 735ZM324 753T343 735T362 690Q362 678 359 666T345 632L278
|
||||
490H218L258 640Q232 660 232 690Q232 716 251 734T297 753Q324 753 343 735Z" />
|
||||
<glyph unicode="„" glyph-name="quotedblbase" horiz-adv-x="406" d="M146 107T165 89T184 44Q184 32 181 20T167 -14L100 -156H40L80 -6Q54 14 54 44Q54 70 73 88T119 107Q146 107 165 89ZM324 107T343 89T362 44Q362 32 359 20T345 -14L278 -156H218L258
|
||||
-6Q232 14 232 44Q232 70 251 88T297 107Q324 107 343 89Z" />
|
||||
<glyph unicode="•" glyph-name="bullet" horiz-adv-x="324" d="M210 454T242 422T274 341Q274 293 242 261T162 229Q114 229 82 261T50 342Q50 390 82 422T162 454Q210 454 242 422Z" />
|
||||
<glyph unicode="‹" glyph-name="guilsinglleft" horiz-adv-x="340" d="M230 535L285 497L150 287L285 77L230 39L55 255V318L230 535Z" />
|
||||
<glyph unicode="›" glyph-name="guilsinglright" horiz-adv-x="340" d="M110 535L285 318V255L110 39L55 77L190 287L55 497L110 535Z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 52 KiB |
@@ -1,365 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs >
|
||||
<font id="IBMPlexMono" horiz-adv-x="600" ><font-face
|
||||
font-family="IBM Plex Mono Medium"
|
||||
units-per-em="1000"
|
||||
panose-1="2 11 6 9 5 2 3 0 2 3"
|
||||
ascent="1025"
|
||||
descent="-275"
|
||||
alphabetic="0" />
|
||||
<glyph unicode=" " glyph-name="space" />
|
||||
<glyph unicode="!" glyph-name="exclam" d="M275 237L280 495L314 698H431L397 495L315 237H275ZM257 -10Q216 -10 199 5T182 42Q182 47 183 55T187 82Q192 109 212 128T278 147Q319 147 336 132T353 95Q353 90 352 82T348 55Q343 28 323 9T257 -10Z" />
|
||||
<glyph unicode=""" glyph-name="quotedbl" d="M442 443L491 740H589L540 443H442ZM380 443L429 740H527L478 443H380Z" />
|
||||
<glyph unicode="#" glyph-name="numbersign" d="M128 208H7L21 290H156L196 408H75L89 490H224L296 698H386L148 0H57L128 208ZM484 698H574L503 490H624L610 408H475L435 290H556L542 208H407L336 0H245L484 698Z" />
|
||||
<glyph unicode="$" glyph-name="dollar" d="M218 -8Q149 0 98 31T21 107L95 174Q148 95 237 82L276 316L258 321Q97 362 97 495Q97 542 114 580T162 646T238 690T337 709L354 811H436L419 705Q480 695 522 667T588 601L514 538Q493 569 465 588T398 614L362 396L383
|
||||
391Q464 370 505 328T546 218Q546 170 529 130T480 59T403 11T299 -11L282 -113H200L218 -8ZM205 505Q205 467 227 448T293 416L326 616Q268 610 237 581T205 505ZM437 208Q437 243 416 264T345 298L310 82Q370 90 403 123T437 208Z" />
|
||||
<glyph unicode="%" glyph-name="percent" d="M190 349Q128 349 93 386T58 494Q58 542 71 581T108 649T165 694T237 710Q299 710 334 673T369 565Q369 517 356 477T319 409T262 365T190 349ZM194 416Q234 416 253 441T278 503Q283 535 286 551T289 579Q289 643
|
||||
233 643Q193 643 174 618T149 556Q144 524 141 508T138 480Q138 416 194 416ZM575 698H663L457 398H369L575 698ZM176 300H264L58 0H-30L176 300ZM396 -12Q334 -12 299 25T264 133Q264 181 277 220T314 288T371 333T443 349Q505 349 540 312T575 204Q575 156 562
|
||||
116T525 48T468 4T396 -12ZM400 55Q440 55 459 80T484 142Q489 174 492 190T495 218Q495 282 439 282Q399 282 380 257T355 195Q350 163 347 147T344 119Q344 55 400 55Z" />
|
||||
<glyph unicode="&" glyph-name="ampersand" d="M159 -12Q87 -12 46 37T5 171Q5 210 14 248T45 316T103 368T194 393Q177 433 168 465T159 531Q159 570 172 603T211 660T272 697T352 710Q428 710 475 666T522 539Q522 449 470 396T326 326L435 86L452 84L526
|
||||
199L593 158L543 70Q518 25 494 7T435 -12Q393 -12 364 23T312 136H307Q296 58 255 23T159 -12ZM189 81Q230 81 254 103T289 167L214 344Q185 339 168 328T140 303T125 271T117 237Q114 218 114 204T113 178Q113 127 132 104T189 81ZM344 629Q304 629 282 604T259
|
||||
532Q259 499 268 467T298 390L306 374Q352 387 378 411T414 473Q419 493 421 509T423 540Q423 586 401 607T344 629Z" />
|
||||
<glyph unicode="'" glyph-name="quotesingle" d="M282 443L331 740H429L380 443H282Z" />
|
||||
<glyph unicode="(" glyph-name="parenleft" d="M191 226Q191 311 214 391T278 541T369 667T476 760H586Q534 724 487 680T403 585T339 478T302 361L287 272Q284 254 283 237T282 203Q282 152 294 103T328 10T377 -71T437 -138H337Q306 -110 280 -72T234 13T203
|
||||
113T191 226Z" />
|
||||
<glyph unicode=")" glyph-name="parenright" d="M429 397Q429 312 406 232T343 82T252 -44T144 -138H35Q86 -102 133 -58T217 38T281 145T318 262L333 350Q336 368 337 385T338 419Q338 470 326 519T292 612T243 693T183 760H283Q314 732 340 694T386 610T417
|
||||
509T429 397Z" />
|
||||
<glyph unicode="*" glyph-name="asterisk" d="M150 50L79 104L224 265L50 330L90 412L267 349L300 549H395L361 349L555 412L569 327L373 260L465 102L386 50L293 212L150 50Z" />
|
||||
<glyph unicode="+" glyph-name="plus" d="M220 62L253 262H64L78 349H268L301 549H396L363 349H552L538 262H348L315 62H220Z" />
|
||||
<glyph unicode="," glyph-name="comma" d="M226 151H378L209 -145H123L226 151Z" />
|
||||
<glyph unicode="-" glyph-name="hyphen" d="M149 251L167 358H466L448 251H149Z" />
|
||||
<glyph unicode="." glyph-name="period" d="M257 -10Q215 -10 198 5T180 44Q180 52 181 61T185 84Q190 116 213 134T279 152Q321 152 338 137T356 98Q356 90 355 81T351 58Q346 26 323 8T257 -10Z" />
|
||||
<glyph unicode="/" glyph-name="slash" d="M15 -138L498 760H596L113 -138H15Z" />
|
||||
<glyph unicode="0" glyph-name="zero" d="M268 -12Q155 -12 103 53T51 238Q51 288 57 342T79 448T117 548T176 632T257 689T362 710Q475 710 527 645T579 460Q579 410 573 356T551 250T513 150T454 66T373 9T268 -12ZM271 78Q309 78 338 92T388 134T424 201T446
|
||||
290L465 404Q469 427 471 447T473 486Q473 549 446 584T359 620Q321 620 292 606T242 564T206 497T184 408L165 294Q161 271 159 251T157 212Q157 149 184 114T271 78ZM307 291Q276 291 263 302T250 330Q250 339 253 357Q257 380 272 393T323 407Q354 407 367 396T380
|
||||
368Q380 359 377 341Q373 318 358 305T307 291Z" />
|
||||
<glyph unicode="1" glyph-name="one" d="M44 0L59 92H254L342 616H333L146 442L84 505L290 698H465L364 92H533L518 0H44Z" />
|
||||
<glyph unicode="2" glyph-name="two" d="M501 0H22L40 106L301 307Q340 337 365 360T407 405T431 447T444 493Q446 502 446 508T447 523Q447 564 419 589T340 615Q311 615 289 606T248 582T217 547T193 504L97 541Q113 576 136 607T190 661T261 697T351 710Q401
|
||||
710 440 697T507 659T548 600T563 525Q563 482 549 446T509 376T445 309T359 240L164 93H517L501 0Z" />
|
||||
<glyph unicode="3" glyph-name="three" d="M293 410Q358 410 395 436T441 507Q445 530 445 537Q445 575 417 596T340 618Q289 618 251 595T184 531L117 597Q137 621 160 641T213 677T277 701T356 710Q402 710 440 699T506 668T548 618T563 550Q563 484 520 435T397
|
||||
368L396 364Q450 355 485 317T520 214Q520 167 502 126T449 55T363 6T246 -12Q196 -12 159 -2T95 27T50 68T19 116L103 172Q113 152 125 135T155 106T196 87T253 80Q316 80 354 108T402 190Q405 208 405 222Q405 267 375 292T284 317H205L221 410H293Z" />
|
||||
<glyph unicode="4" glyph-name="four" d="M321 0L344 136H11L28 235L403 698H543L463 223H562L547 136H449L426 0H321ZM123 223H358L418 579H412L123 223Z" />
|
||||
<glyph unicode="5" glyph-name="five" d="M564 603H249L190 353H196Q211 374 227 390T262 419T304 437T356 443Q397 443 431 430T490 393T529 335T543 256Q543 205 525 157T472 71T384 11T261 -12Q214 -12 178 -2T114 27T67 67T35 114L125 172Q144 132 176 107T268
|
||||
81Q333 81 372 114T421 207Q423 221 424 229T425 249Q425 298 396 325T309 352Q263 352 233 335T179 297L90 309L180 698H580L564 603Z" />
|
||||
<glyph unicode="6" glyph-name="six" d="M265 -12Q161 -12 106 48T51 211Q51 289 80 362T155 499T260 613T377 698H530Q463 656 409 616T313 534T238 444T183 341L189 339Q204 359 221 377T261 410T309 432T368 441Q451 441 499 391T548 255Q548 202 529 154T474
|
||||
69T385 10T265 -12ZM277 77Q340 77 379 111T430 208Q432 217 433 226T434 245Q434 353 317 353Q255 353 215 320T164 223Q162 214 161 205T160 186Q160 132 190 105T277 77Z" />
|
||||
<glyph unicode="7" glyph-name="seven" d="M122 0L479 606H209L187 477H91L128 698H608L592 602L242 0H122Z" />
|
||||
<glyph unicode="8" glyph-name="eight" d="M261 -12Q204 -12 162 1T91 37T48 92T34 163Q34 236 79 289T206 363L207 370Q161 387 137 421T112 507Q112 544 128 580T176 646T257 692T371 710Q473 710 525 667T578 551Q578 490 540 442T430 369L429 362Q483 346
|
||||
513 310T544 210Q544 167 526 127T473 56T384 7T261 -12ZM270 76Q340 76 378 107T425 188Q427 202 428 210T430 228Q430 272 399 296T308 321Q238 321 200 290T153 209Q151 195 150 187T148 169Q148 125 179 101T270 76ZM326 405Q387 405 422 433T465 506Q468 524
|
||||
468 538Q468 578 440 600T358 622Q297 622 262 594T219 521Q216 503 216 489Q216 449 244 427T326 405Z" />
|
||||
<glyph unicode="9" glyph-name="nine" d="M574 487Q574 409 545 336T470 199T365 85T248 0H95Q162 42 216 82T312 164T387 254T442 357L436 359Q421 339 404 321T364 288T316 266T257 257Q174 257 126 307T77 443Q77 495 96 543T151 629T239 688T360 710Q464 710
|
||||
519 650T574 487ZM308 345Q370 345 410 378T461 475Q463 484 464 493T465 512Q465 566 435 593T348 621Q285 621 246 587T195 490Q193 481 192 472T191 453Q191 345 308 345Z" />
|
||||
<glyph unicode=":" glyph-name="colon" d="M257 -10Q215 -10 198 5T180 44Q180 52 181 61T185 84Q190 116 213 134T279 152Q321 152 338 137T356 98Q356 90 355 81T351 58Q346 26 323 8T257 -10ZM318 364Q276 364 259 379T241 418Q241 426 242 435T246 458Q251
|
||||
490 274 508T340 526Q382 526 399 511T417 472Q417 464 416 455T412 432Q407 400 384 382T318 364Z" />
|
||||
<glyph unicode=";" glyph-name="semicolon" d="M226 151H378L209 -145H123L226 151ZM318 364Q276 364 259 379T241 418Q241 426 242 435T246 458Q251 490 274 508T340 526Q382 526 399 511T417 472Q417 464 416 455T412 432Q407 400 384 382T318 364Z" />
|
||||
<glyph unicode="<" glyph-name="less" d="M85 255L102 357L570 598L552 488L192 305L191 297L490 113L473 15L85 255Z" />
|
||||
<glyph unicode="=" glyph-name="equal" d="M82 368L96 455H569L555 368H82ZM47 156L61 243H534L520 156H47Z" />
|
||||
<glyph unicode=">" glyph-name="greater" d="M66 125L426 308L427 316L128 500L145 598L533 358L516 256L48 15L66 125Z" />
|
||||
<glyph unicode="?" glyph-name="question" d="M219 223L244 378Q290 382 325 390T384 414T423 451T443 508Q444 513 444 518T445 532Q445 572 417 594T344 617Q291 617 259 588T208 512L119 552Q131 584 151 612T201 663T269 697T357 710Q453 710 506 662T560
|
||||
532Q560 482 541 444T491 378T420 334T339 311L324 223H219ZM238 -10Q197 -10 180 5T163 42Q163 47 164 55T168 82Q173 109 193 128T259 147Q300 147 317 132T334 95Q334 90 333 82T329 55Q324 28 304 9T238 -10Z" />
|
||||
<glyph unicode="@" glyph-name="at" d="M407 -112H289Q159 -112 104 -43T48 159Q48 202 53 251T66 350Q81 437 104 504T163 616T248 686T363 710Q416 710 455 696T521 655T560 592T573 512Q573 501 572 488T569 460L508 91H420L434 175H430Q413 134 387 107T316
|
||||
79Q213 79 213 237Q213 289 224 338T256 425T309 485T380 508Q420 508 443 486T472 429H476L481 462Q483 476 484 489T486 516Q486 573 456 604T362 635Q328 635 298 625T242 586T197 508T164 380L141 239Q139 228 138 214T136 187T135 161T135 142Q135 100 143
|
||||
67T169 11T219 -24T296 -36H418L407 -112ZM353 152Q373 152 388 163T415 188Q424 200 434 221T450 274L466 368Q468 379 466 391T457 414T438 431T406 438Q334 438 316 326L310 288Q306 262 305 246T304 221Q304 152 353 152Z" />
|
||||
<glyph unicode="A" glyph-name="A" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588Z" />
|
||||
<glyph unicode="B" glyph-name="B" d="M158 698H388Q474 698 519 655T564 537Q564 466 528 422T427 361L426 357Q477 344 506 312T536 220Q536 174 520 134T475 64T403 17T310 0H41L158 698ZM286 85Q342 85 375 108T417 176L422 206Q424 215 425 224T426 242Q426
|
||||
317 327 317H202L163 85H286ZM323 398Q377 398 407 418T445 484L450 514Q453 532 453 543Q453 581 429 597T361 613H251L215 398H323Z" />
|
||||
<glyph unicode="C" glyph-name="C" d="M288 -12Q173 -12 120 55T66 246Q66 343 87 427T148 575T248 674T385 710Q437 710 474 696T535 657T573 601T591 532L488 506Q484 530 478 550T459 586T427 609T377 618Q304 618 261 562T201 406L184 304Q180 281 178 262T176
|
||||
220Q176 156 204 118T298 80Q325 80 347 89T387 114T420 155T452 210L543 175Q523 130 499 96T444 37T375 1T288 -12Z" />
|
||||
<glyph unicode="D" glyph-name="D" d="M159 698H345Q401 698 444 681T516 633T560 558T575 460Q575 232 489 116T250 0H42L159 698ZM255 91Q333 91 378 139T440 283L458 392Q461 410 463 431T465 470Q465 607 333 607H253L167 91H255Z" />
|
||||
<glyph unicode="E" glyph-name="E" d="M42 0L159 698H595L579 605H253L218 400H533L517 307H203L167 93H495L479 0H42Z" />
|
||||
<glyph unicode="F" glyph-name="F" d="M42 0L159 698H607L591 605H253L218 400H527L511 308H203L152 0H42Z" />
|
||||
<glyph unicode="G" glyph-name="G" d="M408 102H401Q387 79 373 58T339 22T296 -3T239 -12Q151 -12 104 52T57 242Q57 338 77 423T136 572T236 673T376 710Q426 710 462 696T523 657T560 600T578 532L475 506Q471 528 465 548T446 584T414 609T365 618Q291 618
|
||||
250 561T193 407L176 307Q173 289 171 265T169 225Q169 158 194 119T279 79Q311 79 336 90T380 121T411 167T428 222L437 273H300L314 356H549L490 0H391L408 102Z" />
|
||||
<glyph unicode="H" glyph-name="H" d="M426 308H192L141 0H31L147 698H257L208 400H441L490 698H600L484 0H374L426 308Z" />
|
||||
<glyph unicode="I" glyph-name="I" d="M38 0L52 84H216L305 614H141L155 698H593L579 614H415L326 84H490L476 0H38Z" />
|
||||
<glyph unicode="J" glyph-name="J" d="M566 698L480 186Q463 82 402 35T246 -12Q155 -12 103 34T46 165L150 186Q152 164 157 145T174 112T204 89T252 81Q352 81 372 198L440 605H195L211 698H566Z" />
|
||||
<glyph unicode="K" glyph-name="K" d="M288 319L181 208L146 0H36L152 698H262L206 362H212L337 502L521 698H654L372 396L543 0H422L288 319Z" />
|
||||
<glyph unicode="L" glyph-name="L" d="M67 0L183 698H293L192 93H511L495 0H67Z" />
|
||||
<glyph unicode="M" glyph-name="M" d="M459 334L498 546H490L288 187L207 546H199L167 334L112 0H14L130 698H260L322 419H329L484 698H617L501 0H403L459 334Z" />
|
||||
<glyph unicode="N" glyph-name="N" d="M228 546H220L129 0H31L147 698H291L403 152H411L502 698H600L484 0H340L228 546Z" />
|
||||
<glyph unicode="O" glyph-name="O" d="M268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552 250T513 150T455 66T374 9T268 -12ZM271 80Q344 80 385 135T443 291L462 406Q466
|
||||
429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80Z" />
|
||||
<glyph unicode="P" glyph-name="P" d="M43 0L159 698H410Q455 698 488 686T544 650T578 595T589 525Q589 410 527 345T352 280H200L153 0H43ZM215 372H347Q452 372 467 462L473 498Q474 503 475 513T476 532Q476 606 385 606H254L215 372Z" />
|
||||
<glyph unicode="Q" glyph-name="Q" d="M394 -192Q365 -192 346 -178T313 -141L224 -9Q135 3 93 66T51 236Q51 286 57 341T79 448T117 548T176 632T257 689T362 710Q475 710 527 645T579 462Q579 417 574 368T557 271T526 178T480 96T417 33T334 -4L398 -101L412
|
||||
-105L506 -17L563 -68L508 -124Q489 -143 475 -156T447 -177T422 -188T394 -192ZM271 80Q344 80 385 135T443 291L462 406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80Z"
|
||||
/>
|
||||
<glyph unicode="R" glyph-name="R" d="M152 0H43L159 698H410Q500 698 544 650T589 525Q589 425 539 365T397 291L511 0H394L292 283H199L152 0ZM347 372Q452 372 467 462L473 498Q474 503 475 513T476 532Q476 606 387 606H254L215 372H347Z" />
|
||||
<glyph unicode="S" glyph-name="S" d="M267 -12Q177 -12 114 19T20 104L95 172Q158 80 273 80Q345 80 385 114T425 208Q425 248 403 270T327 304L255 321Q174 339 138 383T101 494Q101 543 119 583T172 651T253 695T360 710Q445 710 502 680T588 602L512 539Q486
|
||||
578 448 598T355 619Q288 619 251 588T214 504Q214 463 238 443T315 410L385 393Q467 373 502 330T538 220Q538 169 520 126T466 53T381 5T267 -12Z" />
|
||||
<glyph unicode="T" glyph-name="T" d="M413 605L312 0H202L303 605H83L99 698H649L633 605H413Z" />
|
||||
<glyph unicode="U" glyph-name="U" d="M253 698L184 285Q177 244 174 219T171 178Q171 155 175 137T191 106T222 87T271 80Q314 80 340 92T381 128T405 186T420 262L493 698H603L534 284Q522 210 506 155T462 62T387 7T269 -12Q212 -12 173 0T109 36T74 93T63
|
||||
170Q63 199 67 236T78 309L143 698H253Z" />
|
||||
<glyph unicode="V" glyph-name="V" d="M180 0L99 698H211L246 348L270 107H277L380 348L528 698H646L334 0H180Z" />
|
||||
<glyph unicode="W" glyph-name="W" d="M31 0L97 698H193L151 295L132 105H141L288 529H400L409 105H418L459 288L553 698H647L481 0H331L329 406H320L181 0H31Z" />
|
||||
<glyph unicode="X" glyph-name="X" d="M540 0H420L362 140L308 273H302L206 140L101 0H-23L253 360L106 698H226L279 573L330 446H335L428 573L522 698H646L386 356L540 0Z" />
|
||||
<glyph unicode="Y" glyph-name="Y" d="M203 0L246 261L85 698H202L264 523L311 372H317L417 523L535 698H661L357 266L313 0H203Z" />
|
||||
<glyph unicode="Z" glyph-name="Z" d="M507 0H6L22 98L467 605H122L138 698H610L594 600L150 93H523L507 0Z" />
|
||||
<glyph unicode="[" glyph-name="bracketleft" d="M142 -138L292 760H587L574 683H368L244 -61H450L437 -138H142Z" />
|
||||
<glyph unicode="\" glyph-name="backslash" d="M359 -138L173 760H260L446 -138H359Z" />
|
||||
<glyph unicode="]" glyph-name="bracketright" d="M463 760L313 -138H18L31 -61H237L361 683H155L168 760H463Z" />
|
||||
<glyph unicode="^" glyph-name="asciicircum" d="M487 277L363 601H356L132 276L52 318L315 698H432L574 313L487 277Z" />
|
||||
<glyph unicode="_" glyph-name="underscore" d="M-4 -179L12 -85H487L471 -179H-4Z" />
|
||||
<glyph unicode="`" glyph-name="grave" d="M208 750L303 790L366 607L299 579L208 750Z" />
|
||||
<glyph unicode="a" glyph-name="a" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424 343Q432
|
||||
388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75Z" />
|
||||
<glyph unicode="b" glyph-name="b" d="M163 740H270L213 394H217Q232 424 249 448T287 491T334 518T395 528Q475 528 513 476T552 328Q552 266 538 205T493 96T418 18T310 -12Q251 -12 216 15T167 93H162L147 0H40L163 740ZM277 75Q344 75 380 115T428 219L440
|
||||
290Q442 299 443 310T444 333Q444 382 422 411T352 441Q292 441 246 387Q229 368 214 340T193 276L176 173Q168 128 195 102T277 75Z" />
|
||||
<glyph unicode="c" glyph-name="c" d="M271 -12Q171 -12 119 47T67 206Q67 276 87 335T143 437T230 504T342 528Q384 528 416 519T471 492T508 451T530 401L441 362Q428 404 403 421T332 439Q277 439 240 404T190 296L180 236Q178 222 177 211T176 189Q176 133
|
||||
204 105T287 77Q303 77 319 80T354 96T396 132T448 196L519 152Q494 112 468 82T413 30T349 -1T271 -12Z" />
|
||||
<glyph unicode="d" glyph-name="d" d="M387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L490 740H597L474 0H367L387 122ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424 343Q432
|
||||
388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75Z" />
|
||||
<glyph unicode="e" glyph-name="e" d="M279 -12Q173 -12 120 44T66 209Q66 280 87 338T147 439T239 504T358 528Q397 528 430 519T487 493T526 449T540 388Q540 359 528 329T476 274T365 232T175 211Q174 204 174 199T174 191Q174 167 179 146T198 108T233 83T291
|
||||
74Q316 74 336 79T375 97T412 128T452 177L522 132Q501 99 477 73T424 28T359 -1T279 -12ZM348 447Q282 447 240 408T185 289L183 278Q267 281 316 291T392 316T426 348T434 381Q434 410 415 428T348 447Z" />
|
||||
<glyph unicode="f" glyph-name="f" d="M188 -212Q167 -212 149 -205T114 -182T76 -145T30 -91L-22 -28L51 29L182 -123L198 -119L289 429H115L129 516H303L319 612Q328 666 365 703T471 740H646L632 653H433L410 516H610L596 429H396L310 -86Q300 -145 271 -178T188
|
||||
-212Z" />
|
||||
<glyph unicode="g" glyph-name="g" d="M216 -212Q150 -212 103 -195T22 -139L90 -71Q133 -125 217 -125Q248 -125 273 -118T318 -93T351 -46T372 29L391 141H386Q357 79 316 43T208 6Q127 6 89 59T50 204Q50 262 64 320T108 424T182 499T289 528Q349 528 384 501T433
|
||||
423H438L453 516H560L477 18Q467 -43 445 -86T389 -158T312 -199T216 -212ZM251 94Q309 94 356 147Q370 162 386 189T410 256L424 341Q432 387 405 414T323 441Q257 441 220 401T172 296L164 248Q162 236 161 225T160 201Q160 151 181 123T251 94Z" />
|
||||
<glyph unicode="h" glyph-name="h" d="M168 740H275L217 394H222Q251 456 290 492T392 528Q461 528 496 487T532 379Q532 361 531 342T524 296L475 0H368L418 300Q420 314 422 329T424 358Q424 393 407 417T349 441Q319 441 296 427T252 389Q242 377 224 347T198
|
||||
276L152 0H45L168 740Z" />
|
||||
<glyph unicode="i" glyph-name="i" d="M340 611Q302 611 287 625T272 660Q272 666 273 674T276 691Q281 718 298 733T354 749Q392 749 407 735T422 700Q422 694 421 686T418 669Q413 642 396 627T340 611ZM282 -12Q234 -12 210 13T186 78Q186 91 188 104T193 135L250
|
||||
429H76L90 516H373L289 83L309 75L482 234L543 179L465 101Q434 70 409 49T363 14T323 -6T282 -12Z" />
|
||||
<glyph unicode="j" glyph-name="j" d="M251 -212Q230 -212 212 -205T176 -182T136 -142T87 -81L36 -19L108 38L248 -125L263 -120L355 429H152L166 516H476L377 -78Q366 -141 337 -176T251 -212ZM442 611Q404 611 389 625T374 660Q374 666 375 674T378 691Q383
|
||||
718 400 733T456 749Q494 749 509 735T524 700Q524 694 523 686T520 669Q515 642 498 627T442 611Z" />
|
||||
<glyph unicode="k" glyph-name="k" d="M168 740H275L217 394H222Q235 423 252 447T291 490T339 518T399 528Q462 528 498 493T534 403Q534 374 525 347T493 296T432 251T338 215L397 79L411 77L522 181L577 126L514 61Q477 24 448 6T385 -12Q350 -12 329 7T291
|
||||
67L223 227Q333 255 379 292T426 376Q426 407 407 425T349 443Q319 443 295 430T250 389Q232 366 218 340T198 277L152 0H45L168 740Z" />
|
||||
<glyph unicode="l" glyph-name="l" d="M258 -12Q208 -12 186 13T163 80Q163 100 169 132L269 653H99L114 740H393L266 82L287 75L465 236L525 181L439 97Q407 66 382 45T336 12T296 -6T258 -12Z" />
|
||||
<glyph unicode="m" glyph-name="m" d="M2 0L88 516H179L165 431H170Q188 473 214 500T283 528Q325 528 345 501T362 428H366Q385 473 414 500T490 528Q534 528 556 503T579 430Q579 415 577 394T572 354L513 0H422L479 341Q481 355 483 371T485 397Q485 446 446
|
||||
446Q412 446 389 409Q378 391 369 370T356 325L302 0H211L269 346Q271 360 272 372T274 396Q274 446 238 446Q204 446 179 409Q166 390 159 370T148 330L93 0H2Z" />
|
||||
<glyph unicode="n" glyph-name="n" d="M45 0L131 516H238L217 394H222Q251 456 290 492T392 528Q461 528 496 487T532 379Q532 361 531 342T524 296L475 0H368L418 300Q420 314 422 329T424 358Q424 393 407 417T349 441Q319 441 296 427T252 389Q242 377 224
|
||||
347T198 276L152 0H45Z" />
|
||||
<glyph unicode="o" glyph-name="o" d="M265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234 524 175T466 75T377 11T265 -12ZM272 73Q335 73 373 111T422 218L433 284Q435 298
|
||||
436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73Z" />
|
||||
<glyph unicode="p" glyph-name="p" d="M126 516H233L213 394H217Q232 424 249 448T287 491T334 518T395 528Q475 528 513 476T552 328Q552 266 538 205T493 96T418 18T310 -12Q251 -12 216 15T167 93H162L114 -200H7L126 516ZM277 75Q344 75 380 115T428 219L440
|
||||
290Q442 299 443 310T444 333Q444 382 422 411T352 441Q292 441 246 387Q229 368 214 340T193 276L176 173Q168 128 195 102T277 75Z" />
|
||||
<glyph unicode="q" glyph-name="q" d="M387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L440 -200H333L387 122ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424
|
||||
343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75Z" />
|
||||
<glyph unicode="r" glyph-name="r" d="M165 0L236 429H103L118 516H358L333 370H339Q368 437 413 476T533 516H593L575 409H485Q442 409 415 398T366 360Q356 348 339 321T315 258L272 0H165Z" />
|
||||
<glyph unicode="s" glyph-name="s" d="M264 -12Q188 -12 132 11T45 80L113 140Q168 70 272 70Q331 70 364 91T398 151Q398 181 380 192T333 209L258 222Q229 227 203 236T156 260T124 300T111 359Q111 401 128 432T176 485T248 517T337 528Q406 528 456 508T536
|
||||
452L470 389Q455 410 421 428T331 446Q275 446 246 426T216 370Q216 339 235 328T283 312L358 298Q386 293 412 285T458 262T491 224T504 165Q504 124 487 91T439 35T363 0T264 -12Z" />
|
||||
<glyph unicode="t" glyph-name="t" d="M255 -12Q207 -12 183 14T159 85Q159 94 161 106T165 133L214 429H72L86 516H182Q211 516 225 527T244 568L266 698H366L336 516H544L530 429H321L264 87L284 77L480 216L533 152L442 84Q408 58 383 40T335 11T294 -6T255 -12Z" />
|
||||
<glyph unicode="u" glyph-name="u" d="M384 122H379Q350 60 311 24T209 -12Q140 -12 105 29T69 137Q69 155 70 174T77 220L126 516H233L183 216Q181 202 179 187T177 158Q177 123 194 99T252 75Q282 75 305 89T349 127Q359 139 377 169T403 240L449 516H556L470
|
||||
0H363L384 122Z" />
|
||||
<glyph unicode="v" glyph-name="v" d="M273 516L206 76L219 68Q275 80 316 109T384 178T424 266T438 363Q438 433 407 492L505 525Q525 494 535 454T546 366Q546 288 518 220T443 100T333 20T203 -10Q153 -10 129 15T105 84Q105 95 106 106T109 131L155 429H54L68
|
||||
516H273Z" />
|
||||
<glyph unicode="w" glyph-name="w" d="M123 -11Q75 -11 53 17T30 94Q30 109 32 130T38 173L95 516H185L127 179Q125 165 123 151T121 124Q121 76 161 76Q179 76 193 87T219 116Q230 132 237 155T247 196L300 516H387L332 177Q330 162 329 148T327 123Q327 75 365
|
||||
75Q389 75 410 100T447 167T472 261T482 367Q482 403 477 438T461 498L542 522Q556 495 564 456T572 368Q572 278 551 200T490 69Q430 -11 345 -11Q298 -11 275 16T255 96H250Q230 45 200 17T123 -11Z" />
|
||||
<glyph unicode="x" glyph-name="x" d="M106 -12Q55 -12 29 20T2 116Q2 129 3 141T6 174L97 183Q95 172 95 163T95 145Q95 105 104 87T136 68Q169 68 191 99T226 174T245 267T251 352Q251 376 250 400T243 441L229 448L82 353L39 414L107 465Q145 493 179 510T246
|
||||
528Q276 528 293 515T321 478T334 425T337 361H344Q365 451 402 489T495 528Q545 528 571 495T598 401Q598 390 598 376T595 342L504 333Q505 345 505 355T506 373Q506 411 497 429T465 448Q432 448 410 418T375 344T356 253T350 171Q350 145 352 120T360 75L373
|
||||
68L515 168L560 109L510 65Q459 20 423 4T357 -12Q330 -12 312 0T284 35T270 88T266 154L259 155Q238 65 200 27T106 -12Z" />
|
||||
<glyph unicode="y" glyph-name="y" d="M211 -212Q144 -212 97 -195T17 -139L85 -71Q128 -125 212 -125Q276 -125 315 -91T369 31L386 138H382Q353 76 314 40T212 4Q143 4 108 45T72 153Q72 171 73 190T80 236L126 516H233L186 232Q184 218 182 203T180 174Q180
|
||||
139 197 115T255 91Q285 91 308 105T352 143Q362 155 380 185T406 256L449 516H556L472 14Q452 -105 384 -158T211 -212Z" />
|
||||
<glyph unicode="z" glyph-name="z" d="M420 -11Q393 -11 363 -5T297 16L151 73L146 69L135 0H36L52 96L394 393Q346 421 314 431T252 442Q207 442 190 414T173 340H91V351Q91 437 133 482T250 528Q294 528 340 511T441 452L454 444L459 449L470 516H569L553 422L210
|
||||
123L440 73L451 85L420 201L489 228L505 193Q518 166 525 141T532 92Q532 72 525 54T503 21T467 -2T420 -11Z" />
|
||||
<glyph unicode="{" glyph-name="braceleft" d="M259 -138Q210 -138 192 -117T174 -67Q174 -57 176 -38T184 8Q188 35 197 55T216 90T238 118T261 142Q286 168 294 183T303 214Q303 273 200 273H106L119 349H212Q273 349 305 368T338 424Q338 449 318 480Q307 498
|
||||
295 520T282 577Q282 588 285 611T293 668Q299 708 328 734T408 760H584L571 683H384Q377 645 374 621T371 589Q371 564 378 548T396 515Q407 496 417 475T427 427Q427 381 395 351T298 313L297 307Q345 302 369 280T393 222Q393 187 374 161T328 107Q308 87 293
|
||||
66T271 4L260 -61H447L434 -138H259Z" />
|
||||
<glyph unicode="|" glyph-name="bar" d="M189 -138L339 760H430L280 -138H189Z" />
|
||||
<glyph unicode="}" glyph-name="braceright" d="M360 760Q384 760 400 754T427 739T441 717T445 692Q445 680 443 661T435 614Q430 587 422 567T403 531T381 503T358 480Q332 454 324 439T316 408Q316 349 419 349H513L500 273H407Q346 273 314 254T281 198Q281
|
||||
184 285 171T301 142Q315 123 326 101T337 45Q337 34 334 11T326 -46Q320 -86 291 -112T211 -138H35L48 -61H235Q242 -23 245 1T248 33Q248 58 241 73T223 107Q211 127 202 148T192 195Q192 241 224 271T321 309L322 315Q274 320 250 342T226 400Q226 435 245 462T291
|
||||
515Q301 525 309 535T325 556T339 583T348 618L359 683H172L185 760H360Z" />
|
||||
<glyph unicode="~" glyph-name="asciitilde" d="M405 225Q373 225 349 235T298 260Q274 273 253 283T209 294Q181 294 162 276T126 225L52 265Q75 320 115 352T210 385Q242 385 266 375T317 350Q341 337 362 327T406 316Q434 316 453 334T489 385L563 345Q540
|
||||
290 500 258T405 225Z" />
|
||||
<glyph unicode=" " glyph-name="uni00A0" />
|
||||
<glyph unicode="¡" glyph-name="exclamdown" d="M166 -182L200 21L282 279H323L318 21L284 -182H166ZM320 369Q279 369 262 384T245 421Q245 426 246 434T250 461Q255 488 275 507T341 526Q382 526 399 511T416 474Q416 469 415 461T411 434Q406 407 386
|
||||
388T320 369Z" />
|
||||
<glyph unicode="¢" glyph-name="cent" d="M222 -7Q146 8 107 63T67 206Q67 272 84 328T134 426T212 494T311 526L328 630H411L393 523Q454 513 488 480T535 402L450 368Q430 427 375 440L314 75Q327 77 341 83T371 102T406 136T448 188L517 147Q473 76 424
|
||||
37T304 -10L287 -114H204L222 -7ZM172 189Q172 101 242 79L302 440Q256 431 227 395T187 297L177 236Q174 220 173 210T172 189Z" />
|
||||
<glyph unicode="£" glyph-name="sterling" d="M467 -12Q438 -12 403 -4T329 17L134 72L122 0H21L38 105Q65 117 86 131T124 165T148 210T157 270Q157 279 157 286T155 302H51L65 384H141Q137 403 135 423T132 464Q132 518 150 563T202 641T282 692T382 710Q425
|
||||
710 459 699T519 670T562 626T589 574L500 528Q486 566 457 591T377 617Q313 617 277 576T240 456Q240 436 242 419T248 384H427L413 302H263Q265 297 265 289T265 276Q265 231 242 198T174 157L171 151L460 84L471 96L445 208L523 230L536 196Q547 166 553 140T560
|
||||
89Q560 47 536 18T467 -12Z" />
|
||||
<glyph unicode="¥" glyph-name="yen" d="M41 86H220L245 238H67L81 324H217L88 698H201L309 352H314L538 698H660L406 324H543L529 238H349L324 86H503L489 0H27L41 86Z" />
|
||||
<glyph unicode="¦" glyph-name="brokenbar" d="M279 400L339 760H430L370 400H279ZM189 -138L249 222H340L280 -138H189Z" />
|
||||
<glyph unicode="§" glyph-name="section" d="M455 17Q455 -23 440 -56T397 -113T329 -150T239 -164Q213 -164 187 -160T136 -148T90 -128T52 -99L114 -32Q136 -55 169 -67T240 -80Q291 -80 323 -57T356 4Q356 33 337 52T271 85L206 106Q131 130 103 165T74
|
||||
242Q74 300 108 339T215 398L216 407Q184 430 169 462T153 529Q153 569 168 602T211 659T279 696T369 710Q395 710 421 706T472 694T518 674T556 645L494 578Q472 601 439 613T368 626Q317 626 285 603T252 542Q252 513 271 494T337 461L402 440Q477 416 505 381T534
|
||||
304Q534 246 500 207T393 148L392 139Q424 116 439 84T455 17ZM434 270Q434 299 415 321T344 359L278 379Q268 382 255 387Q174 346 174 276Q174 247 193 225T264 187L330 167Q340 164 353 159Q434 200 434 270Z" />
|
||||
<glyph unicode="¨" glyph-name="dieresis" d="M218 608Q184 608 171 620T157 651Q157 656 157 661T160 676Q164 699 179 715T232 731Q266 731 279 719T293 688Q293 683 293 678T290 663Q286 640 271 624T218 608ZM418 608Q384 608 371 620T357 651Q357 656
|
||||
357 661T360 676Q364 699 379 715T432 731Q466 731 479 719T493 688Q493 683 493 678T490 663Q486 640 471 624T418 608Z" />
|
||||
<glyph unicode="©" glyph-name="copyright" d="M271 18Q214 18 166 37T84 93T30 182T11 300Q11 384 37 454T108 574T217 652T356 680Q413 680 460 661T542 605T596 516T616 398Q616 314 590 244T519 124T410 46T271 18ZM276 72Q328 72 373 89T453 137T512
|
||||
212T545 309Q552 350 554 368T556 398Q556 442 545 483T509 556T445 607T351 626Q299 626 254 609T174 561T115 486T82 389Q74 348 73 330T71 300Q71 256 82 215T118 142T182 91T276 72ZM293 164Q224 164 187 205T149 318Q149 361 163 400T202 470T263 517T340
|
||||
535Q396 535 427 510T472 443L400 412Q394 436 380 450T336 464Q298 464 277 441T250 382L240 322Q238 313 238 308T238 297Q238 268 253 252T299 236Q328 236 348 251T385 289L446 253Q423 216 386 190T293 164Z" />
|
||||
<glyph unicode="ª" glyph-name="ordfeminine" d="M373 349L383 409H375Q361 380 336 361T272 342Q221 342 193 366T165 431Q165 492 209 522T338 552H405L409 575Q410 582 410 587T411 598Q411 624 394 636T344 648Q312 648 289 634T250 599L208 643Q227
|
||||
669 263 689T355 710Q417 710 453 683T490 605Q490 582 487 564L451 349H373ZM331 501Q295 501 273 491T246 454Q245 449 245 444T244 436Q244 400 297 400Q331 400 358 415T390 460L397 501H331Z" />
|
||||
<glyph unicode="«" glyph-name="guillemotleft" d="M492 51L319 223L336 322L561 491L586 417L421 266L536 117L492 51ZM470 51L297 223L314 322L539 491L564 417L399 266L514 117L470 51Z" />
|
||||
<glyph unicode="¬" glyph-name="logicalnot" d="M403 68L435 262H65L79 349H539L492 68H403Z" />
|
||||
<glyph unicode="­" glyph-name="uni00AD" d="M149 251L167 358H466L448 251H149Z" />
|
||||
<glyph unicode="®" glyph-name="registered" d="M309 346Q273 346 244 357T192 390T158 440T146 507Q146 548 161 585T204 649T268 693T351 710Q387 710 416 699T468 666T502 616T514 549Q514 508 499 471T456 406T392 362T309 346ZM309 386Q343 386 369
|
||||
396T415 423T446 463T462 511Q464 525 465 533T467 550Q467 602 439 636T351 670Q317 670 291 660T245 633T214 593T198 545Q196 531 195 523T193 506Q193 454 221 420T309 386ZM288 439H242L273 624H361Q388 624 402 611T416 574Q416 550 403 534T369 510L401
|
||||
439H350L325 502H299L288 439ZM335 536Q348 536 355 542T365 558Q366 563 366 565T366 570Q366 588 344 588H313L304 536H335Z" />
|
||||
<glyph unicode="¯" glyph-name="overscore" d="M187 710H476L462 629H173L187 710Z" />
|
||||
<glyph unicode="°" glyph-name="degree" d="M329 354Q293 354 263 365T212 398T178 449T166 515Q166 556 181 591T222 653T285 695T364 710Q400 710 429 699T480 666T514 615T526 549Q526 508 511 472T470 410T407 369T329 354ZM333 430Q383 430 413 464T443
|
||||
547Q443 585 421 609T359 634Q309 634 279 600T249 517Q249 479 271 455T333 430Z" />
|
||||
<glyph unicode="±" glyph-name="plusminus" d="M237 164L268 351H79L93 438H283L314 625H409L378 438H567L553 351H363L332 164H237ZM21 0L35 87H509L495 0H21Z" />
|
||||
<glyph unicode="²" glyph-name="twosuperior" d="M447 329H177L189 399L323 492Q352 512 374 532T401 579Q402 584 402 588T403 597Q403 617 388 628T351 639Q322 639 306 622T281 585L216 611Q232 649 265 676T356 704Q382 704 405 698T446 678T474 645T484
|
||||
599Q484 573 474 552T446 512T406 477T361 446L277 391H457L447 329Z" />
|
||||
<glyph unicode="³" glyph-name="threesuperior" d="M333 550Q370 550 384 563T401 590Q402 595 402 599T403 607Q403 624 390 634T353 644Q303 644 269 598L224 643Q248 671 280 687T359 704Q419 704 450 678T481 611Q481 576 458 552T395 520V518Q426 512
|
||||
443 492T461 439Q461 390 422 357T311 323Q254 323 222 343T175 394L229 432Q240 410 259 397T312 383Q343 383 360 396T381 432Q382 437 382 440T383 447Q383 466 367 477T322 489H281L291 550H333Z" />
|
||||
<glyph unicode="´" glyph-name="acute" d="M321 579L258 614L369 790L456 743L321 579Z" />
|
||||
<glyph unicode="µ" glyph-name="mu" d="M9 -200L128 516H235L185 216Q183 202 181 187T179 158Q179 123 196 99T254 75Q284 75 307 89T351 127Q361 139 379 169T405 240L451 516H558L472 0H365L386 122H381Q370 96 356 72T323 29T280 -1T226 -12Q197 -12
|
||||
176 1T145 45H141L137 -68L116 -200H9Z" />
|
||||
<glyph unicode="¶" glyph-name="paragraph" d="M265 246Q224 246 190 259T130 298T90 359T76 441Q76 499 98 546T157 628T241 680T340 698H601L459 -149H370L498 615H416L288 -149H199L265 246Z" />
|
||||
<glyph unicode="·" glyph-name="middot" d="M297 224Q255 224 238 239T220 278Q220 286 221 295T225 318Q230 350 253 368T319 386Q361 386 378 371T396 332Q396 324 395 315T391 292Q386 260 363 242T297 224Z" />
|
||||
<glyph unicode="¸" glyph-name="cedilla" d="M285 -209Q243 -209 217 -196T180 -166L224 -121Q232 -131 246 -139T284 -148Q304 -148 318 -140T332 -116Q332 -105 321 -94T269 -78L243 -75L280 24H337L307 -58L309 -62Q320 -59 330 -58T348 -57Q376 -57 393
|
||||
-71T411 -117Q411 -140 401 -157T374 -185T334 -203T285 -209Z" />
|
||||
<glyph unicode="¹" glyph-name="onesuperior" d="M202 329L212 389H307L347 626L253 577L229 632L356 698H435L383 389H468L458 329H202Z" />
|
||||
<glyph unicode="º" glyph-name="ordmasculine" d="M320 342Q252 342 213 382T174 489Q174 538 188 578T227 648T289 694T371 710Q439 710 478 670T517 563Q517 514 503 474T464 404T402 358T320 342ZM329 405Q369 405 393 429T424 495L434 554Q435 562 435
|
||||
567T436 578Q436 610 417 628T362 647Q322 647 298 623T267 557L257 498Q256 490 256 485T255 474Q255 442 274 424T329 405Z" />
|
||||
<glyph unicode="»" glyph-name="guillemotright" d="M40 125L205 276L90 425L134 491L307 319L290 220L65 51L40 125ZM274 125L439 276L324 425L368 491L541 319L524 220L299 51L274 125Z" />
|
||||
<glyph unicode="¼" glyph-name="onequarter" d="M439 64H279L290 129L460 335H555L519 117H564L555 64H510L499 0H428L439 64ZM448 117L473 269H470L346 117H448ZM66 421H156L192 634L102 591L83 643L197 698H275L229 421H309L299 363H57L66 421ZM577 698H664L449
|
||||
398H362L577 698ZM183 300H270L55 0H-32L183 300Z" />
|
||||
<glyph unicode="½" glyph-name="onehalf" d="M294 65L419 151Q455 177 470 194T489 229Q490 233 490 238T490 245Q490 263 478 273T445 283Q422 283 406 269T377 230L318 255Q335 291 367 316T453 341Q510 341 538 314T566 249Q566 225 557 206T531 170T495
|
||||
139T452 109L374 57H544L535 0H283L294 65ZM66 421H156L192 634L102 591L83 643L197 698H275L229 421H309L299 363H57L66 421ZM577 698H664L449 398H362L577 698ZM183 300H270L55 0H-32L183 300Z" />
|
||||
<glyph unicode="¾" glyph-name="threequarters" d="M439 64H279L290 129L460 335H555L519 117H564L555 64H510L499 0H428L439 64ZM448 117L473 269H470L346 117H448ZM171 357Q117 357 88 377T46 427L100 460Q108 440 124 427T172 414Q200 414 215 425T234
|
||||
454Q235 459 235 463T236 472Q236 509 178 509H147L156 563H189Q222 563 237 574T254 599Q255 604 255 607T255 615Q255 629 243 638T207 647Q164 647 131 606L91 647Q116 673 145 688T218 704Q271 704 301 682T332 624Q332 589 308 567T248 539V535Q278 531 295
|
||||
513T312 466Q312 418 273 388T171 357ZM577 698H664L449 398H362L577 698ZM183 300H270L55 0H-32L183 300Z" />
|
||||
<glyph unicode="¿" glyph-name="questiondown" d="M241 -194Q145 -194 92 -146T38 -16Q38 33 57 72T107 138T178 182T259 205L274 293H379L354 138Q307 133 273 125T214 102T175 65T155 8Q154 3 154 -2T153 -16Q153 -56 181 -78T254 -101Q307 -101 339 -72T390
|
||||
4L479 -36Q467 -68 447 -96T397 -147T329 -181T241 -194ZM339 369Q298 369 281 384T264 421Q264 426 265 434T269 461Q274 488 294 507T360 526Q401 526 418 511T435 474Q435 469 434 461T430 434Q425 407 405 388T339 369Z" />
|
||||
<glyph unicode="À" glyph-name="Agrave" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM279 920L374 960L437 777L370 749L279 920Z" />
|
||||
<glyph unicode="Á" glyph-name="Aacute" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM392 749L329 784L440 960L527 913L392 749Z" />
|
||||
<glyph unicode="Â" glyph-name="Acircumflex" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM466 943L562 792L503 752L403 868L267 752L215 795L357 943H466Z" />
|
||||
<glyph unicode="Ã" glyph-name="Atilde" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM470 774Q446 774 429 782T395 799Q376 810 360 816T327 822Q311 822 297 815T264 794L231 846Q250 869 278 886T341 903Q365
|
||||
903 382 895T416 878Q435 867 451 861T484 855Q500 855 514 862T547 883L580 831Q561 808 533 791T470 774Z" />
|
||||
<glyph unicode="Ä" glyph-name="Adieresis" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM289 778Q255 778 242 790T228 821Q228 826 228 831T231 846Q235 869 250 885T303 901Q337 901 350 889T364 858Q364
|
||||
853 364 848T361 833Q357 810 342 794T289 778ZM489 778Q455 778 442 790T428 821Q428 826 428 831T431 846Q435 869 450 885T503 901Q537 901 550 889T564 858Q564 853 564 848T561 833Q557 810 542 794T489 778Z" />
|
||||
<glyph unicode="Å" glyph-name="Aring" d="M424 0L404 186H177L95 0H-21L300 698H450L538 0H424ZM362 588H353L217 279H395L362 588ZM382 736Q333 736 301 767T269 846Q269 876 280 902T312 946T358 976T415 987Q464 987 496 956T528 877Q528 847 517 821T485
|
||||
777T439 747T382 736ZM388 795Q414 795 430 808T451 849Q453 863 454 871T456 886Q456 906 444 917T409 928Q383 928 367 915T346 874Q344 860 343 852T341 837Q341 817 353 806T388 795Z" />
|
||||
<glyph unicode="Æ" glyph-name="AE" d="M303 188H173L95 0H-15L287 698H653L639 612H477L441 396H592L578 310H427L389 86H551L537 0H272L303 188ZM349 620L207 274H318L375 620H349Z" />
|
||||
<glyph unicode="Ç" glyph-name="Ccedilla" d="M377 618Q304 618 261 562T201 406L184 304Q180 281 178 262T176 220Q176 156 204 118T298 80Q325 80 347 89T387 114T420 155T452 210L543 175Q505 92 453 44T315 -11L298 -58L300 -62Q311 -59 321 -58T339
|
||||
-57Q367 -57 384 -71T402 -117Q402 -140 392 -157T365 -185T325 -203T276 -209Q234 -209 208 -196T171 -166L215 -121Q223 -131 237 -139T275 -148Q295 -148 309 -140T323 -116Q323 -105 312 -94T260 -78L234 -75L257 -11Q158 -1 112 65T66 246Q66 343 87 427T148
|
||||
575T248 674T385 710Q437 710 474 696T535 657T573 601T591 532L488 506Q484 530 478 550T459 586T427 609T377 618Z" />
|
||||
<glyph unicode="È" glyph-name="Egrave" d="M283 920L378 960L441 777L374 749L283 920ZM42 0L159 698H595L579 605H253L218 400H533L517 307H203L167 93H495L479 0H42Z" />
|
||||
<glyph unicode="É" glyph-name="Eacute" d="M42 0L159 698H595L579 605H253L218 400H533L517 307H203L167 93H495L479 0H42ZM396 749L333 784L444 960L531 913L396 749Z" />
|
||||
<glyph unicode="Ê" glyph-name="Ecircumflex" d="M470 943L566 792L507 752L407 868L271 752L219 795L361 943H470ZM42 0L159 698H595L579 605H253L218 400H533L517 307H203L167 93H495L479 0H42Z" />
|
||||
<glyph unicode="Ë" glyph-name="Edieresis" d="M42 0L159 698H595L579 605H253L218 400H533L517 307H203L167 93H495L479 0H42ZM293 778Q259 778 246 790T232 821Q232 826 232 831T235 846Q239 869 254 885T307 901Q341 901 354 889T368 858Q368 853 368
|
||||
848T365 833Q361 810 346 794T293 778ZM493 778Q459 778 446 790T432 821Q432 826 432 831T435 846Q439 869 454 885T507 901Q541 901 554 889T568 858Q568 853 568 848T565 833Q561 810 546 794T493 778Z" />
|
||||
<glyph unicode="Ì" glyph-name="Igrave" d="M38 0L52 84H216L305 614H141L155 698H593L579 614H415L326 84H490L476 0H38ZM279 920L374 960L437 777L370 749L279 920Z" />
|
||||
<glyph unicode="Í" glyph-name="Iacute" d="M38 0L52 84H216L305 614H141L155 698H593L579 614H415L326 84H490L476 0H38ZM392 749L329 784L440 960L527 913L392 749Z" />
|
||||
<glyph unicode="Î" glyph-name="Icircumflex" d="M38 0L52 84H216L305 614H141L155 698H593L579 614H415L326 84H490L476 0H38ZM466 943L562 792L503 752L403 868L267 752L215 795L357 943H466Z" />
|
||||
<glyph unicode="Ï" glyph-name="Idieresis" d="M38 0L52 84H216L305 614H141L155 698H593L579 614H415L326 84H490L476 0H38ZM289 778Q255 778 242 790T228 821Q228 826 228 831T231 846Q235 869 250 885T303 901Q337 901 350 889T364 858Q364 853 364 848T361
|
||||
833Q357 810 342 794T289 778ZM489 778Q455 778 442 790T428 821Q428 826 428 831T431 846Q435 869 450 885T503 901Q537 901 550 889T564 858Q564 853 564 848T561 833Q557 810 542 794T489 778Z" />
|
||||
<glyph unicode="Ð" glyph-name="Eth" d="M97 327H26L40 410H111L159 698H345Q401 698 444 681T516 633T560 558T575 460Q575 232 489 116T250 0H42L97 327ZM255 91Q333 91 378 139T440 283L458 392Q461 410 463 431T465 470Q465 607 333 607H253L220 407H347L334
|
||||
329H207L167 91H255Z" />
|
||||
<glyph unicode="Ñ" glyph-name="Ntilde" d="M470 774Q446 774 429 782T395 799Q376 810 360 816T327 822Q311 822 297 815T264 794L231 846Q250 869 278 886T341 903Q365 903 382 895T416 878Q435 867 451 861T484 855Q500 855 514 862T547 883L580 831Q561
|
||||
808 533 791T470 774ZM228 546H220L129 0H31L147 698H291L403 152H411L502 698H600L484 0H340L228 546Z" />
|
||||
<glyph unicode="Ò" glyph-name="Ograve" d="M269 920L364 960L427 777L360 749L269 920ZM268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552 250T513 150T455 66T374 9T268
|
||||
-12ZM271 80Q344 80 385 135T443 291L462 406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80Z" />
|
||||
<glyph unicode="Ó" glyph-name="Oacute" d="M382 749L319 784L430 960L517 913L382 749ZM268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552 250T513 150T455 66T374 9T268
|
||||
-12ZM271 80Q344 80 385 135T443 291L462 406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80Z" />
|
||||
<glyph unicode="Ô" glyph-name="Ocircumflex" d="M456 943L552 792L493 752L393 868L257 752L205 795L347 943H456ZM268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552
|
||||
250T513 150T455 66T374 9T268 -12ZM271 80Q344 80 385 135T443 291L462 406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80Z" />
|
||||
<glyph unicode="Õ" glyph-name="Otilde" d="M268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552 250T513 150T455 66T374 9T268 -12ZM271 80Q344 80 385 135T443 291L462
|
||||
406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80ZM460 774Q436 774 419 782T385 799Q366 810 350 816T317 822Q301 822 287 815T254 794L221 846Q240 869 268 886T331 903Q355
|
||||
903 372 895T406 878Q425 867 441 861T474 855Q490 855 504 862T537 883L570 831Q551 808 523 791T460 774Z" />
|
||||
<glyph unicode="Ö" glyph-name="Odieresis" d="M268 -12Q155 -12 103 53T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q475 710 527 645T579 462Q579 411 573 357T552 250T513 150T455 66T374 9T268 -12ZM271 80Q344 80 385 135T443 291L462
|
||||
406Q466 429 467 448T469 485Q469 548 443 583T359 618Q286 618 245 563T187 407L168 292Q164 269 163 250T161 213Q161 150 187 115T271 80ZM279 778Q245 778 232 790T218 821Q218 826 218 831T221 846Q225 869 240 885T293 901Q327 901 340 889T354 858Q354 853
|
||||
354 848T351 833Q347 810 332 794T279 778ZM479 778Q445 778 432 790T418 821Q418 826 418 831T421 846Q425 869 440 885T493 901Q527 901 540 889T554 858Q554 853 554 848T551 833Q547 810 532 794T479 778Z" />
|
||||
<glyph unicode="×" glyph-name="multiply" d="M302 243L119 87L63 153L247 310L119 465L188 524L316 368L499 524L555 458L371 301L499 146L430 87L302 243Z" />
|
||||
<glyph unicode="Ø" glyph-name="Oslash" d="M268 -12Q178 -12 125 32L64 -49L-6 -4L74 101Q62 128 57 162T51 236Q51 286 57 341T78 448T117 548T175 632T256 689T362 710Q452 710 505 666L566 747L636 702L556 597Q568 570 573 536T579 462Q579 411 573
|
||||
357T552 250T513 150T455 66T374 9T268 -12ZM167 296Q164 278 162 261T160 229Q160 223 160 218T161 208L445 582Q417 618 359 618Q287 618 245 564T186 410L167 296ZM271 80Q343 80 385 134T444 288L463 402Q466 420 468 437T470 469Q470 475 470 480T469 490L185
|
||||
116Q213 80 271 80Z" />
|
||||
<glyph unicode="Ù" glyph-name="Ugrave" d="M275 920L370 960L433 777L366 749L275 920ZM253 698L184 285Q177 244 174 219T171 178Q171 155 175 137T191 106T222 87T271 80Q314 80 340 92T381 128T405 186T420 262L493 698H603L534 284Q522 210 506 155T462
|
||||
62T387 7T269 -12Q212 -12 173 0T109 36T74 93T63 170Q63 199 67 236T78 309L143 698H253Z" />
|
||||
<glyph unicode="Ú" glyph-name="Uacute" d="M253 698L184 285Q177 244 174 219T171 178Q171 155 175 137T191 106T222 87T271 80Q314 80 340 92T381 128T405 186T420 262L493 698H603L534 284Q522 210 506 155T462 62T387 7T269 -12Q212 -12 173 0T109 36T74
|
||||
93T63 170Q63 199 67 236T78 309L143 698H253ZM388 749L325 784L436 960L523 913L388 749Z" />
|
||||
<glyph unicode="Û" glyph-name="Ucircumflex" d="M462 943L558 792L499 752L399 868L263 752L211 795L353 943H462ZM253 698L184 285Q177 244 174 219T171 178Q171 155 175 137T191 106T222 87T271 80Q314 80 340 92T381 128T405 186T420 262L493 698H603L534
|
||||
284Q522 210 506 155T462 62T387 7T269 -12Q212 -12 173 0T109 36T74 93T63 170Q63 199 67 236T78 309L143 698H253Z" />
|
||||
<glyph unicode="Ü" glyph-name="Udieresis" d="M253 698L184 285Q177 244 174 219T171 178Q171 155 175 137T191 106T222 87T271 80Q314 80 340 92T381 128T405 186T420 262L493 698H603L534 284Q522 210 506 155T462 62T387 7T269 -12Q212 -12 173 0T109
|
||||
36T74 93T63 170Q63 199 67 236T78 309L143 698H253ZM285 778Q251 778 238 790T224 821Q224 826 224 831T227 846Q231 869 246 885T299 901Q333 901 346 889T360 858Q360 853 360 848T357 833Q353 810 338 794T285 778ZM485 778Q451 778 438 790T424 821Q424 826
|
||||
424 831T427 846Q431 869 446 885T499 901Q533 901 546 889T560 858Q560 853 560 848T557 833Q553 810 538 794T485 778Z" />
|
||||
<glyph unicode="Ý" glyph-name="Yacute" d="M203 0L246 261L85 698H202L264 523L311 372H317L417 523L535 698H661L357 266L313 0H203ZM385 749L322 784L433 960L520 913L385 749Z" />
|
||||
<glyph unicode="Þ" glyph-name="Thorn" d="M42 0L159 698H268L246 564H386Q431 564 464 552T520 516T554 461T565 391Q565 276 503 211T328 146H176L151 0H42ZM192 238H323Q428 238 443 328L449 364Q450 369 451 379T452 398Q452 472 361 472H231L192 238Z" />
|
||||
<glyph unicode="ß" glyph-name="germandbls" d="M43 0L145 611Q156 678 195 709T294 740H432L418 653H258L235 516H570L555 427L365 209Q443 199 487 159T531 44Q531 -13 511 -58T453 -135T361 -183T237 -200H167L181 -114H244Q319 -114 364 -88T417 2Q420
|
||||
25 421 35T422 52Q422 100 386 119T273 138H253L268 224L448 429H220L149 0H43Z" />
|
||||
<glyph unicode="à" glyph-name="agrave" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424
|
||||
343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM233 750L328 790L391 607L324 579L233 750Z" />
|
||||
<glyph unicode="á" glyph-name="aacute" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424
|
||||
343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM346 579L283 614L394 790L481 743L346 579Z" />
|
||||
<glyph unicode="â" glyph-name="acircumflex" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407
|
||||
240L424 343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM420 773L516 622L457 582L357 698L221 582L169 625L311 773H420Z" />
|
||||
<glyph unicode="ã" glyph-name="atilde" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424
|
||||
343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM415 604Q391 604 374 611T340 629Q323 640 306 646T272 652Q256 652 242 645T209 624L176 676Q195 699 223 716T286 733Q310 733 327 726T361 708Q378
|
||||
697 395 691T429 685Q445 685 459 692T492 713L525 661Q506 638 478 621T415 604Z" />
|
||||
<glyph unicode="ä" glyph-name="adieresis" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407
|
||||
240L424 343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM243 608Q209 608 196 620T182 651Q182 656 182 661T185 676Q189 699 204 715T257 731Q291 731 304 719T318 688Q318 683 318 678T315 663Q311
|
||||
640 296 624T243 608ZM443 608Q409 608 396 620T382 651Q382 656 382 661T385 676Q389 699 404 715T457 731Q491 731 504 719T518 688Q518 683 518 678T515 663Q511 640 496 624T443 608Z" />
|
||||
<glyph unicode="å" glyph-name="aring" d="M367 0L387 122H383Q354 62 313 25T205 -12Q125 -12 87 40T48 188Q48 250 62 311T107 420T182 498T290 528Q349 528 384 501T433 423H438L453 516H560L474 0H367ZM248 75Q307 75 354 129Q371 148 386 176T407 240L424
|
||||
343Q432 388 405 414T323 441Q256 441 220 401T172 297L160 226Q158 217 157 206T156 183Q156 134 178 105T248 75ZM336 566Q287 566 255 597T223 676Q223 706 234 732T266 776T312 806T369 817Q418 817 450 786T482 707Q482 677 471 651T439 607T393 577T336 566ZM342
|
||||
625Q368 625 384 638T405 679Q407 693 408 701T410 716Q410 736 398 747T363 758Q337 758 321 745T300 704Q298 690 297 682T295 667Q295 647 307 636T342 625Z" />
|
||||
<glyph unicode="æ" glyph-name="ae" d="M116 -12Q64 -12 31 20T-3 118Q-3 200 52 245T205 293L258 295L266 345Q268 356 269 366T270 384Q270 456 206 456Q173 456 150 437T107 381L47 421Q73 472 113 500T211 528Q268 528 297 503T328 438H332Q354 480 388
|
||||
504T472 528Q529 528 563 495T598 402Q598 373 587 344T546 290T467 250T338 232L335 213Q333 199 332 186T331 162Q331 114 348 89T399 64Q434 64 454 88T491 148L561 116Q537 61 496 25T393 -12Q338 -12 301 19T258 115H253Q222 -12 116 -12ZM141 60Q176 60 201
|
||||
87T235 162L247 231L203 230Q152 228 122 211T85 149Q83 135 83 128T82 116Q82 88 98 74T141 60ZM462 456Q417 456 389 415T350 308L348 295Q396 296 428 305T479 328T507 360T516 399Q516 456 462 456Z" />
|
||||
<glyph unicode="ç" glyph-name="ccedilla" d="M342 528Q384 528 416 519T471 492T508 451T530 401L441 362Q428 404 403 421T332 439Q277 439 240 404T190 296L180 236Q178 222 177 211T176 189Q176 133 204 105T287 77Q303 77 319 80T354 96T396 132T448
|
||||
196L519 152Q473 78 422 37T298 -11L281 -58L283 -62Q294 -59 304 -58T322 -57Q350 -57 367 -71T385 -117Q385 -140 375 -157T348 -185T308 -203T259 -209Q217 -209 191 -196T154 -166L198 -121Q206 -131 220 -139T258 -148Q278 -148 292 -140T306 -116Q306 -105
|
||||
295 -94T243 -78L217 -75L241 -10Q155 -1 111 56T67 206Q67 276 87 335T143 437T230 504T342 528Z" />
|
||||
<glyph unicode="è" glyph-name="egrave" d="M279 -12Q173 -12 120 44T66 209Q66 280 87 338T147 439T239 504T358 528Q397 528 430 519T487 493T526 449T540 388Q540 359 528 329T476 274T365 232T175 211Q174 204 174 199T174 191Q174 167 179 146T198 108T233
|
||||
83T291 74Q316 74 336 79T375 97T412 128T452 177L522 132Q501 99 477 73T424 28T359 -1T279 -12ZM348 447Q282 447 240 408T185 289L183 278Q267 281 316 291T392 316T426 348T434 381Q434 410 415 428T348 447ZM257 750L352 790L415 607L348 579L257 750Z" />
|
||||
<glyph unicode="é" glyph-name="eacute" d="M370 579L307 614L418 790L505 743L370 579ZM279 -12Q173 -12 120 44T66 209Q66 280 87 338T147 439T239 504T358 528Q397 528 430 519T487 493T526 449T540 388Q540 359 528 329T476 274T365 232T175 211Q174
|
||||
204 174 199T174 191Q174 167 179 146T198 108T233 83T291 74Q316 74 336 79T375 97T412 128T452 177L522 132Q501 99 477 73T424 28T359 -1T279 -12ZM348 447Q282 447 240 408T185 289L183 278Q267 281 316 291T392 316T426 348T434 381Q434 410 415 428T348 447Z"
|
||||
/>
|
||||
<glyph unicode="ê" glyph-name="ecircumflex" d="M444 773L540 622L481 582L381 698L245 582L193 625L335 773H444ZM279 -12Q173 -12 120 44T66 209Q66 280 87 338T147 439T239 504T358 528Q397 528 430 519T487 493T526 449T540 388Q540 359 528 329T476
|
||||
274T365 232T175 211Q174 204 174 199T174 191Q174 167 179 146T198 108T233 83T291 74Q316 74 336 79T375 97T412 128T452 177L522 132Q501 99 477 73T424 28T359 -1T279 -12ZM348 447Q282 447 240 408T185 289L183 278Q267 281 316 291T392 316T426 348T434 381Q434
|
||||
410 415 428T348 447Z" />
|
||||
<glyph unicode="ë" glyph-name="edieresis" d="M267 608Q233 608 220 620T206 651Q206 656 206 661T209 676Q213 699 228 715T281 731Q315 731 328 719T342 688Q342 683 342 678T339 663Q335 640 320 624T267 608ZM467 608Q433 608 420 620T406 651Q406 656
|
||||
406 661T409 676Q413 699 428 715T481 731Q515 731 528 719T542 688Q542 683 542 678T539 663Q535 640 520 624T467 608ZM279 -12Q173 -12 120 44T66 209Q66 280 87 338T147 439T239 504T358 528Q397 528 430 519T487 493T526 449T540 388Q540 359 528 329T476
|
||||
274T365 232T175 211Q174 204 174 199T174 191Q174 167 179 146T198 108T233 83T291 74Q316 74 336 79T375 97T412 128T452 177L522 132Q501 99 477 73T424 28T359 -1T279 -12ZM348 447Q282 447 240 408T185 289L183 278Q267 281 316 291T392 316T426 348T434 381Q434
|
||||
410 415 428T348 447Z" />
|
||||
<glyph unicode="ì" glyph-name="igrave" d="M282 -12Q234 -12 210 13T186 78Q186 101 193 135L250 429H76L90 516H373L289 83L309 75L482 234L543 179L465 101Q434 70 409 49T363 14T323 -6T282 -12ZM224 750L319 790L382 607L315 579L224 750Z" />
|
||||
<glyph unicode="í" glyph-name="iacute" d="M337 579L274 614L385 790L472 743L337 579ZM282 -12Q234 -12 210 13T186 78Q186 101 193 135L250 429H76L90 516H373L289 83L309 75L482 234L543 179L465 101Q434 70 409 49T363 14T323 -6T282 -12Z" />
|
||||
<glyph unicode="î" glyph-name="icircumflex" d="M411 773L507 622L448 582L348 698L212 582L160 625L302 773H411ZM282 -12Q234 -12 210 13T186 78Q186 101 193 135L250 429H76L90 516H373L289 83L309 75L482 234L543 179L465 101Q434 70 409 49T363 14T323
|
||||
-6T282 -12Z" />
|
||||
<glyph unicode="ï" glyph-name="idieresis" d="M234 608Q200 608 187 620T173 651Q173 656 173 661T176 676Q180 699 195 715T248 731Q282 731 295 719T309 688Q309 683 309 678T306 663Q302 640 287 624T234 608ZM434 608Q400 608 387 620T373 651Q373 656
|
||||
373 661T376 676Q380 699 395 715T448 731Q482 731 495 719T509 688Q509 683 509 678T506 663Q502 640 487 624T434 608ZM282 -12Q234 -12 210 13T186 78Q186 101 193 135L250 429H76L90 516H373L289 83L309 75L482 234L543 179L465 101Q434 70 409 49T363 14T323
|
||||
-6T282 -12Z" />
|
||||
<glyph unicode="ð" glyph-name="eth" d="M448 646Q491 592 521 517T551 343Q551 257 531 191T472 80T379 12T256 -12Q208 -12 170 3T104 46T63 113T48 201Q48 265 67 320T119 415T199 479T301 502Q355 502 392 477T446 409L452 412Q437 507 362 597L259 536L224
|
||||
588L318 644Q289 670 256 694T184 740H350Q363 730 377 719T405 693L505 753L540 701L448 646ZM271 73Q333 73 373 109T424 213L433 267Q435 281 436 291T438 310Q438 364 407 390T323 416Q261 416 221 380T170 276L161 222Q159 208 158 198T156 179Q156 125 187
|
||||
99T271 73Z" />
|
||||
<glyph unicode="ñ" glyph-name="ntilde" d="M45 0L131 516H238L217 394H222Q251 456 290 492T392 528Q461 528 496 487T532 379Q532 361 531 342T524 296L475 0H368L418 300Q420 314 422 329T424 358Q424 393 407 417T349 441Q319 441 296 427T252 389Q242
|
||||
377 224 347T198 276L152 0H45ZM424 604Q400 604 383 611T349 629Q332 640 315 646T281 652Q265 652 251 645T218 624L185 676Q204 699 232 716T295 733Q319 733 336 726T370 708Q387 697 404 691T438 685Q454 685 468 692T501 713L534 661Q515 638 487 621T424
|
||||
604Z" />
|
||||
<glyph unicode="ò" glyph-name="ograve" d="M265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234 524 175T466 75T377 11T265 -12ZM272 73Q335 73 373 111T422 218L433
|
||||
284Q435 298 436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73ZM251 750L346 790L409 607L342 579L251 750Z" />
|
||||
<glyph unicode="ó" glyph-name="oacute" d="M364 579L301 614L412 790L499 743L364 579ZM265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234 524 175T466 75T377 11T265
|
||||
-12ZM272 73Q335 73 373 111T422 218L433 284Q435 298 436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73Z" />
|
||||
<glyph unicode="ô" glyph-name="ocircumflex" d="M438 773L534 622L475 582L375 698L239 582L187 625L329 773H438ZM265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234
|
||||
524 175T466 75T377 11T265 -12ZM272 73Q335 73 373 111T422 218L433 284Q435 298 436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73Z" />
|
||||
<glyph unicode="õ" glyph-name="otilde" d="M265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234 524 175T466 75T377 11T265 -12ZM272 73Q335 73 373 111T422 218L433
|
||||
284Q435 298 436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73ZM433 604Q409 604 392 611T358 629Q341 640 324 646T290 652Q274 652 260 645T227 624L194 676Q213 699 241 716T304 733Q328
|
||||
733 345 726T379 708Q396 697 413 691T447 685Q463 685 477 692T510 713L543 661Q524 638 496 621T433 604Z" />
|
||||
<glyph unicode="ö" glyph-name="odieresis" d="M261 608Q227 608 214 620T200 651Q200 656 200 661T203 676Q207 699 222 715T275 731Q309 731 322 719T336 688Q336 683 336 678T333 663Q329 640 314 624T261 608ZM461 608Q427 608 414 620T400 651Q400 656
|
||||
400 661T403 676Q407 699 422 715T475 731Q509 731 522 719T536 688Q536 683 536 678T533 663Q529 640 514 624T461 608ZM265 -12Q214 -12 175 4T110 48T69 117T55 208Q55 282 76 341T134 441T223 505T335 528Q386 528 425 512T490 468T531 398T545 308Q545 234
|
||||
524 175T466 75T377 11T265 -12ZM272 73Q335 73 373 111T422 218L433 284Q435 298 436 310T438 331Q438 388 409 415T328 443Q265 443 227 405T178 298L167 232Q165 218 164 206T162 185Q162 128 191 101T272 73Z" />
|
||||
<glyph unicode="÷" glyph-name="divide" d="M64 262L78 349H552L538 262H64ZM267 43Q231 43 216 56T201 89Q201 102 204 120Q209 147 227 162T283 178Q319 178 334 165T349 132Q349 119 346 101Q341 74 323 59T267 43ZM332 433Q296 433 281 446T266 479Q266
|
||||
492 269 510Q274 537 292 552T348 568Q384 568 399 555T414 522Q414 509 411 491Q406 464 388 449T332 433Z" />
|
||||
<glyph unicode="ø" glyph-name="oslash" d="M-3 1L82 88Q69 113 62 143T55 208Q55 282 76 341T134 441T223 505T335 528Q420 528 474 483L549 560L603 515L518 428Q531 403 538 373T545 308Q545 234 524 175T466 75T377 11T265 -12Q180 -12 126 33L51 -44L-3
|
||||
1ZM328 443Q265 443 227 405T178 299L167 232Q165 218 164 206T162 185Q162 180 162 175T163 165L407 416Q378 443 328 443ZM272 73Q335 73 373 111T422 217L433 284Q435 298 436 310T438 331Q438 336 438 341T437 351L193 100Q221 73 272 73Z" />
|
||||
<glyph unicode="ù" glyph-name="ugrave" d="M384 122H379Q350 60 311 24T209 -12Q140 -12 105 29T69 137Q69 155 70 174T77 220L126 516H233L183 216Q181 202 179 187T177 158Q177 123 194 99T252 75Q282 75 305 89T349 127Q359 139 377 169T403 240L449
|
||||
516H556L470 0H363L384 122ZM247 750L342 790L405 607L338 579L247 750Z" />
|
||||
<glyph unicode="ú" glyph-name="uacute" d="M360 579L297 614L408 790L495 743L360 579ZM384 122H379Q350 60 311 24T209 -12Q140 -12 105 29T69 137Q69 155 70 174T77 220L126 516H233L183 216Q181 202 179 187T177 158Q177 123 194 99T252 75Q282 75 305
|
||||
89T349 127Q359 139 377 169T403 240L449 516H556L470 0H363L384 122Z" />
|
||||
<glyph unicode="û" glyph-name="ucircumflex" d="M434 773L530 622L471 582L371 698L235 582L183 625L325 773H434ZM384 122H379Q350 60 311 24T209 -12Q140 -12 105 29T69 137Q69 155 70 174T77 220L126 516H233L183 216Q181 202 179 187T177 158Q177 123
|
||||
194 99T252 75Q282 75 305 89T349 127Q359 139 377 169T403 240L449 516H556L470 0H363L384 122Z" />
|
||||
<glyph unicode="ü" glyph-name="udieresis" d="M257 608Q223 608 210 620T196 651Q196 656 196 661T199 676Q203 699 218 715T271 731Q305 731 318 719T332 688Q332 683 332 678T329 663Q325 640 310 624T257 608ZM457 608Q423 608 410 620T396 651Q396 656
|
||||
396 661T399 676Q403 699 418 715T471 731Q505 731 518 719T532 688Q532 683 532 678T529 663Q525 640 510 624T457 608ZM384 122H379Q350 60 311 24T209 -12Q140 -12 105 29T69 137Q69 155 70 174T77 220L126 516H233L183 216Q181 202 179 187T177 158Q177 123
|
||||
194 99T252 75Q282 75 305 89T349 127Q359 139 377 169T403 240L449 516H556L470 0H363L384 122Z" />
|
||||
<glyph unicode="ý" glyph-name="yacute" d="M211 -212Q144 -212 97 -195T17 -139L85 -71Q128 -125 212 -125Q276 -125 315 -91T369 31L386 138H382Q353 76 314 40T212 4Q143 4 108 45T72 153Q72 171 73 190T80 236L126 516H233L186 232Q184 218 182 203T180
|
||||
174Q180 139 197 115T255 91Q285 91 308 105T352 143Q362 155 380 185T406 256L449 516H556L472 14Q452 -105 384 -158T211 -212ZM367 579L304 614L415 790L502 743L367 579Z" />
|
||||
<glyph unicode="þ" glyph-name="thorn" d="M163 740H270L213 394H217Q232 424 249 448T287 491T334 518T395 528Q475 528 513 476T552 328Q552 266 538 205T493 96T418 18T310 -12Q251 -12 216 15T167 93H162L114 -200H7L163 740ZM277 75Q344 75 380 115T428
|
||||
219L440 290Q442 299 443 310T444 333Q444 382 422 411T352 441Q292 441 246 387Q229 368 214 340T193 276L176 173Q168 128 195 102T277 75Z" />
|
||||
<glyph unicode="ÿ" glyph-name="ydieresis" d="M211 -212Q144 -212 97 -195T17 -139L85 -71Q128 -125 212 -125Q276 -125 315 -91T369 31L386 138H382Q353 76 314 40T212 4Q143 4 108 45T72 153Q72 171 73 190T80 236L126 516H233L186 232Q184 218 182 203T180
|
||||
174Q180 139 197 115T255 91Q285 91 308 105T352 143Q362 155 380 185T406 256L449 516H556L472 14Q452 -105 384 -158T211 -212ZM264 608Q230 608 217 620T203 651Q203 656 203 661T206 676Q210 699 225 715T278 731Q312 731 325 719T339 688Q339 683 339 678T336
|
||||
663Q332 640 317 624T264 608ZM464 608Q430 608 417 620T403 651Q403 656 403 661T406 676Q410 699 425 715T478 731Q512 731 525 719T539 688Q539 683 539 678T536 663Q532 640 517 624T464 608Z" />
|
||||
<glyph unicode="–" glyph-name="endash" d="M63 258L78 350H553L538 258H63Z" />
|
||||
<glyph unicode="—" glyph-name="emdash" d="M3 258L18 350H612L597 258H3Z" />
|
||||
<glyph unicode="‘" glyph-name="quoteleft" d="M381 740H465L362 444H209L381 740Z" />
|
||||
<glyph unicode="’" glyph-name="quoteright" d="M345 740H498L326 444H242L345 740Z" />
|
||||
<glyph unicode="‚" glyph-name="quotesinglbase" d="M234 151H387L215 -145H131L234 151Z" />
|
||||
<glyph unicode="“" glyph-name="quotedblleft" d="M524 740H608L505 444H352L524 740ZM513 740H597L494 444H341L513 740Z" />
|
||||
<glyph unicode="”" glyph-name="quotedblright" d="M483 740H636L464 444H380L483 740ZM471 740H624L452 444H368L471 740Z" />
|
||||
<glyph unicode="„" glyph-name="quotedblbase" d="M380 151H533L361 -145H277L380 151ZM369 151H522L350 -145H266L369 151Z" />
|
||||
<glyph unicode="•" glyph-name="bullet" d="M289 174Q224 174 197 200T170 267Q170 273 171 284T176 318Q180 343 190 364T219 400T264 425T327 434Q392 434 419 408T446 341Q446 335 445 324T440 290Q436 265 426 244T397 208T352 183T289 174Z" />
|
||||
<glyph unicode="‹" glyph-name="guilsinglleft" d="M338 51L165 223L182 322L407 491L432 417L267 266L382 117L338 51Z" />
|
||||
<glyph unicode="›" glyph-name="guilsinglright" d="M171 125L336 276L221 425L265 491L438 319L421 220L196 51L171 125Z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 61 KiB |