A serverless URL shortener built with Cloudflare Workers, Hono, and D1 Database.
- Shorten Links: Public interface at
/c. - Admin Dashboard: Secure management interface at
/a. - Link Management: Create, Pause, Disable, Delete links.
- Interstitial Page: Optional "You are being redirected" page with 5s countdown (configurable per link).
- Analytics: Tracks visit counts.
- Security:
- Cloudflare Turnstile integration for public creation.
- Password-protected admin API.
- 2FA (Two-Factor Authentication) for admin access.
- Notifications: Telegram Bot notifications for:
- New link creation.
- Admin login.
- Link updates/deletions.
- Customization: Custom slugs, expiration dates.
- Node.js installed (for building).
- Cloudflare Account.
First, install dependencies and build the project locally:
npm install
npm run deployNote:
npm run deploywill use Wrangler to deploy your worker. You will be prompted to login to Cloudflare if not already logged in.
- Log in to Cloudflare Dashboard -> Workers & Pages -> D1.
- Click Create Database and name it
shorturl-db. - Go to your Worker -> Settings -> Functions -> D1 Database Bindings.
- Add a new binding:
- Variable name:
DB - D1 Database: Select the
shorturl-dbyou just created.
- Variable name:
- Redeploy the worker (go to Deployments tab -> Deploy or just wait for next deployment).
- Open your D1 database
shorturl-dbin the Cloudflare Dashboard. - Go to the Console tab.
- Copy and paste the following SQL to create the table:
DROP TABLE IF EXISTS links;
CREATE TABLE links (
slug TEXT PRIMARY KEY,
url TEXT NOT NULL,
created_at INTEGER NOT NULL,
expires_at INTEGER,
status TEXT DEFAULT 'active',
interstitial INTEGER DEFAULT 0,
visit_count INTEGER DEFAULT 0,
creator_ip TEXT
);- Click Execute.
- Then paste and execute this index creation command:
CREATE INDEX IF NOT EXISTS idx_expires_at ON links(expires_at);- Create Config Table (for Telegram notifications and 2FA):
CREATE TABLE IF NOT EXISTS config (
id INTEGER PRIMARY KEY CHECK (id = 1),
tg_notify_create INTEGER DEFAULT 0,
tg_notify_login INTEGER DEFAULT 0,
tg_notify_update INTEGER DEFAULT 0,
admin_2fa_secret TEXT,
admin_2fa_enabled INTEGER DEFAULT 0
);
INSERT OR IGNORE INTO config (id, tg_notify_create, tg_notify_login, tg_notify_update) VALUES (1, 0, 0, 0);Go to your Worker -> Settings -> Variables.
Environment Variables (Click "Add variable"):
ROOT_REDIRECT: Target URL for root path/(e.g.,https://example.com).FALLBACK_URL: Target URL for 404s (e.g.,https://example.com/404).TURNSTILE_SITE_KEY: Your Turnstile Site Key (required for/cpage).TG_CHAT_ID: Telegram Chat ID to receive notifications (e.g.,123456789).
Secrets (Click "Add variable" -> "Encrypt"):
ADMIN_PASSWORD: Password for accessing/a.TURNSTILE_SECRET_KEY: Your Turnstile Secret Key.TG_BOT_TOKEN: Telegram Bot Token (e.g.,123456:ABC-DEF...).
- Public Creation: Visit
https://your-worker.workers.dev/c- URL Limit: Max 1000 characters.
- Custom Slug: Min 3 characters.
- Admin Panel: Visit
https://your-worker.workers.dev/a- Login with
ADMIN_PASSWORD. - Admin can create short links with any slug length (e.g., 1 or 2 chars allowed).
- Login with
- Redirect: Visit
https://your-worker.workers.dev/slug