{ pkgs, inputs, lib, ... }: let home-manager = builtins.fetchTarball { url = "https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz"; sha256 = "1kk5qzfb87mkgy6vzm7x8z8akxr3k8k7839yjdy48z034pvidhsr"; }; in { imports = [ ./hardware-configuration.nix (import "${home-manager}/nixos") #../modules/server/nginx.nix #../modules/server/ssh.nix #../modules/server/fail2ban.nix ]; nix.settings = { # make wheel group trusted users allows my "ae" user # to import packages not signed by a trusted key # (aka super duper easier to remote deploy) trusted-users = ["root" "@wheel"]; experimental-features = [ "nix-command" "flakes" ]; }; time.timeZone = "Australia/Brisbane"; i18n.defaultLocale = "en_US.UTF-8"; console = { font = "Lat2-Terminus16"; keyMap = "us"; }; # colmena deployment configuration deployment = { targetHost = "imbored.dev"; targetUser = "ae"; targetPort = 22; buildOnTarget = false; # build locally then deploy }; # super duper minimum grub2 config boot.loader.grub = { enable = true; device = "/dev/vda"; }; networking = { hostName = "hyrule"; networkmanager.enable = true; firewall = { enable = true; allowedTCPPorts = [ 22 # sshd 80 # nginx # 143 # IMAP4 443 # nginx # 587 # SMTPS 2222 # forgejo ssh 2035 # debug (for my job) # 3000 (INTERNAL) forgejo # 3306 (INTERNAL) forgejo sqlite3 database 5000 # debug (for my job) # 8222 (INTERNAL) vaultwarden ]; }; }; users = { defaultUserShell = pkgs.bash; users = { # primary user ae = { isNormalUser = true; extraGroups = ["wheel"]; shell = pkgs.bash; openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCsUZY45rgezi+8iROdcR5vPeacJ2fbMjlDijfUrH9hRX2FzCsg/4e3aFKhi2seZMmyTfbstxmDrrH8paUS5TibFgLFBGNngaF3CTjg85i5pm25Hr4IVo31oziBnTWaG6j3buYKtz5e1qSPzXywinJR+5+FCUJU7Fxa+EWTZcOX4wYgArSj4q73rZmvk5N0X44Mudt4nvpD2chvxygsdTzD6ph92qCuaJ/AbfmOoC7b/xvOaOVydUfgDLpHi9VZbd3akvvKxRfW6ZklldgXEzPXKMuastN0mwcBxvIb5G1Vkj8jtSVtKPc5psZ9/NWA5l38xH4qZ6z7eib6thtEMdtcKmTZEEWDADjqTea5Gj61c1n18cr6f3Tff+0bn/cxsl4Y0esi+aDeuCXYiIYNmeKBx0ttDNIxpk4J5Fdh6Xs+AZif5lnJErtu8TPy2aC0bc9wehTjMyvilTHfyerOD1ZJXhN2XwRVDGN7t7leAJZISJlPjqTDcw3Vfvzte/5JqS+FR+hbpG4uz2ix8kUa20u5YF2oSdGl8+zsdozVsdQm10Iv9WSXBV7t4m+oyodgtfzydBpmXq7aBXudCiEKw+7TC7F+1a4YFrVrCNXKFgKUpd1MiVLl7DIbzm5U9MD2BB3Fy7BPCzr3tW6/ExOhhpBWY+HnzVGQfkNr7dRcqfipKw== ae@imbored.dev" ]; }; # TODO: reduce security implications of subspace subspace = { isNormalUser = true; shell = pkgs.bash; home = "/home/subspace"; packages = with pkgs; [ wishlist ]; }; }; }; virtualisation.docker.enable = true; home-manager = { users = { ae = import ../../homes/ae; subspace = import ../../homes/subspace; }; }; services = { # simple nginx instance to host static construction page # TODO: I want sshd and forgejo's ssh server to both be bound to port 22 # So change sshd to listen on a different address/port (ie 2222 or 127.0.0.3:22, etc) # and change forgejo to use 127.0.0.2:22 (use port 22, ONLY change loopback address) nginx = { enable = true; # in wake of CVE-2022-3602/CVE-2022-3786 package = pkgs.nginxStable.override {openssl = pkgs.libressl;}; recommendedGzipSettings = true; recommendedZstdSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; # streamConfig = '' # server { # listen 127.0.0.1:53 udp reuseport; # proxy_timeout 20s; # proxy_pass 192.168.0.1:53535; # } # ''; virtualHosts = let localhost = "http://127.0.0.1"; std = { # TODO: should I run over QUIC+HTTP3? (experimental) # quic = true; # http3 = true; enableACME = true; # kTLS = true; # offload TLS to the linux kernel }; in { "imbored.dev" = { default = true; addSSL = true; # not strictly enforced <3 root = "/var/www/imbored"; # extraConfig = '' # error_page 404 /custom_404.html; # ''; } // std; # Route "vault" subdomain to vaultwarden "vault.imbored.dev" = { forceSSL = true; locations."/".proxyPass = "${localhost}:8222"; } // std; # Route "forge" subdomain to forgejo # TODO: use `forgejo.settings.server.ENABLE_ACME` instead? "forge.imbored.dev" = { forceSSL = true; extraConfig = '' client_max_body_size 512M; ''; locations."/".proxyPass = "${localhost}:3000"; } // std; }; }; openssh = { enable = true; ports = [22]; settings = { PasswordAuthentication = false; PermitRootLogin = "no"; AllowUsers = ["ae" "subspace"]; # DO NOT ALLOW ALL UseDns = true; X11Forwarding = false; }; }; vaultwarden = { enable = true; dbBackend = "sqlite"; # backupDir = "/var/backup/vaultwarden"; # disable with null # https://mynixos.com/nixpkgs/option/services.vaultwarden.config config = { # internal address and port to listen on ROCKET_ADDRESS = "127.0.0.1"; ROCKET_PORT = 8222; # hostname to listen for DOMAIN = "https://vault.imbored.dev"; # signup policy SIGNUPS_ALLOWED = false; SIGNUPS_VERIFY = true; INVITATIONS_ALLOWED = true; }; # https://mynixos.com/nixpkgs/option/services.vaultwarden.environmentFile environmentFile = "/var/lib/vaultwarden/vaultwarden.env"; }; # stalwart-mail = let # domain = "imbored.dev"; # in { # enable = false; # true; # # openFirewall = true; # im doing this manually rn # settings = { # certificate."${domain}" = { # cert = "file://${certs.${domain}.cert}"; # private-key = "file://${certs.${domain}.key}"; # }; # server = { # hostname = domain; # tls = { # certificate = "${domain}"; # enable = true; # implicit = false; # }; # listener = { # "smtp-submission" = { # bind = ["127.0.0.1:587"]; # protocol = "smtp"; # }; # "imap" = { # bind = ["127.0.0.1:143"]; # protocol = "imap"; # }; # }; # }; # session = { # rcpt.directory = "in-memory"; # auth = { # mechanisms = ["PLAIN"]; # directory = "in-memory"; # }; # }; # jmap.directory = "in-memory"; # queue.outbound.next-hop = ["local"]; # directory."in-memory" = { # type = "memory"; # users = [ # { # name = "me"; # secret = "foobar"; # email = ["me@${domain}"]; # } # { # name = "Emile"; # secret = "foobar"; # email = ["emile@${domain}"]; # } # ]; # }; # }; # }; # more options here: https://mynixos.com/nixpkgs/options/services.forgejo # TODO: set a favicon https://forgejo.org/docs/next/contributor/customization/#changing-the-logo # (might need me to override settings in the nixpkg) # TODO: create a custom theme for forgejo (modify the source files most likely) forgejo = { enable = true; # enable support for Git Large File Storage lfs.enable = true; database = { type = "sqlite3"; # postgres host = "127.0.0.1"; port = "3306"; # 5432 if postgres }; # settings are written directly to the `app.ini` config file # refer to: https://forgejo.org/docs/latest/admin/config-cheat-sheet/ settings = { server = { # ENABLE_ACME = true; # ACME_EMAIL = "eclarkboman@gmail.com"; # change this to "me@imbored.dev" DOMAIN = "forge.imbored.dev"; # should this be "imbored.dev"? ROOT_URL = "https://forge.imbored.dev"; # full public URL of the Forgejo server # address and port to listen on HTTP_ADDR = "127.0.0.1"; HTTP_PORT = 3000; PROTOCOL = "http"; # http internally, reverse proxy uses https externally START_SSH_SERVER = true; DISABLE_SSH = false; SSH_PORT = 2222; }; DEFAULT = { APP_NAME = "tearforge"; APP_SLOGIN = "but cozy"; APP_DISPLAY_NAME_FORMAT = "{APP_NAME} ::{APP_SLOGAN}::"; }; repository = { DEFAULT_PRIVATE = "private"; # last, private, public # repo/org created on push to non-existent ENABLE_PUSH_CREATE_USER = true; ENABLE_PUSH_CREATE_ORG = false; DEFAULT_PUSH_CREATE_PRIVATE = true; MAX_CREATION_LIMIT = -1; }; "repository.upload" = { # max per-file size in MB FILE_MAX_SIZE = 50; # max number of files per upload MAX_FILES = 5; }; badges = let # flat, flat-square, plastic, for-the-badge, social style = "for-the-badge"; in { ENABLED = true; GENERATOR_URL_TEMPLATE = "https://img.shields.io/badge/{{.label}}-{{.text}}-{{.color}}?style=${style}"; }; ui = { DEFAULT_THEME = "forgejo-dark"; THEMES = "forgejo-auto,forgejo-light,forgejo-dark"; }; "ui.meta" = { AUTHOR = "Emile Clark-Boman - emileclarkb"; DESCRIPTION = "This is my personal self-hosted git forge, where I keep and maintain personal projects! PS do butterflies cry when they're sad?"; KEYWORDS = "emile,clark,boman,clarkboman,emileclarkb,git,forge,forgejo,self-hosted,dobutterfliescry,butterfly,butterflies"; }; markdown = { ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true; ENABLE_MATH = true; }; admin = { DEFAULT_EMAIL_NOTIFICATIONS = "enabled"; SEND_NOTIFICATION_EMAIL_ON_NEW_USER = true; }; security = { # Controls access to the installation page. # When set to “true”, the installation page is not accessible. #INSTALL_LOCK = false; PASSWORD_HASH_ALGO = "argon2"; # ARGON2 BEST ALGO FR!! (default: argon2$2$65536$8$50) MIN_PASSWORD_LENGTH = 12; PASSWORD_COMPLEXITY = "lower,upper,digit,spec"; PASSWORD_CHECK_PWN = true; }; service = { DISABLE_REGISTRATION = true; # toggle for new users #DEFAULT_USER_IS_RESTRICTED = true; # Forbid login with third-party services (ie github) ALLOW_ONLY_INTERNAL_REGISTRATION = true; ENABLE_CAPTCHA = true; REQUIRE_CAPTCHA_FOR_LOGIN = true; REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA = true; LOGIN_REMEMBER_DAYS = 365; ENABLE_NOTIFY_MAIL = true; }; "service.explore" = { REQUIRE_SIGNIN_VIEW = false; DISABLE_USERS_PAGE = false; DISABLE_ORGANIZATIONS_PAGE = false; DISABLE_CODE_PAGE = false; }; cache = { ADAPTER = "twoqueue"; HOST = "{\"size\":100, \"recent_ratio\":0.25, \"ghost_ratio\":0.5}"; ITEM_TTL = "16h"; }; # TODO: fill this in once my mail server is configured # email.incoming = { ... }; # optional # TODO: fill this in once my mail server is configured mailer = { ENABLED = false; SMTP_ADDR = "mail.imbored.dev"; FROM = "noreply@imbored.dev"; USER = "noreply@imbored.dev"; }; log = { MODE = "file"; LEVEL = "Info"; # "Trace", "Debug", "Info", "Warn", "Error", "Critical" ENABLE_SSH_LOG = true; }; cron = { ENABLED = true; RUN_AT_START = false; }; other = { SHOW_FOOTER_VERSION = true; SHOW_FOOTER_TEMPLATE_LOAD_TIME = true; SHOW_FOOTER_POWERED_BY = true; ENABLE_SITEMAP = true; ENABLE_FEED = true; }; }; }; }; security = { # accept Lets Encrypt's security policy (for nginx) acme = { acceptTerms = true; # TODO: change this to me@imbored.dev defaults.email = "eclarkboman@gmail.com"; }; sudo.wheelNeedsPassword = true; # allow SSH keys for passwordless auth # TODO: DO NOT USE THIS (create my own alternative to colmena) pam.services.sudo.sshAgentAuth = true; # pam_ssh_agent_auth module }; environment.systemPackages = with pkgs; [ git vim helix ]; programs = { fish.enable = true; bash = { completion.enable = true; interactiveShellInit = '' if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]] then shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION="" exec ${pkgs.fish}/bin/fish $LOGIN_OPTION fi ''; }; }; system.stateVersion = "24.11"; # DO NOT MODIFY }