Configuración de ACME#

El módulo ACME en Angie permite la obtención automática de certificados usando el protocolo ACME. Este protocolo admite varios métodos de verificación de dominio (también llamados "validaciones"); este módulo implementa la validación HTTP, la validación DNS y la validación mediante hooks a través de un servicio externo personalizado.

Pasos de Configuración#

Pasos generales para habilitar solicitudes de certificados en la configuración:

  • Configurar un cliente ACME en el bloque http mediante la directiva acme_client, que especifica un nombre único de cliente y otros parámetros. Se pueden configurar varios clientes ACME.

  • Especificar los dominios para los que se solicitan certificados: Se emitirá un único certificado para todos los nombres de dominio listados en las directivas server_name dentro de todos los bloques server que usen directivas acme que apunten al mismo cliente ACME.

  • Configurar el manejo de solicitudes y las devoluciones de llamada de ACME: Esto es necesario para verificar la propiedad del dominio. La configuración depende del método de validación elegido:

    Método

    Requisitos del Usuario

    Multidominio

    Dominios Wildcard

    Validación HTTP

    Abrir el puerto 80 para conexiones entrantes en el servidor Angie.

    Validación DNS

    Abrir el puerto 53 (o el especificado en acme_dns_port) para conexiones entrantes en el servidor Angie.

    Configurar un registro NS para el subdominio _acme-challenge. apuntando a su servidor Angie.

    Validación mediante hooks

    Crear un servicio externo (script o aplicación) que pueda, a petición de Angie, actualizar registros DNS o servir una respuesta especial mediante el servidor web.

  • Configurar SSL usando el certificado y la clave obtenidos: El módulo pone a disposición certificados y claves como variables integradas que pueden usarse en la configuración para rellenar ssl_certificate y ssl_certificate_key.

    Para instrucciones de configuración SSL, consulte Configuración SSL.

Truco

El proceso de obtención y renovación de certificados depende de muchos servicios y puede llevar tiempo. Sea paciente y, si encuentra problemas o tiene dudas, revise el log de depuración.

Detalles de Implementación#

Las claves y certificados de cliente se almacenan en codificación PEM dentro de subdirectorios del directorio especificado por la opción de compilación --http-acme-client-path (build option):

$ ls /var/lib/angie/acme/example/

  account.key  certificate.pem  private.key

El cliente ACME requiere una cuenta en el servidor CA. Para crear y gestionar esta cuenta, el cliente utiliza una clave privada (account.key). Si no existe clave, se genera al inicio. Luego, el cliente usa esta clave para registrar la cuenta con el servidor.

Nota

Si ya dispone de una clave de cuenta, colóquela en el subdirectorio del cliente antes de iniciar, para reutilizar la cuenta. Alternativamente, especifique el archivo de clave con el parámetro account_key en acme_client.

El cliente ACME también utiliza una clave separada (private.key) para las solicitudes de firma de certificados (CSR). Esta clave se crea automáticamente al inicio si es necesario.

Al arrancar, el cliente solicita un certificado si no existe, firmando y enviando un CSR para todos los dominios bajo su gestión al servidor CA. El servidor verifica la propiedad del dominio usando validación HTTP o validación DNS y emite un certificado, que el cliente guarda localmente (certificate.pem).

Como se mencionó anteriormente, un único certificado cubre todos los nombres de dominio gestionados por el mismo cliente ACME, lo que puede dar lugar a un certificado multidominio. La lista de todos los nombres cubiertos por el certificado puede encontrarse en la sección Subject Alternative Name (SAN) del certificado obtenido. Para comprobarlo desde la línea de comandos:

$ openssl x509 -in certificate.pem -noout -text | grep -A5 "Subject Alternative Name"

Cuando un certificado está a punto de expirar o la lista de dominios cambia, el cliente firma y envía otro CSR al servidor CA. El servidor vuelve a verificar la propiedad y emite un nuevo certificado, que el cliente instala localmente, reemplazando el anterior.

En la configuración, el certificado obtenido y su clave correspondiente están disponibles mediante las variables prefijo $acme_cert_<name> y $acme_cert_key_<name>. Sus valores son los contenidos de los respectivos archivos, que deben usarse con las directivas ssl_certificate y ssl_certificate_key:

