惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
SegmentFault 最新的问题
博客园 - 聂微东
罗磊的独立博客
W
WeLiveSecurity
博客园_首页
Scott Helme
Scott Helme
V
Visual Studio Blog
T
The Exploit Database - CXSecurity.com
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
L
Lohrmann on Cybersecurity
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
About on SuperTechFans
F
Full Disclosure
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 司徒正美
博客园 - Franky
C
CXSECURITY Database RSS Feed - CXSecurity.com
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
阮一峰的网络日志
阮一峰的网络日志
S
Schneier on Security
雷峰网
雷峰网
博客园 - 【当耐特】
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
T
Tor Project blog
V
V2EX
爱范儿
爱范儿
C
Check Point Blog
T
Threatpost
Project Zero
Project Zero
量子位
V
Vulnerabilities – Threatpost
Know Your Adversary
Know Your Adversary
I
Intezer
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
GbyAI
GbyAI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

jola.dev

How to stop Claude from saying load-bearing | jola.dev Let libraries be libraries | jola.dev CI workflows on Tangled for Elixir | jola.dev Automatically syncing your blog to atproto and standard.site | jola.dev Appreciation for the small web | jola.dev Treating LLMs as programming books Publishing your blog to standard.site in Elixir Generating OG images in Elixir The social contract of writing Highest Random Weight in Elixir Building for the joy of building Running local models on an M4 with 24GB memory How to hit your Claude weekly limit so you can go outside and touch grass Dropping Cloudflare for bunny.net Building a blog with Elixir and Phoenix Stay in the Loop: How I Actually Use Claude Code Ruthless Prioritization: The Path to Delivery Estimates Are More Valuable Than You Think When Software Engineers Think They Need More Focus Time If the Goal is Resiliency, Defensive Programming is Your Enemy The Magic of Daily Pull Requests: Why Smaller is Better Building a Distributed Rate Limiter in Elixir with HashRing Announcing Hex Diff Building Hex Diff Push-based GenStage The Erlang :queue module in Elixir Patterns for managing ETS tables Health checks for Plug and Phoenix The new `Registry.select/2` and what match specs are Elixir String Processing Optimization
bunnyx: a bunny.net Elixir client library
Johanna Larsson · 2026-05-17 · via jola.dev

bunny.net is a CDN service provider with lots of extra bells and whistles, most similar to Cloudflare in feature set, but maintained by a European company. Unlike Cloudflare, they’re not free, but they are cheap enough that it doesn’t really matter. Unless you’re making very heavy use of their service, you won’t be paying more than the minimum €1 each month. And as a paying customer, your relationship is a lot different than it is as a non-paying user of Cloudflare.

I’ve been using bunny.net for a lot of things I’ve been building recently, including the landing page and status page feature for Larm, the uptime monitoring project I’ve been working on, and I wrote about migrating my blog from Cloudflare to bunny.net recently. As part of that work, I wanted a feature rich client library for interacting with the extensive bunny.net API.

Introducing: bunnyx

This is not the first Elixir library for interacting with the bunny API. I ended up rolling my own because I wanted something that was flexible enough to fit into my system design. The version that I built into Larm wasn’t as feature rich as what I’ve ended up open sourcing here, but once I had something going, I just got into the flow of testing through the API endpoints end to end, and documenting and verifying each one. And suddenly I had a whole feature complete library.

bunnyx is built with a special focus on the Elixir library guidelines. This means that it avoids certain things: there’s no application config and there’s no application supervisor starting automatically. Instead, it follows the design of the excellent Req library by Wojtek Mach. Not to mention that it internally makes heavy use of it!

Additionally I invested a lot of time and energy into the test suite. Apart from extensive unit test coverage, I built a series of Livebook runbooks that you can feed an API key into and execute each and every request scenario, even running through the whole book to automatically create, read, update, and delete, resources. This means you can easily verify the behavior of bunnyx against the actual bunny API.

Quickstart

# Before running this, you'll need:

# - A bunny.net account and API key (from the Account API section of the dashboard)

# - A storage region code — DE, NY, LA, or SG. See:

# https://docs.bunny.net/reference/storagezonepublic_add

# - A globally unique storage zone name

# - A globally unique pull zone name

# - The file you want to upload

client = Bunnyx.new(api_key: "sk-...")

# 1. Create a storage zone to hold the files

{:ok, storage_zone} = Bunnyx.StorageZone.create(client, name: "my-assets", region: "DE")

# 2. Point a pull zone at the storage zone so the files are served from the CDN

{:ok, pull_zone} = Bunnyx.PullZone.create(client,

name: "my-assets-cdn",

storage_zone_id: storage_zone.id

)

# 3. Upload a file via the separate storage client (its own auth and base URL)

storage = Bunnyx.Storage.new(storage_key: storage_zone.password, zone: storage_zone.name)

{:ok, nil} = Bunnyx.Storage.put(storage, "/images/logo.png", File.read!("logo.png"))

cdn_url = "https://#{pull_zone.name}.b-cdn.net/images/logo.png"

# Your file is now live at cdn_url

# 4. Replace the file, then purge so the new version is served immediately

{:ok, nil} = Bunnyx.Storage.put(storage, "/images/logo.png", File.read!("new-logo.png"))

{:ok, nil} = Bunnyx.Purge.url(client, cdn_url)

If you want to wrap things up for convenience, create your own wrapper module.

defmodule MyApp.Bunny do

def create_pullzone(name, origin_url) do

client = Bunnyx.new(api_key: api_key!())

Bunnyx.PullZone.create(client, name: name, origin_url: origin_url)

end

def api_key! do

Application.fetch_env!(:my_app, :bunny_api_key)

end

end

Feature set

Main API (Bunnyx.new/1)

  • CDN: PullZone (CRUD, hostnames, SSL, edge rules, referrers, IP blocking, statistics)
  • DNS: DnsZone (CRUD, DNSSEC, export/import, statistics), DnsRecord (add, update, delete)
  • Storage management: StorageZone (CRUD, statistics, password reset)
  • Video libraries: VideoLibrary (CRUD, API keys, watermarks, referrers, DRM stats)
  • Cache: Purge (URL and pull zone purging)
  • Security: Shield (zones, WAF rules, rate limiting, access lists, bot detection, metrics, API Guardian)
  • Compute: EdgeScript (scripts, code, releases, secrets, variables), MagicContainers (apps, registries, containers, endpoints, volumes)
  • Account: Billing (details, summary, invoices), Account (affiliate, audit log, search), ApiKey, Logging (CDN + origin logs)
  • Reference: Statistics (global), Country, Region

Separate clients

  • Edge storage (Bunnyx.Storage): upload, download, delete, list files
  • S3 (Bunnyx.S3): PUT, GET, DELETE, HEAD, COPY, ListObjectsV2, multipart uploads
  • Stream (Bunnyx.Stream): video CRUD, upload, fetch, collections, captions, thumbnails, re-encode, transcription, smart actions, analytics, oEmbed

What next

First of all I want to give a huge shoutout to Wojtek Mach for setting an incredible example for the Elixir community on how to design libraries. Req is one of my favorite reference repos and I keep coming back to it and discovering new gems.

Secondly, I want to say that Bunny CDN is a great service and I appreciate having a genuinely powerful alternative to Cloudflare, provided by a European company.

Check out the repo, try out the library, and let me know how you get on!

Written by Johanna Larsson. Thoughts on this post? Find me on Bluesky at @jola.dev or why not give it a vote on Bubbles.