ACME: Difference between revisions

From NixOS Wiki
imported>Onny
Initial page
 
WoutSwinkels (talk | contribs)
 
(13 intermediate revisions by 7 users not shown)
Line 2: Line 2:


== Setup ==
== Setup ==
=== DNS-01 Challenge ===
Following example setup generates certificates using DNS validation. [https://letsencrypt.org/repository/ Let's Encrypt ToS] has to be accepted. Further the contact mail <code>admin+acme@example.com</code> is defined.


Following example setup generates certificates using DNS validation.
<syntaxhighlight lang="nix">
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
    ''}";
  };
};
</syntaxhighlight>
 
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 upstream documentation] on available providers and their specific configuration for the <code>credentialsFile</code> option.
 
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.<syntaxhighlight lang="nix">
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";
    };
  };
};
</syntaxhighlight>
 
=== HTTP-01 Challenge ===
Besides DNS validation it is also possible to obtain certificates by placing a file on your webserver at <code>http://example.org/.well-known/acme-challenge</code>. Instead of using the <code>dnsProvider</code> option, we use the <code>webroot</code> option.


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
security.acme = {
security.acme = {
   acceptTerms = true;
   acceptTerms = true;
   defaults.email = "admin+acme@example.com";
   defaults.email = "admin@example.org";
   certs."example.com" = {
   certs."example.org" = {
     domain = "*.example.com";
     # An acme system user is created. This user belongs to the acme group and the home directory is /var/lib/acme.
     dnsProvider = "rfc2136";
     # This user will try to make the directory .well-known/acme-challenge/ under the webroot directory.
     credentialsFile = "/var/lib/secrets/certs.secret";
     webroot = "/var/lib/acme";
    # We don't need to wait for propagation since this is a local DNS server
    dnsPropagationCheck = false;
   };
   };
};
};
</syntaxhighlight>
We need to make sure that our webserver knows where to redirect <code>http://example.org/.well-known/acme-challenge</code> to. If you use [[Nginx|nginx]] this can be done as follows:
<syntaxhighlight lang="nginx">
location /.well-known/acme-challenge/ {
  rewrite /.well-known/acme-challenge/(.*) /$1 break;
  root /var/lib/acme/.well-known/acme-challenge;
}
</syntaxhighlight>
== Usage ==
After successfull generation, certificates can be found in the directory <code>/var/lib/acme</code>. When using certificates in other applications it may be required to change permissions. The group of the certificate files can be adjusted by setting the <code>group</code> option as a string
<syntaxhighlight lang="nix">
security.acme.certs."example.org".group = "nginx";
</syntaxhighlight>
or reference.
<syntaxhighlight lang="nix">
security.acme.certs."example.org".group = config.services.nginx.group;
</syntaxhighlight>Resulting in the following files and permissions<syntaxhighlight lang="bash">
lrwxrwxrwx 1 acme nginx  13 Aug  4 12:57 cert.pem -> fullchain.pem
-rw-r----- 1 acme nginx 1567 Aug  4 12:57 chain.pem
-rw-r----- 1 acme nginx 2865 Aug  4 12:57 fullchain.pem
-rw-r----- 1 acme nginx 3092 Aug  4 12:57 full.pem
-rw-r----- 1 acme nginx  227 Aug  4 12:57 key.pem
</syntaxhighlight>
== Using Let's Encrypt Staging ==
If you'd like to use the Let's Encrypt [https://letsencrypt.org/docs/staging-environment/ staging environment], eg for its less stringent rate limits, set
<syntaxhighlight lang="nix">
security.acme.defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
</syntaxhighlight>
</syntaxhighlight>


Line 22: Line 95:


* NixOS manual on [https://nixos.org/manual/nixos/stable/index.html#module-security-acme SSL/TLS Certificates with ACME]
* NixOS manual on [https://nixos.org/manual/nixos/stable/index.html#module-security-acme SSL/TLS Certificates with ACME]
[[Category: Server]]
[[Category: Networking]]

Latest revision as of 20:20, 10 October 2024

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.

Setup

DNS-01 Challenge

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 upstream documentation on available providers and their specific configuration for the credentialsFile option.

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";
    };
  };
};

HTTP-01 Challenge

Besides DNS validation it is also possible to obtain certificates by placing a file on your webserver at http://example.org/.well-known/acme-challenge. Instead of using the dnsProvider option, we use the webroot option.

security.acme = {
  acceptTerms = true;
  defaults.email = "admin@example.org";
  certs."example.org" = {
    # An acme system user is created. This user belongs to the acme group and the home directory is /var/lib/acme.
    # This user will try to make the directory .well-known/acme-challenge/ under the webroot directory.
    webroot = "/var/lib/acme";
  };
};

We need to make sure that our webserver knows where to redirect http://example.org/.well-known/acme-challenge to. If you use nginx this can be done as follows:

location /.well-known/acme-challenge/ {
  rewrite /.well-known/acme-challenge/(.*) /$1 break;
  root /var/lib/acme/.well-known/acme-challenge;
}

Usage

After successfull generation, certificates can be found in the directory /var/lib/acme. When using certificates in other applications it may be required to change permissions. The group of the certificate files can be adjusted by setting the group option as a string

security.acme.certs."example.org".group = "nginx";

or reference.

security.acme.certs."example.org".group = config.services.nginx.group;

Resulting in the following files and permissions

lrwxrwxrwx 1 acme nginx   13 Aug  4 12:57 cert.pem -> fullchain.pem
-rw-r----- 1 acme nginx 1567 Aug  4 12:57 chain.pem
-rw-r----- 1 acme nginx 2865 Aug  4 12:57 fullchain.pem
-rw-r----- 1 acme nginx 3092 Aug  4 12:57 full.pem
-rw-r----- 1 acme nginx  227 Aug  4 12:57 key.pem

Using Let's Encrypt Staging

If you'd like to use the Let's Encrypt staging environment, eg for its less stringent rate limits, set

security.acme.defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";

See also