Tool Updated 3 days ago

Ship private or paid Deadlock mods with automatic updates

Selling mods, or sharing them with a small group? Frogtech Mod Loader can install them from your own private repository. Each person gets a key, sees only the mods that key unlocks, and gets your updates automatically. This guide sets it up on Cloudflare's free tier in about half an hour.

How it works

  • Your repository file (repo.json) and your mod zips live on a small server you control.
  • A buyer adds your repository in the loader with their key. The loader sends the key with every request, as Authorization: Bearer <key>, and only ever to your server's address.
  • Your server checks the key, lists only the mods it unlocks, and only hands out those downloads.
  • You raise a version in repo.json: every buyer gets the update, usually within the hour.
A buyer adds your repository with their key and sees what it contains before confirming.

1. Set up storage and keys

  1. 1

    Make a free Cloudflare account, then install Wrangler, its command-line tool, and sign in:

    npm install -g wrangler
    wrangler login
  2. 2

    Create a storage bucket for your files:

    wrangler r2 bucket create my-mods
  3. 3

    Create a key store, and note the id it prints:

    wrangler kv namespace create KEYS

2. The server

Save this as worker.js. It checks the key, filters repo.json to the mods that key owns, and serves only those downloads.

worker.js
// worker.js: a private Frogtech Mod Loader repository on Cloudflare Workers
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const key = (request.headers.get('Authorization') || '').replace(/^Bearer /, '');
    // KEYS (KV): each buyer's key -> the ids of the mods they own, like ["cool_hud"]
    const owned = key ? JSON.parse((await env.KEYS.get(key)) || 'null') : null;
    if (!owned) return new Response('Key not accepted', { status: 401 });

    if (url.pathname === '/repo.json') {
      // FILES (R2): repo.json and the mod zips; each buyer only sees their mods
      const repo = await (await env.FILES.get('repo.json')).json();
      repo.mods = repo.mods.filter((m) => owned.includes(m.id));
      return Response.json(repo);
    }
    const m = url.pathname.match(/^\/dl\/([a-z0-9_-]+)_v[0-9.]+\.zip$/);
    if (m && owned.includes(m[1])) {
      const file = await env.FILES.get(url.pathname.slice(1));
      if (file) return new Response(file.body, { headers: { 'content-type': 'application/zip' } });
    }
    return new Response('Not found', { status: 404 });
  }
};

Next to it, a wrangler.toml that connects the bucket and the key store:

wrangler.toml
name = "my-mods"
main = "worker.js"
compatibility_date = "2026-10-01"

[[r2_buckets]]
binding = "FILES"
bucket_name = "my-mods"

[[kv_namespaces]]
binding = "KEYS"
id = "<the id from step 1>"

Then deploy it. Your repository is now at https://my-mods.<you>.workers.dev/repo.json.

wrangler deploy

3. Upload a mod

  1. 1
    Zip your mod (with its pak01_dir.vpk inside) as <id>_v<version>.zip, for example cool_hud_v1.0.zip.
  2. 2

    Get its checksum. On Windows use certutil -hashfile cool_hud_v1.0.zip SHA256 instead.

    sha256sum cool_hud_v1.0.zip
  3. 3
    Write repo.json with the checksum, like below.
  4. 4

    Upload the zip and repo.json:

    wrangler r2 object put my-mods/dl/cool_hud_v1.0.zip --file cool_hud_v1.0.zip --remote
    wrangler r2 object put my-mods/repo.json --file repo.json --remote
repo.json
{
  "format": 1,
  "name": "My Private Mods",
  "mods": [
    { "id": "cool_hud", "name": "Cool HUD", "version": "1.0",
      "url": "https://my-mods.<you>.workers.dev/dl/cool_hud_v1.0.zip",
      "sha256": "<from sha256sum>", "tags": ["HUD"] }
  ]
}

Tip: The download links point at your own server (the /dl/ path), so the loader sends the key there too. Links on other hosts never receive the key.

4. Give someone access

  1. 1

    Make a long random key:

    openssl rand -hex 24
  2. 2

    Store which mods that key unlocks:

    wrangler kv key put --namespace-id <id> "<key>" '["cool_hud"]' --remote
  3. 3

    Send the buyer the key and this link, which opens the loader's Add repository dialog:

    frogmod://repo/add?url=https%3A%2F%2Fmy-mods.<you>.workers.dev%2Frepo.json

To take access away, delete the key. Their loader then shows "Key not accepted" and stops updating your mods.

wrangler kv key delete --namespace-id <id> "<key>" --remote

Shipping an update

  1. 1

    Upload the new zip with the higher version in its name:

    wrangler r2 object put my-mods/dl/cool_hud_v1.1.zip --file cool_hud_v1.1.zip --remote
  2. 2

    Change that mod's version, url and sha256 in repo.json, and upload it again:

    wrangler r2 object put my-mods/repo.json --file repo.json --remote

That's it: every buyer's loader installs it the next time Deadlock is closed.

Selling keys

Any shop that can send you a webhook or let you deliver a code works: Ko-fi, Patreon, Gumroad or your own site. Make a key when someone buys, store it as in step 4, and send it to them. For free mods you don't need any of this: our GitHub template hosts a public repository for free.

Related

More guides