Modules¶
A module is one service of a Kiwi Network machine. A role picks a set
of modules, and kiwi-server renders them for one host into a stack: a
docker-compose.yml, the module config files and the host units. The host's
role script unpacks and starts the stack on first boot. The machine needs docker
and nothing else, because all templating happens on the machine that runs
kiwi-server.
kiwi-server modules -v lists every module with every setting and its default.
The modules¶
| Module | What it is | Runs on | Requires | Host ports |
|---|---|---|---|---|
vpn-server |
wg-easy: the entry point for every client and node. Its default route points at the VPN client for the double hop | master | none | 51820/udp |
vpn-client |
gluetun: the tunnel every host hangs off. On a node it uses the WireGuard config the master issued; on the master it connects to a commercial VPN (the exit) | both | none | none |
dns |
Pi-hole 6: an ad-blocking resolver for the mesh or the LAN that serves the fleet's own names and, optionally, the Mullvad SOCKS5 proxies' names | both | none | 53 (nodes) |
tor |
A Tor SOCKS5 proxy for mesh clients, pinned to a set of countries | both | none | none |
reverse-proxy |
nginx with TLS: one server block per service the other modules announce, with certificates from the fleet CA | node | none | 80, 443 |
cloud |
Nextcloud All-in-One: files, calendar, contacts, Talk | node | vpn-client, reverse-proxy | 3478 tcp+udp (Talk) |
vault |
Vaultwarden, the Bitwarden-compatible password manager | node | vpn-client, reverse-proxy | none |
downloader |
Transmission and JDownloader inside the VPN client's network namespace: no tunnel, no traffic | node | vpn-client | none |
gateway |
Policy routing on the host: LAN clients that use this machine as their gateway leave through the VPN client | node | vpn-client | none |
dhcp-relay |
Relays the LAN's DHCP broadcasts to the Pi-hole container, so Pi-hole can be the LAN's DHCP server | node | dns | 67/udp |
portainer |
Portainer CE: a web UI for the containers on this machine | both | none | none |
sftp |
An SFTP server on its own port, for fetching downloads from the LAN or the mesh | node | none | 2224/tcp |
Required modules are added automatically and rendered first.
Important settings¶
| Module | Setting | Default | Notes |
|---|---|---|---|
| vpn-server | wg_host |
(none) | the hostname or IP clients connect to |
wg_port |
51820 |
||
server_ip / wg_subnet |
10.8.0.1 / 10.8.0.0/24 |
||
isolated_subnet |
10.8.1.0/24 |
clients here see the server and the nodes, not each other | |
admin_from_mesh |
true |
wg-easy UI (51821) at the server's mesh address, never for isolated clients | |
| vpn-client | vpn_provider |
custom |
custom = a WireGuard config file (a node); or a gluetun provider (mullvad, protonvpn, airvpn, ivpn, windscribe, …) |
wireguard_config |
(none) | for custom: the client config wg-easy issued |
|
wireguard_private_key, wireguard_addresses |
(none) | for commercial providers | |
server_countries, server_cities |
(none) | where the exit is | |
dot_providers |
quad9 |
gluetun's DNS-over-TLS upstream | |
extra_dnat_rules |
[] |
e.g. 2222/tcp:172.128.0.1:22 for SSH from the mesh |
|
| dns | pihole_password |
(secret) | |
fallback_dns |
9.9.9.9;149.112.112.112 |
only while the master is unreachable | |
dhcp_enabled (+ dhcp_start, dhcp_end, dhcp_router) |
false |
Pi-hole as the LAN's DHCP server, with dhcp-relay | |
fleet_records |
true |
every host and service name at its mesh address | |
mullvad_socks |
false (true on master) |
see DNS | |
| tor | countries |
de,ch,at,nl,fr |
entry and exit nodes; everything else excluded (StrictNodes) |
socks_policy_accept |
10.8.0.0/16 |
who may use it | |
| cloud | nextcloud_datadir |
<stack directory>/knnc-data |
point it at a big disk |
memory_limit, upload_limit |
4096M, 50G |
||
startup_apps |
deck twofactor_totp tasks calendar contacts notes |
||
| vault | signups_allowed |
false |
turn on for the first account, then off again |
admin_token |
(empty) | empty keeps /admin off |
|
| downloader | download_dir |
(required) | |
jdownloader |
true |
||
| reverse-proxy | tls_fullchain, tls_privkey |
(fleet CA) | bring your own certificate |
hsts |
true |
||
| sftp | sftp_port |
2224 |
|
| portainer | admin_password |
(secret) | set before the first start, so no first-run page waits open |
Several admin interfaces bind to 127.0.0.1 by default: wg-easy (51821),
Pi-hole's plain-HTTP UI (8080), and the Nextcloud AIO master container, which
holds the docker socket (8080). Reach them through the reverse proxy, the
mesh, or ssh -L.
Default names¶
Each module announces its names to the reverse proxy and to the fleet's DNS, under the host's name:
| Service | Name |
|---|---|
| Nextcloud | cloud.<hostname> (admin: nc-admin.<hostname>) |
| Vaultwarden | vault.<hostname> |
| Transmission / JDownloader | dl.<hostname> / jd.<hostname> |
| Pi-hole | pihole.<hostname> |
| Portainer | portainer.<hostname> |
Container addresses¶
Addresses follow the v1 plan, so a migrated machine keeps them: vpn-client .2,
vpn-server .3, dns .4, reverse-proxy .5, cloud .6, vault .7, tor .8,
downloader .9, gateway .10, portainer .250, sftp .251. Any other module
counts up from .100. A host overrides one with container_ip: in that
module's block.
Writing a module¶
modules/<name>/
├── module.yaml what it is, what it needs, its settings
├── docker-compose.yml.j2 its services (merged into the host's compose file)
└── *.j2 any config file it ships (nginx.conf, torrc, …)
module.yaml declares the module's metadata, its dependencies, the host
ports to open, firewall rules (collected into gluetun's post-rules or applied by
the module itself), its templates and where their output goes, storage, host
integration (sysctls, kernel modules), the URLs printed when the role has
finished, nginx server blocks for the reverse proxy, and its user-facing
settings. The settings schema validates the fleet file and builds the GUI form.
Templates are Jinja2 and see the host context: the hostname and node type,
the container prefix and network, every module's address, the mesh and master
addresses, the fleet's domain and DNS records, every enabled module (has_…),
and every module's resolved settings.
Fedora CoreOS and uCore run docker with SELinux enabled, so bind mounts carry
the :z label (ro,z for read-only mounts). A mount of /var/run/docker.sock
or /lib/modules must never be labelled.
To try a new module, add it to a role's modules: (or a host's modules:
override), render a host and read output/<host>/<host>.stack/.
KIWI_SERVER_MODULES=/path/to/modules points kiwi-server at another module
tree. The full format reference is
docs/modules.md
in the repository.