mirror of
https://github.com/SignalWalker/nix.nginx.vhost-defaults.git
synced 2025-10-05 15:52:39 +02:00
initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
result
|
||||
result-*
|
60
README.md
Normal file
60
README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Nginx Virtual Host Defaults
|
||||
|
||||
A small NixOS module adding the option `services.nginx.virtualHostDefaults`, which is a submodule merged into every virtual host configuration, allowing you to set options common to every Nginx virtual host.
|
||||
|
||||
It also adds `services.nginx.virtualHosts.<name>.blockAgents`, which allows you to easily block a a set of user agent strings from accessing a vhost.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
`flake.nix`:
|
||||
```nix
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
nginx-vhost-defaults = {
|
||||
url = "github:signalwalker/nix.nginx.vhost-defaults";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
outputs = inputs @ {
|
||||
self,
|
||||
nixpkgs,
|
||||
...
|
||||
}: {
|
||||
nixosConfigurations."example" = nixpkgs.lib.nixosSystem {
|
||||
# ...
|
||||
modules = [
|
||||
inputs.nginx-vhost-defaults.nixosModules.default
|
||||
./nixos-module.nix
|
||||
# ...
|
||||
];
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
`nixos-module.nix`:
|
||||
```nix
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
config = {
|
||||
services.nginx = {
|
||||
virtualHostDefaults = {
|
||||
# force SSL on every virtual host
|
||||
forceSSL = true;
|
||||
# Block a set of user agents from accessing any virtual host.
|
||||
blockAgents = {
|
||||
enable = true;
|
||||
# Use `lib.mkOptionDefault` if you want to preserve the default agent list, which includes all agents found in https://github.com/ai-robots-txt/ai-robots-txt
|
||||
agents = lib.mkOptionDefault ["SemrushBot"];
|
||||
# This is the default, which causes Nginx to drop the connection without any response.
|
||||
method = "return 444";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
122
flake.lock
generated
Normal file
122
flake.lock
generated
Normal file
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"nodes": {
|
||||
"ai-robots-txt": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1725844581,
|
||||
"narHash": "sha256-3A1cuHtqrFeJKvdizAVQxYBOZRDs/MF02HNR0DICMsM=",
|
||||
"owner": "ai-robots-txt",
|
||||
"repo": "ai.robots.txt",
|
||||
"rev": "6b8d7f5890d6bed722a95297996c054c210bd3b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ai-robots-txt",
|
||||
"repo": "ai.robots.txt",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"alejandra": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flakeCompat": "flakeCompat",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1719514321,
|
||||
"narHash": "sha256-ys1nJdZ8zB8JlpUbQmnj0hZalg03bEPgQdZN30DhETE=",
|
||||
"owner": "kamadorueda",
|
||||
"repo": "alejandra",
|
||||
"rev": "d7552fef2ccf1bbf0d36b27f6fddb19073f205b7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kamadorueda",
|
||||
"repo": "alejandra",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"alejandra",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1668234453,
|
||||
"narHash": "sha256-FmuZThToBvRsqCauYJ3l8HJoGLAY5cMULeYEKIaGrRw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "8f219f6b36e8d0d56afa7f67e6e3df63ef013cdb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flakeCompat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1650374568,
|
||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1727089097,
|
||||
"narHash": "sha256-ZMHMThPsthhUREwDebXw7GX45bJnBCVbfnH1g5iuSPc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "568bfef547c14ca438c56a0bece08b8bb2b71a9c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"ai-robots-txt": "ai-robots-txt",
|
||||
"alejandra": "alejandra",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1668182250,
|
||||
"narHash": "sha256-PYGaOCiFvnJdVz+ZCaKF8geGdffXjJUNcMwaBHv0FT4=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "45ec315e01dc8dd1146dfeb65f0ef6e5c2efed78",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
25
flake.nix
Normal file
25
flake.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
description = "A NixOS module for easily blocking user agents from Nginx.";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
alejandra = {
|
||||
url = "github:kamadorueda/alejandra";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
ai-robots-txt = {
|
||||
url = "github:ai-robots-txt/ai.robots.txt";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
outputs = inputs @ {
|
||||
self,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
with builtins; let
|
||||
std = nixpkgs.lib;
|
||||
in {
|
||||
formatter = std.mapAttrs (system: pkgs: pkgs.default) inputs.alejandra.packages;
|
||||
nixosModules.default = import ./nixos-module.nix {inherit self;};
|
||||
};
|
||||
}
|
83
nixos-module.nix
Normal file
83
nixos-module.nix
Normal file
@@ -0,0 +1,83 @@
|
||||
{self}: {
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with builtins; let
|
||||
std = pkgs.lib;
|
||||
nginx = config.services.nginx;
|
||||
mkRobotsTxt = robots: let
|
||||
agents = std.concatStringsSep "\n" (map (agent: "User-agent: ${agent}") robots);
|
||||
in
|
||||
pkgs.writeText "robots.txt" ''
|
||||
${agents}
|
||||
Disallow: /
|
||||
'';
|
||||
regexEscapes = ["\"" "[" "]" "(" ")" "{" "}" "^" "$" "+" "*" "." "|" "?" "\\"];
|
||||
defaultBlockList = attrNames (fromJSON (readFile "${self.inputs.ai-robots-txt}/robots.json"));
|
||||
in {
|
||||
options = with lib; {
|
||||
services.nginx = {
|
||||
virtualHostDefaults = mkOption {
|
||||
type = types.deferredModuleWith {
|
||||
staticModules = [];
|
||||
};
|
||||
description = "Default configuration merged into every virtual host.";
|
||||
default = {};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
# type-merge the `virtualHosts` submodule so we can import `nginx.virtualHostDefaults` into every virtualHost
|
||||
type = types.attrsOf (types.submoduleWith {
|
||||
modules = [
|
||||
nginx.virtualHostDefaults
|
||||
({
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
options = {
|
||||
blockAgents = {
|
||||
enable = mkEnableOption "blocking a set of user agents from accessing this virtual host.";
|
||||
agents = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "User agent strings to block from accessing this virtual host.";
|
||||
default = defaultBlockList;
|
||||
defaultText = "The user agent list from [github:ai-robots-txt/ai-robots-txt](https://github.com/ai-robots-txt/ai-robots-txt).";
|
||||
example = ["Amazonbot" "AI2Bot" "Applebot"];
|
||||
};
|
||||
method = mkOption {
|
||||
type = types.str;
|
||||
description = "Method by which to block agents.";
|
||||
default = "return 444";
|
||||
defaultText = "`return 444`, dropping the connection.";
|
||||
example = "return 307 https://ash-speed.hetzner.com/10GB.bin";
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf (config.blockAgents.enable && (length config.blockAgents.agents) > 0) {
|
||||
locations."=/robots.txt" = {
|
||||
alias = nginx.robotsTxt;
|
||||
};
|
||||
extraConfig = let
|
||||
agentRules = pkgs.lib.concatStringsSep "|" (map (lib.strings.escape regexEscapes) config.blockAgents.agents);
|
||||
in ''
|
||||
if ($http_user_agent ~* "(${agentRules})") {
|
||||
${config.blockAgents.method};
|
||||
}
|
||||
'';
|
||||
})
|
||||
];
|
||||
})
|
||||
];
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
disabledModules = [];
|
||||
imports = [];
|
||||
config = {};
|
||||
meta = {};
|
||||
}
|
Reference in New Issue
Block a user