server {

    listen 443 ssl;

    server_name example.com www.example.com;
    acme example;

    ssl_certificate $acme_cert_example;
    ssl_certificate_key $acme_cert_key_example;
}

Validación HTTP#

La validación se gestiona automáticamente. El proceso implica que el servidor ACME, al recibir una solicitud, recupere un archivo token especial vía HTTP desde el cliente en la dirección /.well-known/acme-challenge/<TOKEN>. Nuestro módulo ACME rastrea y procesa dichas solicitudes automáticamente. Cuando se recibe la respuesta esperada con el contenido correcto, el servidor ACME confirma que el dominio pertenece al cliente.

Ejemplo de Configuración#

En este ejemplo, el cliente ACME llamado example gestiona certificados para example.com y www.example.com (tenga en cuenta que los certificados wildcard no están soportados con validación HTTP):

http {

    resolver 127.0.0.53; # Requerido para la directiva 'acme_client'

    acme_client example https://acme-v02.api.letsencrypt.org/directory;

    server {

        listen 80; # Puede residir en un bloque 'server' distinto
        # con una lista de dominios diferente
        # o incluso sin ella

        listen 443 ssl;

        server_name example.com www.example.com;
        acme example;

        ssl_certificate $acme_cert_example;
        ssl_certificate_key $acme_cert_key_example;
    }
}

Como se mencionó anteriormente, el puerto 80 debe estar abierto para manejar las llamadas HTTP de ACME. Sin embargo, como se muestra en este ejemplo, la directiva listen para este puerto puede colocarse en un bloque server separado. Si no existe un bloque con esta directiva, puede limitar el nuevo bloque únicamente a llamadas de ACME:

server {

    listen 80;
    return 444; # Sin respuesta, conexión cerrada
}

¿Por qué funciona esto? El módulo intercepta solicitudes a /.well-known/acme-challenge/<TOKEN> después de leer las cabeceras pero antes de seleccionar un servidor virtual y procesar las directivas rewrite y location. Estas solicitudes interceptadas se procesan si el valor de <TOKEN> coincide con el esperado para la llamada específica. No ocurre acceso a directorios; la solicitud se maneja completamente dentro del módulo.

Validación DNS#

La validación se gestiona automáticamente. Al procesar una solicitud de certificado, el servidor ACME realiza una consulta DNS especial al subdominio _acme-challenge. del dominio en verificación. Una vez recibida la respuesta esperada, el servidor ACME confirma que el dominio pertenece al cliente.

Nuestro módulo ACME rastrea y procesa dichas solicitudes automáticamente, siempre que sus registros DNS estén configurados correctamente para designar al servidor Angie como servidor de nombres autoritativo para el subdominio _acme-challenge..

Por ejemplo, para verificar el dominio example.com usando un servidor Angie en la dirección IP 93.184.215.14, la configuración DNS de su dominio debería incluir los siguientes registros:

_acme-challenge.example.com. 60    IN      NS       ns.example.com.
             ns.example.com. 60    IN       A       93.184.215.14

Esta configuración delega la resolución DNS de _acme-challenge.example.com a ns.example.com, asegurando que ns.example.com sea accesible al asignarlo a la dirección IP (93.184.215.14).

Este método permite solicitar certificados wildcard, por ejemplo, un certificado que incluya la entrada *.example.com en la sección Subject Alternative Name (SAN). Para solicitar explícitamente un certificado para un subdominio, como www.example.com, debe verificar ese subdominio por separado utilizando el método descrito anteriormente.

Advertencia

La aplicabilidad de este escenario depende en gran medida de las capacidades que ofrezca su proveedor de DNS; algunos no permiten este tipo de configuraciones.

Ejemplo de Configuración#

En general, la configuración es similar al ejemplo de la sección anterior. No se necesitan ajustes específicos de HTTP; basta con establecer challenge=dns en la directiva acme_client.

En este ejemplo, el cliente ACME llamado example gestiona certificados para example.com y *.example.com:

http {

    resolver 127.0.0.53;

    acme_client example https://acme-v02.api.letsencrypt.org/directory
        challenge=dns;

    server {

        server_name example.com *.example.com;
        acme example;

        ssl_certificate $acme_cert_example;
        ssl_certificate_key $acme_cert_key_example;
    }
}

Validación mediante Hooks#

