xip is an authoritative DNS server for dashed-IP hostnames, intended for pullpreview-style ephemeral environments.
Examples:
1-2-3-4-preview.example.test->1.2.3.4preview-1-2-3-4.example.test->1.2.3.4
This project uses mise to manage Go.
mise installmake test
make buildBinary output: dist/xip
make check-fmt
make lint
make testTo auto-run checks before each commit, install pre-commit hooks:
make precommit-installRun them manually:
make precommit-runxip accepts CLI flags and environment variables prefixed with XIP_.
- CLI flags always take precedence over environment variables.
- If a value is not provided via flags, the corresponding
XIP_*env var is used.
| Flag | Env var | Default |
|---|---|---|
--domain |
XIP_DOMAIN |
xip.test |
--root-addresses |
XIP_ROOT_ADDRESSES |
127.0.0.1 |
--ns-addresses |
XIP_NS_ADDRESSES |
127.0.0.1 |
--timestamp |
XIP_TIMESTAMP |
0 |
--ttl |
XIP_TTL |
300 |
--listen-udp |
XIP_LISTEN_UDP (or XIP_LISTEN) |
:53 |
--listen-tcp |
XIP_LISTEN_TCP (or XIP_LISTEN) |
:53 |
--listen-http |
XIP_LISTEN_HTTP |
:80 |
--listen-https |
XIP_LISTEN_HTTPS |
:443 |
--root-redirect-url |
XIP_ROOT_REDIRECT_URL |
empty (disabled) |
--blocklist-path |
XIP_BLOCKLIST_PATH |
/etc/xip/blocklist.csv |
--blocklist-reload-interval |
XIP_BLOCKLIST_RELOAD_INTERVAL |
60s |
--acme-cache-dir |
XIP_ACME_CACHE_DIR |
/etc/xip/acme-cache |
--acme-email |
XIP_ACME_EMAIL |
empty |
Address lists accept comma or whitespace separators.
The blocklist file is a CSV with 2 columns:
fqdn,reason
abusive.preview.example.com,Malware distribution- FQDN matching is exact and case-insensitive.
- DNS
Arequests for blocked FQDNs are answered with root IP(s). - The file is reloaded from disk every 60 seconds by default.
HTTP server (--listen-http) serves:
GET /health: JSON withblocked_domainsandlast_reload_time.- Blocked hostnames: an inlined error page with the block reason and support contact.
For non-blocked hostnames:
- If
--root-redirect-urlis set, requests are redirected there. - Otherwise the response is
404.
HTTPS server (--listen-https) uses automatic Let's Encrypt certificates via ACME (autocert) with on-disk cache at --acme-cache-dir (default /etc/xip/acme-cache).
Certificate issuance is allowed for any hostname in the configured zone (--domain and all subdomains).
Example:
XIP_ROOT_REDIRECT_URL=https://pullpreview.com/?ref=xip
XIP_ACME_CACHE_DIR=/var/lib/xip/acme-cachexip emits:
- OTEL metric
xip_dns_requests_totalfor every DNS request. - OTEL application logs (bridged from
slog).
Metric attributes:
fqdn: queried fully-qualified domain name (normalized)domain: fqdn with the dashed-IP token removed (for exampleip-1-2-3-4.preview.run->preview.run)tld: registrable domain (eTLD+1) derived fromdomainusing the public suffix list (for examplepreview.hello.co.uk->hello.co.uk)
Use standard OTEL env vars, for example:
OTEL_EXPORTER_OTLP_ENDPOINT=ingest.eu.signoz.cloud
OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key>Signal-specific endpoint overrides are also supported:
OTEL_EXPORTER_OTLP_METRICS_ENDPOINTOTEL_EXPORTER_OTLP_LOGS_ENDPOINT
If endpoint env vars omit a scheme, xip defaults them to https://.
XIP_DOMAIN=preview.example.com \
XIP_ROOT_ADDRESSES=203.0.113.10 \
XIP_NS_ADDRESSES=203.0.113.10 \
make run- Create
config/.envfromconfig/.env.exampleand edit values. - Deploy with:
make deployDefault remote target is root@xip.preview.run.
make deploy does the following:
- Builds
xipforlinux/amd64 - SSHes to the target host
- Uploads binary + systemd unit + logrotate policy +
config/.env - Installs binary to
/usr/local/bin/xip - Installs service to
/etc/systemd/system/xip.service - Installs logrotate config to
/etc/logrotate.d/xip - Syncs env file to
/etc/default/xip - Ensures
/etc/xipexists for blocklist + ACME cache - Ensures
/etc/xip/blocklist.csvexists - Ensures
/var/log/xip/xip.logexists - Reloads systemd and restarts
xip.service
Optional deploy overrides:
REMOTE_HOST(defaultxip.preview.run)SSH_USER(defaultroot)SSH_PORT(default22)REMOTE_BIN,REMOTE_SYSTEMD_UNIT,REMOTE_ENV_FILE
Verify deployed service health and print recent logs:
make deploy-checkSync only the blocklist CSV (default target root@xip.preview.run):
make blocklistOptional blocklist sync overrides:
REMOTE_HOST(defaultxip.preview.run)SSH_USER/SSH_PORTLOCAL_BLOCKLIST_FILE
docker build -t xip .
docker run --rm -p 53:53/udp -p 53:53/tcp -p 80:80 -p 443:443 --env-file config/.env xip