diff --git a/container/Change.nix b/container/Change.nix new file mode 100644 index 0000000..c3b4bd8 --- /dev/null +++ b/container/Change.nix @@ -0,0 +1,25 @@ +{ container, ... } @args: let + cfg = container.config.change; +in { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.change = container.mkContainer cfg { + bindMounts = { + "/var/lib/changedetection-io" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.changedetection-io = { + enable = true; + baseURL = cfg.domain; + behindProxy = true; + listenAddress = cfg.address; + }; + }; + }; +} diff --git a/container/Cloud.nix b/container/Cloud.nix new file mode 100644 index 0000000..c095cbd --- /dev/null +++ b/container/Cloud.nix @@ -0,0 +1,43 @@ +{ container, ... } @args: let + cfg = container.config.cloud; +in { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.cloud = container.mkContainer cfg { + bindMounts = { + "/var/www/html" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { pkgs, config, ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ pkgs.postgresql ]; + services.nextcloud = { + enable = true; + package = pkgs.nextcloud29; + hostName = cfg.domain; + config = { + adminuser = "root"; + adminpassFile = "${pkgs.writeText "NextcloudPassword" "root"}"; + + dbhost = container.config.postgres.address; + dbname = "nextcloud"; + # dbpassFile = "${pkgs.writeText "NextcloudDbPassword" "nextcloud"}"; + dbtype = "pgsql"; + dbuser = "nextcloud"; + }; + extraApps = { + inherit (config.services.nextcloud.package.packages.apps) contacts calendar; + }; + extraAppsEnable = true; + settings = { + trusted_domains = [ cfg.address ]; + trusted_proxies = [ container.config.proxy.address ]; + }; + }; + }; + }; +} diff --git a/container/Paste.nix b/container/Paste.nix new file mode 100644 index 0000000..ff4a698 --- /dev/null +++ b/container/Paste.nix @@ -0,0 +1,101 @@ +{ pkgs, util, container, ... } @args: let + cfg = container.config.paste; + package = (pkgs.callPackage ./pastebin args); +in { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + "tmp" + "nginxtmp" + ]; + + containers.paste = container.mkContainer cfg { + bindMounts = { + "/srv/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + "/tmp" = { + hostPath = "${cfg.storage}/tmp"; + isReadOnly = false; + }; + "/var/lib/nginx/tmp" = { + hostPath = "${cfg.storage}/nginxtmp"; + isReadOnly = false; + }; + "/srv/config" = { + hostPath = "${cfg.storage}/config"; + isReadOnly = false; + }; + }; + + config = { config, ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ package ]; + systemd.packages = [ package ]; + + users.users.paste = { + group = "nginx"; + isSystemUser = true; + }; + + services.phpfpm.pools.paste = { + user = "paste"; + group = "nginx"; + + phpPackage = pkgs.php; + + settings = { + "pm" = "dynamic"; + "php_admin_value[error_log]" = "stderr"; + "php_admin_flag[log_errors]" = true; + "listen.owner" = "nginx"; + "catch_workers_output" = true; + "pm.max_children" = "32"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "2"; + "pm.max_spare_servers" = "4"; + "pm.max_requests" = "500"; + }; + + phpEnv = { + # CONFIG_PATH = "${package}/cfg"; + }; + }; + + services.nginx = { + enable = true; + virtualHosts.${cfg.domain} = container.mkServer { + default = true; + root = "${package}"; + + locations = { + "/".extraConfig = '' + rewrite ^ /index.php; + ''; + + "~ \\.php$".extraConfig = util.trimTabs '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools.paste.socket}; + include ${config.services.nginx.package}/conf/fastcgi.conf; + include ${config.services.nginx.package}/conf/fastcgi_params; + ''; + + "~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = util.trimTabs '' + add_header Cache-Control "public, max-age=15778463"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header Referrer-Policy no-referrer; + access_log off; + ''; + }; + + extraConfig = util.trimTabs '' + try_files $uri /index.php; + ''; + }; + }; + }; + }; +} diff --git a/container/Postgres.nix b/container/Postgres.nix new file mode 100644 index 0000000..6988a4a --- /dev/null +++ b/container/Postgres.nix @@ -0,0 +1,40 @@ +{ container, ... } @args: let + cfg = container.config.postgres; +in { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.postgres = container.mkContainer cfg { + bindMounts = { + "/var/lib/postgresql/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { pkgs, ... }: container.mkContainerConfig cfg { + services.postgresql = let + databases = [ + "privatebin" + "nextcloud" + ]; + in { + enable = true; + package = pkgs.postgresql_14; + dataDir = "/var/lib/postgresql/data/14"; + enableTCPIP = true; + authentication = '' + host all all ${container.host}/32 trust + host privatebin privatebin ${container.config.paste.address}/32 trust + host nextcloud nextcloud ${container.config.cloud.address}/32 trust + ''; + ensureDatabases = databases; + ensureUsers = map (name: { + inherit name; + ensureDBOwnership = true; + }) databases; + }; + }; + }; +} diff --git a/container/Proxy.nix b/container/Proxy.nix new file mode 100644 index 0000000..437f057 --- /dev/null +++ b/container/Proxy.nix @@ -0,0 +1,79 @@ +{ domain, util, container, ... } @args: let + cfg = container.config.proxy; + virtualHosts = util.catSet (util.ls ./proxy/host) args; +in { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "challenge" + "letsencrypt" + ]; + + containers.proxy = container.mkContainer cfg { + bindMounts = { + "/etc/letsencrypt" = { + hostPath = "${cfg.storage}/letsencrypt"; + isReadOnly = true; + }; + "/var/www/.well-known" = { + hostPath = "${cfg.storage}/challenge"; + isReadOnly = false; + }; + }; + + config = { pkgs, ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ certbot ]; + + services.nginx = { + inherit virtualHosts; + + enable = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + appendConfig = util.trimTabs '' + worker_processes 4; + ''; + eventsConfig = util.trimTabs '' + worker_connections 4096; + ''; + appendHttpConfig = util.trimTabs '' + server { + server_name default_server; + listen 80; + + location / { + return 301 https://$host$request_uri; + } + } + + map $http_accept_language $resume { + default https://git.${domain}/voronind/resume/releases/download/latest/voronind_en.pdf; + ~ru https://git.${domain}/voronind/resume/releases/download/latest/voronind_ru.pdf; + } + + server { + server_name ${domain}; + listen 443 ssl; + + ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + + return 301 $resume; + } + + server { + listen 443 ssl default_server; + server_name _; + + ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + + return 403; + } + ''; + }; + }; + }; +} diff --git a/container/default.nix b/container/default.nix new file mode 100644 index 0000000..3a1f7cb --- /dev/null +++ b/container/default.nix @@ -0,0 +1,62 @@ +{ lib +, const +, host +, storage +, domain +, ... }: { + inherit host; + + mkContainer = config: cfg: lib.recursiveUpdate cfg { + autoStart = true; + hostAddress = host; + localAddress = config.address; + privateNetwork = true; + }; + + mkContainerConfig = config: cfg: lib.recursiveUpdate cfg { + system.stateVersion = const.stateVersion; + + users.users.root.password = ""; + users.mutableUsers = false; + + networking = { + nameservers = [ + "1.1.1.1" + ]; + useHostResolvConf = lib.mkForce false; + firewall.enable = false; + }; + }; + + mkContainerDir = cfg: dirs: map (path: "d '${cfg.storage}/${path}' 1777 root root - -") dirs; + + mkServer = cfg: lib.recursiveUpdate cfg { + forceSSL = false; + }; + + config = { + change = { + address = "10.1.0.41"; + domain = "change.${domain}"; + storage = "${storage}/change"; + }; + cloud = { + address = "10.1.0.13"; + domain = "cloud.${domain}"; + storage = "${storage}/cloud"; + }; + paste = { + address = "10.1.0.14"; + domain = "paste.${domain}"; + storage = "${storage}/paste"; + }; + proxy = { + address = "10.1.0.2"; + storage = "${storage}/proxy"; + }; + postgres = { + address = "10.1.0.3"; + storage = "${storage}/postgres"; + }; + }; +} diff --git a/container/pastebin/Config.nix b/container/pastebin/Config.nix new file mode 100644 index 0000000..e149bbd --- /dev/null +++ b/container/pastebin/Config.nix @@ -0,0 +1,281 @@ +{ util, ... }: { + text = util.trimTabs '' + ;project page." + + ; (optional) notice to display + ; notice = "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service." + + ; by default PrivateBin will guess the visitors language based on the browsers + ; settings. Optionally you can enable the language selection menu, which uses + ; a session cookie to store the choice until the browser is closed. + languageselection = false + + ; set the language your installs defaults to, defaults to English + ; if this is set and language selection is disabled, this will be the only language + ; languagedefault = "en" + + ; (optional) URL shortener address to offer after a new paste is created. + ; It is suggested to only use this with self-hosted shorteners as this will leak + ; the pastes encryption key. + ; urlshortener = "https://shortener.example.com/api?link=" + + ; (optional) Let users create a QR code for sharing the paste URL with one click. + ; It works both when a new paste is created and when you view a paste. + ; qrcode = true + + ; (optional) Let users send an email sharing the paste URL with one click. + ; It works both when a new paste is created and when you view a paste. + ; email = true + + ; (optional) IP based icons are a weak mechanism to detect if a comment was from + ; a different user when the same username was used in a comment. It might get + ; used to get the IP of a comment poster if the server salt is leaked and a + ; SHA512 HMAC rainbow table is generated for all (relevant) IPs. + ; Can be set to one these values: + ; "none" / "identicon" (default) / "jdenticon" / "vizhash". + ; icon = "none" + + ; Content Security Policy headers allow a website to restrict what sources are + ; allowed to be accessed in its context. You need to change this if you added + ; custom scripts from third-party domains to your templates, e.g. tracking + ; scripts or run your site behind certain DDoS-protection services. + ; Check the documentation at https://content-security-policy.com/ + ; Notes: + ; - If you use any bootstrap theme, you can remove the allow-popups from the + ; sandbox restrictions. + ; - If you use the bootstrap5 theme, you must change default-src to 'self' to + ; enable display of the svg icons + ; - By default this disallows to load images from third-party servers, e.g. when + ; they are embedded in pastes. If you wish to allow that, you can adjust the + ; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images + ; for details. + ; - The 'unsafe-eval' is used in two cases; to check if the browser supports + ; async functions and display an error if not and for Chrome to enable + ; webassembly support (used for zlib compression). You can remove it if Chrome + ; doesn't need to be supported and old browsers don't need to be warned. + ; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads" + + ; stay compatible with PrivateBin Alpha 0.19, less secure + ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of + ; sha256 in HMAC for the deletion token + ; zerobincompatibility = false + + ; Enable or disable the warning message when the site is served over an insecure + ; connection (insecure HTTP instead of HTTPS), defaults to true. + ; Secure transport methods like Tor and I2P domains are automatically whitelisted. + ; It is **strongly discouraged** to disable this. + ; See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection for more information. + ; httpwarning = true + + ; Pick compression algorithm or disable it. Only applies to pastes/comments + ; created after changing the setting. + ; Can be set to one these values: "none" / "zlib" (default). + ; compression = "zlib" + + [expire] + ; expire value that is selected per default + ; make sure the value exists in [expire_options] + default = "1week" + + [expire_options] + ; Set each one of these to the number of seconds in the expiration period, + ; or 0 if it should never expire + 5min = 300 + 10min = 600 + 1hour = 3600 + 1day = 86400 + 1week = 604800 + ; Well this is not *exactly* one month, it's 30 days: + 1month = 2592000 + 1year = 31536000 + never = 0 + + [formatter_options] + ; Set available formatters, their order and their labels + plaintext = "Plain Text" + syntaxhighlighting = "Source Code" + markdown = "Markdown" + + [traffic] + ; time limit between calls from the same IP address in seconds + ; Set this to 0 to disable rate limiting. + limit = 10 + + ; (optional) Set IPs addresses (v4 or v6) or subnets (CIDR) which are exempted + ; from the rate-limit. Invalid IPs will be ignored. If multiple values are to + ; be exempted, the list needs to be comma separated. Leave unset to disable + ; exemptions. + ; exempted = "1.2.3.4,10.10.10/24" + + ; (optional) If you want only some source IP addresses (v4 or v6) or subnets + ; (CIDR) to be allowed to create pastes, set these here. Invalid IPs will be + ; ignored. If multiple values are to be exempted, the list needs to be comma + ; separated. Leave unset to allow anyone to create pastes. + ; creators = "1.2.3.4,10.10.10/24" + + ; (optional) if your website runs behind a reverse proxy or load balancer, + ; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR + ; header = "X_FORWARDED_FOR" + + [purge] + ; minimum time limit between two purgings of expired pastes, it is only + ; triggered when pastes are created + ; Set this to 0 to run a purge every time a paste is created. + limit = 300 + + ; maximum amount of expired pastes to delete in one purge + ; Set this to 0 to disable purging. Set it higher, if you are running a large + ; site + batchsize = 10 + + ;[model] + ; name of data model class to load and directory for storage + ; the default model "Filesystem" stores everything in the filesystem + ;class = Filesystem + ;[model_options] + ;dir = PATH "data" + + ;[model] + ; example of a Google Cloud Storage configuration + ;class = GoogleCloudStorage + ;[model_options] + ;bucket = "my-private-bin" + ;prefix = "pastes" + ;uniformacl = false + + ;[model] + ; example of DB configuration for MySQL + ;class = Database + ;[model_options] + ;dsn = "mysql:host=localhost;dbname=privatebin;charset=UTF8" + ;tbl = "privatebin_" ; table prefix + ;usr = "privatebin" + ;pwd = "Z3r0P4ss" + ;opt[12] = true ; PDO::ATTR_PERSISTENT + + ;[model] + ; example of DB configuration for SQLite + ;class = Database + ;[model_options] + ;dsn = "sqlite:" PATH "data/db.sq3" + ;usr = null + ;pwd = null + ;opt[12] = true ; PDO::ATTR_PERSISTENT + + [model] + ; example of DB configuration for PostgreSQL + class = Database + [model_options] + dsn = "pgsql:host=10.1.0.3;dbname=privatebin" + tbl = "privatebin_" ; table prefix + usr = "privatebin" + pwd = "privatebin" + opt[12] = true ; PDO::ATTR_PERSISTENT + + ;[model] + ; example of S3 configuration for Rados gateway / CEPH + ;class = S3Storage + ;[model_options] + ;region = "" + ;version = "2006-03-01" + ;endpoint = "https://s3.my-ceph.invalid" + ;use_path_style_endpoint = true + ;bucket = "my-bucket" + ;accesskey = "my-rados-user" + ;secretkey = "my-rados-pass" + + ;[model] + ; example of S3 configuration for AWS + ;class = S3Storage + ;[model_options] + ;region = "eu-central-1" + ;version = "latest" + ;bucket = "my-bucket" + ;accesskey = "access key id" + ;secretkey = "secret access key" + + ;[model] + ; example of S3 configuration for AWS using its SDK default credential provider chain + ; if relying on environment variables, the AWS SDK will look for the following: + ; - AWS_ACCESS_KEY_ID + ; - AWS_SECRET_ACCESS_KEY + ; - AWS_SESSION_TOKEN (if needed) + ; for more details, see https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain + ;class = S3Storage + ;[model_options] + ;region = "eu-central-1" + ;version = "latest" + ;bucket = "my-bucket" + + [yourls] + ; When using YOURLS as a "urlshortener" config item: + ; - By default, "urlshortener" will point to the YOURLS API URL, with or without + ; credentials, and will be visible in public on the PrivateBin web page. + ; Only use this if you allow short URL creation without credentials. + ; - Alternatively, using the parameters in this section ("signature" and + ; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin + ; instance with "?shortenviayourls&link=" appended. For example: + ; urlshortener = "''${basepath}?shortenviayourls&link=" + ; This URL will in turn call YOURLS on the server side, using the URL from + ; "apiurl" and the "access signature" from the "signature" parameters below. + + ; (optional) the "signature" (access key) issued by YOURLS for the using account + ; signature = "" + ; (optional) the URL of the YOURLS API, called to shorten a PrivateBin URL + ; apiurl = "https://yourls.example.com/yourls-api.php" + ''; +} diff --git a/container/pastebin/default.nix b/container/pastebin/default.nix new file mode 100644 index 0000000..a59dc88 --- /dev/null +++ b/container/pastebin/default.nix @@ -0,0 +1,35 @@ +{ php, pkgs, util, ... } @args: let + cfg = pkgs.writeText "PrivateBinConfig" (import ./Config.nix args).text; +in php.buildComposerProject (finalAttrs: { + pname = "PrivateBin"; + version = "1.7.3"; + + src = pkgs.fetchFromGitHub { + owner = "PrivateBin"; + repo = "PrivateBin"; + rev = finalAttrs.version; + hash = "sha256-9aTpLixvvyy3xTk8QQFj4rI6gFtElO4naPgTARtpo1k="; + }; + + vendorHash = "sha256-JGuO8kXLLXqq76EccdNSoHwYO5OuJT3Au1O2O2szAHI="; + + installPhase = '' + runHook preInstall + + mv $out/share/php/PrivateBin/* $out + rm -r $out/share + + cp ${cfg} $out/cfg/conf.php + + touch $out/.env + pushd $out + + runHook postInstall + ''; + + postFixup = '' + substituteInPlace $out/index.php --replace-fail \ + "define('PATH', ''')" \ + "define('PATH', '$out/')" + ''; +}) diff --git a/container/proxy/host/Change.nix b/container/proxy/host/Change.nix new file mode 100644 index 0000000..0da2a3b --- /dev/null +++ b/container/proxy/host/Change.nix @@ -0,0 +1,22 @@ +{ domain, util, container, ... }: let + cfg = container.config.change; +in { + ${cfg.domain} = container.mkServer { + extraConfig = util.trimTabs '' + listen 443 ssl; + set $change ${cfg.address}:5000; + + location / { + allow 192.168.1.0/24; + allow 10.1.0.1; + deny all; + proxy_pass http://$change$request_uri; + } + + ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + ''; + }; +} diff --git a/container/proxy/host/Cloud.nix b/container/proxy/host/Cloud.nix new file mode 100644 index 0000000..971c21a --- /dev/null +++ b/container/proxy/host/Cloud.nix @@ -0,0 +1,26 @@ +{ domain, util, container, ... }: let + cfg = container.config.cloud; +in { + ${cfg.domain} = container.mkServer { + extraConfig = util.trimTabs '' + listen 443 ssl; + set $cloud ${cfg.address}:80; + + location ~ ^/(settings/admin|settings/users|settings/apps|login|api) { + allow 192.168.1.0/24; + allow 10.1.0.1; + deny all; + proxy_pass http://$cloud$request_uri; + } + location / { + proxy_pass http://$cloud$request_uri; + } + + ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + ''; + }; +} + diff --git a/container/proxy/host/Paste.nix b/container/proxy/host/Paste.nix new file mode 100644 index 0000000..1e677d0 --- /dev/null +++ b/container/proxy/host/Paste.nix @@ -0,0 +1,22 @@ +{ domain, util, container, ... }: let + cfg = container.config.paste; +in { + ${cfg.domain} = container.mkServer { + extraConfig = util.trimTabs '' + listen 443 ssl; + set $paste ${cfg.address}:80; + + location = / { + return 403; + } + location / { + proxy_pass http://$paste$request_uri; + } + + ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + ''; + }; +} diff --git a/flake.nix b/flake.nix index b819e46..d14d6de 100644 --- a/flake.nix +++ b/flake.nix @@ -125,7 +125,7 @@ # Constant values. const = { droidStateVersion = "22.11"; - stateVersion = "23.11"; + stateVersion = "24.05"; timeZone = "Europe/Moscow"; url = "https://git.voronind.com/voronind/nixos.git"; }; diff --git a/host/desktop/Container.nix b/host/desktop/Container.nix new file mode 100644 index 0000000..f11a4e0 --- /dev/null +++ b/host/desktop/Container.nix @@ -0,0 +1,33 @@ +{ pkgs, const, lib, config, util, ... }: let + args = let + storage = "/storage/hot/container"; + domain = "local"; + host = "192.168.1.3"; + in { + inherit storage domain host pkgs const lib config util; + + container = import ../../container args; + }; +in { + networking.nat = { + enable = true; + internalInterfaces = [ "ve-+" ]; + externalInterface = "enp4s0"; + }; + + # TODO: Remove this. + networking.extraHosts = '' + 10.1.0.2 change.local + 10.1.0.2 cloud.local + 10.1.0.2 paste.local + 10.1.0.2 local + ''; + + imports = [ + (import ../../container/Change.nix args) + (import ../../container/Cloud.nix args) + (import ../../container/Paste.nix args) + (import ../../container/Postgres.nix args) + (import ../../container/Proxy.nix args) + ]; +} diff --git a/host/desktop/default.nix b/host/desktop/default.nix index 277f895..297578d 100644 --- a/host/desktop/default.nix +++ b/host/desktop/default.nix @@ -1,5 +1,6 @@ { ... }: { imports = [ + ./Container.nix ./Filesystem.nix ]; } diff --git a/host/work/Container.nix b/host/work/Container.nix new file mode 100644 index 0000000..a79278b --- /dev/null +++ b/host/work/Container.nix @@ -0,0 +1,25 @@ +{ pkgs, const, lib, config, util, ... }: let + args = let + storage = "/tmp/container"; + domain = "local"; + host = "192.168.0.174"; + in { + inherit storage domain host pkgs const lib config util; + }; +in { + networking.nat = { + enable = true; + internalInterfaces = [ "ve-+" ]; + externalInterface = "enp4s0"; + }; + + # NOTE: Remove this. + networking.extraHosts = '' + 10.1.0.2 paste.local + ''; + + imports = [ + (import ../../container/Paste.nix args) + (import ../../container/Proxy.nix args) + ]; +} diff --git a/host/work/default.nix b/host/work/default.nix index 6ac0fae..94f3dbb 100644 --- a/host/work/default.nix +++ b/host/work/default.nix @@ -1,5 +1,6 @@ { lib, ... }: { imports = [ + ./Container.nix ./Fprint.nix ]; diff --git a/module/common/Kernel.nix b/module/common/Kernel.nix index 91b3f1a..718e91a 100644 --- a/module/common/Kernel.nix +++ b/module/common/Kernel.nix @@ -3,24 +3,24 @@ boot.kernelPackages = pkgs.linuxPackages_latest; boot.kernel.sysctl = { - # Spoof protection. - "net.ipv4.conf.default.rp_filter" = 1; - "net.ipv4.conf.all.rp_filter" = 1; + # # Spoof protection. + # "net.ipv4.conf.default.rp_filter" = 1; + # "net.ipv4.conf.all.rp_filter" = 1; - # Packet forwarding. - "net.ipv4.ip_forward" = 1; - # "net.ipv6.conf.all.forwarding" = 1; + # # Packet forwarding. + # "net.ipv4.ip_forward" = 1; + # # "net.ipv6.conf.all.forwarding" = 1; - # MITM protection. - "net.ipv4.conf.all.accept_redirects" = 0; - "net.ipv6.conf.all.accept_redirects" = 0; + # # MITM protection. + # "net.ipv4.conf.all.accept_redirects" = 0; + # "net.ipv6.conf.all.accept_redirects" = 0; - # Do not send ICMP redirects (we are not a router). - "net.ipv4.conf.all.send_redirects" = 0; + # # Do not send ICMP redirects (we are not a router). + # "net.ipv4.conf.all.send_redirects" = 0; - # Do not accept IP source route packets (we are not a router). - "net.ipv4.conf.all.accept_source_route" = 0; - "net.ipv6.conf.all.accept_source_route" = 0; + # # Do not accept IP source route packets (we are not a router). + # "net.ipv4.conf.all.accept_source_route" = 0; + # "net.ipv6.conf.all.accept_source_route" = 0; # Allow sysrq. "kernel.sysrq" = 1; @@ -36,23 +36,23 @@ "kernel.core_uses_pid" = 1; "kernel.kptr_restrict" = 2; - # IP hardening. - "net.ipv4.conf.all.log_martians" = 1; - "net.ipv4.conf.default.accept_redirects" = 0; - "net.ipv4.conf.default.accept_source_route" = 0; - "net.ipv4.conf.default.log_martians" = 0; - "net.ipv4.tcp_timestamps" = 0; - "net.ipv6.conf.default.accept_redirects" = 0; + # # IP hardening. + # "net.ipv4.conf.all.log_martians" = 1; + # "net.ipv4.conf.default.accept_redirects" = 0; + # "net.ipv4.conf.default.accept_source_route" = 0; + # "net.ipv4.conf.default.log_martians" = 0; + # "net.ipv4.tcp_timestamps" = 0; + # "net.ipv6.conf.default.accept_redirects" = 0; # Increase file watchers. "fs.inotify.max_user_instances" = 999999; "fs.inotify.max_user_watches" = 999999; "fs.inotify.max_user_event" = 999999; - # Disable ipv6. - "net.ipv6.conf.all.disable_ipv6" = 1; - "net.ipv6.conf.default.disable_ipv6" = 1; - "net.ipv6.conf.lo.disable_ipv6" = 1; - "net.ipv6.conf.eth0.disable_ipv6" = 1; + # # Disable ipv6. + # "net.ipv6.conf.all.disable_ipv6" = 1; + # "net.ipv6.conf.default.disable_ipv6" = 1; + # "net.ipv6.conf.lo.disable_ipv6" = 1; + # "net.ipv6.conf.eth0.disable_ipv6" = 1; }; } diff --git a/module/common/httptoolkit/default.nix b/module/common/httptoolkit/default.nix new file mode 100644 index 0000000..5f07a7c --- /dev/null +++ b/module/common/httptoolkit/default.nix @@ -0,0 +1,56 @@ +# Apple San Francisco and New York fonts. +# They are not available in Nixpkgs repo, so this script +# downloads the fonts from Apple website and adds them to Nix store. +{ lib, stdenv, fetchurl, pkgs }: stdenv.mkDerivation { + pname = "httptoolkit"; + version = "1.15.0"; + + src = fetchurl { + url = "https://github.com/httptoolkit/httptoolkit-desktop/releases/download/v1.15.0/HttpToolkit-linux-x64-1.15.0.zip"; + hash = "sha256-wb4is5IX1/Sjea4tggFP48snAx7+Bp4ux+306xFBMtM="; + }; + + nativeBuildInputs = with pkgs; [ + autoPatchelfHook + unzip + ]; + + sourceRoot = "."; + + buildInputs = with pkgs; [ + alsa-lib + atk + cairo + cups + dbus + expat + glib + gtk3 + libGL + libxkbcommon + mesa + nss + pango + playwright + xorg.libXcomposite + xorg.libXrandr + xorg.libxcb + ]; + + preBuild = '' + addAutoPatchelfSearchPath . + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp -r * $out/bin + install -m755 -D httptoolkit $out/bin + runHook postInstall + ''; + + meta = with lib; { + homapage = "https://github.com/httptoolkit/httptoolkit-desktop"; + platform = platforms.linux; + }; +}