我正在尝试使用 Traefik 反向代理在子域上运行演示 Node.js 应用程序。我正在使用 security.acme 选项生成通配符 Let's Encrypt 证书。当我在 Nginx 配置中导入证书时,它可以正常工作。但是,当我尝试将其添加到 Traefik 时,出现以下错误:
安全连接失败
连接到 hello.domain.com 时发生错误 SSL 对等方没有所请求的 DNS 名称的证书。
错误代码:SSL_ERROR_UNRECOGNIZED_NAME_ALERT
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified. Please contact the website owners to inform them of this problem.
这是我的配置.nix:
{ pkgs, ... }: {
# imports = [ ... ];
config = {
environment.systemPackages = with pkgs; [
openssl
git
nodejs
yarn
nodePackages.npm
];
security.acme = {
acceptTerms = true;
defaults.email = "[email protected]";
certs."domain.com" = {
domain = "domain.com";
extraDomainNames = [ "*.domain.com" ];
dnsProvider = "ovh";
dnsPropagationCheck = true;
credentialsFile = "/etc/nixos/credentials.txt";
};
};
services.traefik = {
enable = true;
staticConfigOptions = {
global = {
checkNewVersion = false;
sendAnonymousUsage = false;
};
entryPoints = {
web = {
address = ":80";
http.redirections.entrypoint = {
to = "websecure";
scheme = "https";
};
};
websecure.address = ":443";
};
providers.docker.exposedByDefault = false;
};
dynamicConfigOptions = {
tls = {
stores.default = {
defaultCertificate = {
certFile = "/var/lib/acme/domain.com/cert.pem";
keyFile = "/var/lib/acme/domain.com/key.pem";
};
};
certificates = [
{
certFile = "/var/lib/acme/domain.com/cert.pem";
keyFile = "/var/lib/acme/domain/key.pem";
stores = "default";
}
];
};
http.routers.hello = {
rule = "Host(`hello.domain.com`)";
entryPoints = [ "websecure" ];
service = "hello";
tls = true;
};
http.services.hello = {
loadBalancer.servers = [{
url = "http://localhost:8000";
}];
};
};
};
systemd.services."hello-world" = {
description = "Hello World";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.nodejs}/bin/node /etc/nixos/app.js";
Restart = "always";
RestartSec = "3";
};
};
networking.firewall.allowedTCPPorts = [ 80 443 8000 ];
users.users.traefik.extraGroups = [ "docker" ];
};
}
当我注释掉这部分时:
# stores.default = {
# defaultCertificate = {
# certFile = "/var/lib/acme/domain.com/cert.pem";
# keyFile = "/var/lib/acme/domain.com/key.pem";
# };
# };
我收到“警告:前方存在潜在安全风险”,但我可以访问子域页面。这是因为 Traefik 使用了默认证书:
| Common Name (CN)|TRAEFIK DEFAULT CERT|
|---|---|
|Organization (O)|<Not Part Of Certificate>|
|Organizational Unit (OU)|<Not Part Of Certificate>|
|Common Name (CN)|TRAEFIK DEFAULT CERT|
|Organization (O)|<Not Part Of Certificate>|
|Organizational Unit (OU)|<Not Part Of Certificate>|
|Issued On|Monday, May 29, 2023 at 10:48:12 AM|
|Expires On|Tuesday, May 28, 2024 at 10:48:12 AM|
我该如何修复我的配置才能正确使用 Let's encrypt 通配符证书和 Treafik?
答案1
您在通配符证书的密钥文件路径中输入了拼写错误,以下是正确的版本:
certificates = [
{
certFile = "/var/lib/acme/domain.com/cert.pem";
keyFile = "/var/lib/acme/domain.com/key.pem";
stores = "default";
}
];
答案2
我已经修复了。以下是可供参考的工作配置:
{ pkgs, ... }: {
# imports = [ ... ];
config = {
environment.systemPackages = with pkgs; [
openssl
git
nodejs
yarn
nodePackages.npm
];
security.acme = {
acceptTerms = true;
defaults.email = "[email protected]";
certs."domain.com" = {
domain = "domain.com";
extraDomainNames = [ "*.domain.com" ];
dnsProvider = "ovh";
dnsPropagationCheck = true;
credentialsFile = "/etc/nixos/credentials.txt";
};
};
services.traefik = {
enable = true;
staticConfigOptions = {
global = {
checkNewVersion = false;
sendAnonymousUsage = false;
};
entryPoints = {
web = {
address = ":80";
http.redirections.entrypoint = {
to = "websecure";
scheme = "https";
};
};
websecure = {
address = ":443";
};
};
providers.docker.exposedByDefault = false;
};
dynamicConfigOptions = {
tls = {
stores.default = {
defaultCertificate = {
certFile = "/var/lib/acme/domain.com/cert.pem";
keyFile = "/var/lib/acme/domain.com/key.pem";
};
};
certificates = [
{
certFile = "/var/lib/acme/domain.com/cert.pem";
keyFile = "/var/lib/acme/domain.com/key.pem";
stores = "default";
}
];
};
http.routers.hello = {
rule = "Host(`hello.domain.com`)";
entryPoints = [ "websecure" ];
service = "hello";
tls = {
certResolver = "my-resolver";
domains = {
main = [ "domain.com" ];
sans = [ "*.domain.com" ];
};
};
};
http.services.hello = {
loadBalancer.servers = [{
url = "http://localhost:8000";
}];
};
};
};
# services.caddy = {
# enable = true;
# virtualHosts."hello.domain.com".extraConfig = ''
# reverse_proxy http://localhost:8000
# '';
# extraConfig = ''
# domain.com {
# root * /var/www
# file_server
# }
# '';
# };
virtualisation.docker.enable = true;
systemd.services.copy-landing-page = {
description = "Copy index";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/cp ${./html/index.html} /var/www/index.html";
};
};
systemd.services."hello-world" = {
description = "Hello World Node.js app";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.nodejs}/bin/node /etc/nixos/app.js";
Restart = "always";
RestartSec = "3";
};
};
networking.firewall.allowedTCPPorts = [ 80 443 8000 ];
users.users.traefik.extraGroups = [ "docker" "acme" ];
# users.users.traefik = {
# isSystemUser = false;
# isNormalUser = true;
# group = "traefik";
# };
};
}
凭证.txt
OVH_APPLICATION_KEY=<key>
OVH_APPLICATION_SECRET=<key>
OVH_CONSUMER_KEY=<key>
OVH_ENDPOINT=ovh-eu