ACME: Difference between revisions
→DNS challenge: mention services.nginx.virtualHosts.<name>.acmeRoot should also be set to null for nginx. |
Formatting, Wording, Prune |
||
| Line 3: | Line 3: | ||
= Basics = | = Basics = | ||
This process should generate three key files. The naming and usage of | This process should generate three key files. The naming and usage of the three key files is common to all programs and services in NixOS. | ||
the three key files is common to all programs and services in NixOS. | |||
We let <code>sslCertDir = | We let <code>sslCertDir = config.security.acme.certs.${domainName}.directory;</code> in the | ||
config.security.acme.certs.${domainName}.directory;</code> in the | |||
following paragraph. | following paragraph. | ||
| Line 18: | Line 16: | ||
* <code>sslServerKey = "/var/host.key";</code> Path to server SSL certificate key. Located at <code>"${sslCertDir}/key.pem"</code>. | * <code>sslServerKey = "/var/host.key";</code> Path to server SSL certificate key. Located at <code>"${sslCertDir}/key.pem"</code>. | ||
The <code>useACMEHost</code> option can be used with a wide variety of services[https://search.nixos.org/options?channel=25.05&query=useACMEHost], which simplifies the configuration and enables the automatic checking of correct private and public key permissions during nixos-rebuild. | |||
with a wide variety of services | |||
[https://search.nixos.org/options?channel=25.05&query=useACMEHost], | |||
which simplifies the configuration and enables the automatic checking | |||
of correct private and public key permissions during nixos-rebuild. | |||
= Obtaining a new certificate = | = Obtaining a new certificate = | ||
| Line 31: | Line 22: | ||
== Basics == | == Basics == | ||
You need to agree to the Terms of Service, provide an email address, | You need to agree to the Terms of Service, provide an email address, provide a domain name, and, if any, extra domain names. | ||
provide a domain name, and, if any, extra domain names. | |||
DNS challenge supports obtaining certificates for wildcard domains, | DNS challenge supports obtaining certificates for wildcard domains, such as <code>*.example.org</code>. | ||
such as <code>*.example.org</code>. | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
| Line 85: | Line 74: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== DNS challenge == | == DNS challenge == | ||
If you want to use the DNS challenge with nginx, you should also set [https://search.nixos.org/options?show=services.nginx.virtualHosts.%3Cname%3E.acmeRoot service.nginx.virtualHosts.<name>.acmeRoot] to <code>null</code>. | If you want to use the DNS challenge with nginx, you should also set [https://search.nixos.org/options?show=services.nginx.virtualHosts.%3Cname%3E.acmeRoot service.nginx.virtualHosts.<name>.acmeRoot] to <code>null</code>. | ||
| Line 110: | Line 97: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Certificates are getting generated for the domain | Certificates are getting generated for the domain <code>mx1.example.org</code> using the DNS provider <code>inwx</code>. See [https://go-acme.github.io/lego/dns<nowiki> upstream documentation] on available providers and their specific configuration for the </nowiki><code>credentialsFile</code> option. | ||
<code>mx1.example.org</code> using the DNS provider | |||
<code>inwx</code>. See [https://go-acme.github.io/lego/dns upstream | |||
documentation] on available providers and their specific configuration | |||
for the <code>credentialsFile</code> option. | |||
=== With Cloudflare as DNS provider === | === With Cloudflare as DNS provider === | ||
| Line 143: | Line 126: | ||
== Setting file permission with postRun == | == Setting file permission with postRun == | ||
Use the <code>security.acme.certs.*.postRun</code> to set permissions | Use the <code>security.acme.certs.*.postRun</code> to set permissions on the key directory and the key files: | ||
on the key directory and the key files: | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
| Line 175: | Line 157: | ||
Many service modules support obtaining certificates. But if you were | Many service modules support obtaining certificates. But if you were | ||
to configure certificate options separately for each service module, | to configure certificate options separately for each service module, it would be time-consuming and risks hitting the certificate renewal | ||
it would be time consuming and risks hitting the certificate renewal | |||
limits of the service provider. | limits of the service provider. | ||
Instead, centrally manage certificate options within the security.acme | Instead, centrally manage certificate options within the security.acme module; then point other services to security.acme with | ||
module; then point other services to security.acme with | |||
<code>useACMEHost</code> option. | <code>useACMEHost</code> option. | ||
| Line 194: | Line 174: | ||
services.nginx.virtualHosts."site2.example.org".useACMEHost = "example.org"; | services.nginx.virtualHosts."site2.example.org".useACMEHost = "example.org"; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
= Using Let's Encrypt Staging = | = Using Let's Encrypt Staging = | ||
For testing your Let's Encrypt configuration it makes sense to use their [https://letsencrypt.org/docs/staging-environment/ staging environment], because it offers less stringent rate limits. | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
Latest revision as of 18:56, 14 December 2025
NixOS supports automatic domain validation & certificate retrieval and renewal using the ACME protocol. Any provider can be used, but by default NixOS uses Let's Encrypt. The alternative ACME client lego is used under the hood.
Basics
This process should generate three key files. The naming and usage of the three key files is common to all programs and services in NixOS.
We let sslCertDir = config.security.acme.certs.${domainName}.directory; in the
following paragraph.
The three key files and their location are
sslServerCert = "/var/host.cert";Path to server SSL certificate. Located at"${sslCertDir}/fullchain.pem".
sslServerChain = "/var/ca.pem";Path to server SSL chain file. Located at"${sslCertDir}/chain.pem".
sslServerKey = "/var/host.key";Path to server SSL certificate key. Located at"${sslCertDir}/key.pem".
The useACMEHost option can be used with a wide variety of services[1], which simplifies the configuration and enables the automatic checking of correct private and public key permissions during nixos-rebuild.
Obtaining a new certificate
Basics
You need to agree to the Terms of Service, provide an email address, provide a domain name, and, if any, extra domain names.
DNS challenge supports obtaining certificates for wildcard domains, such as *.example.org.
let
domainName = "example.org";
in
{
security.acme = {
acceptTerms = true;
defaults.email = "admin@${domainName}";
certs = {
"${domainName}" = {
group = config.services.nginx.group;
extraDomainNames = [
"mail.${domainName}"
"www.${domainName}"
];
};
};
};
}
HTTP challenge
To use HTTP challenge, you need to have your DNS record pointing to this computer. You also need to enable a web server and allow plaintext traffic on port 80. This example is based on the previous section:
security.acme = {
defaults.webroot = "/var/lib/acme/acme-challenge/";
# We are using nginx as webserver, therefore set correct key permissions
certs."${domainName}".group = config.services.nginx.group;
};
# for acme plain http challenge
networking.firewall.allowedTCPPorts = [ 80 ];
# webserver for http challenge
services.nginx = {
enable = true;
virtualHosts."${domainName}" = {
forceSSL = true;
useACMEHost = "${domainName}";
locations."/.well-known/".root = "/var/lib/acme/acme-challenge/";
};
};
DNS challenge
If you want to use the DNS challenge with nginx, you should also set service.nginx.virtualHosts.<name>.acmeRoot to null.
With inwx as DNS provider
Following example setup generates certificates using DNS validation. Let's Encrypt ToS has to be accepted. Further the contact mail admin+acme@example.com is defined.
security.acme = {
acceptTerms = true;
defaults.email = "admin+acme@example.org";
certs."mx1.example.org" = {
dnsProvider = "inwx";
# Supplying password files like this will make your credentials world-readable
# in the Nix store. This is for demonstration purpose only, do not use this in production.
environmentFile = "${pkgs.writeText "inwx-creds" ''
INWX_USERNAME=xxxxxxxxxx
INWX_PASSWORD=yyyyyyyyyy
''}";
};
};
Certificates are getting generated for the domain mx1.example.org using the DNS provider inwx. See [https://go-acme.github.io/lego/dns upstream documentation] on available providers and their specific configuration for the credentialsFile option.
With Cloudflare as DNS provider
The next example issues a wildcard certificate and uses Cloudflare for validation. We're also adding the group "nginx" here so that the certificate files can be used by nginx later on.
security.acme = {
acceptTerms = true;
defaults.email = "admin@example.org";
certs = {
"example.org" = {
domain = "*.example.org";
group = "nginx";
dnsProvider = "cloudflare";
# location of your CLOUDFLARE_DNS_API_TOKEN=[value]
# https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#EnvironmentFile=
environmentFile = "/home/admin/cloudflare";
};
};
};
TLS challenge
Todo.
Integration with service modules
Setting file permission with postRun
Use the security.acme.certs.*.postRun to set permissions on the key directory and the key files:
security.acme.certs.${domainName}.postRun = ''
# set permission on dir
${pkgs.acl}/bin/setfacl -m \
u:nginx:rx,u:turnserver:rx,u:prosody:rx,u:dovecot2:rx,u:postfix:rx \
/var/lib/acme/${domainName}
# set permission on key file
${pkgs.acl}/bin/setfacl -m \
u:nginx:r,u:turnserver:r,u:prosody:r,u:dovecot2:r,u:postfix:r \
/var/lib/acme/${domainName}/*.pem
'';
Reload services after renewal
security.acme.certs.${domainName}.reloadServices = [
"prosody"
"coturn"
"nginx"
"dovecot2"
"postfix"
];
Using useACMEHost
Many service modules support obtaining certificates. But if you were to configure certificate options separately for each service module, it would be time-consuming and risks hitting the certificate renewal limits of the service provider.
Instead, centrally manage certificate options within the security.acme module; then point other services to security.acme with
useACMEHost option.
security.acme.certs."example.org".extraDomainNames = [
"syncplay.example.org"
"reposilite.example.org"
"site2.example.org"
];
services.syncplay.useACMEHost = "example.org";
services.reposilite.useACMEHost = "example.org";
services.nginx.virtualHosts."site2.example.org".useACMEHost = "example.org";
Using Let's Encrypt Staging
For testing your Let's Encrypt configuration it makes sense to use their staging environment, because it offers less stringent rate limits.
security.acme.defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
See also
- NixOS manual on SSL/TLS Certificates with ACME