Nickel-Auth is a proxy server designed to facilitate authentication between the iOS app Nickel and the Cobalt.Tools API servers because Swift lacks current turnstile implementation that cobalt uses to secure their servers.
- Acts as a bridge between the Nickel app and Cobalt.Tools API.
- Uses Apple's AppAttest authentication method to authenticate server with app.
- Enables the Nickel-Auth feature in the Nickel app for seamless authentication.
- Built-in rate limiting and security features
- Prometheus metrics for monitoring
- Auto-updating Docker containers with Watchtower
If you'd like to add your instance to the Nickel app, please contact us at support@tfourj.com.
You can also view a list of public instances at Nickel's Website.
- Docker and Docker Compose installed on your system.
- Basic knowledge of environment variables and JSON configuration.
-
Create a project directory
mkdir Nickel-Auth cd Nickel-Auth -
Create docker-compose.yml file
nano docker-compose.yml
Paste the following configuration:
services: nickel-auth: image: tfourj/nickel-auth:latest container_name: nickel-auth ports: - '3000:3000' # Use 127.0.0.1:3000:3000 if you want to use reverse proxy restart: unless-stopped volumes: - ./api_keys.json:/app/api_keys.json:ro - ./banned-ips.log:/app/banned-ips.log env_file: ".env" labels: - com.centurylinklabs.watchtower.enable=true - com.centurylinklabs.watchtower.scope=nickel-auth watchtower-nickel-auth: image: containrrr/watchtower container_name: watchtower-nickel-auth volumes: - /var/run/docker.sock:/var/run/docker.sock command: --cleanup --interval 300 --scope nickel-auth restart: unless-stopped
-
Create environment configuration file
nano .env
Add your configuration (replace with your actual values):
JWT_SECRET=your-super-secure-jwt-secret-here APPLE_TEAM_ID=your-apple-team-id APPLE_BUNDLE_ID=your.app.bundle.id PORT=3000 RATE_LIMIT=50 CHALLENGE_CACHE_TTL=300 AUTH_CACHE_TTL=600 NODE_ENV=production MONITORING_ORIGIN=http://example.com or false LOG_LEVEL=log LOG_FILTERED_IPS= LB_HEALTHCHECK_CACHE_TTL=10 LB_HEALTHCHECK_TIMEOUT_MS=1500 LB_HEALTHCHECK_PATH=/ LB_HEALTHCHECK_METHOD=GET USE_CLOUDFLARE_IPS=false TRUSTED_PROXY_CIDRS= CLOUDFLARE_IPV4_URL=https://www.cloudflare.com/ips-v4 CLOUDFLARE_IPV6_URL=https://www.cloudflare.com/ips-v6
-
Create API keys configuration file
nano api_keys.json
Add your Cobalt API endpoints and keys:
{ "https://cobalt-api.example.com": "your-api-key-here", "https://another-cobalt-instance.com": "another-api-key" } -
Start the services
docker-compose up -d
-
Verify the server is running
docker-compose logs -f nickel-auth
The server should be accessible at
http://your-server-ip:3000
JWT_SECRET: A secure random string for signing JWT tokensAPPLE_TEAM_ID: Your Apple Developer Team ID (required for AppAttest)APPLE_BUNDLE_ID: Your app's bundle identifier
PORT: Server port (default: 3200)RATE_LIMIT: Maximum requests per IP per time window (default: 50)CHALLENGE_CACHE_TTL: Challenge expiration time in seconds (default: 300)AUTH_CACHE_TTL: Authentication token expiration time in seconds (default: 600)NODE_ENV: Set toproductionfor production deploymentMONITORING_ORIGIN: CORS origin for metrics endpoint (default: false)LOG_LEVEL: Logging verbosity (log,warn,debug);warnanddebugadd on top oflogoutput (errors always log)LOG_FILTERED_IPS: Comma- or space-separated list of IPs to hide from request logs (exact match only)LB_HEALTHCHECK_CACHE_TTL: Health check cache TTL in seconds for load-balanced Cobalt backends (default: 10)LB_HEALTHCHECK_TIMEOUT_MS: Timeout for backend health checks in milliseconds (default: 1500)LB_HEALTHCHECK_PATH: Health-check path appended to each backend base URL (default:/)LB_HEALTHCHECK_METHOD: HTTP method for health checks (default:GET)USE_CLOUDFLARE_IPS: Iftrue, fetch Cloudflare IPv4/IPv6 ranges at startup and merge them withTRUSTED_PROXY_CIDRS; in this mode client IP resolution only trustsCF-Connecting-IPfrom trusted proxy peers (default:false)TRUSTED_PROXY_CIDRS: Comma- or space-separated CIDRs for trusted reverse proxies (for example your internal load balancer or tunnel subnet); forwarded IP headers are only trusted when the direct peer matches one of these rangesCLOUDFLARE_IPV4_URL: URL used to fetch Cloudflare IPv4 ranges whenUSE_CLOUDFLARE_IPS=true(default:https://www.cloudflare.com/ips-v4)CLOUDFLARE_IPV6_URL: URL used to fetch Cloudflare IPv6 ranges whenUSE_CLOUDFLARE_IPS=true(default:https://www.cloudflare.com/ips-v6)
The api_keys.json file maps Cobalt API server URLs to their respective authentication keys. Each entry should be in the format:
{
"https://cobalt-server-url": "api-key-for-that-server"
}For load balancing, you can provide per-server keys (or a shared key) and a list of backend servers. The least-used server is selected per request:
{
"https://cobalt-main.example": {
"servers": {
"https://cobalt-one.example": "cobalt-one-key",
"https://cobalt-two.example": "cobalt-two-key"
}
}
}- Access Prometheus metrics at
/metricsendpoint - Monitor container logs:
docker-compose logs -f - Check container status:
docker-compose ps
The Watchtower service automatically updates the container when new versions are released. You can also manually update:
docker-compose pull
docker-compose up -dThis project is licensed under the GPU License. See the LICENSE file for details.