diff --git a/.github/skills/update-blog-cover-image/SKILL.md b/.github/skills/update-blog-cover-image/SKILL.md new file mode 100644 index 0000000..9b4d42a --- /dev/null +++ b/.github/skills/update-blog-cover-image/SKILL.md @@ -0,0 +1,121 @@ + +--- +name: update-blog-cover-image +description: Updates a blog post cover image path and file with SEO-friendly naming, then regenerates metadata and validates it in dev. +--- + +# Update Blog Cover Image + +## When to use this skill + +Use this skill when asked to change, replace, rename, or fix the cover image for an existing blog post. + +This skill covers the full workflow: + +- Renaming the image to an SEO-friendly filename +- Updating the post metadata cover image path +- Regenerating blog metadata JSON +- Restarting dev server when needed +- Verifying the new cover is rendered + +## Key files involved + +- `src/routes/blog//metadata.ts` +- `static/images/posts//...` +- `static/blogMetadata.json` (generated) +- `scripts/generateMetadata.ts` + +## Steps + +### 1. Identify the post slug and current metadata + +Open the target post metadata file: + +```bash +cat src/routes/blog//metadata.ts +``` + +Confirm current `coverImage` value. + +### 2. Place or rename the image in the post images folder + +Use a descriptive, lowercase, kebab-case filename. + +Good example: + +```text +one-core-packet-processing-bottleneck-cover.webp +``` + +Rename if needed: + +```bash +mv "static/images/posts//.webp" \ + "static/images/posts//.webp" +``` + +### 3. Update `coverImage` in metadata + +Edit `src/routes/blog//metadata.ts` so `coverImage` points to the new path: + +```ts +coverImage: '/images/posts//.webp'; +``` + +### 4. Regenerate static metadata + +The website reads blog metadata from `static/blogMetadata.json` at runtime. +After updating `metadata.ts`, regenerate: + +```bash +npx tsx scripts/generateMetadata.ts +``` + +If this step is skipped, the old cover can keep appearing. + +### 5. Restart dev server if already running + +The metadata loader caches results in memory, so restart dev server after regeneration. + +```bash +pkill -f "vite dev" || true +npm run dev +``` + +### 6. Validate the result + +Check both metadata and rendered output. + +```bash +rg -n "|.webp" static/blogMetadata.json +curl -I http://localhost:5173/images/posts//.webp +curl -s http://localhost:5173/blog/ | rg ".webp" +``` + +Expected: + +- New filename appears in `static/blogMetadata.json` +- Image URL returns `200 OK` +- Blog HTML references the new filename + +## Scope boundary + +This skill is intentionally limited to in-repo implementation tasks for coding agents. + +For standalone guidance on prompting external AI image models for blog banners, see: + +- `docs/blog-cover-image-prompting.md` + +## Troubleshooting + +- **Still seeing old image in browser:** force refresh (`Ctrl+Shift+R`) or use an incognito window. +- **Page still references old cover:** regenerate metadata and restart dev server. +- **`Post not found` error:** run `npx tsx scripts/generateMetadata.ts` and restart dev server. + +## Checklist + +- [ ] Cover image file uses SEO-friendly filename +- [ ] `coverImage` in post metadata updated +- [ ] `static/blogMetadata.json` regenerated +- [ ] Dev server restarted (if previously running) +- [ ] New cover image confirmed in rendered blog page diff --git a/.prettierignore b/.prettierignore index 7ffda2e..1197bc2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,4 +16,7 @@ pnpm-lock.yaml yarn.lock src/routes/blog/**/*.md -static/blogMetadata.json \ No newline at end of file +static/blogMetadata.json +.github/**/*.md +.github/**/*.yml +.github/**/*.yaml \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 42163d6..da0b738 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,7 @@ Common tasks are documented as [Agent Skills](https://agentskills.io/) in `.gith - [**add-blog-post**](.github/skills/add-blog-post/SKILL.md) — Create or publish a new blog post - [**add-component**](.github/skills/add-component/SKILL.md) — Add a new Svelte UI component +- [**update-blog-cover-image**](.github/skills/update-blog-cover-image/SKILL.md) — Update a blog post cover image with metadata regeneration and validation - [**update-contributors**](.github/skills/update-contributors/SKILL.md) — Refresh the contributors list from the Torrust GitHub org - [**deploy-site**](.github/skills/deploy-site/SKILL.md) — Deploy the site to GitHub Pages - [**run-checks**](.github/skills/run-checks/SKILL.md) — Run the full quality check suite before committing diff --git a/docs/blog-cover-image-prompting.md b/docs/blog-cover-image-prompting.md new file mode 100644 index 0000000..1537458 --- /dev/null +++ b/docs/blog-cover-image-prompting.md @@ -0,0 +1,34 @@ +# Blog Cover Image Prompting + +This document explains how to prompt external generative AI image models to create cover images for Torrust blog posts. + +Use this as independent author documentation, separate from coding-agent skills. + +## Required banner constraints + +- Size: 1774 x 887 +- Keep top text-safe band: at least 200 px with no text +- Keep bottom text-safe band: at least 200 px with no text + +These safe bands help the website layout keep title and overlays readable. + +## Recommended reusable prompt template + +```text +I want you to create a cover image for the following Torrust blog post. +- The size must be 1774 x 887. +- Leave two horizontal bands at the top and bottom of at least 200 px with no text. + +Article: + +``` + +## After image generation + +1. Export as webp when possible. +2. Rename to an SEO-friendly filename in kebab-case. +3. Place under "static/images/posts/post-slug/". +4. Update coverImage in "src/routes/blog/post-slug/metadata.ts". +5. Regenerate metadata with: npx tsx scripts/generateMetadata.ts. +6. Restart dev server if already running. +7. Validate that the new image appears in the rendered blog page. diff --git a/project-words.txt b/project-words.txt index f6ceb40..fe61671 100644 --- a/project-words.txt +++ b/project-words.txt @@ -23,6 +23,7 @@ certonly cgbosse Chatrooms Chihaya +conntrack containerfile Containerfiles corepack @@ -51,6 +52,7 @@ heaptrack Heiko Helpdesk Histoire +hotspot hotspots hungfnt iconify @@ -64,6 +66,7 @@ Katson kcachegrind keyrings Kimbatt +ksoftirqd Laravel ldpr letsencrypt @@ -79,6 +82,7 @@ mdsvex Metainfo mickvandijke mika +mpstat Multiuser naim Newtrackon diff --git a/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.server.ts b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.server.ts new file mode 100644 index 0000000..5cf0731 --- /dev/null +++ b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.server.ts @@ -0,0 +1,14 @@ +import { getMetadata } from '$lib/data/metadata'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ url }) => { + const slug = url.pathname.split('/').filter(Boolean).pop(); + if (!slug) throw new Error('Slug could not be determined.'); + + const metadata = await getMetadata(); + const currentPost = metadata.find((post) => post.slug === slug); + + if (!currentPost) throw new Error(`Post not found: ${slug}`); + + return { currentPost, allPosts: metadata }; +}; diff --git a/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.svelte b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.svelte new file mode 100644 index 0000000..7aa20b4 --- /dev/null +++ b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/+page.svelte @@ -0,0 +1,453 @@ + + + + +
+ +
+

