| Crates.io | ivoryvalley |
| lib.rs | ivoryvalley |
| version | 0.4.0 |
| created_at | 2025-12-26 01:18:31.143807+00 |
| updated_at | 2026-01-08 11:00:02.669872+00 |
| description | A transparent deduplication proxy for Mastodon and the Fediverse |
| homepage | https://github.com/jensens/ivoryvalley |
| repository | https://github.com/jensens/ivoryvalley |
| max_upload_size | |
| id | 2005111 |
| size | 1,035,604 |
Status: Under Heavy Development - This project is in early development. APIs and features may change without notice.
A transparent deduplication proxy for Mastodon and the Fediverse.
Following users across multiple Fediverse accounts often results in seeing the same posts repeatedly due to boosts/reposts. Your timeline can show the same content 10+ times.
IvoryValley sits between your Mastodon client and the upstream server, filtering out duplicate posts before they reach you. It tracks seen post URIs and removes duplicates from timeline responses.
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Client │────▶│ IvoryValley │────▶│ Mastodon │
│ (Tusky, │◀────│ │◀────│ Instance │
│ etc.) │ │ - Filter dupes │ │ │
└─────────────┘ │ - Store URIs │ └──────────────┘
│ - Pass auth │
└─────────────────┘
/health endpoint for load balancers and Kubernetes probesPull and run the latest image:
docker pull ghcr.io/jensens/ivoryvalley:latest
docker run -d \
--name ivoryvalley \
-p 8080:8080 \
-v ivoryvalley-data:/data \
-e IV_UPSTREAM_URL=https://mastodon.social \
ghcr.io/jensens/ivoryvalley:latest
Or use docker-compose (see docker-compose.yml):
# Edit docker-compose.yml with your upstream URL
docker compose up -d
cargo install ivoryvalley
Download the appropriate binary for your platform from the Releases page.
git clone https://github.com/jensens/ivoryvalley.git
cd ivoryvalley
cargo build --release
The binary will be at target/release/ivoryvalley.
# Using Docker (recommended)
docker run -d -p 8080:8080 \
-v ivoryvalley-data:/data \
-e IV_UPSTREAM_URL=https://mastodon.social \
ghcr.io/jensens/ivoryvalley:latest
# Or using the binary directly
ivoryvalley --upstream-url https://mastodon.social
Point your Mastodon client to your IvoryValley URL instead of your instance URL. Most clients require HTTPS - see Client Setup for detailed instructions and Local HTTPS Setup for development options.
Use your regular credentials. IvoryValley passes authentication through to your instance transparently.
# Basic usage
ivoryvalley --upstream-url https://mastodon.social
# With custom host and port
ivoryvalley --upstream-url https://mastodon.social --host 127.0.0.1 --port 3000
# With environment variables
IV_UPSTREAM_URL=https://mastodon.social ivoryvalley
# With a config file
ivoryvalley --config /path/to/ivoryvalley.toml
IvoryValley supports configuration via:
IV_)config.toml, config.yaml, ivoryvalley.toml, or ivoryvalley.yaml)| Option | Env Variable | Default | Description |
|---|---|---|---|
--upstream-url |
IV_UPSTREAM_URL |
https://mastodon.social |
Upstream Mastodon instance URL |
--host |
IV_HOST |
0.0.0.0 |
Address to bind to |
-p, --port |
IV_PORT |
8080 |
Port to listen on |
--database-path |
IV_DATABASE_PATH |
ivoryvalley.db |
SQLite database path |
--max-body-size |
IV_MAX_BODY_SIZE |
52428800 (50MB) |
Maximum request body size in bytes |
--connect-timeout-secs |
IV_CONNECT_TIMEOUT_SECS |
10 |
HTTP connection timeout in seconds |
--request-timeout-secs |
IV_REQUEST_TIMEOUT_SECS |
30 |
HTTP request timeout in seconds |
--record-traffic-path |
IV_RECORD_TRAFFIC_PATH |
- | Path to record traffic (JSONL format) |
--cleanup-interval-secs |
IV_CLEANUP_INTERVAL_SECS |
3600 (1 hour) |
Interval between cleanup runs in seconds |
--cleanup-max-age-secs |
IV_CLEANUP_MAX_AGE_SECS |
604800 (7 days) |
Maximum age of stored URIs in seconds |
-c, --config |
IV_CONFIG |
- | Path to configuration file |
Create an ivoryvalley.toml file:
upstream_url = "https://mastodon.social"
host = "127.0.0.1"
port = 8080
database_path = "/var/lib/ivoryvalley/seen.db"
Or ivoryvalley.yaml:
upstream_url: "https://mastodon.social"
host: "127.0.0.1"
port: 8080
database_path: "/var/lib/ivoryvalley/seen.db"
The proxy exposes a /health endpoint for monitoring and orchestration systems.
curl http://localhost:8080/health
Response:
{"status": "healthy", "version": "x.y.z"}
Use the ?deep=true query parameter to include database connectivity verification:
curl http://localhost:8080/health?deep=true
Response:
{"status": "healthy", "version": "x.y.z", "checks": {"database": "ok"}}
This endpoint:
IvoryValley works with any Mastodon-compatible client. You simply change the server URL from your instance (e.g., https://mastodon.social) to IvoryValley (e.g., http://localhost:8080).
Note: Despite being desktop applications, many Mastodon clients require HTTPS even for localhost connections due to OAuth security requirements and embedded browser security policies. See Local HTTPS Setup for workarounds.
flatpak install flathub dev.geopjr.Tubahttps://localhost:8443 or your mkcert domain)apt install tokodon or via your package managerMobile clients require HTTPS. You need to deploy IvoryValley behind a reverse proxy with a valid SSL certificate.
Recommended: Deploy with a Reverse Proxy
Use Caddy, nginx, or Traefik with a valid SSL certificate. This enables full functionality including WebSocket streaming.
Example with Caddy:
ivoryvalley.example.com {
reverse_proxy localhost:8080
}
You can also access Mastodon's web interface through IvoryValley:
# Open in browser
xdg-open http://localhost:8080
Note that the web interface works best with HTTPS for all features.
For local development and testing with desktop/mobile clients, you'll need HTTPS with trusted certificates. Here are recommended approaches:
mkcert creates locally-trusted development certificates.
# Install mkcert
# macOS
brew install mkcert
# Linux (check your package manager, or use the binary release)
# See https://github.com/FiloSottile/mkcert#installation
# Create and install the local CA
mkcert -install
# Generate certificates for localhost
mkcert localhost 127.0.0.1 ::1
# This creates localhost+2.pem and localhost+2-key.pem
Then use a reverse proxy like Caddy to serve IvoryValley over HTTPS:
# Caddyfile
localhost:8443 {
tls localhost+2.pem localhost+2-key.pem
reverse_proxy localhost:8080
}
Caddy can automatically provision certificates. For local development with a custom domain:
/etc/hosts: 127.0.0.1 ivoryvalley.local# Caddyfile
ivoryvalley.local {
tls internal
reverse_proxy localhost:8080
}
For the most seamless experience, deploy IvoryValley on a server with a real domain name. Caddy will automatically obtain Let's Encrypt certificates:
# Caddyfile
ivoryvalley.example.com {
reverse_proxy localhost:8080
}
"Connection refused" error
curl http://localhost:8080/api/v1/instance"Timeout" errors
curl https://mastodon.social/api/v1/instanceivoryvalley --upstream-url https://mastodon.social \
--connect-timeout-secs 30 \
--request-timeout-secs 120
OAuth login fails or redirects to wrong URL
"Unauthorized" errors after login
Duplicates still appear
Want to reset seen posts?
Delete the database file to start fresh:
# Find the database location
ls -la ivoryvalley.db
# Stop IvoryValley, delete database, restart
rm ivoryvalley.db
Container won't start
docker logs ivoryvalleyIV_UPSTREAM_URL environment variable is setDatabase not persisting
-v ivoryvalley-data:/dataEnable debug logging to see detailed information:
# With the binary
RUST_LOG=ivoryvalley=debug ivoryvalley --upstream-url https://mastodon.social
# With Docker
docker run -e RUST_LOG=ivoryvalley=debug \
-e IV_UPSTREAM_URL=https://mastodon.social \
ghcr.io/jensens/ivoryvalley:latest
Log levels: error, warn, info, debug, trace
If you need to debug API issues, you can record all traffic:
ivoryvalley --upstream-url https://mastodon.social \
--record-traffic-path /tmp/traffic.jsonl
This creates a JSONL file with all request/response pairs.
This project uses just as a command runner. Install with cargo install just.
# List all available commands
just
# Run the proxy in development mode
just dev
# Run all tests
just test
# Run all quality checks before committing
just check
See Client Setup for detailed client configuration.
For quick HTTPS testing with the web interface only:
just dev-https
Note: The development HTTPS proxy does not support WebSocket connections, so native clients (desktop/mobile apps) won't have working streaming. For full client testing, deploy with a proper reverse proxy like Caddy.
# Run with logging
RUST_LOG=ivoryvalley=debug cargo run -- --upstream-url https://mastodon.social
# Check code quality
cargo clippy --all-features -- -D warnings
# Format code
cargo fmt
See CONTRIBUTING.md for guidelines.
MIT