A diferencia de los métodos anteriores, esta validación requiere un esfuerzo adicional. El servidor ACME realiza la validación HTTP o la validación DNS estándar, pero en lugar de interactuar directamente con el servidor Angie, se comunica con un servicio externo gestionado por el servidor Angie mediante llamadas hook (acme_hook). Este servicio configura un servidor DNS o HTTP separado donde el servidor ACME envía sus solicitudes.

Una vez que el servidor ACME recibe la respuesta esperada desde el servidor DNS o HTTP configurado, confirma la propiedad del dominio.

Angie invoca el servicio externo cuando es necesario actualizar certificados mediante el protocolo ACME. Las llamadas se realizan redirigiendo solicitudes y datos a servidores FastCGI, SCGI y similares usando directivas como fastcgi_pass, scgi_pass, etc.

El servicio debe devolver un código de estado 2xx, que puede enviarse mediante la cabecera Status. Cualquier otro código se trata como un error y se detiene la renovación del certificado. La salida del servicio se ignora.

Ejemplo de Configuración#

En este ejemplo, el cliente ACME example está configurado para la verificación de dominio usando callbacks DNS, indicado por el parámetro challenge=dns en la directiva acme_client.

El bloque server se aplica a todos los subdominios de example.com (p. ej., *.example.com) y usa el cliente ACME example para gestionar certificados, tal como especifica la directiva acme.

Se configura un bloque location con nombre para manejar las llamadas de servicios externos para la verificación DNS. La directiva acme_hook enlaza el servidor con el cliente ACME example. Las solicitudes se redireccionan a un servidor FastCGI local en el puerto 9000 mediante la directiva fastcgi_pass. Las directivas fastcgi_param pasan datos sobre el cliente ACME, el hook, el tipo de desafío, el dominio, el token y la autorización de clave al servicio externo.

acme_client example https://acme-v02.api.letsencrypt.org/directory
    challenge=dns;

server {

    listen 80;

    server_name *.example.com;

    acme example;

    ssl_certificate $acme_cert_example;
    ssl_certificate_key $acme_cert_key_example;

    location @acme_hook_location {

        acme_hook example;

        fastcgi_pass localhost:9000;

        fastcgi_param ACME_CLIENT $acme_hook_client;
        fastcgi_param ACME_HOOK $acme_hook_name;
        fastcgi_param ACME_CHALLENGE $acme_hook_challenge;
        fastcgi_param ACME_DOMAIN $acme_hook_domain;
        fastcgi_param ACME_TOKEN $acme_hook_token;
        fastcgi_param ACME_KEYAUTH $acme_hook_keyauth;

        include fastcgi.conf;
    }
}

El siguiente script en Perl demuestra un servicio FastCGI externo correspondiente:

#!/usr/bin/perl

use strict; use warnings;

use FCGI;

my $socket = FCGI::OpenSocket(":9000", 5);
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);

while ($request->Accept() >= 0) {
    print "\r\n";

    my $client =    $ENV{ACME_CLIENT};
    my $hook =      $ENV{ACME_HOOK};
    my $challenge = $ENV{ACME_CHALLENGE};
    my $domain =    $ENV{ACME_DOMAIN};
    my $token =     $ENV{ACME_TOKEN};
    my $keyauth =   $ENV{ACME_KEYAUTH};

    if ($hook eq 'add') {

        DNS_set_TXT_record("_acme-challenge.$domain.", $keyauth);

    } elsif ($hook eq 'remove') {

        DNS_clear_TXT_record("_acme-challenge.$domain.");
    }
};

FCGI::CloseSocket($socket);

Aquí, DNS_set_TXT_record() y DNS_clear_TXT_record() son funciones que se supone añaden y eliminan registros TXT en la configuración de un servidor DNS externo que consulta el servidor ACME. Estos registros deben contener los datos proporcionados por el servidor Angie para permitir que el servidor DNS externo pase la validación con éxito, similar al proceso descrito en Validación DNS. Los detalles de implementación de tales funciones están fuera del alcance de esta guía; por ejemplo, los parámetros también pueden pasarse a través de la URI de la solicitud:

# ...

location @acme_hook_location {

    acme_hook example uri=/acme_hook/$acme_hook_name?domain=$acme_hook_domain&key=$acme_hook_keyauth;

    fastcgi_pass localhost:9000;

    fastcgi_param REQUEST_URI $request_uri;
    fastcgi_param ACME_CLIENT $acme_hook_client;
    fastcgi_param ACME_CHALLENGE $acme_hook_challenge;
    fastcgi_param ACME_TOKEN $acme_hook_token;

    include fastcgi.conf;
}

