mirror of
https://github.com/funkypenguin/geek-cookbook/
synced 2025-12-12 17:26:19 +00:00
Add post on Mastodon CDN
Signed-off-by: David Young <davidy@funkypenguin.co.nz>
This commit is contained in:
@@ -150,5 +150,6 @@
|
||||
"images/blog/multiple-renovate-prs-detail.png": "da36aab8f9c343ffba0b5ddea3982a23da3594c1",
|
||||
"images/blog/haproxy_backends.png": "eded975e1c08c346bad7d4b8177c267a121a503f",
|
||||
"images/blog/haproxy_health_checks.png": "db00b7adafb53286e7083242638155298327c0b3",
|
||||
"images/blog/haproxy_stats-1.png": "3a36d2429c752b8d4612655473820c5bb2146d3f"
|
||||
"images/blog/haproxy_stats-1.png": "3a36d2429c752b8d4612655473820c5bb2146d3f",
|
||||
"images/blog/mastodon_cloudflare_transform_rules.png": "b2552805791734279de05452f4b0f39088a67146"
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
65
.cache/plugin/privacy/assets/external/so.fnky.nz/embed.js
vendored
Normal file
65
.cache/plugin/privacy/assets/external/so.fnky.nz/embed.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// @ts-check
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @param {() => void} loaded
|
||||
*/
|
||||
var ready = function(loaded) {
|
||||
if (['interactive', 'complete'].indexOf(document.readyState) !== -1) {
|
||||
loaded();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', loaded);
|
||||
}
|
||||
};
|
||||
|
||||
ready(function() {
|
||||
/** @type {Map<number, HTMLIFrameElement>} */
|
||||
var iframes = new Map();
|
||||
|
||||
window.addEventListener('message', function(e) {
|
||||
var data = e.data || {};
|
||||
|
||||
if (typeof data !== 'object' || data.type !== 'setHeight' || !iframes.has(data.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var iframe = iframes.get(data.id);
|
||||
|
||||
if ('source' in e && iframe.contentWindow !== e.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
iframe.height = data.height;
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('iframe.mastodon-embed'), function(iframe) {
|
||||
// select unique id for each iframe
|
||||
var id = 0, failCount = 0, idBuffer = new Uint32Array(1);
|
||||
while (id === 0 || iframes.has(id)) {
|
||||
id = crypto.getRandomValues(idBuffer)[0];
|
||||
failCount++;
|
||||
if (failCount > 100) {
|
||||
// give up and assign (easily guessable) unique number if getRandomValues is broken or no luck
|
||||
id = -(iframes.size + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iframes.set(id, iframe);
|
||||
|
||||
iframe.scrolling = 'no';
|
||||
iframe.style.overflow = 'hidden';
|
||||
|
||||
iframe.onload = function() {
|
||||
iframe.contentWindow.postMessage({
|
||||
type: 'setHeight',
|
||||
id: id,
|
||||
}, '*');
|
||||
};
|
||||
|
||||
iframe.onload();
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: Funky Penguin's Blog
|
||||
---
|
||||
# Funky Penguin's Geek Cookblog
|
||||
|
||||
Welcome to Funky Penguin's Blog!
|
||||
|
||||
After years of trying to use alternate platforms (*I still ❤️ ya, [Ghost](/recipes/ghost/) ! 👻*), I've decided to move my technical blog entries here instead - I **far** prefer the way [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) lets me format documentation for technical consumption!
|
||||
Welcome to Funky Penguin's Geeky Blog!
|
||||
|
||||
--8<-- "common-links.md"
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
date: 2022-11-17
|
||||
categories:
|
||||
- note
|
||||
tags:
|
||||
- renovate
|
||||
title: How running a pod as GID 1337 can cause a Kubernetes pod to bypass istio-proxy
|
||||
description: Is your pod bypassing istio-proxy? Check your GUID isn't set to 1337!
|
||||
---
|
||||
|
||||
# Is your pod bypassing istio-proxy? Check your GUID
|
||||
|
||||
After spending hours debugging why a particular pod can't properly communicate with another pod via Istio's service mesh, I stumbled into the answer..
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<iframe src="https://so.fnky.nz/@funkypenguin/109356967728428702/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://so.fnky.nz/embed.js" async="async"></script>
|
||||
|
||||
Here's more details.. Istio creates iptables rules to intercept pod-to-pod traffic. The rules look something like this (from the istio-cni pod, in my case):
|
||||
|
||||
```text
|
||||
* nat
|
||||
-N ISTIO_INBOUND
|
||||
-N ISTIO_REDIRECT
|
||||
-N ISTIO_IN_REDIRECT
|
||||
-N ISTIO_OUTPUT
|
||||
-A ISTIO_INBOUND -p tcp --dport 15008 -j RETURN
|
||||
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
|
||||
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
|
||||
-A PREROUTING -p tcp -j ISTIO_INBOUND
|
||||
-A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN
|
||||
-A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN
|
||||
-A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN
|
||||
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
|
||||
-A OUTPUT -p tcp -j ISTIO_OUTPUT
|
||||
-A ISTIO_OUTPUT -p tcp --dport 15020 -j RETURN
|
||||
-A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN
|
||||
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
|
||||
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
|
||||
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
|
||||
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
|
||||
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
|
||||
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
|
||||
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
|
||||
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
|
||||
COMMIT
|
||||
```
|
||||
|
||||
And the offending pod was using this:
|
||||
|
||||
```yaml
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
privileged: false
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
runAsNonRoot: true
|
||||
runAsUser: 10001
|
||||
runAsGroup: 1337
|
||||
```
|
||||
|
||||
See the problem? Any traffic egressing the pod coming from a process running as GUID 1337 will bypass the iptables rules, and travel "outside" of the service mesh.
|
||||
|
||||
In my case, this simply caused the service to break, but if you were using Istio to enforce egress policy, this would be a gotcha!
|
||||
|
||||
[^1]: It turns out this was an old istio configuration no longer required in current versions
|
||||
|
||||
--8<-- "blog-footer.md"
|
||||
47
docs/blog/posts/notes/run-mastodon-and-media-behind-cdn.md
Normal file
47
docs/blog/posts/notes/run-mastodon-and-media-behind-cdn.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
date: 2023-02-09
|
||||
categories:
|
||||
- note
|
||||
tags:
|
||||
- mastodon
|
||||
title: Leveraging Cloudflare for your Mastdon instance, including media in B2 object storage
|
||||
description: Want to run your Mastodon instance behind Cloudflare, but put your media in B2 object storage with free egress? Here's how!
|
||||
---
|
||||
|
||||
# Mastodon + CloudFlare + B2 Object Storage = free egress
|
||||
|
||||
When setting up my [Mastodon instance](https://so.fnky.nz), I jumped directly to storing all media in object storage (*Backblaze B2, in my case*), because I didn't want to allocate / estimate local storage requirements.
|
||||
|
||||
This turned out to be a great decision, as my media bucket quickly grew to over 100GB, but as a result, all of my media was served behind URLs like `https://f007.backblaze.com/file/something/something-else/another-something.jpg`, and could _technically_ be scraped without using my Mastodon URL.
|
||||
|
||||
Here's how to improve this, and also serve your Mastodon instance from behind a CloudFlare proxy...
|
||||
|
||||
<!-- more -->
|
||||
|
||||
## How to CDN Mastodon with Cloudflare
|
||||
|
||||
After stumbling across some [#mastoadmin](https://so.fnky.nz/tags/mastoadmin) posts re the "[Bandwidth Alliance](https://www.backblaze.com/b2/solutions/content-delivery.html)", I discovered that CloudFlare and Backblaze have an agreement, under which egress traffic from Backblaze B2 buckets is free, provided they're fronted by CloudFlare's CDN.
|
||||
|
||||
Not knowing up-front how much I'd be using the media storage, I felt that this was a sensible idea. I also wanted my media URLs to be more "branded" that the default B2 bucket URLs.
|
||||
|
||||
I found some [instructions](https://www.backblaze.com/blog/free-image-hosting-with-cloudflare-transform-rules-and-backblaze-b2/) by the BackBlaze team on how to implement CloudFlare caching of B2 buckets using a custom domain, using CloudFlare's transform rules.
|
||||
|
||||
The initial config based on the transform rule linked above worked great, when my instance was **not** being proxied by CloudFlare. As soon as I enabled proxying for my instance, I'd get weird 404s when trying to access Mastodon.
|
||||
|
||||
## Try not to transform non-media URLs!
|
||||
|
||||
It turned out (*as I discovered after turning on access log debugging in Traefik*) that the above transform rule was applied to **all** traffic hitting my DNS name, and happily transforming **every** URL requested from Mastodon!
|
||||
|
||||
I made the change illustrated below, which resolved the issue, and now permits the Mastodon web components to be proxied behind CloudFlare, but also allows me to serve my media behind the B2 bucket, with a nicely-branded FQDN:
|
||||
|
||||

|
||||
|
||||
## Success, #dogstodon 🐶
|
||||
|
||||
Now I'm one step closer to a resilient Mastodon instance which can hopefully survive the occasional traffic spike / DOS when I post something **really amazingly** interesting, like my photo-bombing dog[^1]...
|
||||
|
||||
<iframe src="https://so.fnky.nz/@funkypenguin/109396952935616062/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://so.fnky.nz/embed.js" async="async"></script>
|
||||
|
||||
[^1]: Her name is Jessie, she's a cross Labrador / Rhodesian Ridgeback, and she was just over 1 year old at the time of this photobombing! 🐾
|
||||
|
||||
--8<-- "blog-footer.md"
|
||||
@@ -15,7 +15,6 @@ I'm approaching the end of the journey of applying Velero to a client's "hardene
|
||||
|
||||
<!-- more -->
|
||||
|
||||
|
||||
## What is a hardened Kubernetes cluster?
|
||||
|
||||
In this particular case, the following apply:
|
||||
|
||||
BIN
docs/images/blog/mastodon_cloudflare_transform_rules.png
Normal file
BIN
docs/images/blog/mastodon_cloudflare_transform_rules.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
Reference in New Issue
Block a user