Nginx: Difference between revisions
Malteneuss (talk | contribs) Add a Private Local LAN Server Example |
WomboCombo (talk | contribs) m Documented configuration of nginx modules and where to find the module definitions. |
||
| (8 intermediate revisions by 7 users not shown) | |||
| Line 1: | Line 1: | ||
[https://nginx.org/ {{PAGENAME}}] ([[wikipedia:en:{{PAGENAME}}]]) is a lightweight webserver. | [https://nginx.org/ {{PAGENAME}}] ([[wikipedia:en:{{PAGENAME}}]]) is a lightweight webserver. | ||
== Installation == | |||
To install Nginx, add the following to your NixOS configuration:{{file|/etc/nixos/configuration.nix|nix|3=services.nginx.enable = true;}} | |||
More options are available: {{nixos:option|services.nginx.}} | |||
== Sample setups == | == Sample setups == | ||
| Line 8: | Line 12: | ||
services.nginx = { | services.nginx = { | ||
enable = true; | enable = true; | ||
locations."/" = { | virtualHosts.localhost = { | ||
locations."/" = { | |||
return = "200 '<html><body>It works</body></html>'"; | |||
extraConfig = '' | |||
default_type text/html; | |||
''; | |||
}; | |||
}; | }; | ||
}; | }; | ||
| Line 29: | Line 35: | ||
}; | }; | ||
}; | }; | ||
# Optional: You can configure the email address used with Let's Encrypt. | |||
# This way you get renewal reminders (automated by NixOS) as well as expiration emails. | networking.firewall.allowedTCPPorts = [ 80 443 ]; | ||
security.acme = { | |||
# Accept the CA’s terms of service. The default provider is Let’s Encrypt, you can find their ToS at https://letsencrypt.org/repository/. | |||
acceptTerms = true; | |||
# Optional: You can configure the email address used with Let's Encrypt. | |||
# This way you get renewal reminders (automated by NixOS) as well as expiration emails. | |||
defaults.email = "youremail@address.com"; | |||
}; | }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 70: | Line 81: | ||
}; | }; | ||
}; | }; | ||
</syntaxhighlight> | |||
'''Robots.txt''' | |||
If you want to set a robots.txt for your domain (or any subdomains), add this: | |||
<syntaxhighlight lang="nix"> | |||
locations."/robots.txt" = { | |||
extraConfig = '' | |||
rewrite ^/(.*) $1; | |||
return 200 "User-agent: *\nDisallow: /"; | |||
''; | |||
}; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 262: | Line 287: | ||
systemd.services.hedgedoc.serviceConfig.UMask = "0000"; | systemd.services.hedgedoc.serviceConfig.UMask = "0000"; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Modules == | |||
Nginx can be run with optional modules. You can add them like this: | |||
services.nginx.package = (pkgs.nginx.override { modules = [ | |||
pkgs.nginxModules.dav | |||
pkgs.nginxModules.lua | |||
... | |||
]; }); | |||
See [https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/http/nginx/modules.nix#L69 this] for a more comprehensive list of modules available via configuration. | |||
== Let's Encrypt certificates == | == Let's Encrypt certificates == | ||
| Line 287: | Line 322: | ||
We can also have a private server running in our local network (including VPN), that isn't reachable from the internet, but that still can get valid Let's Encrypt certificates that are accepted in a browser. | We can also have a private server running in our local network (including VPN), that isn't reachable from the internet, but that still can get valid Let's Encrypt certificates that are accepted in a browser. | ||
1. We have to '''modify DNS such that our domain''' like <code>myhost.org</code> '''resolves to the local IP address of our private server''' and port 80 and 443 have been opened. [https://www.youtube.com/watch?v=qlcVx-k-02E See this video tutorial] for an example on how to do that. | 1. We have to '''modify DNS such that our domain''' like <code>myhost.org</code> '''resolves to the local IP address of our private server''' and port 80 and 443 have been opened. [https://www.youtube.com/watch?v=qlcVx-k-02E See this video tutorial] for an example on how to do that. Hint: You might need to '''add an exception to your router''' (definitely on Fritzboxes), because resolving to local IP address is usually blocked to prevent '''"DNS rebind attacks"'''. | ||
2. We have to setup the Let's Encrypt NixOS ACME services such that it uses an API token in a secrets file ([https://github.com/ryantm/agenix secrets for a server can be conveniently and securely deployed in NixOS with agenix]; just follow the tutorial) against our DNS provider to prove from our server that we own the domain. This way our server doesn't need to be exposed and reachable from the internet. NixOS ACME uses the [https://go-acme.github.io/lego/ LEGO library] to communicate to DNS providers and therefore we have to provide the token(s) in that | 2. We have to setup the Let's Encrypt NixOS ACME services such that it uses an '''API token in a secrets file''' ([https://github.com/ryantm/agenix secrets for a server can be conveniently and securely deployed in NixOS with agenix]; just follow the tutorial) against our DNS provider to '''prove from our server that we own the domain'''. This way our server doesn't need to be exposed and reachable from the internet. NixOS ACME uses the [https://go-acme.github.io/lego/ LEGO library] to communicate to DNS providers (it supports a lot) and therefore we have to provide the token(s) in that library's secrets file format. | ||
In the example we use Hetzner as our "dnsProvider" that only needs a single API token environment in our secrets file: | In the example we use Hetzner as our "dnsProvider" that only needs a single API token environment in our secrets file: | ||
| Line 296: | Line 331: | ||
</syntaxhighlight>Other [https://carjorvaz.com/posts/setting-up-wildcard-lets-encrypt-certificates-on-nixos/ DNS providers need like OVH] require more environment variables. | </syntaxhighlight>Other [https://carjorvaz.com/posts/setting-up-wildcard-lets-encrypt-certificates-on-nixos/ DNS providers need like OVH] require more environment variables. | ||
See the section "Credentials" on what you have to specify in the secrets file: https://go-acme.github.io/lego/dns/hetzner/ | See the section "'''Credentials'''" on what you have to specify in the secrets file: https://go-acme.github.io/lego/dns/hetzner/ | ||
See Hetzner guide on how to get an API token for its "DNS console": https://docs.hetzner.com/dns-console/dns/general/api-access-token/ | See Hetzner guide on how to get an API token for its "DNS console": https://docs.hetzner.com/dns-console/dns/general/api-access-token/ | ||
| Line 302: | Line 337: | ||
3. Point our virtualHost to the ACME entry. | 3. Point our virtualHost to the ACME entry. | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
services.nginx | { | ||
services.nginx = { | |||
enable = true; | |||
# we can use the main domain or any subdomain that's mentioned by | |||
# "extraDomainNames" in the acme certificate. | |||
}; | virtualHosts."subdomain.example.org" = { | ||
security.acme | # 3. Instead of "enableACME = true;" we | ||
# reuse the certificate from "security.acme.certs."example.org" | |||
defaults.email = " | # down below | ||
}; | useACMEHost = "example.org"; | ||
forceSSL = true; | |||
locations."/" = { | |||
return = "200 '<html><body>It works</body></html>'"; | |||
extraConfig = '' | |||
default_type text/html; | |||
''; | |||
}; | |||
}; | |||
}; | |||
security.acme.acceptTerms = true; | |||
security.acme.defaults.email = "info@example.org"; | |||
# 2. Let NixOS generate a Let's Encrypt certificate that we can reuse | |||
# above for several virtualhosts above. | |||
security.acme.certs."example.org" = { | |||
domain = "example.org"; | |||
extraDomainNames = [ "subdomain.example.org" ]; | |||
# The LEGO DNS provider name. Depending on the provider, need different | |||
# contents in the credentialsFile below. | |||
dnsProvider = "hetzner"; | |||
dnsPropagationCheck = true; | |||
# agenix will decrypt our secrets file (below) on the server and make it available | |||
# under /run/agenix/secrets/hetzner-dns-token (by default): | |||
# credentialsFile = "/run/agenix/secrets/hetzner-dns-token"; | |||
credentialsFile = config.age.secrets."hetzner-dns-token.age".path; | |||
}; | |||
# Let agenix know about and copy our (encrypted) DNS API token secrets file | |||
# (containing "HETZNER_API_KEY=...") to the server an decrypt it there. | |||
# Follow the agenix tutorial on how to encrypt a secrets file | |||
# to a .age file and how to setup your Nix flake to use it. | |||
age.secrets."hetzner-dns-token.age".file = .../hetzner-dns-token.age; | |||
users.users.nginx.extraGroups = [ "acme" ]; | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
This will set up nginx to serve files for | This will set up nginx to serve files for example.org, automatically request an ACME SSL Certificate using a "DNS-01" challenge (meaning '''your server doesn't need to be exposed to the internet''', which is great for self-hosting) and will configure systemd timers to renew the certificate if required. | ||
== Troubleshooting == | == Troubleshooting == | ||
| Line 384: | Line 456: | ||
services.nginx.package = pkgs.nginxStable.override { openssl = pkgs.libressl; }; | services.nginx.package = pkgs.nginxStable.override { openssl = pkgs.libressl; }; | ||
</syntaxHighlight> | </syntaxHighlight> | ||
== Extra config == | |||
Apart native options, Nix allows to specify verbatim Nginx configuration. Some options are mutually exclusive. | |||
Below table assumes "services.nginx." prefix for all options. These options allows to keep using Nix configuration file while taking advantage of Nginx features which are not representend in options. | |||
{| class="wikitable" | |||
|+ | |||
!Options | |||
!Block | |||
!Behaviour | |||
|- | |||
|config | |||
|nginx.conf | |||
|Verbatim <code>nginx.conf</code> configuration | |||
|- | |||
|appendConfig | |||
|nginx.conf | |||
|Lines appended to the generated Nginx configuration file | |||
|- | |||
|httpConfig | |||
|http block | |||
|exclusive with the structured configuration via virtualHosts | |||
|- | |||
|appendHttpConfig | |||
|http block | |||
|lines appended. exclusive with using config and httpConfig | |||
|- | |||
|virtualHosts.<name>.extraConfig | |||
|server | |||
|These lines go to the end of the vhost verbatim. | |||
|- | |||
|virtualHosts.<name>.locations.<name>.extraConfig | |||
|server | |||
|These lines go to the end of the location verbatim | |||
|} | |||
== See more == | == See more == | ||