Otro ejemplo usando PHP-FPM:

location @acme_hook_location {

    acme_hook example;
    root /var/www/dns;
    fastcgi_pass unix:/run/php-fpm/php-dns.sock;
    fastcgi_index hook.php;
    fastcgi_param SCRIPT_FILENAME /var/www/dns/hook.php;
    include fastcgi_params;

    fastcgi_param ACME_CLIENT $acme_hook_client;
    fastcgi_param ACME_HOOK $acme_hook_name;
    fastcgi_param ACME_CHALLENGE $acme_hook_challenge;
    fastcgi_param ACME_DOMAIN $acme_hook_domain;
    fastcgi_param ACME_TOKEN $acme_hook_token;
    fastcgi_param ACME_KEYAUTH $acme_hook_keyauth;
}
[dns]
listen = /run/php-fpm/php-dns.sock
listen.mode = 0666
user = angie
group = angie
chdir = /var/www/dns
# ...

Los parámetros pasados pueden accederse en PHP a través de $_SERVER['...'].

ACME en el Módulo Stream#

El módulo stream ACME habilita la emisión y el uso automatizado de certificados para tráfico TCP. Para un funcionamiento correcto, primero debe configurarse el equivalente HTTP: el cliente ACME debe declararse en el contexto http, y el bloque stream debe colocarse después del bloque http en la configuración.

Ejemplo de Configuración#

Por defecto, se utiliza la validación HTTP para obtener certificados. Como se mencionó en Validación HTTP, esto requiere un servidor HTTP escuchando en el puerto 80:

# Sección HTTP
http {

    resolver 127.0.0.53;

    # Cliente ACME para la sección stream
    acme_client example https://acme-v02.api.letsencrypt.org/directory;

    # Servidor para validación HTTP
    server {

        listen 80;
        return 444;
    }
}

# Sección Stream
stream {

    server {

        listen 12345 ssl;
        proxy_pass backend_upstream;

        ssl_certificate $acme_cert_example;
        ssl_certificate_key $acme_cert_key_example;

        server_name example.com www.example.com;
        acme example; # referencia al cliente ACME definido en la sección HTTP
    }

    upstream backend_upstream {

        server 127.0.0.1:54321;
    }
}

También puede usarse la validación DNS configurando challenge=dns en la directiva acme_client; en este caso, no se necesita el servidor.

Migración desde certbot#

Si anteriormente usaba certbot para obtener y renovar certificados SSL de Let's Encrypt antes de migrar de nginx a Angie, siga estos pasos para pasar a usar el módulo ACME.

Supongamos que inicialmente configuró certificados con el siguiente comando:

$ sudo certbot --nginx -d example.com -d www.example.com

La configuración creada automáticamente por certbot suele encontrarse en /etc/nginx/sites-available/example.conf y se parece a lo siguiente:

server {

    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {

    listen 443 ssl;
    server_name example.com www.example.com;

    root /var/www/example;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {

        try_files $uri $uri/ =404;
    }
}

En el ejemplo anterior, las líneas resaltadas deben modificarse. Dependiendo de sus circunstancias y preferencias, configure la validación HTTP o la validación DNS usando el módulo ACME.

La configuración Angie resultante podría verse así:

http {

    resolver 127.0.0.53;

    acme_client example https://acme-v02.api.letsencrypt.org/directory;

    server {

        listen 80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name example.com www.example.com;

        root /var/www/example;
        index index.html;

        acme                 example;

        ssl_certificate      $acme_cert_example;
        ssl_certificate_key  $acme_cert_key_example;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

Recuerde recargar la configuración después de hacer cambios:

$ sudo kill -HUP $(cat /run/angie.pid)

Una vez haya verificado que esta configuración funciona, puede eliminar los certificados de certbot y deshabilitar o eliminar completamente certbot del servidor si ya no se usa en otro lugar, por ejemplo:

$ sudo rm -rf /etc/letsencrypt

$ sudo systemctl stop certbot.timer
$ sudo systemctl disable certbot.timer
$ # -- o --
$ sudo rm /etc/cron.d/certbot

$ sudo apt remove certbot
$ # -- o --
$ sudo dnf remove certbot