No description
Find a file
2026-01-30 13:37:09 -05:00
.github (chore) init rails app 2026-01-27 13:13:46 -05:00
app lawg in 2026-01-30 13:37:02 -05:00
bin (chore) init rails app 2026-01-27 13:13:46 -05:00
config sentry? 2026-01-30 13:33:14 -05:00
db viridis quota 2026-01-30 12:19:02 -05:00
lib/tasks (chore) init rails app 2026-01-27 13:13:46 -05:00
log (chore) init rails app 2026-01-27 13:13:46 -05:00
public (chore) init rails app 2026-01-27 13:13:46 -05:00
script (chore) init rails app 2026-01-27 13:13:46 -05:00
storage (chore) init rails app 2026-01-27 13:13:46 -05:00
test api? 2026-01-29 16:24:14 -05:00
tmp (chore) init rails app 2026-01-27 13:13:46 -05:00
vendor (chore) init rails app 2026-01-27 13:13:46 -05:00
.dockerignore (chore) init rails app 2026-01-27 13:13:46 -05:00
.env.example read me 2026-01-30 13:36:50 -05:00
.gitattributes (chore) init rails app 2026-01-27 13:13:46 -05:00
.gitignore (chore) init rails app 2026-01-27 13:13:46 -05:00
.rubocop.yml (chore) init rails app 2026-01-27 13:13:46 -05:00
.ruby-version (chore) init rails app 2026-01-27 13:13:46 -05:00
config.ru (chore) init rails app 2026-01-27 13:13:46 -05:00
Dockerfile dock'er? i hardly 2026-01-30 13:37:09 -05:00
Gemfile sentry? 2026-01-30 13:33:14 -05:00
Gemfile.lock sentry? 2026-01-30 13:33:14 -05:00
package.json whole buncha stuff 2026-01-29 00:51:48 -05:00
Procfile.dev (chore) init rails app 2026-01-27 13:13:46 -05:00
Rakefile (chore) init rails app 2026-01-27 13:13:46 -05:00
README.md read me 2026-01-30 13:36:50 -05:00
vite.config.ts wrow 2026-01-29 10:21:54 -05:00
yarn.lock whole buncha stuff 2026-01-29 00:51:48 -05:00

flag

cdn.hackclub.com

Deep under the waves and storms there lies a vault...

Banner

Banner illustration by @maxwofford.

Slack Channel

A Rails 8 application for hosting and managing CDN uploads, with OAuth authentication via Hack Club.

Prerequisites

  • Ruby 3.4.4 (see .ruby-version)
  • PostgreSQL
  • Node.js + Yarn (for Vite frontend)
  • A Cloudflare R2 bucket (or S3-compatible storage)

Setup

  1. Clone and install dependencies:

    git clone https://github.com/hackclub/cdn.git
    cd cdn
    bundle install
    yarn install
    
  2. Configure environment variables:

    cp .env.example .env
    

    Edit .env with your credentials (see below for details).

  3. Setup the database:

    bin/rails db:create db:migrate
    
  4. Generate encryption keys (for API key encryption):

    # Generate a 32-byte hex key for Lockbox
    ruby -e "require 'securerandom'; puts SecureRandom.hex(32)"
    
    # Generate a 32-byte hex key for BlindIndex
    ruby -e "require 'securerandom'; puts SecureRandom.hex(32)"
    
    # Generate Active Record encryption keys
    bin/rails db:encryption:init
    
  5. Start the development servers:

    # In one terminal, run the Vite dev server:
    bin/vite dev
    
    # In another terminal, run the Rails server:
    bin/rails server
    

Environment Variables

See .env.example for the full list. Key variables:

Variable Description
R2_ACCESS_KEY_ID Cloudflare R2 access key
R2_SECRET_ACCESS_KEY Cloudflare R2 secret key
R2_BUCKET_NAME R2 bucket name
R2_ENDPOINT R2 endpoint URL
CDN_HOST Public hostname for CDN URLs
HACKCLUB_CLIENT_ID OAuth client ID from Hack Club Auth
HACKCLUB_CLIENT_SECRET OAuth client secret
LOCKBOX_MASTER_KEY 64-char hex key for encrypting API keys
BLIND_INDEX_MASTER_KEY 64-char hex key for searchable encryption

API

The API uses bearer token authentication. Create an API key from the web dashboard after logging in.

Upload a file:

curl -X POST https://cdn.hackclub.com/api/v4/upload \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@image.png"

Upload from URL:

curl -X POST https://cdn.hackclub.com/api/v4/upload_from_url \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/image.png"}'

See /docs in the running app for full API documentation.

Architecture

  • Rails 8 with Vite for frontend assets
  • Phlex + Primer ViewComponents for UI
  • Active Storage with Cloudflare R2 backend
  • Solid Queue/Cache/Cable for background jobs and caching (production)
  • Pundit for authorization
  • Lockbox + BlindIndex for API key encryption

Made with 💜 for Hack Club