happyDomain is an interface that centralize your domain names and reduces the usual friction points.
Our interface centralizes your domains and includes all the features you’d expect in 2025 for effortless domain management.
We built happyDomain because we want to save operational teams time by giving them superpowers:
to have all the power of domain names, without having to read and learn all the new standards, by staying focused on needs.
Here’s an overview of happyDomain’s main features:
consolidate domain names from over 45 domain name providers or authoritative servers,
guide administrators with clear forms,
clearly visualize the changes that will be propagated,
keep a history of changes made to the zone,
return to a previous zone status with a single click,
group records by services/needs: email, delegation, server, load balancing, etc.
abstract all technical complexity into a logical view,
import/export the zone as a standard file,
keep track of actions for later auditing,
automate tasks via a REST API.
We are a free and open source project: you can use the official interface available at www.happydomain.org, or install it at home.
The source code is available on framagit, GitLab or GitHub: you can consult it, copy it, give your opinion, report bugs or make modifications, as you wish.
Join us on Matrix! đź’¬
We’re building a community of users who want to regain control of their DNS zones.
Join us!
happyDomain is a service that centralizes the management of your domain names from different registrars, hosts or authoritative DNS servers.
It’s a web interface and a REST API that offer a simpler domain experience than most of the interfaces we usually see for managing domains, including features we’d expect to see in 2025.
At happyDomain, we want to make sure that domain names and DNS are no longer a daunting experience, but instead give you all the tools you need to understand and make changes in peace.
Can’t wait to get started? Follow the guide!
1. Online or on premise
happyDomain is free (as in free speech) software.
This means, among other things, that you can install it at home.
If you’re not familiar with the command line, or if you’d like to evaluate the software quickly, we recommend that you create an account on our online service.
happyDomain will connect to your hosting provider (or local authoritative server).
Your domain remains hosted where it is today; using happyDomain does not imply any transfer or change of ownership.
When you log on to happyDomain for the first time, a wizard will guide you through the process of linking your first domain.
Depending on your hosting provider, the procedure will differ.
But for most, you’ll need to go to your host’s customer account, and request an API key.
For OVH, the procedure is simplified, as all you have to do is follow the instructions and authorize happyDomain to access the domain-related part of your account.
If you have your own authoritative server, you’ll need to get the keys to interact with it either from the administrator or by looking in the configuration.
Once the connection between happyDomain and your first host or server has been established, all you have to do is select the domains you want happyDomain to manage.
3. Consult the DNS zone
The DNS zone refers to the technical content of your domain.
To view the zone corresponding to a domain, click on the domain name that appears on the happyDomain home page.
After a few seconds of fully automatic import and analysis, you’ll immediately see a list of registrations or services as they are currently distributed to your visitors.
About the “services”
The complexity of DNS stems in part from the mismatch between purely technical constraints and the actual use of records.
happyDomain tries to simplify this by grouping technical records under their concrete uses. This is what we call “service”.
4. Modify a record
In the zone display screen, click on a record to view its details.
Each DNS record has particular characteristics and constraints.
Context-sensitive help tries as far as possible to give you the essential information to guide you through the modifications you need to make.
When you make a modification to a record, it is not directly published to your host or server.
5. Distribute your changes
Once you’ve made all the changes you need, click on the “Distribute my changes” button.
A dialog box will appear showing you the exact changes that will be applied to your host.
At this point, there’s still time to select the changes you don’t want/no longer want to be applied.
Before validating the window, you can add a message that will be recorded in the log, enabling you to quickly recall the reason for the change.
So now you know how to use happyDomain’s main features.
If you encounter any problems or have any ideas for improvement, please let us know.
Installation and deployment
Depending on your concerns, happyDomain can be deployed in different kind of environment.
Thanks to some modularity, there is certainly a path to your needs.
Follow this installation guide if you want to use happyDomain directly on your machine, as simply as possible, without user management.
This is a simple configuration, suitable for evaluating happyDomain or for using it without authentication on your own machine, or with authentication provided by a reverse proxy.
You can deploy it using Docker or by downloading one of the available executables. Both methods are described below.
Via Docker/podman
If you are familiar with Docker (or podman), you can have happyDomain up and running in seconds with the following command:
docker container run -e HAPPYDOMAIN_NO_AUTH=1 -p 8081:8081 happydomain/happydomain
If you want to make the data persistent, you need to add a volume:
Start by downloading the executable matching your processor architecture from: https://get.happydomain.org/master/.
The darwin versions are for macOS, while the linux versions are for GNU/Linux. All distributed versions are static and should work regardless of your libc (GNU libc in most cases, musl for Alpine, …).
Make the binary you downloaded executable: chmod +x happydomain-OS-ARCH.
Run the binary: HAPPYDOMAIN_NO_AUTH=1 ./happydomain-OS-ARCH.
The HAPPYDOMAIN_NO_AUTH=1 option is a parameter that tells happyDomain not to require authentication: domains are shared among all incoming connections. In practice, this automatically creates a default user and disables all login, account registration, and related features.
Can I expose it on the Internet like this?
No! It is essential that you do not expose your happyDomain instance on the Internet without authentication.
Without it, all its content would be accessible to anyone, and they could take control of your domain(s).
Always use a reverse proxy such as nginx, Apache, HAproxy, Traefik, … adding a filtering or basic authentication step.
For example, you can filter the IPs that can access the service.
Here is a sample nginx configuration filtering IPs (using the allow directive):
happyDomain is sponsored by Docker.
You’ll find the official container image on the Docker Hub.
This image will run happyDomain as a single process, with a LevelDB database (similarly to sqlite, LevelDB is stored on disk, no need to configure anything).
Supported tags and architectures
All tags are build for amd64, arm64 and arm/v7 and are based on alpine.
Currently, available tags are:
latest: this is a the most up to date version, corresponding to the master branch.
Using this image
For testing purpose
You can test happyDomain or use it for your own usage, with the option HAPPYDOMAIN_NO_AUTH=1: this will automatically creates a default account, and disable all features related to the user management (signup, login, …).
docker run -e HAPPYDOMAIN_NO_AUTH=1 -p 8081:8081 happydomain/happydomain
Data are stored in /data directory. If you want to keep your settings from one run to another, you’ll need to attach this directory to a Docker managed volume or to a directory on your host:
happyDomain needs to send e-mail, in order to verify addresses and doing password recovery, so you need basically to configure a SMTP relay.
Use the options HAPPYDOMAIN_MAIL_SMTP_HOST, HAPPYDOMAIN_MAIL_SMTP_PORT (default 25), HAPPYDOMAIN_MAIL_SMTP_USERNAME and HAPPYDOMAIN_MAIL_SMTP_PASSWORD for this purpose:
If you prefer using a configuration file, you can place it either in /data/happydomain.conf to use the volume, or bind your file to /etc/happydomain.conf:
docker run -v happydomain.conf:/etc/happydomain.conf -p 8081:8081 happydomain/happydomain
Extend the base image
By default, happyDomain uses sendmail, if you prefer, you can create you own image with the package ssmtp:
FROM happydomain/happydomain
RUN apk --no-cache add ssmtp
COPY my_ssmtp.conf /etc/ssmtp/ssmtp.conf
Admin Interface
happyDomain exposes some administration command through a unix socket. The docker container contains a script to access this admin part: hadmin.
This is in fact a wrapper above curl, but you have to start by the URL, and place options after it.
Configuration
happyDomain respects the methodology 12 factor and allows to act on the application configuration in several ways.
How do I configure happyDomain?
It is possible to configure happyDomain in three different ways: configuration file, environment, command line. All options are available for each of these mechanisms.
The precedence, when an option is defined by several mechanisms simultaneously, is that an option present in a configuration file will be overwritten by the environment, which will be overwritten by an option passed on the command line
Configuration by file
When the application is launched, the first configuration file from the following list will be used:
./happydomain.conf
$XDG_CONFIG_HOME/happydomain/happydomain.conf
/etc/happydomain.conf
Only the first existing file is taken into account. It is not possible to have part of its options in /etc/happydomain.conf and part in ./happydomain.conf, only the latter configuration file will be taken into account.
It is possible to specify a custom path by adding it as an additional parameter to the command line. Thus, to use the configuration file located at /etc/happydomain/config, we would use :
./happydomain /etc/happydomain/config
Configuration file format
Comments line has to begin with #, it is not possible to have comments at the end of a line, by appending # followed by a comment.
Place on each line the name of the config option and the expected value, separated by =. For example:
The complete list of configurable items can be listed by calling happyDomain with the -h or --help option.
Here is a list of the main options:
General parameters
bind
Bind port/socket to use to expose happyDomain.
admin-bind
Bind port/socket to use to expose the administration API.
default-ns
Address and port of the name resolver server to be used by default when name resolution is required.
dev
URL to which all requests related to the graphical interface will be returned.
externalurl
URL of the service, as it should appear in emails and content to the public.
disable-providers-edit
Disallow all actions on provider (add/edit/delete), eg. for demo mode.
Page layout
custom-head-html
String to be placed before the end of the HTML header.
custom-body-html
String to be placed before the end of the HTML body.
hide-feedback-button
Hide the icon on page that permit to give feedback.
msg-header-text
Custom message banner to add at the top of the app.
msg-header-color
Background color class of the banner added at the top of the app (default “danger”, can be primary, secondary, info, success, warning, danger, light, dark, or any bootstrap color class).
Data storage
storage-engine
Allows you to choose the data storage mechanism among all supported mechanisms.
LevelDB (storage-engine=leveldb)
leveldb-path
Path to the folder containing the LevelDB database to use.
Defines the name and address of the sender of emails sent by the service.
Note that without the mail-smtp-* options, happyDomain will use the sendmail binary to send mail. This can be coupled with the msmtp or ssmtp packages, for example, to set the parameters for the whole system.
mail-smtp-host
IP or host name of the SMTP server to use.
mail-smtp-port
Port to use on the remote server.
mail-smtp-username
When authentication is required on the remote server, username to use.
mail-smtp-password
When authentication is required on the remote server, password to use.
Authentication
no-auth
Disables the notion of users and access control. A default account is used.
disable-embedded-login
Disables the internal user/password login in favor of external-auth or OIDC.
disable-registration
Forbids new account creation through public form/API (still allow registration from external services).
external-auth
URL base of the authentication and registration service to be used instead of the embedded login system.
happyDomain supports user authentication via the OpenID Connect protocol. If you have an authentication provider (Auth0, Okta, …) or Identity Provider (IdP) software such as Keycloak, Authentik, Authelia, … you can use it with happyDomain, and possibly dispense with the embedded registration and authentication system.
Configuration
To enable OpenID Connect, you’ll need to set the following options:
The PROVIDER_URL setting should be defined to the base URL of your authentication service.
The service should expose a settings discovery endpoint (at /.well-known/openid-configuration).
OpenID Connect provider settings
You’ll need to setup a new application in your authentication provider, with the following settings:
This documentation will guide you through configuring BIND to enable Dynamic DNS and connect your domains to happyDomain.
Configure BIND to enable Dynamic DNS
First, you need to edit the main BIND configuration file (usually /etc/named.conf or /etc/bind/named.conf depending on your distribution) to add a secret that will be shared between happyDomain and BIND to authenticate the changes. Then you must indicate which domains will be managed by happyDomain.
Adding a Shared Secret
Under the main key section of your configuration, add the following key:
Replace <SOME_SECRET> with a string obtained using openssl rand -base64 48.
Creating an Authorization Rule for happyDomain
In addition to the key, you must specify how the key can be used by defining an ACL and allowing updates from it.
Add the following ACL to your configuration:
acl "happydomain_acl" {
key happydomain;
};
Allowing Updates for Each Zone
Now that you have created a rule allowing the happydomain key to make changes, you need to indicate to which zones this rule applies.
For each zone, you must add an update-policy statement referencing the happydomain_acl ACL:
For example, for an existing happydomain.org zone, add the update-policy statement as follows:
zone "happydomain.org" {
type master;
file "/var/named/happydomain.org.db";
update-policy {
grant happydomain_acl name happydomain.org. ANY;
};
};
The update-policy statement is a list, so you may already have other policies in this list. In this case, just add the grant statement for happydomain_acl.
Allowing Updates for All Zones
If you manage many zones, it may be more convenient to set the default authorization for all zones. In this case, you can use a globalupdate-policy in the options section:
options {
update-policy {
grant happydomain_acl zonesub ANY;
};
};
This will apply the update-policy to all zones, allowing the happydomain_acl to update any record.
Apply the Configuration
After modifying the configuration file, reload the BIND service to apply the changes:
First, you have to edit the main knot configuration file (usually /etc/knot/knot.conf) to add a secret that will be shared between happyDomain and knot to authenticate the changes. Then you have to indicate which domains will be managed by happyDomain.
Adding a shared secret
Under the main key section of your configuration, add the following key:
The acl element is a list, so you may already have other acl elements in this list. In this case you just need to add the acl_happydomain element to the already existing list.
You have to add this acl element for each zone, unless you use the following trick.
Associate the authorization to all zones
If you manage many zones, it may be more convenient to set the default authorization for all zones. In this case, instead of the previous section, we will modify the default template:
Key Name : corresponds to id in knot’s configuration ;
Key Algorithm : corresponds to algorithm ;
Secret Key : corresponds to secret.
Once the provider is added, it does not allow you to list existing domains, but you can still manually add all your domains.
OVH API configuration
In order to manage domains hosted by OVH, an additional configuration step is required.
Authentication to the OVH API works in 2 stages:
First, you need to register an application (e.g. happyDomain). An application has an identifier and a secret that must be entered as a happyDomain parameter.
For each OVH account you wish to manage, the happyDomain interface redirects you to the OVH page for creating the Consumer key.
The application must be created from an existing OVH account, regardless of whether it has domains or not; it is a matter of identifying the person responsible for implementing the designated application.
Access to account data, and in particular to the domains they manage, is via the Consumer key.
Test a domain
{class=“children children-type-tree children-sort-”}
Subsections of Features
Centralize your domains
Your domains
The home page presents the list of all the domains managed by happyDomain, whatever their host:
Click one of the domains to start make changes (add a sub-domain, add a service, …).
Your registries and domain hosts
On the right, you can see the list of the different hosting providers for your:
The hosters of your domains](hosters-list.png)
You can add new host by clicking on the + button in the table header.
Clicking on a row in this table will filter the list of domains to show only domains managed by this host.
You will also see, if the host allows you to list the domains that belong to you, the domains that you can add to happyDomain:
To view the entire list again, simply click on the selected host again.
Modify or remove a host
If you find an error or no longer need a hosting provider, click on the … on the line of the host concerned. You will then be able to choose between update information or delete the host:
Note that you will not be able to remove the host as long as domains referring to it exist in the list on the left.
Add a domain
You have a new domain you want to manage in happyDomain? Start by entering its name in the field below the list. You will then be guided to the [to choose the host] screen (/en/pages/domain-new/).
The field does not show when a host is selected on the right. Unless this host does not allow to list:
In this case, validating the field will automatically search for the new domain with the selected host, as indicated by the message just above the field.
List your name providers
You can access this page by clicking on the the top menu link “The hosts of my domains”.
Your registries and domain hosts
This page shows only the list of registries and domain hosts you have added to your account, and allows you to add more.
You can add a new host by clicking on the “+” button at the top of the page.
By clicking on a row of the table, you will access the parameters used by happyDomain to contact this host.
This is where you’ll be able to modify the name you gave to this host, and where you’ll be able to modify the access parameters.
Add a provider
You access this screen by clicking on the “My domain providers” link in the top menu, then by clicking on the “+ Add a new domain host” button.
Compatible registries and domain hosts
When you want to add a domain, the first step is to determine at which host it is located.
In this screen, you will be asked to select the host among the list of compatible hosts where you have your:
More will be added later, if you can’t find yours, contact us!
Hosting provider settings
You access this screen either:
when you want to add a host, after having selected the provider,
when you want to change the connection settings between happyDomain and a host, for example on the home page.
Connection name
In order to find you among the different hosts, the first field you are asked for is a name.
This name will only be used to allow you to easily identify the host of your domain, if you have several.
Other fields
Each host needs different information to establish a connection with happyDomain.
Follow the instructions on each screen.
Import a domain
Importing a domain into happyDomain does not make happyDomain the owner of your domain. This action does not involve any changes to your usual hosting provider. happyDomain will contact your hosting provider or server to check which services are currently registered.
You can see on this screen the different hosts you have already configured.
If your domain is part of one of the listed accounts, just click on it, it will be added automatically.
If you haven’t added the host yet, you can do it now by following the link “Add now!”.
Your domain
Need help to write this Documentation page
Publish modifications
When you make a change in happyDomain, it is not directly passed on to your host or server.
Once you’ve made all the changes you wish to be propagated, click on the “Distribute my changes” button.
A window will open showing exactly which concrete changes will be passed on to your host or server.
If at this stage you don’t want to apply all the changes, you can uncheck some of them.
Don’t forget to enter a message in the appropriate field: this message will be recorded in your log.
Later, when you need to see what changes you’ve made, it might be simpler to read “Changing host from Wordpress to Alwaysdata” rather than trying to interpret IP changes, …
View change history
Every time you publish changes with happyDomain, they are recorded in a log. This log allows you to easily retrieve the status of your domains as they were previously deployed, and to see when you made each change.
Set up your profile
You access this page by clicking on the top menu “My Account” link.
Account Settings
The screen is divided into three parts. The first one will allow you to change the settings related to your account: such as the language of the interface or the way the contextual help is displayed.
Change password
The second part of the screen allows you to change the password.
Change account email address
It is currently not possible to change the email address of your account. We invite you to contact us if you wish to change it.
Delete your account
The last part of the page allows you to delete your happyDomain account.
Once the deletion is validated, your account will no longer be accessible and all data belonging to you will be deleted shortly after, during a regular database cleanup.
From the moment you delete your account, your domains will continue to respond according to the last update you made on happyDomain. The deletion will not affect the distributed data.
The E-Mail service allows you to define an e-mail server on the zone, as well as the zone settings for sending/receiving e-mails.
Plugins
Plugins are external pieces of code — shared libraries loaded at startup — that extend happyDomain’s functionality without recompiling the server. An operator simply drops a .so file into a configured directory, and happyDomain picks it up automatically on the next start.
happyDomain supports external test plugins — shared libraries (.so files) that add domain or service health checks to a running instance. Plugins are loaded at startup without recompiling the server; the operator simply drops a .so file into a configured directory.
How it works
A plugin receives a set of options assembled from several configuration scopes, runs a check (HTTP call, DNS query, …), and returns a result with a status level and an optional detailed report. Results are stored and displayed in the happyDomain UI alongside the domain or service they concern.
When happyDomain starts it scans every directory listed in the plugins-directories configuration option. For each file it finds, it:
Opens the shared library.
Looks up the exported symbol NewTestPlugin.
Calls NewTestPlugin() to obtain a plugin value.
Registers the plugin under each name returned by PluginEnvName().
If the file is not a valid Go plugin, if NewTestPlugin is missing, or if it returns an error, a warning is logged and the file is skipped. The server always starts regardless of individual plugin load failures.
The replace directive points to your local happyDomain checkout, ensuring the plugin is compiled against the exact same types as the server.
Warning
A Go plugin and the host process share the same runtime. They **must** be compiled with the same Go toolchain version and the same versions of every shared dependency. Any mismatch produces a hard error at load time.
The constructor is a good place to perform one-time initialisation (open config files, create an HTTP client, …). Return an error if the plugin cannot function.
Naming — PluginEnvName()
Returns one or more short, lowercase identifiers. These names are used to look up the plugin via the API and to key its stored configuration.
Choose names that are unlikely to collide (e.g. "zonemaster", "matrixim") and keep them stable across versions because they are persisted alongside user configuration. If two loaded plugins claim the same name, the second one is skipped and a conflict is logged.
Version and availability — Version()
Describes the plugin and controls where it appears in the UI:
func (p*MyPlugin) Version() happydns.PluginVersionInfo {
returnhappydns.PluginVersionInfo{
Name: "My Plugin",
Version: "1.0",
AvailableOn: happydns.PluginAvailability{
ApplyToDomain: true,
ApplyToService: false,
LimitToProviders: nil, // nil or empty = all providersLimitToServices: []string{"abstract.MatrixIM"},
},
}
}
Field
Type
Description
ApplyToDomain
bool
Plugin can be run against a whole domain
ApplyToService
bool
Plugin can be run against a specific DNS service
LimitToProviders
[]string
Restrict to certain DNS provider identifiers (empty = no restriction)
LimitToServices
[]string
Restrict to certain service type identifiers, e.g. "abstract.MatrixIM" (empty = no restriction)
Both ApplyToDomain and ApplyToService may be true simultaneously.
Options — AvailableOptions()
Options are key/value pairs (map[string]any) that configure each test run. They are declared grouped by scope, i.e. who sets them and how long they persist:
Before RunTest is called, happyDomain merges all scoped values from least specific (admin) to most specific (run-time). More-specific values silently override less-specific ones. RunTest always receives a single flat map and does not need to know which scope each value came from.
Option fields
Each option is a PluginOptionDocumentation (an alias for Field):
Field
Type
Description
Id
string
Required. Key used in the PluginOptions map inside RunTest
Type
string
Input type: "string", "select"
Label
string
Human-readable label shown in the UI
Placeholder
string
Placeholder text for the input field
Default
any
Default value pre-filled in the form
Choices
[]string
Options for "select" inputs
Required
bool
Whether the field must be filled before running
Secret
bool
Marks the field as sensitive (e.g. an API key)
Hide
bool
Hides the field from the user entirely
Textarea
bool
Renders a multiline text area
Description
string
Help text displayed below the field
AutoFill
string
Populate the field automatically from context (see below)
Auto-fill
When AutoFill is set, happyDomain populates the field from the test context; the user is not prompted:
Constant
String value
Populated with
happydns.AutoFillDomainName
"domain_name"
FQDN of the domain under test, e.g. "example.com."
happydns.AutoFillSubdomain
"subdomain"
Subdomain relative to the zone, e.g. "www" — service-scoped tests only
happydns.AutoFillServiceType
"service_type"
Service type identifier, e.g. "abstract.MatrixIM" — service-scoped tests only
RunTest receives the merged option map and a metadata map (reserved for future use), performs the check, and returns a PluginResult.
Always assert option values to a concrete type before use — the map holds any:
func (p*MyPlugin) RunTest(optshappydns.PluginOptions, _map[string]string) (*happydns.PluginResult, error) {
domain, ok:=opts["domainName"].(string)
if !ok||domain=="" {
returnnil, fmt.Errorf("domainName option is required")
}
// … perform the check …return&happydns.PluginResult{
Status: happydns.PluginResultStatusOK,
StatusLine: "All good",
Report: myStructuredReport,
}, nil}
Return a non-nil error only for unexpected failures (network errors, invalid configuration). For expected check failures — the monitored service is down, DNS records are wrong — return a PluginResult with an appropriate status and a human-readable StatusLine.
Result fields
Field
Type
Description
Status
PluginResultStatus
Overall result level (see below)
StatusLine
string
Short summary displayed in the UI
Report
any
Any JSON-serialisable value stored as structured diagnostic data
Status levels (worst → best)
Constant
Meaning
PluginResultStatusKO
Check failed
PluginResultStatusWarn
Check passed with warnings
PluginResultStatusInfo
Informational, no action required
PluginResultStatusOK
Check fully passed
Building
go build -buildmode=plugin -o happydomain-plugin-test-myplugin.so \
git.happydns.org/happyDomain/plugins/myplugin
Minimal Makefile:
PLUGIN_NAME=myplugin
TARGET=../happydomain-plugin-test-$(PLUGIN_NAME).so
all:$(TARGET)$(TARGET): *.go
go build -buildmode=plugin -o $@ git.happydns.org/happyDomain/plugins/$(PLUGIN_NAME)
The prefix happydomain-plugin-test- is a convention; happyDomain loads every file in the plugin directories regardless of its name.
Multiple directories may be listed as a comma-separated value.
3. Check the logs
On a successful load:
Plugin My Plugin loaded (version 1.0)
On a name conflict or load error a warning is logged with the filename and reason.
Reference implementations
Two plugins are bundled in this directory:
matrix/ — queries the Matrix federation tester API. Demonstrates ApplyToService with LimitToServices and AdminOpts for the backend URL.
zonemaster/ — drives the Zonemaster JSON-RPC API, polls for completion, and maps results to severity levels. Demonstrates AutoFillDomainName, UserOpts for language selection, and multi-level status mapping.