TL;DR

+

+ We found a production bottleneck where one CPU core was saturated by kernel packet work (softirq) while other cores still had spare capacity. +

+ +

Current Load Snapshot

+

+ To keep this report actionable, we also captured a fresh live sample from the server while + the service stayed healthy. +

+ +

Latest observed values:

+
    +
  • + Load average: 11.71 / 11.91 / 11.48 (also sampled at + 12.16 / 11.99 / 11.50) +
  • +
  • CPU2 softirq: 48.48%
  • +
  • All-CPU softirq: 29.63%
  • +
  • All-CPU idle: 18.52%
  • +
  • Memory available: 27 GiB of 30 GiB
  • +
+

+ This reinforces the same conclusion: the packet-processing hotspot remains controlled and + distributed, while total host load remains high enough to justify separate capacity + follow-up. +

+

We ran two isolated experiments:

+
    +
  1. Disable HTTP/3 (QUIC) on Caddy by removing UDP 443.
  2. +
  3. Enable RPS/RFS to spread packet receive processing across all CPUs.
  4. +
+

Results:

+
    +
  • Disabling HTTP/3 did not improve the one-core softirq hotspot.
  • +
  • Enabling RPS/RFS reduced CPU2 %soft from ~100% to ~48.51%.
  • +
  • The improvement persisted at T+1h and T+next-day checkpoints.
  • +
  • + Global host load remained high (11.83 / 11.59 / 10.82), so we treated this + as a distribution fix, not a full capacity fix. +
  • +
+ +

What Problem We Detected

+

+ The tracker host was under sustained CPU pressure. Standard process-level checks showed + high utilization, but one pattern stood out: kernel networking work was concentrated on + CPU2. +

+
    +
  • mpstat repeatedly showed CPU2 pinned in %soft.
  • +
  • ksoftirqd/2 appeared near the top CPU consumers.
  • +
  • + User-space load was real, but the single-core kernel hotspot was the main anomaly. +
  • +
+

+ For context, softirq is kernel-side packet processing work. If this work is not + distributed well, one core can saturate even when the machine still has available cores. +

+ +

Initial htop Snapshot (Before Patch)

+

+ This is the initial screenshot where CPU2 was pinned at 100% usage during the softirq + hotspot. +

+
+ Initial htop snapshot showing CPU2 pinned at 100 percent usage +

+ Before patch: CPU2 was saturated, indicating concentrated packet-processing load. +

+
+ +

Method: One Variable at a Time

+

+ To avoid ambiguous conclusions, we changed one thing per phase and compared snapshots + using the same metrics: +

+
    +
  • mpstat -P ALL 1 1 for per-CPU softirq distribution.
  • +
  • + ps -eo pid,comm,%cpu,%mem,stat --sort=-%cpu | head -20 for top CPU processes. +
  • +
  • docker stats --no-stream for container-level CPU snapshots.
  • +
  • Prometheus HTTP/UDP request rates to keep traffic context comparable.
  • +
  • External endpoint checks from newtrackon.com/raw.
  • +
+ +

Phase 2: Disable HTTP/3 (QUIC)

+

+ Hypothesis: UDP 443 (HTTP/3) on Caddy might be adding packet-processing pressure. We + removed only that UDP publish and restarted Caddy. +

+ + + + + +

Selected checkpoint after this phase:

+ + +

+ Conclusion: disabling HTTP/3 was good hygiene, but it did not change the one-core softirq + bottleneck. +

+ +

Phase 3: Enable RPS/RFS

+

+ Next hypothesis: packet receive-side work was not being distributed across CPUs. Before + the change, steering was effectively disabled. +

+ + + +

We applied the live test change:

+ + +

Immediate post-change snapshot:

+ + +

+ At T+1h and T+next-day, CPU2 remained around 49.48-49.49% softirq and load stayed + distributed. This confirms RPS/RFS removed the one-core packet hotspot. +

+ +

htop Snapshot After Patch

+

+ After enabling RPS/RFS, load was distributed across CPUs instead of being concentrated on + CPU2. +

+
+ htop snapshot after RPS and RFS patch showing load distributed among CPUs +

After patch: packet-processing pressure is spread across cores.

+
+ +

Why This Did Not Fully Solve Host Load

+

+ RPS/RFS solved distribution, not demand. The host still + ran with high global load averages after the fix. In other words, the previous failure + mode (single-core saturation) was mitigated, but total workload pressure remained near + capacity. +

+

+ Even with high server load, observed tracker availability on NewTrackon stayed above + 99%. This is an important distinction: high load reduced headroom, but + service quality remained strong during the observation window. +

