|
| 1 | +# short-it |
| 2 | + |
| 3 | +A minimal, self-hosted URL shortener written in Go using bbolt (BoltDB). This project is inspired by [Erisa's worker-links](https://github.com/Erisa/worker-links). I wanted something that can do functionally the same as that project, without being fully locked into Cloudflare's services. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- Shorten URLs with autogenerated 6-character keys |
| 8 | +- Create custom paths |
| 9 | +- List stored URLs with cursor-based pagination |
| 10 | +- Simple token-based authorization |
| 11 | +- Single-file embedded database (bbolt) |
| 12 | + |
| 13 | +## Quick Start |
| 14 | + |
| 15 | +Prerequisites: Go 1.24 or Docker. |
| 16 | + |
| 17 | +Run locally: |
| 18 | + |
| 19 | +```bash |
| 20 | +go build -o short-it ./cmd/short-it |
| 21 | +APP_TOKEN=your-secret-token DB_PATH=short-it.db PORT=8080 ./short-it |
| 22 | +``` |
| 23 | + |
| 24 | +Run with Docker: |
| 25 | + |
| 26 | +```bash |
| 27 | +docker build -t short-it . |
| 28 | +docker run -e APP_TOKEN=your-secret-token -p 8080:8080 -v $(pwd)/data:/data short-it |
| 29 | +``` |
| 30 | + |
| 31 | +Or use the provided docker-compose configuration: |
| 32 | + |
| 33 | +```bash |
| 34 | +docker-compose up -d |
| 35 | +# edit docker-compose.yml to set APP_TOKEN or update the environment |
| 36 | +``` |
| 37 | + |
| 38 | +The server listens on `PORT` (default `8080`) and stores the BoltDB file at `DB_PATH` (default `short-it.db`). |
| 39 | + |
| 40 | +## Configuration |
| 41 | + |
| 42 | +Environment variables: |
| 43 | + |
| 44 | +- `APP_TOKEN` (required): token used for authorization on protected endpoints |
| 45 | +- `PORT` (optional): HTTP port (default `8080`) |
| 46 | +- `DB_PATH` (optional): path to BoltDB file (default `short-it.db`) |
| 47 | + |
| 48 | +## HTTP API |
| 49 | + |
| 50 | +All endpoints that modify or list data require the `Authorization` header to equal the `APP_TOKEN` value. |
| 51 | + |
| 52 | +- Create a short URL |
| 53 | + - `POST /` |
| 54 | + - Headers: `Authorization`, `URL` (or JSON body `{ "url": "..." }`) |
| 55 | + - Response: `{"key":"<generated-key>"}` |
| 56 | + |
| 57 | +- List URLs (paginated) |
| 58 | + - `GET /` |
| 59 | + - Headers: `Authorization`, optional `Cursor`, optional `Limit` (max 100) |
| 60 | + - Response: `{ "items": [{"key":"...","value":"..."}], "next":"<cursor>" }` |
| 61 | + |
| 62 | +- Redirect |
| 63 | + - `GET /{key}` |
| 64 | + - Redirects (302) to the stored URL if found |
| 65 | + |
| 66 | +- Create/Update custom path |
| 67 | + - `PUT /{path}` |
| 68 | + - Headers: `Authorization`, `URL` (or JSON body) |
| 69 | + - Response: `201 Created` |
| 70 | + |
| 71 | +- Delete path |
| 72 | + - `DELETE /{path}` |
| 73 | + - Headers: `Authorization` |
| 74 | + - Response: `204 No Content` |
| 75 | + |
| 76 | +Examples: |
| 77 | + |
| 78 | +```bash |
| 79 | +# shorten a URL (using header) |
| 80 | +curl -X POST -H "Authorization: your-secret-token" -H "URL: https://example.com" http://localhost:8080/ |
| 81 | + |
| 82 | +# get redirect |
| 83 | +curl -v http://localhost:8080/:key |
| 84 | + |
| 85 | +# create custom path |
| 86 | +curl -X PUT -H "Authorization: your-secret-token" -H "URL: https://custom.example" http://localhost:8080/custom |
| 87 | + |
| 88 | +# delete |
| 89 | +curl -X DELETE -H "Authorization: your-secret-token" http://localhost:8080/custom |
| 90 | + |
| 91 | +# list |
| 92 | +curl -H "Authorization: your-secret-token" http://localhost:8080/ |
| 93 | +``` |
| 94 | + |
| 95 | +## Development & Tests |
| 96 | + |
| 97 | +Run unit tests: |
| 98 | + |
| 99 | +```bash |
| 100 | +go test ./cmd/short-it |
| 101 | +``` |
| 102 | + |
| 103 | +Key implementation files: |
| 104 | + |
| 105 | +- [cmd/short-it/main.go](cmd/short-it/main.go#L1) — HTTP handlers and core logic |
| 106 | +- [cmd/short-it/main_test.go](cmd/short-it/main_test.go#L1) — unit tests for handlers and DB ops |
| 107 | +- [Dockerfile](Dockerfile) — container build |
| 108 | +- [docker-compose.yml](docker-compose.yml) — example compose configuration |
| 109 | + |
| 110 | +## Notes |
| 111 | + |
| 112 | +- The app uses a BoltDB bucket named `urls` to store key → URL mappings. |
| 113 | +- The autogenerated keys are 6 characters drawn from `a-zA-Z0-9`. |
| 114 | + |
0 commit comments