Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.local domain for each app using mDNS #1985

Open
giladgd opened this issue Feb 9, 2025 · 2 comments
Open

.local domain for each app using mDNS #1985

giladgd opened this issue Feb 9, 2025 · 2 comments

Comments

@giladgd
Copy link

giladgd commented Feb 9, 2025

It would be nice to have a different .local domain for each installed app instead of using a different port for each one.

To do this, you can use the following approach:

  • Use the multicast-dns package to resolve a given domain to the device running umbrelOS.
  • Use Traefik/Nginx or a custom proxy implementation in node.js to route incoming traffic based on the domain to the right service.

You can also make sure that each app gets a "subdomain" of umbrel.local (e.g. homebridge.umbrel.local).
There's no such concept of a subdomain for mDNS, but you can make it work with the same convention.

I'm already using this approach on my Raspberri Pi and it works great.
The nice thing about it is that I have multiple domains on my local network, without configuring any device with a custom DNS server or anything.

To resolve any .local domain you want, you can use this code snippet:

import os from "os";
import mdns from "multicast-dns";

const additionalHostnames = new Set([
    "homebridge.local",
    "umbrel.local",
    "homebridge.umbrel.local"
]);
const hostnameTtl = 300;

const mdnsResponder = mdns();

mdnsResponder.on("query", async (query) => {
    const answers = [];
    for (const question of query.questions) {
        if (additionalHostnames.has(question.name) && question.type == "A") {
            const ip = getNetworkIp();
            if (ip == null)
                continue;

            console.debug(`Answering to "${question.name}" mDNS query with IP "${ip}"`);
            answers.push({
                name: question.name,
                type: "A",
                ttl: hostnameTtl,
                data: ip
            });
        }
    }

    if (answers.length > 0)
        mdnsResponder.respond(answers);
});

function getNetworkIp() {
    const ifaces = os.networkInterfaces();
    for (const iface of Object.values(ifaces)) {
        for (const alias of iface) {
            if (alias.family === "IPv4" && alias.address !== "" && !alias.internal)
                return alias.address;
        }
    }

    return null;
}

I run the mDNS responder on the device itself and not inside of a docker container, so you might need some additional configuration to make it work through docker.

I think this would significantly improve the experience of using umbrelOS, and I wanted to show how easy it is to implement the resolver.

One implementation detail that you should take into account it that trying to resolve a .local domain from inside a docker container doesn't work without intervention.
You can either append the relevant domains to the /etc/hosts file of the host machine (to make it available to all containers, with the machine's external static IP) or by using the extra_hosts key in a docker compose service. For example:

services:
  homebridge:
    image: ...
    ...
    extra_hosts:
      - "homebridge.local:host-gateway"
      - "homebridge.umbrel.local:host-gateway"
@kauelima
Copy link

Expanding on this and making it more flexible, I think there should be a way to configure some data in each app compose file. Adding a custom url is one of them, people will use different methods for that, but after doing it, there should be a way to use that url on umbrel dashboard as well.

On this broader thing of customizing the compose we could even have env variables as well because multiple apps use those for advanced configuration. Today I can edit on the command line but all edits are lost upon updating umbrel.

@IMPranshu
Copy link

Well, it can be a feature, but instead of this, why not use a reverse proxy to try and access it from the internet?
Reverse-proxy doesn't need any modifications on the docker-compose.yml file and can also work after updating apps without the need of any modification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants