A common use case you might have is to host services and applications which are only reachable within your clan.
This guide explains how to set up such secure, clan-internal web services using a custom top-level domain (TLD) with SSL certificates.
Your services will be accessible only within your clan network and secured with proper SSL certificates that all clan machines trust.
By combining the coredns and certificates clan services, you can:
.c)https://api.c, https://dashboard.c)The setup uses two clan services working together:
https://service.c.c domains, the query is forwarded to your clan's CoreDNS server. All
other domains will be resolved as usual.The following setup assumes you have a VPN (e.g. ZeroTier) already running. The IPs configured in the options below will probably the ZeroTier IPs of the respective machines.
The CoreDNS service has two roles:
server: Runs the DNS server for your custom TLDdefault: Makes machines use the DNS server for TLD resolution and allows exposing servicesAdd this to your inventory:
inventory = {
machines = {
dns-server = { }; # Machine that will run the DNS server
web-server = { }; # Machine that will host web services
client = { }; # Any other machines in your clan
};
instances = {
coredns = {
# Add the default role to all machines
roles.default.tags = [ "all" ];
# DNS server for the .c TLD
roles.server.machines.dns-server.settings = {
ip = "192.168.1.10"; # IP of your DNS server machine
tld = "c";
};
# Machine hosting services (example: ca.c and admin.c)
roles.default.machines.web-server.settings = {
ip = "192.168.1.20"; # IP of your web server
services = [ "ca" "admin" ];
};
};
};
}; The certificates service also has two roles:
ca: Sets up the certificate authority on a serverdefault: Makes machines trust the CA and allows them to request certificatesAdd this to your inventory:
inventory = {
instances = {
# ... coredns configuration from above ...
certificates = {
# Set up CA for .c domain
roles.ca.machines.dns-server.settings = {
tlds = [ "c" ];
acmeEmail = "admin@example.com"; # Optional: your email
};
# Add default role to all machines to trust the CA
roles.default.tags = [ "all" ];
};
};
}; Here's a complete working example:
nventory = {
machines = {
caserver = { }; # DNS server + CA + web services
webserver = { }; # Additional web services
client = { }; # Client machine
};
instances = {
coredns = {
# Add the default role to all machines
roles.default.tags = [ "all" ];
# DNS server for the .c TLD
roles.server.machines.caserver.settings = {
ip = "192.168.8.5";
tld = "c";
};
# machine hosting https://ca.c (our CA for SSL)
roles.default.machines.caserver.settings = {
ip = "192.168.8.5";
services = [ "ca" ];
};
# machine hosting https://blub.c (some internal web-service)
roles.default.machines.webserver.settings = {
ip = "192.168.8.6";
services = [ "blub" ];
};
};
# Provide https for the .c top-level domain
certificates = {
roles.ca.machines.caserver.settings = {
tlds = [ "c" ];
acmeEmail = "admin@example.com";
};
roles.default.tags = [ "all" ];
};
};
}; DNS resolution can be tested with:
# On any clan machine, test DNS resolution
nslookup ca.c
nslookup blub.c You should also now be able to visit https://ca.c to access the certificate authority or visit https://blub.c to access your web service.
# On the DNS server machine
systemctl status coredns # Check if the right nameservers are configured
cat /etc/resolv.conf
systemctl status systemd-resolved # Query the DNS server directly
dig @192.168.8.5 ca.c # On the CA machine
systemctl status step-ca
systemctl status nginx # Test certificate trust
curl -v https://ca.c
openssl s_client -connect ca.c:443 -verify_return_error # View ACME certificates
ls /var/lib/acme/
journalctl -u acme-ca.c.service