中文 | English
A proxy server that gracefully intercepts aria2.addUri JSON-RPC requests, archiving download URLs and their associated payload options (custom headers, cookies, output paths) into a local SQLite database instead of executing the downloads directly.
Built with TypeScript, Express 5, and Bun (dev runtime). Provides a reactive Vue.js 3 & Tailwind CSS v4 Web UI to monitor captured links and export them as a standard aria2c -i input file at any time. Ideal for capturing and forwarding heavy cross-site download requests generated by browser extensions.
- JSON-RPC Interception: Listens on
/jsonrpcas a mock Aria2 endpoint and captures raw URLs alongside their full payload options. - RPC Authorization: Supports the standard Aria2 RPC Secret token — set
ARIA2_RPC_SECRETto require authentication on all requests. - Smart Header Normalization: Correctly extracts
User-Agent,Referer, andCookiefrom JSON payloads even under strict CORS policies, deduplicating them before storage. - Global User-Agent Override: Optionally force all exports to use a specific
User-AgentviaUSER_AGENTenvironment variable. - Premium Web Dashboard: Glassmorphism dark-mode UI built with Vue 3 CDN — no build step required. Auto-refreshes every 2.5 s and supports inline header inspection per request.
- One-Click Export: Exports all pending requests into a properly formatted
aria2cmulti-URL input file for batch downloading. - Automated Rename Rules: Optional string replacements applied transparently to the filename based on
data/rename-rules.yaml.
| Layer | Technology |
|---|---|
| Language | TypeScript 6 (strict mode, compiled to CommonJS) |
| Runtime (dev) | Bun — runs .ts files natively with zero config |
| Runtime (prod) | Node.js 22 — runs the compiled dist/ output |
| Backend | Express 5, pino logger |
| Database | bun:sqlite (Bun) / better-sqlite3 (Node.js) — detected at runtime |
| Frontend | Vue 3 CDN + Tailwind CSS v4 CDN |
| Testing | Jest + ts-jest + Supertest |
| Linting | ESLint v10 (flat config) + typescript-eslint |
| Formatting | Prettier (semi: false, singleQuote: true) |
-
Install dependencies:
npm install
-
Configure environment:
cp .env.example .env
Edit
.envto set the proxy port, RPC secret, and optional User-Agent override. -
Start the dev server (Bun — runs TypeScript directly):
npm run dev
Or build and run with Node.js:
npm run build # compiles TypeScript → dist/ npm start # runs dist/server.js with Node.js
-
Open the dashboard: http://localhost:6800
-
Point your browser extension to the proxy: In your download extension or user-script, change the Aria2 RPC endpoint to:
http://localhost:6800/jsonrpcThe proxy silently intercepts every
aria2.addUricall and stores it.
You can apply automated text replacements to incoming output filenames by creating a rename-rules.yaml file inside the data/ directory.
The file should be a YAML array containing pairs of strings ["TARGET", "REPLACEMENT"]:
# You can include comments!
- ["EXAMPLE-TO-REMOVE-", ""]When a new download request is received, the proxy evaluates the out parameter against these rules. If any string matches a target, it automatically replaces ALL occurrences of the target with the corresponding replacement string. If a rule produces an empty or invalid filename, it is safely ignored.
| Variable | Default | Description |
|---|---|---|
PORT |
6800 |
Port the proxy listens on |
ARIA2_RPC_SECRET |
(unset) | If set, all RPC requests must include token:<secret> |
USER_AGENT |
(unset) | If set, overrides the User-Agent on all exported requests |
UI_USERNAME |
hello |
Username for accessing the Dashboard and /api natively |
UI_PASSWORD |
world |
Password for accessing the Dashboard and /api natively |
LOG_LEVEL |
debug |
Pino log level (trace / debug / info / warn / error) |
| Script | Description |
|---|---|
npm run dev |
Start dev server with Bun (runs TypeScript natively) |
npm start |
Start production server from compiled dist/ |
npm run build |
Compile TypeScript → dist/ via tsc |
npm test |
Run Jest test suite (Node.js + ts-jest) |
npm run lint |
Lint src/ and tests/ with ESLint v10 |
npm run format |
Format all files with Prettier |
src/
├── server.ts Express app configurator — middleware, router mounting, entry point guard
├── jsonrpc.ts JSON-RPC 2.0 handler — secret auth, addUri interception, header normalization
├── api.ts REST endpoints powering the frontend dashboard
├── db.ts Runtime-aware SQLite adapter (bun:sqlite under Bun, better-sqlite3 under Node)
├── types.ts Shared TypeScript interfaces (DB, RequestRecord, Aria2Options, JsonRpcPayload)
└── bun.d.ts Ambient type declarations for bun:sqlite (allows tsc to build without Bun)
public/
├── index.html Vue 3 SPA dashboard (CDN-based, no build step)
└── app.js Vue Composition API app logic
tests/
├── api.test.ts REST API integration tests
└── jsonrpc.test.ts JSON-RPC handler tests
When you click Export Pending in the dashboard, the proxy generates a standard aria2c input file:
https://example.com/file.7z
out=downloads/file.7z
header=User-Agent: Mozilla/5.0...
header=Cookie: session_id=1234
header=Referer: https://source-site.com
Feed it directly to aria2:
aria2c -i aria2_downloads.txtPre-built multi-arch images (linux/amd64 and linux/arm64) are published to GitHub Container Registry on every push to main and on version tags.
docker pull ghcr.io/windix/aria-proxy:mainRun with Docker:
docker run -d \
-p 6800:6800 \
-e ARIA2_RPC_SECRET=your_secret \
-v $(pwd)/data:/app/data \
ghcr.io/windix/aria-proxy:mainBuild locally (single arch, loads into local Docker daemon):
docker buildx build \
--platform linux/amd64 \
--build-arg GIT_COMMIT=$(git rev-parse --short HEAD) \
--build-arg GIT_TAG=$(git describe --tags --exact-match 2>/dev/null || true) \
-t aria-proxy --load .Build locally for multiple architectures (requires pushing to a registry):
# One-time setup: create a buildx builder with multi-arch support
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
# Build and push
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/windix/aria-proxy:latest \
--push .Use the built-in npm version command — it bumps package.json, commits, tags, and the postversion hook pushes everything to GitHub in one step (which triggers the Docker image build in CI):
npm version patch # 1.0.0 → 1.0.1 (bug fixes)
npm version minor # 1.0.0 → 1.1.0 (new features)
npm version major # 1.0.0 → 2.0.0 (breaking changes)
npm version 1.2.3 # set a specific versionTo delete a tag and re-release if something went wrong:
git tag -d v1.2.3
git push origin --delete v1.2.3# Run tests
npm test
# Type check only (no emit)
npx tsc --noEmit
# Lint + format in one pass
npm run lint && npm run format