Service Recipes
Publish thirteen common databases and self-hosted apps on the overlay, each with the exact commands and settings it needs.
The Two Machines
Every recipe uses two machines with conflux installed: a server that runs the service, and a client that connects to it.
The service stays on loopback, where it already listens. The overlay makes it reachable from every machine whose taints are compatible with the server's.
Set up the two machines once, as shown below for the instance VeilNet hosts. Every recipe on this page then works between them.
Run
proxyon the server, so nothing changes on the host. The first run mints a taint, and--ipv4answers the only question conflux would ask. Copy the taint:$ sudo conflux proxy 5432=127.0.0.1:5432 --ipv4 10.128.0.5/24 Minted a taint for this network: brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf
Some setups need a different approach:
- In Docker, publish the container's port to
127.0.0.1. Conflux connects from the host, where container names do not resolve. - If the server already runs
conflux up, it has no proxy. Bind the service to the overlay address instead, as each recipe describes. - For several services on one server, run one
proxycommand with every spec in it. See Several Services on One Machine.
Choosing a Service
PostgreSQL
Reach a database from laptops, CI runners and app servers without opening port 5432 to anything else.
# PostgreSQL listens on localhost by default; leave it there $ sudo conflux proxy 5432=127.0.0.1:5432 --ipv4 10.128.0.5/24
$ docker run -d --name postgres -e POSTGRES_PASSWORD='change-me' \
-p 127.0.0.1:5432:5432 postgres:17
$ sudo conflux proxy 5432=127.0.0.1:5432 --ipv4 10.128.0.5/24$ psql "postgresql://app@10.128.0.5:5432/app" $ psql "postgresql://app@[fd80:c4b9:99ae:4411:c531:fd4f:754f:f08a]:5432/app"
If the server runs conflux up instead
# postgresql.conf listen_addresses = 'localhost,10.128.0.5' # pg_hba.conf: the client's own overlay IPv6, which is bound to its identity host app app fd80:c4b9:99ae:df9b:5261:d178:18f1:783c/128 scram-sha-256
Have clients connect to the server's IPv6 address, so pg_hba.conf can tell each client apart. Over IPv4, clients arrive from the shared 198.18.0.0/15 range.
MySQL and MariaDB
Share one MySQL or MariaDB server with the machines that need it and with no others.
# keep bind-address = 127.0.0.1 in my.cnf $ sudo conflux proxy 3306=127.0.0.1:3306 --ipv4 10.128.0.5/24
$ docker run -d --name mariadb -e MARIADB_ROOT_PASSWORD='change-me' \
-p 127.0.0.1:3306:3306 mariadb:11
$ sudo conflux proxy 3306=127.0.0.1:3306 --ipv4 10.128.0.5/24$ mysql -h 10.128.0.5 -P 3306 -u app -p
If the server runs conflux up instead
# my.cnf [mysqld] bind-address = 10.128.0.5
Grant each account to a client's overlay IPv6 address, and have the client connect over IPv6. A grant to an IPv4 address in 198.18.0.0/15 applies to whichever peer arrives from that address.
Redis and Valkey
Share a cache or queue across machines and sites, with no port open to the internet.
# redis.conf: bind 127.0.0.1 -::1 (the default), and set a password requirepass change-me $ sudo conflux proxy 6379=127.0.0.1:6379 --ipv4 10.128.0.5/24
$ docker run -d --name valkey -p 127.0.0.1:6379:6379 \
valkey/valkey:8 valkey-server --requirepass 'change-me'
$ sudo conflux proxy 6379=127.0.0.1:6379 --ipv4 10.128.0.5/24$ redis-cli -h 10.128.0.5 -p 6379 --askpass $ valkey-cli -h 10.128.0.5 -p 6379 --askpass
If the server runs conflux up instead
# redis.conf bind 127.0.0.1 10.128.0.5 requirepass change-me
Bind the overlay address as well as loopback, and keep the password. The overlay decides who can connect, not who may run commands.
MongoDB
Let your services reach a document store across the overlay by address.
# mongod.conf: net.bindIp is 127.0.0.1 by default; leave it $ sudo conflux proxy 27017=127.0.0.1:27017 --ipv4 10.128.0.5/24
$ docker run -d --name mongo -p 127.0.0.1:27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD='change-me' \
mongo:8
$ sudo conflux proxy 27017=127.0.0.1:27017 --ipv4 10.128.0.5/24$ mongosh "mongodb://admin@10.128.0.5:27017/?authSource=admin"
If the server runs conflux up instead
# mongod.conf net: bindIp: 127.0.0.1,10.128.0.5 security: authorization: enabled
Bind the overlay address as well as loopback, and turn authorisation on.
Grafana
Serve dashboards to the whole team at a plain http://10.128.0.5/, with no reverse proxy to run.
# grafana.ini [server] http_addr = 127.0.0.1 root_url = http://10.128.0.5/ $ sudo conflux proxy 80=127.0.0.1:3000 --ipv4 10.128.0.5/24
$ docker run -d --name grafana -p 127.0.0.1:3000:3000 \
-e GF_SERVER_ROOT_URL=http://10.128.0.5/ grafana/grafana
$ sudo conflux proxy 80=127.0.0.1:3000 --ipv4 10.128.0.5/24# in a browser, on any machine that shares the taint http://10.128.0.5/
If the server runs conflux up instead
# grafana.ini [server] http_addr = 10.128.0.5 root_url = http://10.128.0.5:3000/
Grafana keeps its own port here, because a host port below 1024 needs privileges that an overlay port does not.
Gitea and Forgejo
Run a private Git forge with cloning over SSH and HTTP, reachable only from machines that share its taint.
# app.ini (Forgejo reads the same keys) [server] HTTP_ADDR = 127.0.0.1 ROOT_URL = http://10.128.0.5/ START_SSH_SERVER = true SSH_LISTEN_PORT = 2222 SSH_DOMAIN = 10.128.0.5 SSH_PORT = 22 $ sudo conflux proxy 80=127.0.0.1:3000 22=127.0.0.1:2222 --ipv4 10.128.0.5/24
$ docker run -d --name gitea -p 127.0.0.1:3000:3000 -p 127.0.0.1:2222:22 \
-e GITEA__server__ROOT_URL=http://10.128.0.5/ \
-e GITEA__server__SSH_DOMAIN=10.128.0.5 -e GITEA__server__SSH_PORT=22 \
gitea/gitea
$ sudo conflux proxy 80=127.0.0.1:3000 22=127.0.0.1:2222 --ipv4 10.128.0.5/24$ git clone git@10.128.0.5:team/app.git $ git clone http://10.128.0.5/team/app.git
If the server runs conflux up instead
# app.ini [server] HTTP_ADDR = 10.128.0.5 ROOT_URL = http://10.128.0.5:3000/
Over SSH, clients reach the host's own sshd at the overlay address, as on any network.
MinIO
Provide S3-compatible storage for backups and artefacts, with its web console alongside.
$ sudo conflux proxy 9000=127.0.0.1:9000 9001=127.0.0.1:9001 --ipv4 10.128.0.5/24
$ docker run -d --name minio -p 127.0.0.1:9000:9000 -p 127.0.0.1:9001:9001 \
-e MINIO_ROOT_USER=admin -e MINIO_ROOT_PASSWORD='change-me-please' \
-e MINIO_SERVER_URL=http://10.128.0.5:9000 \
minio/minio server /data --console-address :9001
$ sudo conflux proxy 9000=127.0.0.1:9000 9001=127.0.0.1:9001 --ipv4 10.128.0.5/24$ mc alias set overlay http://10.128.0.5:9000 admin 'change-me-please' $ mc ls overlay # the console, in a browser http://10.128.0.5:9001/
If the server runs conflux up instead
$ minio server /data --address 10.128.0.5:9000 --console-address 10.128.0.5:9001
Listen on the overlay address only, and set the server URL to the same address.
Prometheus
Query metrics from anywhere on the overlay, and scrape machines on other networks without exposing their exporters to those networks.
$ prometheus --web.listen-address=127.0.0.1:9090 $ sudo conflux proxy 9090=127.0.0.1:9090 --ipv4 10.128.0.5/24
$ docker run -d --name prometheus -p 127.0.0.1:9090:9090 prom/prometheus $ sudo conflux proxy 9090=127.0.0.1:9090 --ipv4 10.128.0.5/24
$ curl 'http://10.128.0.5:9090/api/v1/query?query=up'
If the server runs conflux up instead
# on each machine with an exporter, in the server's taint
$ sudo conflux proxy 9100=127.0.0.1:9100 --taint brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf --ipv4 10.128.0.7/24
# prometheus.yml, on a Prometheus server running conflux up in the same taint
scrape_configs:
- job_name: node
static_configs:
- targets: ['10.128.0.7:9100', '10.128.0.8:9100']Scraping makes outgoing connections, so the Prometheus server must run conflux up. Each exporter can stay on loopback behind a proxy. Give every exporter and the server the same --taint. An exporter started without one mints its own taint, and the server then sees DATA no for it.
Home Assistant
Reach Home Assistant from anywhere, with no port forward on the router and no cloud relay in between.
# Home Assistant listens on 8123 $ sudo conflux proxy 80=127.0.0.1:8123 --ipv4 10.128.0.5/24
$ docker run -d --name homeassistant --network=host \
-v /srv/homeassistant:/config ghcr.io/home-assistant/home-assistant:stable
$ sudo conflux proxy 80=127.0.0.1:8123 --ipv4 10.128.0.5/24# in a browser, on any machine that shares the taint http://10.128.0.5/
If the server runs conflux up instead
Home Assistant listens on every interface, so running conflux up on its host is enough. Home Assistant then answers at http://10.128.0.5:8123/.
Nextcloud
Give a team files, calendars and contacts that only the team's own machines can reach.
$ docker run -d --name nextcloud -p 127.0.0.1:8080:80 \
-v nextcloud:/var/www/html nextcloud
$ sudo conflux proxy 80=127.0.0.1:8080 --ipv4 10.128.0.5/24$ docker exec -u www-data nextcloud php occ config:system:set trusted_domains 1 --value=10.128.0.5 $ docker exec -u www-data nextcloud php occ config:system:set overwrite.cli.url --value=http://10.128.0.5
# in a browser, or as the server address in the desktop and mobile apps http://10.128.0.5/
If the server runs conflux up instead
Publish the container on all addresses with -p 8080:80, and add 10.128.0.5:8080 to trusted_domains in the same way.
Jellyfin
Stream your media library to every device that shares the taint, at home or away.
$ sudo conflux proxy 8096=127.0.0.1:8096 --ipv4 10.128.0.5/24
$ docker run -d --name jellyfin -p 127.0.0.1:8096:8096 \
-v /srv/jellyfin/config:/config -v /srv/media:/media jellyfin/jellyfin
$ sudo conflux proxy 8096=127.0.0.1:8096 --ipv4 10.128.0.5/24# in a Jellyfin app: Add server http://10.128.0.5:8096
If the server runs conflux up instead
Jellyfin listens on every interface, so conflux up on its host is enough.
Pi-hole and AdGuard Home
Run your own DNS resolver and filter for every machine on the overlay, wherever it is. This recipe shows how to publish a UDP service.
$ sudo conflux proxy 53=127.0.0.1:53 53/udp=127.0.0.1:53 80=127.0.0.1:8080 --ipv4 10.128.0.5/24
$ docker run -d --name pihole \
-p 127.0.0.1:53:53/tcp -p 127.0.0.1:53:53/udp -p 127.0.0.1:8080:80 \
-e FTLCONF_webserver_api_password='change-me' pihole/pihole
$ sudo conflux proxy 53=127.0.0.1:53 53/udp=127.0.0.1:53 80=127.0.0.1:8080 --ipv4 10.128.0.5/24$ dig @10.128.0.5 example.com # the admin interface, in a browser http://10.128.0.5/admin/
If the server runs conflux up instead
Bind the resolver as usual, and check that its listening setting accepts queries that arrive on the overlay interface.
Ollama and Open WebUI
Give your team a private chat interface that runs on your own GPU, without exposing the model API to anyone.
# Ollama stays on 127.0.0.1:11434, its default, and is never published $ open-webui serve --host 127.0.0.1 --port 8080 $ sudo conflux proxy 80=127.0.0.1:8080 --ipv4 10.128.0.5/24
$ docker network create ai
$ docker run -d --name ollama --network ai -v ollama:/root/.ollama ollama/ollama
$ docker run -d --name open-webui --network ai -p 127.0.0.1:3000:8080 \
-e OLLAMA_BASE_URL=http://ollama:11434 \
-v open-webui:/app/backend/data ghcr.io/open-webui/open-webui:main
$ sudo conflux proxy 80=127.0.0.1:3000 --ipv4 10.128.0.5/24# in a browser, on any machine that shares the taint http://10.128.0.5/
If the server runs conflux up instead
# to share Ollama's own API with your tools, on a host running conflux up $ OLLAMA_HOST=10.128.0.5 ollama serve
Do this only inside a compartment of trusted machines, because the API has no authentication of its own.