mirava
Universal proxy for Docker registry and PyPI mirrors with automatic failover.
Features
- Docker Registry Proxy: Transparent mirror for Docker Hub with fallback
- PyPI Proxy: Python package index mirror with automatic retry
- Health Monitoring: Automatic mirror health checks and degradation
- Dynamic Configuration: Add/remove mirrors via API
- Swagger UI: Built-in API documentation
Installation
git clone https://github.com/yourusername/mirava.git
cd mirava
uv sync
Quick Start
# Run with default configuration
uv run mirava
# Or run directly
uv run python -m hyper_mirror.main
Server starts on http://localhost:8080
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Server bind address |
PORT |
8080 |
Server port |
PYPI_OFFICIAL_URL |
https://pypi.org/simple |
Official PyPI index |
PYPI_MIRRORS |
(built-in) | Comma-separated PyPI mirrors |
DOCKER_OFFICIAL_URL |
https://registry-1.docker.io |
Official Docker registry |
DOCKER_MIRRORS |
(built-in) | Comma-separated Docker mirrors |
Examples
# Use custom PyPI index
PYPI_OFFICIAL_URL=https://pypi.company.internal/simple uv run mirava
# Custom mirrors only
PYPI_MIRRORS="https://mirror1.com/simple,https://mirror2.com/simple" \
DOCKER_MIRRORS="https://docker-mirror1.com,https://docker-mirror2.com" \
uv run mirava
Docker Setup
Configure Docker to use the proxy:
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["http://127.0.0.1:8080"],
"insecure-registries": ["127.0.0.1:8080"]
}
EOF
sudo systemctl restart docker
Now use Docker normally:
docker pull hello-world
docker pull nginx
PyPI Setup
Configure pip to use the proxy:
# Global config
pip config set global.index-url http://127.0.0.1:8080/simple
pip config set global.trusted-host 127.0.0.1
# Or per-command
pip install --index-url http://127.0.0.1:8080/simple --trusted-host 127.0.0.1 requests
Or use environment variables:
export PIP_INDEX_URL=http://127.0.0.1:8080/simple
export PIP_TRUSTED_HOST=127.0.0.1
pip install requests
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Service info |
/docs |
GET | Swagger UI |
/redoc |
GET | ReDoc documentation |
/health |
GET | Mirror health status |
/v2/ |
GET/HEAD | Docker registry root |
/v2/{path} |
GET/HEAD/POST | Docker registry proxy |
/simple/{package}/ |
GET | PyPI package proxy |
/mirrors/{type} |
POST | Add mirror dynamically |
/config/{type}/official |
PUT | Update official URL |
API Usage Examples
# Check health
curl http://localhost:8080/health
# Add mirror dynamically
curl -X POST "http://localhost:8080/mirrors/pypi?url=https://new.mirror.com/simple&name=newmirror&priority=5"
# Update official PyPI URL
curl -X PUT "http://localhost:8080/config/pypi/official?url=https://test.pypi.org/simple"
Project Structure
src/hyper_mirror/
├── __init__.py # Package init
├── main.py # FastAPI application
├── cli.py # CLI entry point
├── config.py # Configuration management
├── base.py # Base classes and utilities
├── mirrors.py # Mirror registry and initialization
├── docker.py # Docker registry routes
└── pypi.py # PyPI proxy routes
Adding New Mirror Types
- Create new file
src/hyper_mirror/npm.py:
from fastapi import APIRouter
from .mirrors import registry
router = APIRouter(tags=["NPM"])
@router.get("/npm/{package}")
async def npm_proxy(package: str):
# Implementation
pass
- Add mirrors to
mirrors.py:
NPM_MIRRORS = [
("https://registry.npmmirror.com", "npmmirror", 0),
]
- Register in
init_mirrors():
npm_mgr = BaseMirrorManager("npm")
npm_mgr.official_url = "https://registry.npmjs.org"
for url, name, priority in NPM_MIRRORS:
npm_mgr.add_mirror(url, name, priority)
registry.register("npm", npm_mgr)
- Include router in
main.py:
from . import npm
app.include_router(npm.router)
Development
# Run in development mode with auto-reload
uv run --reload mirava
# Or with Python directly
cd src
PYTHONPATH=. uvicorn hyper_mirror.main:create_app --factory --reload
Docker Compose
version: '3.8'
services:
mirava:
build: .
ports:
- "8080:8080"
environment:
- PYPI_OFFICIAL_URL=https://pypi.org/simple
- PYPI_MIRRORS=https://mirror1.com/simple,https://mirror2.com/simple
restart: unless-stopped
License
MIT License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
mirava-0.2.0.tar.gz
(6.8 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mirava-0.2.0.tar.gz.
File metadata
- Download URL: mirava-0.2.0.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12f42593da7209e72620c69c6d3976f6850f8ecab394e8014ab3a47ae9174836
|
|
| MD5 |
8f3e5e836267b5bca64f568a3f64e9a9
|
|
| BLAKE2b-256 |
1e28343d4347987c5958fa01e395c66a9e77b75f30a4c1ca5d95a51468d58797
|
File details
Details for the file mirava-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mirava-0.2.0-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b799ff664342339478a5430eb1ca437a136ff4ba2525379c508b97b58be42b66
|
|
| MD5 |
0cfd1f565c350b96c41d6aa47a759f46
|
|
| BLAKE2b-256 |
01eb19631b412902e180d4a42456ef4a4ef0f3e835b84cf4b6f741e073406bdd
|