mirror of
https://github.com/Sevi-py/tnyr.me.git
synced 2026-02-19 11:54:45 -05:00
110 lines
3.2 KiB
Markdown
110 lines
3.2 KiB
Markdown
<div align="center">
|
|
<img src="logo-256px-no-padding.png" />
|
|
<h1> https://tnyr.me - Privacy-First URL Shortener</h1>
|
|
</div>
|
|
|
|
[](https://opensource.org/licenses/MIT)
|
|
|
|
A secure, self-hosted URL shortener with custom passwordless encryption. Perfect for privacy-conscious users and organizations.
|
|
|
|

|
|
|
|
## Key Features
|
|
|
|
🔒 **Passwordless Encryption**
|
|
📡 **No Tracking**
|
|
🌐 **Modern Web Interface**
|
|
|
|
## Encryption Process
|
|
|
|
1. **ID Generation**
|
|
- Unique random ID created for each link (e.g. `iA4y6jMjFk`)
|
|
- Example: `google.com` → `tnyr.me/#iA4y6jMjFk`
|
|
|
|
2. **Hashing**
|
|
- Two Scrypt hashes are calculated by using different salts
|
|
- Original URL encrypted with AES-256 using Hash 2
|
|
- The whole encryption and decryption process happens in the browser
|
|
|
|
3. **Storage**
|
|
- Only Hash 1 (storage key) and the encrypted URL are saved in database
|
|
|
|
## Self Hosting and Development
|
|
|
|
### Self-host (recommended): Docker / Docker Compose
|
|
|
|
#### Prerequisites
|
|
- Docker (and optionally Docker Compose)
|
|
|
|
#### 1) Generate salts (only if you hosted tnyr.me before **Dec 30, 2025**)
|
|
|
|
```bash
|
|
python3 backend/generate_salts.py --env
|
|
```
|
|
|
|
#### 2) Run with Docker Compose (no secrets required)
|
|
|
|
```bash
|
|
mkdir -p data
|
|
export TNYR_PUBLIC_URL=https://example.com # (or http://1.2.3.4:5502)
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Required env vars:
|
|
- `TNYR_PUBLIC_URL` (example `https://example.com`, `http://1.2.3.4:5502`)
|
|
|
|
Optional env vars:
|
|
- `TNYR_DB_PATH` (defaults to `/data/urls.db` in the container via compose)
|
|
- `TNYR_DELETION_TOKEN` (set to enable `POST /delete-url`)
|
|
- **Legacy link support (only if you hosted tnyr.me before Dec 30, 2025)**:
|
|
- `TNYR_SALT1_HEX` (16 bytes = 32 hex chars)
|
|
- `TNYR_SALT2_HEX` (16 bytes = 32 hex chars)
|
|
- `TNYR_ARGON2_TIME_COST` (default `3`)
|
|
- `TNYR_ARGON2_MEMORY_COST` (default `65536`)
|
|
- `TNYR_ARGON2_PARALLELISM` (default `1`)
|
|
- `TNYR_ARGON2_HASH_LENGTH` (default `32`)
|
|
|
|
**Note**: Creating new legacy links via `POST /shorten-server` is disabled. The legacy env vars above are only for resolving existing old `/<id>` links.
|
|
|
|
#### 3) Or run with plain Docker
|
|
|
|
```bash
|
|
docker build -t tnyr .
|
|
docker run --rm \
|
|
-p 5502:5502 \
|
|
-v "$PWD/data:/data" \
|
|
-e TNYR_PUBLIC_URL="${TNYR_PUBLIC_URL:-http://localhost:5502}" \
|
|
-e TNYR_DB_PATH="/data/urls.db" \
|
|
tnyr
|
|
```
|
|
|
|
Then open `http://localhost:5502`.
|
|
|
|
**Note**: On container start, the entrypoint will initialize the SQLite schema (if missing) and replace `%VITE_PUBLIC_URL%` / `%VITE_DOMAIN%` placeholders in `backend/dist` based on `TNYR_PUBLIC_URL`.
|
|
|
|
### Development
|
|
|
|
1. **Start development server:**
|
|
```bash
|
|
cd frontend
|
|
npm run dev
|
|
```
|
|
|
|
2. **Start backend server:**
|
|
```bash
|
|
cd backend
|
|
pip install -r requirements.txt
|
|
# Required:
|
|
export TNYR_PUBLIC_URL=https://example.com
|
|
# Optional (legacy server-side mode only):
|
|
# export TNYR_SALT1_HEX=... # 32 hex chars
|
|
# export TNYR_SALT2_HEX=... # 32 hex chars
|
|
python main.py
|
|
```
|
|
|
|
## Why Choose [tnyr.me](https://tnyr.me)?
|
|
|
|
- **Privacy by Design**: We literally can't view your links
|
|
- **No Tracking**: Zero cookies, analytics, or fingerprinting
|
|
- **Self-Hostable**: Full control over your data
|