Rust URL Shortener - A fast, secure, and elegant URL shortening web application built with Rust 🦀
- 🔒 JWT Authentication - Secure user registration and login with bcrypt password hashing
- 💾 SQLite Persistence - Reliable data storage with SQLite database
- 📊 Click Tracking - Monitor how many times each shortened URL is accessed
- ✏️ Custom Names - Give your shortened URLs memorable names
- 🗑️ URL Management - Delete URLs you no longer need
- 🚀 Fast Performance - Built with Rust and Actix-web for maximum speed
- 🎨 Modern Dark UI - Beautiful, responsive web interface with Rust-themed colors
- 🦀 Custom 404 Page - Friendly error page with panicked crab when short codes aren't found
- 🐳 Docker Support - Easy deployment with Docker Compose
- Rust 1.91.0 or higher
- Cargo (comes with Rust)
Or use Docker for containerized deployment.
- Clone the repository:
git clone https://github.com/joshrandall8478/rus.git
cd rus- Create a
.envfile with your JWT secret:
JWT_SECRET=<base64-encoded-32-bytes>- Build and run the project:
cargo build --release
cargo run --releaseThe application will start on http://localhost:8080
docker compose up --build- Sign Up - Create an account at
/signup.html - Log In - Authenticate at
/login.html - Dashboard - Manage your URLs at
/dashboard.html:- Shorten new URLs
- View click statistics
- Rename URLs with custom names
- Copy short URLs to clipboard
- Delete URLs you no longer need
Register a new user:
POST /api/register
Content-Type: application/json
{
"username": "myuser",
"password": "mypassword"
}Login:
POST /api/login
Content-Type: application/json
{
"username": "myuser",
"password": "mypassword"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}Redirect to Original URL:
GET /{short_code}Redirects to the original URL and increments the click counter.
Shorten a URL:
POST /api/shorten
Content-Type: application/json
Authorization: Bearer {TOKEN}
{
"url": "https://example.com/very/long/url"
}Response:
{
"short_code": "abc123",
"short_url": "http://localhost:8080/abc123",
"original_url": "https://example.com/very/long/url"
}Get all user URLs:
GET /api/urls
Authorization: Bearer {TOKEN}Get URL statistics:
GET /api/stats/{short_code}
Authorization: Bearer {TOKEN}Response:
{
"original_url": "https://example.com/very/long/url",
"short_code": "abc123",
"name": "My Link",
"clicks": 42
}Delete a URL:
DELETE /api/urls/{short_code}
Authorization: Bearer {TOKEN}Rename a URL:
PATCH /api/urls/{short_code}/name
Content-Type: application/json
Authorization: Bearer {TOKEN}
{
"name": "My Custom Name"
}Register:
curl -X POST http://localhost:8080/api/register \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"password123"}'Login and save token:
TOKEN=$(curl -s -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"password123"}' | jq -r '.token')Shorten a URL:
curl -X POST http://localhost:8080/api/shorten \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"url":"https://github.com/joshrandall8478/rus"}'Get your URLs:
curl http://localhost:8080/api/urls \
-H "Authorization: Bearer $TOKEN"rus/
├── src/
│ └── main.rs # Main application code
├── static/
│ ├── index.html # Landing page
│ ├── login.html # Login page
│ ├── signup.html # Registration page
│ ├── dashboard.html # URL management dashboard
│ ├── 404.html # Custom 404 error page
│ ├── styles.css # Global styles
│ └── auth.js # Authentication utilities
├── data/
│ └── rus.db # SQLite database (auto-created)
├── Cargo.toml # Rust dependencies
├── compose.yml # Docker Compose configuration
├── Dockerfile # Docker build configuration
└── README.md # This file
- Actix-web - High-performance web framework for Rust
- SQLite - Embedded relational database via rusqlite
- JSON Web Tokens - Secure authentication via jsonwebtoken
- bcrypt - Secure password hashing
- Serde - Serialization/deserialization framework
- Tokio - Async runtime for Rust
| Variable | Description | Default |
|---|---|---|
JWT_SECRET |
Base64-encoded 32-byte secret for JWT signing | Required |
DB_PATH |
Path to SQLite database file | ./data/rus.db |
HOST |
Server bind address | 0.0.0.0 |
PORT |
Server port | 8080 |
users table:
userID- Primary keyusername- Unique usernamepassword- bcrypt hashed passwordcreated_at- Account creation timestamp
urls table:
id- Primary keyuser_id- Foreign key to usersoriginal_url- The original long URLshort_code- Unique 6-character code (indexed)name- Optional custom nameclicks- Click countercreated_at- URL creation timestamp
cargo runcargo testcargo clippycargo fmtcargo build --releaseThe optimized binary will be available at ./target/release/rus
- JWT tokens with 24-hour expiry
- bcrypt password hashing (cost factor 12)
- Tokens stored in localStorage on frontend
- 6-character alphanumeric codes (A-Z, a-z, 0-9)
- 62^6 = ~56.8 billion possible combinations
- Collision detection ensures unique codes
- Each redirect increments a counter
- View statistics in dashboard or via API
- Useful for analytics and monitoring
- Validates URLs and authentication
- Custom 404 page with friendly error message
- Returns proper HTTP status codes
- User-friendly error messages
- ✅ JWT-based authentication
- ✅ bcrypt password hashing
- ✅ Protected API endpoints
- ✅ User-scoped URL management
- ✅ SQL injection prevention via parameterized queries
For production deployment, also consider:
- Implementing rate limiting
- Setting up HTTPS with TLS
- Adding CORS configuration
- Configuring proper logging and monitoring
- Using connection pooling for the database
Contributions are welcome! Feel free to:
- Report bugs
- Suggest features
- Submit pull requests
This project is open source and available under the MIT License.
- Built with ❤️ using Rust
- Inspired by URL shortening services like bit.ly and TinyURL
- Special thanks to the Rust and Actix-web communities
Made with 🦀 and Rust