+
    +
  • + udp://udp1.torrust-tracker-demo.com:6969/announce: latency + 21 ms +
  • +
  • + https://http1.torrust-tracker-demo.com:443/announce: latency + 29 ms +
  • +
+

+ At peak, we are handling about 1200 UDP req/s and a little over + 2200 HTTP req/s. +

+

Traffic Over the Last 15 Days

+

+ This Grafana Generic Tracker Dashboard screenshot shows announce requests per second over + the last 15 days for both UDP1 and HTTP1 trackers. +

+
+ Grafana dashboard showing announce requests per second for UDP1 and HTTP1 over the last 15 days +

+ Last 15 days: announce request rate trends for + udp1.torrust-tracker-demo.com and + http1.torrust-tracker-demo.com. +

+
+ + + This is an important operational lesson: eliminating one bottleneck can improve stability + and fairness across CPUs without creating enough long-term headroom for sustained growth. + + +

Timeline Checkpoints

+
    +
  • Before changes: CPU2 repeatedly near 100% softirq.
  • +
  • After HTTP/3 disable: no meaningful improvement in CPU2 softirq.
  • +
  • + Immediate after RPS/RFS: CPU2 softirq dropped to 48.51%. +
  • +
  • + T+1h: distribution remained stable, CPU2 around 49.48%. +
  • +
  • + T+next-day: distribution persisted, CPU2 around 49.49%. +
  • +
+ +

Final Operational Decision

+
    +
  1. Keep RPS/RFS enabled permanently on the current host.
  2. +
  3. Close the tuning scope in ISSUE-29 as completed.
  4. +
  5. Track capacity follow-up separately (scale-up planning in ISSUE-30).
  6. +
+

+ The practical outcome is clear: packet-path tuning fixed the single-core bottleneck, and + capacity planning becomes the next lever for sustained growth. +

+ +

References

