summaryrefslogtreecommitdiff
path: root/aphrodite
diff options
context:
space:
mode:
authortoufic ar <contact@toufy.me>2026-04-22 14:08:19 +0300
committertoufic ar <contact@toufy.me>2026-04-22 14:08:19 +0300
commitc7349e466fef7ecff5a46b1d0c819975a6bdcb8c (patch)
tree2a3fc53016ae4d0b31d7583171bd4b8e60f4cc17 /aphrodite
downloadservers-c7349e466fef7ecff5a46b1d0c819975a6bdcb8c.tar.gz
servers-c7349e466fef7ecff5a46b1d0c819975a6bdcb8c.zip
initial commit
Diffstat (limited to 'aphrodite')
-rw-r--r--aphrodite/default.nix9
-rw-r--r--aphrodite/devops/default.nix6
-rw-r--r--aphrodite/devops/docker.nix13
-rw-r--r--aphrodite/devops/git.nix95
-rw-r--r--aphrodite/mail/default.nix79
-rw-r--r--aphrodite/network.nix20
-rw-r--r--aphrodite/search/default.nix108
-rw-r--r--aphrodite/search/engines.nix166
8 files changed, 496 insertions, 0 deletions
diff --git a/aphrodite/default.nix b/aphrodite/default.nix
new file mode 100644
index 0000000..fb4101c
--- /dev/null
+++ b/aphrodite/default.nix
@@ -0,0 +1,9 @@
+{
+ imports = [
+ ./network.nix
+ ./devops
+ ./mail
+ ./search
+ ];
+ system.stateVersion = "25.11";
+}
diff --git a/aphrodite/devops/default.nix b/aphrodite/devops/default.nix
new file mode 100644
index 0000000..74fb9aa
--- /dev/null
+++ b/aphrodite/devops/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./docker.nix
+ ./git.nix
+ ];
+}
diff --git a/aphrodite/devops/docker.nix b/aphrodite/devops/docker.nix
new file mode 100644
index 0000000..cb53fcb
--- /dev/null
+++ b/aphrodite/devops/docker.nix
@@ -0,0 +1,13 @@
+{pkgs, ...}: {
+ environment.systemPackages = with pkgs; [
+ docker-compose
+ ];
+ virtualisation = {
+ docker = {
+ enable = true;
+ storageDriver = "btrfs";
+ autoPrune.enable = true;
+ };
+ oci-containers.backend = "docker";
+ };
+}
diff --git a/aphrodite/devops/git.nix b/aphrodite/devops/git.nix
new file mode 100644
index 0000000..7b2800b
--- /dev/null
+++ b/aphrodite/devops/git.nix
@@ -0,0 +1,95 @@
+{
+ config,
+ pkgs,
+ ...
+}: let
+ domain = "git.${config.customOps.domain.fqdn}";
+ cgitPatched = pkgs.fetchpatch2 {
+ url = "https://git.zx2c4.com/cgit/patch/?id=601ba0f25d6d9df488a5a37c7877818ac47966b0";
+ sha256 = "sha256-yW54g40Bj2QxUwj4KZUjHMT1JGvVKW7o16NM83XDqsQ=";
+ };
+in {
+ programs.git = {
+ enable = true;
+ lfs.enable = true;
+ config = {
+ init = {
+ defaultBranch = "main";
+ };
+ };
+ };
+
+ services.gitolite = {
+ enable = true;
+ user = "git";
+ group = "git";
+ adminPubkey = config.customOps.owner.pubkey;
+ extraGitoliteRc = ''
+ %RC = (
+ UMASK => 0027,
+ GIT_CONFIG_KEYS => '.*',
+ LOG_EXTRA => 1,
+ ROLES => {
+ READERS => 1,
+ WRITERS => 1,
+ },
+ ENABLE => [
+ 'help',
+ 'desc',
+ 'info',
+ 'perms',
+ 'writable',
+ 'ssh-authkeys',
+ 'git-config',
+ 'daemon',
+ 'gitweb',
+ ],
+ );
+ '';
+ };
+
+ services.cgit.${domain} = {
+ enable = true;
+ package = pkgs.cgit.overrideAttrs (old: {
+ patches = (old.patches or []) ++ [cgitPatched];
+ });
+ user = "git";
+ group = "git";
+ gitHttpBackend = {
+ enable = true;
+ checkExportOkFiles = true;
+ };
+ scanPath = "${config.services.gitolite.dataDir}/repositories";
+ settings = {
+ root-title = domain;
+ root-desc = "toufy's project repositories";
+ snapshots = "tar.gz zip";
+ clone-url = "https://${domain}/$CGIT_REPO_URL";
+ enable-index-owner = true;
+ enable-index-links = true;
+ remove-suffix = true;
+ enable-blame = true;
+ enable-commit-graph = true;
+ enable-log-filecount = true;
+ enable-log-linecount = true;
+ strict-export = "git-daemon-export-ok";
+ branch-sort = "age";
+ virtual-root = "/";
+ enable-git-config = true;
+ "mimetype.gif" = "image/gif";
+ "mimetype.html" = "text/html";
+ "mimetype.jpg" = "image/jpeg";
+ "mimetype.jpeg" = "image/jpeg";
+ "mimetype.pdf" = "application/pdf";
+ "mimetype.png" = "image/png";
+ "mimetype.svg" = "image/svg+xml";
+ readme = ":README.md";
+ project-list = "${config.services.gitolite.dataDir}/projects.list";
+ };
+ };
+
+ services.nginx.virtualHosts.${domain} = {
+ forceSSL = true;
+ enableACME = true;
+ };
+}
diff --git a/aphrodite/mail/default.nix b/aphrodite/mail/default.nix
new file mode 100644
index 0000000..c12e79d
--- /dev/null
+++ b/aphrodite/mail/default.nix
@@ -0,0 +1,79 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ domainFqdn = config.customOps.domain.fqdn;
+ hostname = config.networking.hostName;
+in {
+ sops.secrets = let
+ accounts = config.customOps.mailAccounts;
+ in
+ builtins.listToAttrs (
+ map (acc: {
+ name = accounts.${acc}.passwdFile;
+ value = {owner = "dovecot2";};
+ }) (builtins.attrNames accounts)
+ );
+
+ mailserver = {
+ enable = true;
+ stateVersion = 3;
+ fqdn = "${hostname}.${domainFqdn}";
+ domains = [domainFqdn];
+ systemDomain = domainFqdn;
+ systemName = domainFqdn;
+ systemContact = "postmaster@${domainFqdn}";
+
+ dmarcReporting.enable = true;
+ tlsrpt.enable = true;
+
+ fullTextSearch.enable = true;
+ virusScanning = true;
+
+ mailboxes = {
+ Archive = {
+ auto = "subscribe";
+ specialUse = "Archive";
+ };
+ Drafts = {
+ auto = "subscribe";
+ specialUse = "Drafts";
+ };
+ Junk = {
+ auto = "subscribe";
+ specialUse = "Junk";
+ };
+ Sent = {
+ auto = "subscribe";
+ specialUse = "Sent";
+ };
+ Trash = {
+ auto = "subscribe";
+ specialUse = "Trash";
+ };
+ };
+
+ loginAccounts =
+ lib.mapAttrs (account: cfg: {
+ aliases = cfg.aliases;
+ aliasesRegexp = cfg.aliasesRegex;
+ catchAll = cfg.catchAll;
+ hashedPasswordFile = config.sops.secrets.${cfg.passwdFile}.path;
+ sendOnly = cfg.sendOnly;
+ })
+ config.customOps.mailAccounts;
+ certificateScheme = "acme";
+ };
+
+ services.roundcube = {
+ enable = true;
+ hostName = "mail.${domainFqdn}";
+ extraConfig = ''
+ $config['imap_host'] = "ssl://${hostname}.${domainFqdn}";
+ $config['smtp_host'] = "ssl://${hostname}.${domainFqdn}";
+ $config['smtp_user'] = "%u";
+ $config['smtp_pass'] = "%p";
+ '';
+ };
+}
diff --git a/aphrodite/network.nix b/aphrodite/network.nix
new file mode 100644
index 0000000..a5fa512
--- /dev/null
+++ b/aphrodite/network.nix
@@ -0,0 +1,20 @@
+{
+ networking = {
+ hostName = "aphrodite";
+ interfaces.ens3.ipv6 = {
+ addresses = [
+ {
+ address = "2a0a:4cc0:c0:2991::10";
+ prefixLength = 64;
+ }
+ ];
+ routes = [
+ {
+ address = "::";
+ via = "fe80::1";
+ prefixLength = 0;
+ }
+ ];
+ };
+ };
+}
diff --git a/aphrodite/search/default.nix b/aphrodite/search/default.nix
new file mode 100644
index 0000000..172e8f8
--- /dev/null
+++ b/aphrodite/search/default.nix
@@ -0,0 +1,108 @@
+{config, ...}: let
+ searxDomain = "search.${config.customOps.domain.fqdn}";
+in {
+ imports = [./engines.nix];
+
+ sops.secrets.searx.owner = "searx";
+
+ services.searx = {
+ enable = true;
+ redisCreateLocally = true;
+
+ limiterSettings = {
+ real_ip = {
+ x_for = 1;
+ ipv4_prefix = 32;
+ ipv6_prefix = 56;
+ };
+
+ botdetection = {
+ ip_limit = {
+ filter_link_local = true;
+ link_token = true;
+ };
+ };
+ };
+
+ faviconsSettings = {
+ favicons = {
+ cfg_schema = 1;
+ cache = {
+ db_url = "/var/cache/searx/faviconcache.db";
+ HOLD_TIME = 5184000;
+ LIMIT_TOTAL_BYTES = 2147483648;
+ BLOB_MAX_BYTES = 40960;
+ MAINTENANCE_MODE = "auto";
+ MAINTENANCE_PERIOD = 600;
+ };
+ };
+ };
+
+ settings = {
+ general = {
+ debug = false;
+ instance_name = "${config.customOps.owner.username}'s search";
+ donation_url = false;
+ contact_url = false;
+ privacypolicy_url = false;
+ enable_metrics = false;
+ };
+
+ ui = {
+ static_use_hash = true;
+ default_locale = "en";
+ query_in_title = false;
+ infinite_scroll = true;
+ center_alignment = false;
+ default_theme = "simple";
+ theme_args.simple_style = "auto";
+ search_on_category_select = true;
+ hotkeys = "vim";
+ url_formatting = "full";
+ };
+
+ search = {
+ safe_search = 0;
+ autocomplete_min = 2;
+ autocomplete = "duckduckgo";
+ favicon_resolver = "allesedv";
+ ban_time_on_fail = 5;
+ max_ban_time_on_fail = 120;
+ };
+
+ server = {
+ base_url = "https://${searxDomain}";
+ port = 8888;
+ bind_address = "127.0.0.1";
+ secret_key = config.sops.secrets.searx.path;
+ limiter = true;
+ public_instance = true;
+ image_proxy = false;
+ method = "POST";
+ };
+
+ outgoing = {
+ request_timeout = 30.0;
+ pool_connections = 100;
+ pool_maxsize = 15;
+ enable_http2 = true;
+ };
+
+ enabled_plugins = [
+ "Basic Calculator"
+ "Hash plugin"
+ "Tor check plugin"
+ "Open Access DOI rewrite"
+ "Hostnames plugin"
+ "Unit converter plugin"
+ "Tracker URL remover"
+ ];
+ };
+ };
+
+ services.nginx.virtualHosts.${searxDomain} = {
+ forceSSL = true;
+ enableACME = true;
+ locations."/".proxyPass = "http://localhost:8888";
+ };
+}
diff --git a/aphrodite/search/engines.nix b/aphrodite/search/engines.nix
new file mode 100644
index 0000000..6b112de
--- /dev/null
+++ b/aphrodite/search/engines.nix
@@ -0,0 +1,166 @@
+{lib, ...}: {
+ services.searx.settings.engines =
+ lib.mapAttrsToList (
+ name: value: {inherit name;} // value
+ ) {
+ # unnecessary
+ "wiby".inactive = true;
+ "bandcamp".inactive = true;
+ "github".inactive = true;
+ "dictzone".inactive = true;
+ "lingva".inactive = true;
+ "mymemory translated".inactive = true;
+ "mozhi".inactive = true;
+ "presearch".inactive = true;
+ "presearch images".inactive = true;
+ "presearch videos".inactive = true;
+ "presearch news".inactive = true;
+ "seznam".inactive = true;
+ "goo".inactive = true;
+ "naver".inactive = true;
+ "naver videos".inactive = true;
+ "naver images".inactive = true;
+ "naver news".inactive = true;
+ "alexandria".inactive = true;
+ "ask".inactive = true;
+ "crowdview".inactive = true;
+ "mwmbl".inactive = true;
+ "searchmysite".inactive = true;
+ "stract".inactive = true;
+ "bpb".inactive = true;
+ "tagesschau".inactive = true;
+ "wikimini".inactive = true;
+ "findthatmeme".inactive = true;
+ "frinkiac".inactive = true;
+ "livespace".inactive = true;
+ "sepiasearch".inactive = true;
+ "mediathekviewweb".inactive = true;
+ "ina".inactive = true;
+ "niconio".inactive = true;
+ "acfun".inactive = true;
+ "iqiyi".inactive = true;
+ "wolframalpha".inactive = true;
+ "ansa".inactive = true;
+ "il post".inactive = true;
+ "deezer".inactive = true;
+ "habrahabr".inactive = true;
+ "btdigg".inactive = true;
+ "duden".inactive = true;
+ "woxikon.de synonyme".inactive = true;
+ "jisho".inactive = true;
+ "moviepilot".inactive = true;
+ "senscritique".inactive = true;
+ "geizhals".inactive = true;
+ "openmeteo".inactive = true;
+ "fyyd".inactive = true;
+ "yummly".inactive = true;
+ "chefkoch".inactive = true;
+ "destatis".inactive = true;
+ # big brother
+ "google play movies".inactive = true;
+ "google play apps".inactive = true;
+ "google news".inactive = true;
+ "google images".inactive = true;
+ "google videos".inactive = true;
+ "google scholar".inactive = true;
+ "youtube".inactive = true;
+ "bing images".inactive = true;
+ "bing videos".inactive = true;
+ "bing news".inactive = true;
+ "microsoft learn".inactive = true;
+ "material icons".inactive = true;
+ "apple maps".inactive = true;
+ "apple app store".inactive = true;
+ "goodreads".inactive = true;
+ # captcha
+ "cppreference".inactive = true;
+ "lib.rs".inactive = true;
+ "sourcehut".inactive = true;
+ "free software directory".inactive = true;
+ "searchcode code".inactive = true;
+ "pdbe".inactive = true;
+ "1337x".inactive = true;
+ "kickass".inactive = true;
+ "library genesis".inactive = true;
+ "openrepos".inactive = true;
+ "tokyotoshokan".inactive = true;
+ "duckduckgo images".inactive = true;
+ "duckduckgo videos".inactive = true;
+ "duckduckgo news".inactive = true;
+ "duckduckgo weather".inactive = true;
+ "mojeek images".inactive = true;
+ "mojeek news".inactive = true;
+ "qwant images".inactive = true;
+ "qwant videos".inactive = true;
+ "qwant news".inactive = true;
+ # non-free
+ "tineye".inactive = true;
+ "1x".inactive = true;
+ "adobe stock".inactive = true;
+ "adobe stock video".inactive = true;
+ "adobe stock audio".inactive = true;
+ "deviantart".inactive = true;
+ "flickr".inactive = true;
+ "imgur".inactive = true;
+ "library of congress".inactive = true;
+ "pinterest".inactive = true;
+ "unsplash".inactive = true;
+ "bilibili".inactive = true;
+ "dailymotion".inactive = true;
+ "vimeo".inactive = true;
+ "yahoo".inactive = true;
+ "yahoo news".inactive = true;
+ "genius".inactive = true;
+ "mixcloud".inactive = true;
+ "soundcloud".inactive = true;
+ "huggingface".inactive = true;
+ "huggingface datasets".inactive = true;
+ "huggingface spaces".inactive = true;
+ "9gag".inactive = true;
+ "reddit".inactive = true;
+ "imdb".inactive = true;
+ "rottentomatoes".inactive = true;
+ # shady
+ "right dao".inactive = true;
+ "quark".inactive = true;
+ "quark images".inactive = true;
+ "sogou".inactive = true;
+ "sogou images".inactive = true;
+ "sogou wechat".inactive = true;
+ "sogou videos".inactive = true;
+ # LLM
+ "cloudflareai".inactive = true;
+ "yacy".inactive = true;
+ "yacy images".inactive = true;
+ "yep".inactive = true;
+ "yep images".inactive = true;
+ "yep news".inactive = true;
+ "360search".inactive = true;
+ "360search videos".inactive = true;
+ "baidu".inactive = true;
+ "baidu images".inactive = true;
+ "baidu kaifa".inactive = true;
+ "seekr images".inactive = true;
+ "seekr news".inactive = true;
+ "seekr videos".inactive = true;
+ # censorship
+ "reuters".inactive = true;
+ # far-right/disinformation/misinformation
+ "bitchute".inactive = true;
+ "rumble".inactive = true;
+ # slow
+ "crossref".inactive = true;
+ "wikidata".inactive = true;
+
+ # enabled - general
+ "mojeek".disabled = false;
+ "startpage".disabled = false;
+ "qwant".disabled = false;
+ "mulvaddelta".disabled = false;
+ "duckduckgo".disabled = false;
+ "mulvaddelta brave".disabled = false;
+ "brave".disabled = false;
+ "google".disabled = false;
+ "bing".disabled = false;
+ };
+}