summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Aristote <quentin@aristote.fr>2021-08-06 16:20:44 +0200
committerQuentin Aristote <quentin@aristote.fr>2021-08-06 16:20:44 +0200
commit210d4e7c2e7102355e8ef92681800157faa57d16 (patch)
treec1c599a66e34cc86056c094c438fe742ae41c03e
initial commit
-rw-r--r--config/boot.nix12
-rw-r--r--config/default.nix22
-rw-r--r--config/environment.nix16
-rw-r--r--config/hardware-configuration.nix28
-rw-r--r--config/networking.nix37
-rw-r--r--config/searx/default.nix236
-rw-r--r--config/searx/filtron.json129
-rw-r--r--config/users.nix11
-rw-r--r--configuration.nix10
-rw-r--r--modules/default.nix7
-rw-r--r--modules/filtron.nix87
-rw-r--r--pkgs/academic-webpage/default.nix21
-rw-r--r--pkgs/default.nix6
-rw-r--r--pkgs/filtron/default.nix16
14 files changed, 638 insertions, 0 deletions
diff --git a/config/boot.nix b/config/boot.nix
new file mode 100644
index 0000000..df60fea
--- /dev/null
+++ b/config/boot.nix
@@ -0,0 +1,12 @@
+{ ... }:
+
+{
+ boot = {
+ loader.grub = {
+ enable = true;
+ version = 2;
+ enableCryptodisk = true;
+ device = "/dev/vda";
+ };
+ };
+}
diff --git a/config/default.nix b/config/default.nix
new file mode 100644
index 0000000..39de497
--- /dev/null
+++ b/config/default.nix
@@ -0,0 +1,22 @@
+{ pkgs, modulesPath, ... }:
+
+{
+ imports = [
+ (modulesPath + "/profiles/headless.nix")
+ (modulesPath + "/profiles/minimal.nix")
+ ./boot.nix
+ ./environment.nix
+ ./hardware-configuration.nix
+ ./networking.nix
+ ./searx
+ ./users.nix
+ ];
+
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It‘s perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system.stateVersion = "20.03"; # Did you read the comment?
+}
diff --git a/config/environment.nix b/config/environment.nix
new file mode 100644
index 0000000..e8faf42
--- /dev/null
+++ b/config/environment.nix
@@ -0,0 +1,16 @@
+{ pkgs, ... }:
+
+{
+ environment.systemPackages = with pkgs; [ vim ];
+ programs.bash.promptInit = ''
+ PS1='\n\[\033[1;32m\][\[\e]0;\u@\H: \w\a\]\u@\H:\w]\$\[\033[0m\] '
+ '';
+
+ i18n.defaultLocale = "en_US.UTF-8";
+ console = {
+ font = "Lat2-Terminus16";
+ keyMap = "fr";
+ };
+
+ time.timeZone = "Europe/Paris";
+}
diff --git a/config/hardware-configuration.nix b/config/hardware-configuration.nix
new file mode 100644
index 0000000..efcdb77
--- /dev/null
+++ b/config/hardware-configuration.nix
@@ -0,0 +1,28 @@
+{ lib, modulesPath, ... }:
+
+{
+ imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
+
+ boot.initrd.availableKernelModules =
+ [ "ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-amd" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/2b302948-5608-41c6-b54c-1c0e39ff6a58";
+ fsType = "ext4";
+ };
+
+ boot.initrd.luks.devices."root".device =
+ "/dev/disk/by-uuid/eaec758b-ba22-42ab-8992-e765cec9be55";
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/74d78eba-c29a-4724-8fb7-624e0a03faa5";
+ fsType = "ext4";
+ };
+
+ swapDevices = [{ device = "/swap"; }];
+
+ nix.maxJobs = lib.mkDefault 1;
+}
diff --git a/config/networking.nix b/config/networking.nix
new file mode 100644
index 0000000..21bcc83
--- /dev/null
+++ b/config/networking.nix
@@ -0,0 +1,37 @@
+{ ... }:
+
+{
+ networking = {
+ hostName = "hermes.aristote.fr";
+
+ useDHCP = false;
+ interfaces.ens3.ipv4.addresses = [{
+ address = "93.95.228.53";
+ prefixLength = 16;
+ }];
+ defaultGateway = "93.95.228.1";
+ nameservers = [ "93.95.224.28" "93.95.224.29" ];
+
+ firewall = {
+ enable = true;
+ allowedTCPPorts = [ 80 443 ];
+ };
+ };
+
+ services.nginx = {
+ enable = true;
+ virtualHosts = {
+ "quentin.aristote.fr" = { root = "${pkgs.personal.academic-webpage}"; };
+ };
+ };
+
+ services.openssh = {
+ enable = true;
+ permitRootLogin = "no";
+ passwordAuthentication = false;
+ extraConfig = ''
+ AcceptEnv PS1
+ '';
+ };
+ services.fail2ban.enable = true;
+}
diff --git a/config/searx/default.nix b/config/searx/default.nix
new file mode 100644
index 0000000..1181d22
--- /dev/null
+++ b/config/searx/default.nix
@@ -0,0 +1,236 @@
+{ pkgs, lib, ... }:
+
+let
+ ports = {
+ searx = 8888;
+ filtron = {
+ listen = 4004;
+ api = 4005;
+ };
+ morty = 3000;
+ };
+ keys = { morty = "1t/rvXuoX/9OKwZ6Zby1zBc5t1DRFYIiE15xhIi72TKX"; };
+in {
+ # Nginx
+ services.nginx.virtualHosts."searx.aristote.fr" = {
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:${toString ports.filtron.listen}";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header Connection $http_connection;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Scheme $scheme;
+ # proxy_set_header X-Script-Name /;
+ '';
+ };
+ "/static/" = { alias = "${pkgs.searx}/share/static/"; };
+ "/morty" = {
+ proxyPass = "http://127.0.0.1:${toString ports.morty}";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header Connection $http_connection;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Scheme $scheme;
+ '';
+ };
+ };
+ };
+
+ # Searx
+ services.searx = {
+ enable = true;
+ environmentFile = /etc/searx/secrets;
+ settings = {
+ use_default_settings = true;
+ general = {
+ debug = false;
+ contact_url = "mailto:quentin@aristote.fr";
+ enable_stats = false;
+ };
+ search = {
+ autocomplete = "dbpedia";
+ default_lang = "fr-FR";
+ };
+ server = {
+ secret_key = "@SECRET_KEY@";
+ image_proxy = true;
+ http_protocol_version = "1.0";
+ method = "GET";
+ };
+ ui = {
+ # default_locale = "fr";
+ theme_args = { oscar_style = "pointhi"; };
+ };
+ # result_proxy = {
+ # url = "http://searx.aristote.fr/morty";
+ # key = ''!!binary | "${keys.morty}"'';
+ # };
+ enabled_plugins = [
+ "Open Access DOI rewrite"
+ "Hash plugin"
+ "HTTPS rewrite"
+ "Self Informations"
+ "Search on category select"
+ "Tracker URL remover"
+ "Vim-like hotkeys"
+ ];
+ };
+ runInUwsgi = true;
+ uwsgiConfig = {
+ cache2 = "name=searxcache,items=2000,blocks=2000,blocksize=4096,bitmap=1";
+ http = ":${toString ports.searx}";
+ };
+ };
+
+ # Filtron
+ # users.users.filtron = {
+ # description = "Filtron daemon user";
+ # group = "filtron";
+ # isSystemUser = true;
+ # };
+ # users.groups.filtron = { };
+
+ # systemd.services.filtron = {
+ # wantedBy = [ "multi-user.target" ];
+ # after = [ "network.target" ];
+ # description = "Start a filtron instance.";
+ # serviceConfig = {
+ # User = "filtron";
+ # ExecStart = ''
+ # ${pkgs.personal.filtron}/bin/filtron -rules ${./filtron.json} \
+ # -api "127.0.0.1:${toString ports.filtron.api}" \
+ # -listen "127.0.0.1:${toString ports.filtron.listen}" \
+ # -target "127.0.0.1:${toString ports.searx}"
+ # '';
+ # };
+ # };
+
+ services.filtron = {
+ enable = true;
+ rules = [
+ {
+ name = "roboagent limit";
+ filters = [
+ "Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client|Ruby|UniversalFeedParser)"
+ ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "botlimit";
+ filters = [
+ "Header:User-Agent=(Googlebot|bingbot|Baiduspider|yacybot|YandexMobileBot|YandexBot|Yahoo! Slurp|MJ12bot|AhrefsBot|archive.org_bot|msnbot|MJ12bot|SeznamBot|linkdexbot|Netvibes|SMTBot|zgrab|James BOT)"
+ ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "suspiciously frequent IP";
+ filters = [ ];
+ interval = 600;
+ limit = 30;
+ aggregations = [ "Header:X-Forwarded-For" ];
+ actions = [{ name = "log"; }];
+ }
+ {
+ name = "search request";
+ filters = [ "Param:q" "Path=^(/|/search)$" ];
+ interval = 61;
+ limit = 999;
+ subrules = [
+ {
+ name = "missing Accept-Language";
+ filters = [ "!Header:Accept-Language" ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "suspiciously Connection=close header";
+ filters = [ "Header:Connection=close" ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "IP limit";
+ interval = 61;
+ limit = 9;
+ stop = true;
+ aggregations = [ "Header:X-Forwarded-For" ];
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "rss/json limit";
+ filters = [ "Param:format=(csv|json|rss)" ];
+ interval = 121;
+ limit = 2;
+ stop = true;
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ {
+ name = "useragent limit";
+ interval = 61;
+ limit = 199;
+ aggregations = [ "Header:User-Agent" ];
+ actions = [
+ { name = "log"; }
+ {
+ name = "block";
+ params = { message = "Rate limit exceeded"; };
+ }
+ ];
+ }
+ ];
+ }
+ ];
+ };
+
+ # Morty
+ # services.morty = {
+ # enable = true;
+ # key = keys.morty;
+ # port = ports.morty;
+ # };
+}
diff --git a/config/searx/filtron.json b/config/searx/filtron.json
new file mode 100644
index 0000000..285d933
--- /dev/null
+++ b/config/searx/filtron.json
@@ -0,0 +1,129 @@
+[
+ {
+ name = "roboagent limit";
+ filters = [
+ "Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client|Ruby|UniversalFeedParser)"
+ ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; };
+ { name = "block";
+ params = {
+ message = "Rate limit exceeded"
+ };
+ };
+ ];
+ };
+ {
+ name = "botlimit";
+ filters = [
+ "Header:User-Agent=(Googlebot|bingbot|Baiduspider|yacybot|YandexMobileBot|YandexBot|Yahoo! Slurp|MJ12bot|AhrefsBot|archive.org_bot|msnbot|MJ12bot|SeznamBot|linkdexbot|Netvibes|SMTBot|zgrab|James BOT)"
+ ];
+ limit = 0;
+ stop = true;
+ actions = [
+ { name = "log"; };
+ { name = "block";
+ params = {
+ message = "Rate limit exceeded"
+ };
+ };
+ ];
+ };
+ {
+ name = "suspiciously frequent IP";
+ filters = [];
+ interval = 600;
+ limit = 30;
+ aggregations = [
+ "Header:X-Forwarded-For"
+ ];
+ actions =[
+ {name ="log"; };
+ ];
+ };
+ {
+ name = "search request";
+ filters = [
+ "Param:q";
+ "Path=^(/|/search)$"
+ ];
+ interval = 61;
+ limit = 999;
+ subrules = [
+ {
+ name = "missing Accept-Language";
+ filters = ["!Header:Accept-Language"];
+ limit = 0;
+ stop = true;
+ actions = [
+ {name ="log"; };
+ {name = "block";
+ params = {"message": "Rate limit exceeded"; }};
+ ];
+ };
+ {
+ name = "suspiciously Connection=close header";
+ filters = ["Header:Connection=close"];
+ limit = 0;
+ stop = true;
+ actions = [
+ {name ="log"; };
+ {name = "block";
+ params = {"message": "Rate limit exceeded"; }};
+ ];
+ };
+ {
+ name = "IP limit";
+ interval = 61;
+ limit = 9;
+ stop = true;
+ aggregations = [
+ "Header:X-Forwarded-For"
+ ];
+ actions = [
+ { name = "log"; };
+ { name = "block";
+ params = {
+ message = "Rate limit exceeded"
+ };
+ };
+ ];
+ };
+ {
+ name = "rss/json limit";
+ filters = [
+ "Param:format=(csv|json|rss)"
+ ];
+ interval = 121;
+ limit = 2;
+ stop = true;
+ actions = [
+ { name = "log"; };
+ { name = "block";
+ params = {
+ message = "Rate limit exceeded"
+ };
+ };
+ ];
+ };
+ {
+ name = "useragent limit";
+ interval = 61;
+ limit = 199;
+ aggregations = [
+ "Header:User-Agent"
+ ];
+ actions = [
+ { name = "log"; };
+ { name = "block";
+ params = {
+ message = "Rate limit exceeded"
+ };
+ };
+ ];
+ };
+ ];
+ };
+];
diff --git a/config/users.nix b/config/users.nix
new file mode 100644
index 0000000..99a497d
--- /dev/null
+++ b/config/users.nix
@@ -0,0 +1,11 @@
+{ ... }:
+
+{
+ users.users.qaristote = {
+ isNormalUser = true;
+ extraGroups = [ "wheel" ];
+ openssh.authorizedKeys.keys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK4wGbl3++lqCjLUhoRyABBrVEeNhIXYO4371srkRoyq qaristote@latitude-7490"
+ ];
+ };
+}
diff --git a/configuration.nix b/configuration.nix
new file mode 100644
index 0000000..958a63c
--- /dev/null
+++ b/configuration.nix
@@ -0,0 +1,10 @@
+{ ... }:
+
+{
+ imports = [ ./config ./modules ];
+
+ nixpkgs = {
+ overlays =
+ [ (final: prev: { personal = import ./pkgs { pkgs = final; }; }) ];
+ };
+}
diff --git a/modules/default.nix b/modules/default.nix
new file mode 100644
index 0000000..d09a8c0
--- /dev/null
+++ b/modules/default.nix
@@ -0,0 +1,7 @@
+{ ... }:
+
+{
+ imports = [
+ ./filtron.nix
+ ];
+}
diff --git a/modules/filtron.nix b/modules/filtron.nix
new file mode 100644
index 0000000..55374a7
--- /dev/null
+++ b/modules/filtron.nix
@@ -0,0 +1,87 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.filtron;
+ addressType = types.submodule {
+ options = {
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ };
+ port = mkOption { type = types.port; };
+ };
+ };
+in {
+ options.services.filtron = {
+ enable = mkEnableOption { name = "filtron"; };
+ package = mkOption {
+ type = types.package;
+ default = pkgs.personal.filtron;
+ defaultText = literalExample "pkgs.personal.filtron";
+ description = ''
+ The package containing the filtron executable.
+ '';
+ };
+ api = mkOption {
+ type = addressType;
+ default = { address = "localhost"; port = 4005; };
+ description = ''
+ API listen address and port.
+ '';
+ };
+ listen = mkOption {
+ type = addressType;
+ default = { port = 4004; };
+ description = ''
+ Proxy listen address and port.
+ '';
+ };
+ target = mkOption {
+ type = addressType;
+ default = { port = 8888; };
+ description = ''
+ Target address and port for reverse proxy.
+ '';
+ };
+ rules = mkOption {
+ type = with types; listOf (attrsOf anything);
+ description = ''
+ Rule list.
+ '';
+ };
+ readBufferSize = mkOption {
+ type = types.int;
+ default = 16384;
+ description = ''
+ Size of the buffer used for reading.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ users.users.filtron = {
+ description = "Filtron daemon user";
+ group = "filtron";
+ isSystemUser = true;
+ };
+ users.groups.filtron = { };
+
+ systemd.services.filtron = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ description = "Start a filtron instance.";
+ serviceConfig = {
+ User = "filtron";
+ ExecStart = with builtins; ''
+ ${cfg.package}/bin/filtron \
+ -rules ${toFile "filtron-rules.json" (toJSON cfg.rules)} \
+ -api "${cfg.api.address}:${toString cfg.api.port}" \
+ -listen "${cfg.listen.address}:${toString cfg.listen.port}" \
+ -target "${cfg.target.address}:${toString cfg.target.port}" \
+ -read-buffer-size ${toString cfg.readBufferSize}
+ '';
+ };
+ };
+ };
+}
diff --git a/pkgs/academic-webpage/default.nix b/pkgs/academic-webpage/default.nix
new file mode 100644
index 0000000..4c909ff
--- /dev/null
+++ b/pkgs/academic-webpage/default.nix
@@ -0,0 +1,21 @@
+{ pkgs, stdenv, ... }:
+
+stdenv.mkDerivation {
+ name = "academic-webpage";
+
+ buildInputs = with pkgs; [ hugo ];
+
+ src = pkgs.fetchFromGitHub {
+ owner = "qaristote";
+ repo = "academic-webpage";
+ rev = "18e00fdd22643831376e012793574d9293243f6f";
+ sha256 = "148gknjlwr71q5gkp4q7bnza64222izhn949ki14k7b9y7j486c6";
+ fetchSubmodules = true;
+ };
+
+ phases = [ "unpackPhase" "buildPhase" ];
+
+ buildPhase = ''
+ hugo --destination $out
+ '';
+}
diff --git a/pkgs/default.nix b/pkgs/default.nix
new file mode 100644
index 0000000..8182baa
--- /dev/null
+++ b/pkgs/default.nix
@@ -0,0 +1,6 @@
+{ pkgs }:
+
+{
+ academic-webpage = pkgs.callPackage ./academic-webpage { };
+ filtron = pkgs.callPackage ./filtron {};
+}
diff --git a/pkgs/filtron/default.nix b/pkgs/filtron/default.nix
new file mode 100644
index 0000000..863dc4c
--- /dev/null
+++ b/pkgs/filtron/default.nix
@@ -0,0 +1,16 @@
+{ stdenv, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+ pname = "filtron";
+ version = "1.0.0";
+
+ src = fetchFromGitHub {
+ owner = "asciimo";
+ repo = "filtron";
+ rev = "v${version}";
+ sha256 = "18d3h0i2sfqbc0bjx26jm2n9f37zwp8z9z4wd17sw7nvkfa72a26";
+ };
+
+ doCheck = false;
+ vendorSha256 = "05q2g591xl08h387mm6njabvki19yih63dfsafgpc9hyk5ydf2n9";
+}