A high-performance URL shortening service built with Cloudflare Workers and Rust.
- π High Performance: Built on Cloudflare Workers global edge network
- π¦ Rust Powered: Written in Rust and WebAssembly for exceptional performance
- π Easy to Use: Supports custom short links and automatic generation
- π Global Deployment: Automatically deployed across 200+ cities worldwide
- π Real-time Logging: Built-in request logging and error handling
- π§ Easy Configuration: Simple configuration through environment variables
- π― Git Integration: Fallback to Git commit URLs when KV storage lookup fails
- Runtime: Cloudflare Workers
- Language: Rust + WebAssembly
- Storage: Cloudflare KV Store
- Framework: worker-rs
- Build Tool: worker-build + wrangler
GET /
Automatically redirects to the configured homepage address.
Response:
301 Moved Permanently- Redirects to the address configured in the HOME environment variable
GET /:shortCode
Redirects to the target URL based on the short link code. If no short link is found in KV storage, the service will attempt to fetch and redirect based on Git commit information.
Parameters:
shortCode- Short link code
Response:
301 Moved Permanently- Redirects to target URL (from KV storage or Git commit)404 Not Found- Short link does not exist and Git fallback failed400 Bad Request- Invalid request
Git Integration Fallback: When a short link is not found in KV storage, the service will:
- Construct a Git patch URL:
{GIT_REPO}/commit/{path}.patch - Fetch the patch file from the Git repository
- Extract the commit subject from the patch
- Redirect to the extracted URL or the repository itself
Example:
# Access short link
curl -I https://your-domain.workers.dev/abc123
# Response (from KV storage)
HTTP/2 301
location: https://example.com
# Response (from Git fallback)
HTTP/2 301
location: https://github.com/user/repo/commit/abc123- β
Rust installed (
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh) - β Node.js installed
- β Cloudflare account
-
Clone project
git clone https://github.com/longcipher/cfly.git cd cfly/cfly -
Install dependencies
npm install -g wrangler rustup target add wasm32-unknown-unknown
-
Login to Cloudflare
wrangler login
-
Create KV storage
npx wrangler kv namespace create cfly npx wrangler kv namespace create cfly --preview
-
Configure wrangler.toml Update
wrangler.tomlwith your KV namespace IDs and settings:name = "your-worker-name" [[kv_namespaces]] binding = "cfly" preview_id = "your-preview-kv-id" id = "your-production-kv-id" [vars] HOME = "https://your-homepage.com" GIT_REPO = "https://github.com/your-user/your-repo" # Optional for Git fallback
-
Deploy
npx wrangler build npx wrangler deploy
When a short link is not found in KV storage, Cfly can fallback to Git commit URLs:
- Set
GIT_REPOenvironment variable inwrangler.toml - Access
/commit-hashwill fetch{GIT_REPO}/commit/commit-hash.patch - Redirects to the extracted commit URL or repository
Example: https://your-domain.workers.dev/abc123 β fetches commit patch β redirects to commit URL
wrangler login# Create production KV namespace
npx wrangler kv namespace create cfly
# Create preview KV namespace
npx wrangler kv namespace create cfly --previewAfter executing the commands, copy the KV namespace configuration output to wrangler.toml.
Edit wrangler.toml and update the following configuration:
name = "your-worker-name" # Change to your Worker name
main = "build/worker/shim.mjs"
compatibility_date = "2025-08-19"
[build]
command = "cargo install -q worker-build && worker-build --release"
[[kv_namespaces]]
binding = "cfly"
preview_id = "your-preview-kv-namespace-id" # Replace with actual preview environment ID
id = "your-production-kv-namespace-id" # Replace with actual production environment ID
[vars]
HOME = "https://your-homepage.com" # Change to your homepage address
[observability]
enabled = true# Use just (recommended)
just dev
# Or use wrangler directly
npx wrangler devThe service will start at http://localhost:8787.
Before local development or deployment, add some short link data:
# Add single short link
npx wrangler kv key put --binding=cfly --preview false "github" "https://github.com/longcipher/cfly"
npx wrangler kv key put --binding=cfly --preview false "blog" "https://blog.example.com"
# Or batch add (create urls.json file)
echo '[
{"key": "github", "value": "https://github.com/longcipher/cfly"},
{"key": "blog", "value": "https://blog.example.com"},
{"key": "docs", "value": "https://docs.example.com"}
]' > urls.json
npx wrangler kv bulk put --binding=cfly urls.json
npx wrangler kv bulk put --binding=cfly --preview false urls.json# Use just (recommended)
just deploy
# Or use wrangler directly
npx wrangler deployCreate KV namespace in Cloudflare Dashboard:
- Login to Cloudflare Dashboard
- Select your account
- Go to Workers & Pages > KV
- Click Create a namespace
- Enter namespace name (e.g.,
cfly) - Record the generated Namespace ID
Or create using CLI:
# Create production namespace
npx wrangler kv namespace create cfly
# Create preview namespace
npx wrangler kv namespace create cfly --previewUpdate KV configuration in wrangler.toml:
[[kv_namespaces]]
binding = "cfly" # Binding name used in code
preview_id = "your-preview-kv-id" # Development environment KV ID
id = "your-production-kv-id" # Production environment KV IDConfigure environment variables in wrangler.toml:
[vars]
HOME = "https://your-homepage.com" # Root path redirect address
GIT_REPO = "https://github.com/your-user/your-repo" # Git repository for fallback redirect (optional)Or set in Cloudflare Dashboard:
- Go to Workers & Pages
- Select your Worker
- Go to Settings > Variables
- Add environment variables
# Add single short link
npx wrangler kv key put --binding=cfly --preview false "abc123" "https://example.com"
# View all short links (production)
npx wrangler kv key list --binding=cfly --preview false
# View all short links (preview)
npx wrangler kv key list --binding=cfly --preview
# Get specific short link (production)
npx wrangler kv key get --binding=cfly --preview false "abc123"
# Delete short link (production)
npx wrangler kv key delete --binding=cfly --preview false "abc123"Create a JSON file urls.json:
[
{"key": "github", "value": "https://github.com/longcipher/cfly"},
{"key": "blog", "value": "https://blog.example.com"},
{"key": "docs", "value": "https://docs.example.com"},
{"key": "twitter", "value": "https://twitter.com/yourhandle"}
]Import data:
npx wrangler kv bulk put --binding=cfly urls.json- Go to Workers & Pages > KV
- Select your namespace
- Click Add entry
- Enter key-value pair:
- Key: Short link code (e.g.,
abc123) - Value: Target URL (e.g.,
https://example.com)
- Key: Short link code (e.g.,
Configure custom domain:
- In Cloudflare Dashboard, go to Workers & Pages
- Select your Worker
- Go to Settings > Triggers
- Click Add Custom Domain
- Enter your domain (e.g.,
s.example.com) - Complete DNS verification
The project uses just as a task runner:
# Build project
just build
# Start development server
just dev
# Deploy to production
just deployYou can also use wrangler commands directly:
# Local development
npx wrangler dev
# Build project
npx wrangler build
# Deploy
npx wrangler deploy
# View logs
npx wrangler tail
# KV operations
# Production KV operations (explicitly target production with --preview false)
npx wrangler kv key list --binding=cfly --preview false
npx wrangler kv key get --binding=cfly --preview false "key-name"
npx wrangler kv key put --binding=cfly --preview false "key-name" "value"
npx wrangler kv key delete --binding=cfly --preview false "key-name"
# Preview KV operations
npx wrangler kv key list --binding=cfly --preview
npx wrangler kv key get --binding=cfly --preview "key-name"
npx wrangler kv key put --binding=cfly --preview "key-name" "value"
npx wrangler kv key delete --binding=cfly --preview "key-name"# Worker basic information
name = "cfly" # Worker name, must be globally unique
main = "build/worker/shim.mjs" # Entry file path
compatibility_date = "2025-08-19" # Compatibility date
# Build configuration
[build]
command = "cargo install -q worker-build && worker-build --release"
# KV storage binding
[[kv_namespaces]]
binding = "cfly" # Binding name used in code
preview_id = "preview-namespace-id" # Development environment KV ID
id = "production-namespace-id" # Production environment KV ID
# Environment variables
[vars]
HOME = "https://your-homepage.com" # Root path redirect address
# Monitoring configuration
[observability]
enabled = true # Enable logging and monitoringKey dependencies and optimization configuration:
[dependencies]
worker = { version = "0.6.1", features = ['http', 'axum'] }
worker-macros = { version = "0.6.1", features = ['http'] }
# Important: Disable wasm-opt to avoid compatibility issues
[package.metadata.wasm-pack.profile.release]
wasm-opt = false
# Release configuration optimization
[profile.release]
lto = true # Link-time optimization
strip = true # Remove debug information
opt-level = "s" # Optimize for code size
codegen-units = 1 # Reduce code generation units# View all logs
npx wrangler tail
# Formatted output
npx wrangler tail --format=pretty
# Only error logs
npx wrangler tail --format=json | jq 'select(.level == "error")'
# Filter by time
npx wrangler tail --since="2025-08-19T10:00:00Z"In Cloudflare Dashboard you can view:
- Request count and frequency statistics
- Error rate and response time analysis
- Traffic source and geographic distribution
- CPU usage and memory consumption
-
wasm-bindgen version error
error: expected bool value, got 168Solution: Ensure
wasm-opt = falseis set inCargo.toml -
KV binding error
KvError::InvalidKvStore: cflySolution: Check that the KV binding name in
wrangler.tomlmatchesctx.kv("cfly")in the code -
Build failure
Missing entry-point to Worker scriptSolution: Ensure
worker-buildhas been run andbuild/worker/shim.mjsfile is generated -
Deployment permission error
Authentication errorSolution: Run
wrangler loginto re-authenticate with Cloudflare -
KV namespace not found
Namespace not foundSolution: Ensure KV namespace is created and ID is correctly configured in
wrangler.toml
-
Enable verbose logging:
RUST_LOG=debug npx wrangler dev
-
Check KV data:
npx wrangler kv key list --binding=cfly --preview npx wrangler kv key get --binding=cfly "test-key" --preview -
Local debugging mode:
npx wrangler dev --local --port 8080
-
Check Worker status:
npx wrangler whoami npx wrangler list
-
Validate configuration:
npx wrangler dev --dry-run
You can modify error responses in src/lib.rs:
// Custom 404 page
Response::from_html(r#"
<!DOCTYPE html>
<html>
<head><title>Short Link Not Found</title></head>
<body><h1>Sorry, this short link does not exist</h1></body>
</html>
"#)?.with_status(404)You can record access statistics in KV:
// Increment access count
let count_key = format!("stats:{}", name);
let current_count: u64 = ctx.kv("cfly")?
.get(&count_key)
.text()
.await?
.unwrap_or_default()
.parse()
.unwrap_or(0);
ctx.kv("cfly")?
.put(&count_key, (current_count + 1).to_string())?
.execute()
.await?;Set TTL when adding short links:
# Set to expire after 1 hour
npx wrangler kv key put --binding=cfly "temp123" "https://example.com" --ttl 3600- Fork the project
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use
cargo fmtto format code - Use
cargo clippyto check code quality - Ensure all tests pass with
cargo test - Update relevant documentation
- Cloudflare Workers - Edge computing platform
- worker-rs - Rust Workers framework
- wrangler - Workers development tools
- just - Command runner
- hink - Use github commit for short link
This project is licensed under the Apache-2.0 License - see the LICENSE file for details.
If this project helps you, please give it a βοΈ!