+ +
+
+
+ + +
+ + diff --git a/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/metadata.ts b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/metadata.ts new file mode 100644 index 0000000..ef6af0c --- /dev/null +++ b/src/routes/blog/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/metadata.ts @@ -0,0 +1,12 @@ +export const metadata = { + title: 'How We Fixed a One-Core Packet Processing Bottleneck in Torrust Tracker', + slug: 'how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker', + contributor: 'Jose Celano', + contributorSlug: 'jose-celano', + date: '2026-05-06T12:00:00.000Z', + coverImage: + '/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/one-core-packet-processing-bottleneck-cover.webp', + excerpt: + 'We investigated a one-core softirq hotspot in the Torrust Tracker demo, ran isolated HTTP/3 and RPS/RFS experiments, and documented why better CPU distribution did not fully solve overall host load.', + tags: ['Tracker Demo', 'Performance', 'Linux Networking', 'Softirq', 'RPS', 'RFS'] +}; diff --git a/static/blogMetadata.json b/static/blogMetadata.json index 6b4fb82..bd4d94d 100644 --- a/static/blogMetadata.json +++ b/static/blogMetadata.json @@ -13,17 +13,19 @@ ] }, { - "title": "Containerizing Rust Applications", - "slug": "containerizing-rust-applications-best-practices", + "title": "Building with AI Agents, Building for AI Agents", + "slug": "building-with-ai-agents-building-for-ai-agents", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2023-11-09T12:08:04.295Z", - "coverImage": "/images/posts/rust-crab-carrying-a-shipping-container.jpeg", - "excerpt": "Torrust services (Tracker and Index) support docker, we want to ensure that contributors understand our containerfile and we also want to share good practices for containerizing Rust applications.", + "date": "2026-02-27T12:00:00.000Z", + "coverImage": "/images/posts/building-with-ai-agents-building-for-ai-agents/ai-agent-developer-tools-workflow.webp", + "excerpt": "I spent months building the Torrust Tracker Deployer without writing a single line of code directly — every line came from a GitHub Copilot agent. But this post is about something bigger: the shift in thinking that came from that experience and what it taught us about designing tools that AI agents can actually use well.", "tags": [ - "Torrent", - "Tracker", - "BitTorrent" + "AI", + "Rust", + "Torrust", + "DevOps", + "Tutorial" ] }, { @@ -54,6 +56,20 @@ "Contributors" ] }, + { + "title": "Containerizing Rust Applications", + "slug": "containerizing-rust-applications-best-practices", + "contributor": "Jose Celano", + "contributorSlug": "jose-celano", + "date": "2023-11-09T12:08:04.295Z", + "coverImage": "/images/posts/rust-crab-carrying-a-shipping-container.jpeg", + "excerpt": "Torrust services (Tracker and Index) support docker, we want to ensure that contributors understand our containerfile and we also want to share good practices for containerizing Rust applications.", + "tags": [ + "Torrent", + "Tracker", + "BitTorrent" + ] + }, { "title": "Bencode to JSON Converter in Rust", "slug": "bencode-to-json-converter-in-rust", @@ -69,22 +85,6 @@ "Rust" ] }, - { - "title": "Building with AI Agents, Building for AI Agents", - "slug": "building-with-ai-agents-building-for-ai-agents", - "contributor": "Jose Celano", - "contributorSlug": "jose-celano", - "date": "2026-02-27T12:00:00.000Z", - "coverImage": "/images/posts/building-with-ai-agents-building-for-ai-agents/ai-agent-developer-tools-workflow.webp", - "excerpt": "I spent months building the Torrust Tracker Deployer without writing a single line of code directly — every line came from a GitHub Copilot agent. But this post is about something bigger: the shift in thinking that came from that experience and what it taught us about designing tools that AI agents can actually use well.", - "tags": [ - "AI", - "Rust", - "Torrust", - "DevOps", - "Tutorial" - ] - }, { "title": "Deploying the Torrust Tracker Demo with the Torrust Tracker Deployer", "slug": "deploying-torrust-tracker-with-the-deployer", @@ -154,19 +154,6 @@ "Guide" ] }, - { - "title": "Introducing the New Sample Torrent Migration Tool", - "slug": "introducing-the-new-sample-torrent-migration-tool", - "contributor": "Jose Celano", - "contributorSlug": "jose-celano", - "date": "2023-09-04T13:24:27.241Z", - "coverImage": "/images/posts/pexels-david-dibert-7177008.jpg", - "excerpt": "Looking to migrate to the Torrust Index? Dive into our Torrents Importer Sample to seamlessly transfer your torrents to Torrust.", - "tags": [ - "Migration Tool", - "Sample" - ] - }, { "title": "How To Setup The Dev Env", "slug": "how-to-setup-the-development-environment", @@ -181,6 +168,36 @@ "BitTorrent" ] }, + { + "title": "How We Fixed a One-Core Packet Processing Bottleneck in Torrust Tracker", + "slug": "how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker", + "contributor": "Jose Celano", + "contributorSlug": "jose-celano", + "date": "2026-05-06T12:00:00.000Z", + "coverImage": "/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/one-core-packet-processing-bottleneck-cover.webp", + "excerpt": "We investigated a one-core softirq hotspot in the Torrust Tracker demo, ran isolated HTTP/3 and RPS/RFS experiments, and documented why better CPU distribution did not fully solve overall host load.", + "tags": [ + "Tracker Demo", + "Performance", + "Linux Networking", + "Softirq", + "RPS", + "RFS" + ] + }, + { + "title": "Introducing the New Sample Torrent Migration Tool", + "slug": "introducing-the-new-sample-torrent-migration-tool", + "contributor": "Jose Celano", + "contributorSlug": "jose-celano", + "date": "2023-09-04T13:24:27.241Z", + "coverImage": "/images/posts/pexels-david-dibert-7177008.jpg", + "excerpt": "Looking to migrate to the Torrust Index? Dive into our Torrents Importer Sample to seamlessly transfer your torrents to Torrust.", + "tags": [ + "Migration Tool", + "Sample" + ] + }, { "title": "Introducing the Torrust Tracker Deployer", "slug": "introducing-the-torrust-tracker-deployer", @@ -243,17 +260,18 @@ ] }, { - "title": "Released Torrust Tracker Deployer v0.1.0", - "slug": "released-torrust-tracker-deployer-v0-1-0", + "title": "PostgreSQL Support in Torrust Tracker", + "slug": "postgresql-support-in-torrust-tracker", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2026-04-15T00:00:00.000Z", - "coverImage": "/images/posts/released-torrust-tracker-deployer-v0-1-0/torrust-tracker-deployer-v0-1-0-release-announcement-cover.webp", - "excerpt": "We're happy to announce the first stable release of the Torrust Tracker Deployer: v0.1.0. This milestone makes automated Torrust Tracker deployment publicly available, with production-tested workflows and comprehensive documentation.", + "date": "2026-05-01T12:00:00.000Z", + "coverImage": "/images/posts/postgresql-support-in-torrust-tracker/postgresql-support-in-torrust-tracker.webp", + "excerpt": "Torrust Tracker now supports PostgreSQL as a first-class database backend. Learn about the journey from a community feature request to a full persistence overhaul, the new tools built along the way, and what this means for the upcoming major release.", "tags": [ + "Rust", + "PostgreSQL", "Announcement", - "Release", - "Deployment" + "Release" ] }, { @@ -274,41 +292,40 @@ ] }, { - "title": "PostgreSQL Support in Torrust Tracker", - "slug": "postgresql-support-in-torrust-tracker", + "title": "Released version v3.0.0", + "slug": "released-v3-0-0-beta", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2026-05-01T12:00:00.000Z", - "coverImage": "/images/posts/postgresql-support-in-torrust-tracker/postgresql-support-in-torrust-tracker.webp", - "excerpt": "Torrust Tracker now supports PostgreSQL as a first-class database backend. Learn about the journey from a community feature request to a full persistence overhaul, the new tools built along the way, and what this means for the upcoming major release.", + "date": "2024-10-03T11:05:14.597Z", + "coverImage": "/images/posts/released-v3-0-0/team.png", + "excerpt": "We’re thrilled to announce the official release of version 3.0.0 of the Torrust software.", "tags": [ - "Rust", - "PostgreSQL", "Announcement", "Release" ] }, { - "title": "Released version v3.0.0-beta", - "slug": "released-v3-0-0", + "title": "Released Torrust Tracker Deployer v0.1.0", + "slug": "released-torrust-tracker-deployer-v0-1-0", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2024-09-03T14:30:38.554Z", - "coverImage": "/images/posts/released-v3-0-0-beta/team.png", - "excerpt": "We're excited to announce the release of v3.0.0-beta, marking a significant step towards our upcoming major release, v3.0.0. This release solidifies the features and prepares us for the beta phase.", + "date": "2026-04-15T00:00:00.000Z", + "coverImage": "/images/posts/released-torrust-tracker-deployer-v0-1-0/torrust-tracker-deployer-v0-1-0-release-announcement-cover.webp", + "excerpt": "We're happy to announce the first stable release of the Torrust Tracker Deployer: v0.1.0. This milestone makes automated Torrust Tracker deployment publicly available, with production-tested workflows and comprehensive documentation.", "tags": [ "Announcement", - "Release" + "Release", + "Deployment" ] }, { - "title": "Released version v3.0.0", - "slug": "released-v3-0-0-beta", + "title": "Released version v3.0.0-beta", + "slug": "released-v3-0-0", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2024-10-03T11:05:14.597Z", - "coverImage": "/images/posts/released-v3-0-0/team.png", - "excerpt": "We’re thrilled to announce the official release of version 3.0.0 of the Torrust software.", + "date": "2024-09-03T14:30:38.554Z", + "coverImage": "/images/posts/released-v3-0-0-beta/team.png", + "excerpt": "We're excited to announce the release of v3.0.0-beta, marking a significant step towards our upcoming major release, v3.0.0. This release solidifies the features and prepares us for the beta phase.", "tags": [ "Announcement", "Release" @@ -329,22 +346,6 @@ "Third-party" ] }, - { - "title": "How to Run a UDP Tracker Behind a Floating IP on Ubuntu", - "slug": "setup-udp-tracker-behind-floating-ip", - "contributor": "Jose Celano", - "contributorSlug": "jose-celano", - "date": "2026-04-14T00:00:00.000Z", - "coverImage": "/images/posts/setup-udp-tracker-behind-floating-ip/udp-tracker-floating-ip-ipv6-docker-configuration.webp", - "excerpt": "A practical guide to running a UDP BitTorrent tracker behind floating IPs (also known as static, reserved, or elastic IPs) on Ubuntu, including policy routing, Docker IPv6 networking, and SNAT for correct reply paths.", - "tags": [ - "BitTorrent", - "Tracker", - "Networking", - "IPv6", - "Deployment" - ] - }, { "title": "Setting Up Torrust with Claude Code", "slug": "setting-up-torrust-with-claude-code", @@ -360,17 +361,19 @@ ] }, { - "title": "The Enigmatic Torrent \"Source\" Field", - "slug": "the-enigmatic-torrent-source-field", + "title": "How to Run a UDP Tracker Behind a Floating IP on Ubuntu", + "slug": "setup-udp-tracker-behind-floating-ip", "contributor": "Jose Celano", "contributorSlug": "jose-celano", - "date": "2023-08-08T13:56:28.769Z", - "coverImage": "/images/posts/deprecated-and-outdated-bittorrent-documentation.png", - "excerpt": "Delving into BitTorrent’s Mysteries. What is the \"source\" field in the torrent info used for?", + "date": "2026-04-14T00:00:00.000Z", + "coverImage": "/images/posts/setup-udp-tracker-behind-floating-ip/udp-tracker-floating-ip-ipv6-docker-configuration.webp", + "excerpt": "A practical guide to running a UDP BitTorrent tracker behind floating IPs (also known as static, reserved, or elastic IPs) on Ubuntu, including policy routing, Docker IPv6 networking, and SNAT for correct reply paths.", "tags": [ - "Torrent", + "BitTorrent", "Tracker", - "BitTorrent" + "Networking", + "IPv6", + "Deployment" ] }, { @@ -389,6 +392,20 @@ "Demo" ] }, + { + "title": "The Enigmatic Torrent \"Source\" Field", + "slug": "the-enigmatic-torrent-source-field", + "contributor": "Jose Celano", + "contributorSlug": "jose-celano", + "date": "2023-08-08T13:56:28.769Z", + "coverImage": "/images/posts/deprecated-and-outdated-bittorrent-documentation.png", + "excerpt": "Delving into BitTorrent’s Mysteries. What is the \"source\" field in the torrent info used for?", + "tags": [ + "Torrent", + "Tracker", + "BitTorrent" + ] + }, { "title": "Torrust - Enhancing the BitTorrent Ecosystem", "slug": "torrust-enhancing-the-bittorrent-ecosystem", diff --git a/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/grafana-announce-requests-udp1-http1-last-15-days.png b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/grafana-announce-requests-udp1-http1-last-15-days.png new file mode 100644 index 0000000..603064a Binary files /dev/null and b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/grafana-announce-requests-udp1-http1-last-15-days.png differ diff --git a/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-after-rps-rfs.png b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-after-rps-rfs.png new file mode 100644 index 0000000..90c0b97 Binary files /dev/null and b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-after-rps-rfs.png differ diff --git a/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-before-rps-rfs.png b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-before-rps-rfs.png new file mode 100644 index 0000000..eadb0f7 Binary files /dev/null and b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/htop-before-rps-rfs.png differ diff --git a/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/one-core-packet-processing-bottleneck-cover.webp b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/one-core-packet-processing-bottleneck-cover.webp new file mode 100644 index 0000000..b69a148 Binary files /dev/null and b/static/images/posts/how-we-fixed-a-one-core-packet-processing-bottleneck-in-torrust-tracker/one-core-packet-processing-bottleneck-cover.webp differ