opentracker.toml.example
| 1 | # opentracker configuration. Every field can also be set as OT_<UPPERCASE>. |
| 2 | # Copy to opentracker.toml and edit. All values shown are the defaults. |
| 3 | |
| 4 | # HTTP API and web UI. Localhost by default: nginx or Caddy terminates TLS. |
| 5 | http_addr = "127.0.0.1:7372" |
| 6 | |
| 7 | # OTP/1 UDP listener. |
| 8 | # |
| 9 | # THE TRAP: HTTP reverse proxies do not forward UDP. This port must be exposed |
| 10 | # directly by a firewall or NAT rule. If it is not, every phone silently falls |
| 11 | # back to TLS-over-TCP and you lose the whole point of the protocol. |
| 12 | udp_addr = "0.0.0.0:7373" |
| 13 | |
| 14 | # TLS-over-TCP fallback for UDP-hostile networks. Also needs its own rule. |
| 15 | # tls_addr = "0.0.0.0:7374" |
| 16 | |
| 17 | # What the login response tells phones to connect to. These are the *public* |
| 18 | # names, which are usually not the same as the bind addresses above. |
| 19 | public_udp_host = "localhost" |
| 20 | public_udp_port = 7373 |
| 21 | # public_tls_url = "tls://track.example.com:7374" |
| 22 | |
| 23 | base_url = "http://localhost:7372" |
| 24 | |
| 25 | # REQUIRED. The OSM tile usage policy demands a contactable User-Agent, and an |
| 26 | # unidentified tile proxy is blocked without notice. The server refuses to start |
| 27 | # while this is the placeholder. |
| 28 | admin_email = "you@example.com" |
| 29 | |
| 30 | db_path = "opentracker.db" |
| 31 | cache_dir = "cache" |
| 32 | |
| 33 | # Tile cache ceiling in bytes; eviction runs down to 90% of it. 1 GiB. |
| 34 | max_cache_bytes = 1073741824 |
| 35 | |
| 36 | # Point at your own renderer here if you ever run one. |
| 37 | tile_upstream_url = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" |
| 38 | |
| 39 | # Hard drop for points older than this. Points older than 24 h are also thinned |
| 40 | # to roughly one per 5 minutes. The live marker lives in its own table and is |
| 41 | # never affected. |
| 42 | retention_days = 7 |
| 43 | |
| 44 | # Mark tokens with no activity for this long as revoked. A phone idle for a |
| 45 | # month has to log in again — the same contract as an expiring browser session. |
| 46 | # |
| 47 | # The row and its wrapped key are kept, not deleted. The key is the only thing |
| 48 | # that can seal a message the phone will believe, and a phone idle for a month is |
| 49 | # exactly the one that needs telling. A token row is about a hundred bytes. |
| 50 | token_stale_days = 30 |
| 51 | |
| 52 | # Accept client timestamps within ±this many days. |
| 53 | # |
| 54 | # This is the only server-side handling of a client timestamp anywhere. Nothing |
| 55 | # corrects a ts, nothing measures clock skew, and no message in the protocol |
| 56 | # carries the server's clock. This bound exists purely so a phone whose clock says |
| 57 | # 2106 cannot write rows the retention sweep will never reach. |
| 58 | ts_window_days = 30 |
| 59 | |
| 60 | # Answer a datagram naming an unknown token with a sealed REVOKED notice instead |
| 61 | # of silence, so a phone whose token the server has forgotten lands on the login |
| 62 | # screen instead of reporting into nothing. |
| 63 | # |
| 64 | # THE TRADE: this is the one reply the server sends without having verified the |
| 65 | # request, which makes the UDP port a reflector — UDP source addresses are |
| 66 | # forgeable, so the reply goes wherever the sender claimed to be. Three things |
| 67 | # bound it: the notice is 38 bytes and is refused to any shorter request, so it |
| 68 | # can never amplify; it is limited to one per destination address per minute |
| 69 | # under a global ceiling of 10/s; and naming unknown tokens still earns strikes |
| 70 | # and a ban either way. It cannot be forged, because it is sealed with a key |
| 71 | # derived from the server master and that token_id. |
| 72 | # |
| 73 | # Turning it off costs little. A revoked token keeps its row and its key, so the |
| 74 | # ordinary "you are logged out" answer is a fully authenticated NACK that never |
| 75 | # takes this path. This switch only matters when the row is genuinely gone: a |
| 76 | # restored backup predating the login, or a rotated OT_SECRET_KEY. With it off, |
| 77 | # those devices get silence until someone opens the app. |
| 78 | revocation_notices = true |
| 79 | |
| 80 | # Argon2id. 19 MiB / 2 passes / 1 lane is OWASP's second recommended profile. |
| 81 | # Raising these later does not invalidate existing hashes: each hash carries its |
| 82 | # own parameters and is transparently upgraded on the next successful login. |
| 83 | argon2_memory_kib = 19456 |
| 84 | argon2_iterations = 2 |
| 85 | argon2_parallelism = 1 |
| 86 | |
| 87 | # Number of SO_REUSEPORT receive tasks. Defaults to min(cpus, 4). |
| 88 | # udp_workers = 4 |
| 89 |