├── .ci └── build-matrix.py ├── .devcontainer.json ├── .drone.star ├── .editorconfig ├── .envrc ├── .github └── workflows │ ├── build.yaml │ ├── upgrade_stable.yaml │ └── upgrade_unstable.yaml ├── .gitignore ├── .gitlab-ci.yml ├── .gitpod.yml ├── .vscode └── settings.json ├── README.md ├── build-cache.bash ├── default.nix ├── flake.lock ├── flake.nix ├── flake ├── dev.nix ├── modules.nix └── packages.nix ├── home ├── all-modules.nix └── programs │ ├── alacritty.nix │ ├── default.nix │ ├── direnv.nix │ ├── git.nix │ ├── nvim.nix │ ├── nvim │ └── autoload │ │ ├── index.vim │ │ └── index │ │ ├── base.vim │ │ ├── plugins.vim │ │ └── plugins │ │ ├── nerdtree.vim │ │ └── term.vim │ ├── sway.nix │ ├── vscode.nix │ └── waybar.nix ├── kexec.nix ├── lib ├── attrs.nix ├── default.nix └── modules.nix ├── modules ├── all-modules.nix ├── darwin │ ├── base.nix │ ├── default.nix │ ├── font.nix │ └── homebrew.nix ├── desktop │ ├── font.nix │ ├── fontconfig.xml │ ├── ime.nix │ └── sway.nix ├── devices │ └── mlx4-mode.nix ├── environment │ ├── acme │ │ └── default.nix │ ├── base.nix │ ├── efi.nix │ ├── qemu.nix │ └── shell.nix ├── installer │ ├── iso.nix │ └── qcow2.nix ├── network │ ├── netclient.nix │ ├── nftables │ │ └── default.nix │ ├── tailscale │ │ ├── cert.nix │ │ └── default.nix │ └── wireguard.nix ├── services │ ├── argo.nix │ ├── atftpd.nix │ ├── clash │ │ ├── default.nix │ │ ├── subscribe-config.nix │ │ ├── subscribe.nix │ │ └── utils.nix │ ├── cloudreve.nix │ ├── dhcp │ │ ├── default.nix │ │ ├── host-options.nix │ │ ├── subnet-options.nix │ │ └── utils.nix │ ├── dns │ │ └── default.nix │ ├── drone-docker.nix │ ├── drone-exec.nix │ ├── drone-web.nix │ ├── forwarding │ │ ├── default.nix │ │ └── rule-options.nix │ ├── frpc │ │ ├── default.nix │ │ ├── rule-options.nix │ │ └── server-options.nix │ ├── frps │ │ └── default.nix │ ├── hpool-miner.nix │ ├── influxdb.nix │ ├── k3s.nix │ ├── ksmbd.nix │ ├── leaf.nix │ ├── libvirt │ │ ├── default.nix │ │ ├── devices │ │ │ ├── README.md │ │ │ ├── basic-io.nix │ │ │ ├── block.nix │ │ │ ├── bridge.nix │ │ │ ├── custom.nix │ │ │ ├── default.nix │ │ │ ├── iso.nix │ │ │ ├── qcow2.nix │ │ │ ├── tpm.nix │ │ │ └── veth-pair.nix │ │ ├── fixes │ │ │ └── remove-default-network.nix │ │ ├── library.nix │ │ ├── models.nix │ │ ├── nix-to-libvirt.xsl │ │ └── tools │ │ │ ├── default.nix │ │ │ ├── qemu-img.nix │ │ │ └── zfs.nix │ ├── nginx.nix │ ├── novnc.nix │ ├── prometheus.nix │ ├── pufferpanel.nix │ ├── reader.nix │ ├── secrets │ │ └── default.nix │ ├── ssh.nix │ ├── teleport-agent.nix │ ├── transmission.nix │ ├── vlmcsd.nix │ ├── vouch.nix │ ├── vpncloud.nix │ └── wiretrustee-client.nix └── system │ └── uboot │ ├── bootloader.sh │ └── default.nix ├── packages ├── alist │ └── pkg.nix ├── aliyundrive-webdav │ └── pkg.nix ├── asterisk-chan-quectel │ └── pkg.nix ├── babel │ ├── .gitignore │ ├── package.json │ ├── pkg.nix │ └── yarn.lock ├── build-electron-appimage │ └── default.nix ├── build-vm-qcow │ └── default.nix ├── candy │ └── pkg.nix ├── chnroutes │ └── pkg.nix ├── clash-dsl │ ├── combinators.nix │ ├── pkg.nix │ └── types │ │ ├── default.nix │ │ ├── profile.nix │ │ ├── proxy.nix │ │ ├── proxy │ │ ├── default.nix │ │ └── http.nix │ │ └── rules │ │ ├── DOMAIN-KEYWORD.nix │ │ ├── DOMAIN-SUFFIX.nix │ │ ├── DOMAIN.nix │ │ ├── DST-PORT.nix │ │ ├── GEOIP.nix │ │ ├── IP-CIDR.nix │ │ ├── IP-CIDR6.nix │ │ ├── MATCH.nix │ │ ├── PROCESS-NAME.nix │ │ ├── SRC-IP-CIDR.nix │ │ ├── SRC-PORT.nix │ │ └── default.nix ├── cloudreve │ └── pkg.nix ├── cockpit-machines │ └── pkg.nix ├── commit-notifier │ └── pkg.nix ├── default.nix ├── derper │ └── pkg.nix ├── dnslookup │ └── pkg.nix ├── dnsmasq-china-list │ └── pkg.nix ├── fcitx5-material-color │ └── pkg.nix ├── hev-socks5-tproxy │ └── pkg.nix ├── index-firefox │ └── pkg.nix ├── kcptun │ └── pkg.nix ├── landrop │ └── pkg.nix ├── leaf │ └── pkg.nix ├── libcron │ └── pkg.nix ├── libvirt-dbus │ └── pkg.nix ├── mainsail │ └── pkg.nix ├── mattermost-ent │ └── pkg.nix ├── mcsmanager │ └── pkg.nix ├── microsocks │ └── pkg.nix ├── miui-auto-tasks │ └── pkg.nix ├── mmdb-ipip │ └── pkg.nix ├── mumble-discord-bridge │ └── pkg.nix ├── nettrace │ └── pkg.nix ├── novnc │ └── pkg.nix ├── onepush │ └── pkg.nix ├── os-specific │ └── linux │ │ ├── default.nix │ │ └── ksmbd │ │ ├── kernel.nix │ │ └── tools.nix ├── ping-exporter │ └── pkg.nix ├── pufferpanel │ └── default.nix ├── quickjspp │ └── pkg.nix ├── rapidjson │ └── pkg.nix ├── reader │ └── pkg.nix ├── realm │ └── pkg.nix ├── safenet-driver │ └── pkg.nix ├── simple-obfs │ └── pkg.nix ├── speedtest │ └── pkg.nix ├── stickerpicker │ └── pkg.nix ├── teleport-ent │ ├── pkg.nix │ ├── update.sh │ └── version.nix ├── transmission-web-control │ └── pkg.nix ├── trojan-go │ └── pkg.nix ├── tun2socks │ └── pkg.nix ├── tzsp2pcap │ └── pkg.nix ├── vlmcsd │ └── pkg.nix ├── vpncloud │ └── pkg.nix ├── wondershaper │ └── pkg.nix ├── yacd-meta │ └── pkg.nix └── yacd │ └── pkg.nix ├── update.bash └── update_daily.bash /.ci/build-matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import json 5 | 6 | path = os.popen('nix build --print-out-paths --no-link .#packageList').read().strip() 7 | 8 | pkgs = [] 9 | 10 | with open(path, 'r') as file: 11 | pkgs = json.load(file) 12 | 13 | 14 | 15 | if not os.getenv('GITHUB_OUTPUT'): 16 | print("GITHUB_OUTPUT env not found") 17 | sys.exit(1) 18 | 19 | with open(os.getenv('GITHUB_OUTPUT'), 'w') as file: 20 | value = json.dumps({ 21 | "pacakges": list(map(lambda x: ({ 'name': x }), pkgs)) 22 | }) 23 | print(f"matirx -> {value}") 24 | file.write(f"matrix={value}\n") 25 | -------------------------------------------------------------------------------- /.devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/base:ubuntu", 3 | "features": { 4 | "ghcr.io/devcontainers/features/nix:1": { 5 | "extraNixConfig": "experimental-features = nix-command flakes,substituters = https://attic.indexyz.me/indexyz https://indexyz.cachix.org https://colmena.cachix.org https://cache.nixos.org/,trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ= colmena.cachix.org-1:7BzpDnjjH8ki2CT3f6GdOk7QAzPOl+1t3LvTLXqYcSg=,trusted-users = vscode,sandbox = true,system-features = nixos-test benchmark big-parallel kvm" 6 | }, 7 | "ghcr.io/devcontainers/features/docker-in-docker:1": {}, 8 | "ghcr.io/christophermacgown/devcontainer-features/direnv:1": {}, 9 | "ghcr.io/meaningful-ooo/devcontainer-features/fish:1": {}, 10 | "ghcr.io/devcontainers-contrib/features/starship:1": {} 11 | }, 12 | "onCreateCommand": "direnv allow", 13 | "updateContentCommand": "direnv reload", 14 | "customizations": { 15 | "vscode": { 16 | "extensions": [ 17 | "EditorConfig.EditorConfig", 18 | "bbenoist.Nix" 19 | ], 20 | "settings": { 21 | "workbench.colorTheme": "Default Dark+ Experimental", 22 | "editor.fontFamily": "Iosevka", 23 | "terminal.integrated.fontFamily": "Iosevka" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.drone.star: -------------------------------------------------------------------------------- 1 | def step(arch, node): 2 | return { 3 | "kind": "pipeline", 4 | "name": "build-%s" % arch, 5 | "type": "exec", 6 | "trigger": { 7 | "branch": [ "master" ] 8 | }, 9 | "platform": { 10 | "arch": arch 11 | }, 12 | "steps": [ 13 | { 14 | "name": "lint", 15 | "commands": [ "nixpkgs-fmt --check ." ] 16 | }, 17 | { 18 | "name": "build", 19 | "environment": { 20 | "NIX_PATH": "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos", 21 | "CACHIX_TOKEN": { 22 | "from_secret": "CACHIX_TOKEN" 23 | } 24 | }, 25 | "commands": [ 26 | "cachix authtoken $CACHIX_TOKEN", 27 | "bash build-cache.bash" 28 | ] 29 | } 30 | ], 31 | "node": node 32 | } 33 | 34 | def main(ctx): 35 | return [ 36 | step("arm64", { 37 | "os": "nixos", 38 | "arch": "aarch64", 39 | "type": "exec", 40 | "hostname": "oracle" 41 | }), 42 | step("amd64", { 43 | "os": "nixos", 44 | "arch": "amd64", 45 | "type": "exec", 46 | "hostname": "wirecat" 47 | }) 48 | ] 49 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 2 3 | indent_style = space 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | tab_width = 2 9 | 10 | [*.py] 11 | indent_size = 4 12 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build cache 2 | on: 3 | push: 4 | 5 | jobs: 6 | generate-matrix: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | matrix: ${{ steps.set-matrix.outputs.matrix }} 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Install Nix 13 | uses: DeterminateSystems/nix-installer-action@main 14 | with: 15 | extra-conf: | 16 | substituters = https://attic.indexyz.me/indexyz https://indexyz.cachix.org https://cache.nixos.org/ 17 | trusted-public-keys = indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 18 | 19 | - run: python .ci/build-matrix.py 20 | id: set-matrix 21 | 22 | build: 23 | name: Build ${{ matrix.pacakges.name }} 24 | runs-on: ubuntu-latest 25 | 26 | if: needs.generate-matrix.outputs.matrix != '' 27 | needs: [generate-matrix] 28 | 29 | strategy: 30 | fail-fast: false 31 | max-parallel: 6 32 | matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }} 33 | 34 | steps: 35 | - uses: actions/checkout@v2 36 | - name: Install Nix 37 | uses: DeterminateSystems/nix-installer-action@main 38 | with: 39 | extra-conf: | 40 | substituters = https://attic.indexyz.me/indexyz https://indexyz.cachix.org https://cache.nixos.org/ 41 | trusted-public-keys = indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 42 | 43 | - name: Build packages 44 | run: | 45 | set -ex 46 | nix profile install nixpkgs#attic-client 47 | 48 | attic login indexyz https://attic.indexyz.me "${{ secrets.ATTIC_TOKEN }}" 49 | nix --version 50 | 51 | PACKAGE="${{ matrix.pacakges.name }}" 52 | 53 | nix build --no-link ".#"$PACKAGE 54 | echo "Build Package Successfully"s 55 | PACKAGE_LOCATION=$(nix eval --raw ".#"$PACKAGE) 56 | echo "Package location: $PACKAGE_LOCATION" 57 | attic push indexyz $PACKAGE_LOCATION 58 | PACKAGE_DRV_LOCATION=$(nix eval --raw ".#"$PACKAGE".drvPath") 59 | echo "Package drv location: $PACKAGE_DRV_LOCATION" 60 | attic push indexyz $PACKAGE_DRV_LOCATION 61 | -------------------------------------------------------------------------------- /.github/workflows/upgrade_stable.yaml: -------------------------------------------------------------------------------- 1 | name: Upgrade sofrware stable 2 | on: 3 | schedule: 4 | # Every hour 5 | - cron: '0 * * * *' 6 | push: 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: docker/setup-qemu-action@v3 14 | - uses: cachix/install-nix-action@master 15 | with: 16 | nix_path: nixpkgs=channel:nixos-unstable 17 | install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.14.0pre20230127_ccaadc9/install 18 | extra_nix_config: | 19 | experimental-features = nix-command flakes 20 | substituters = https://attic.indexyz.me/indexyz https://indexyz.cachix.org https://cache.nixos.org/ 21 | trusted-public-keys = indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 22 | extra-platforms = aarch64-linux 23 | 24 | - name: Check Package 25 | run: | 26 | git config --global user.email github-actions[bot]@users.noreply.github.com 27 | git config --global user.name github-actions[bot] 28 | 29 | nix develop -c -- bash update.bash 30 | git push 31 | -------------------------------------------------------------------------------- /.github/workflows/upgrade_unstable.yaml: -------------------------------------------------------------------------------- 1 | name: Upgrade sofrware unstable 2 | on: 3 | schedule: 4 | # Every day 5 | - cron: '0 1 * * *' 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: docker/setup-qemu-action@v3 14 | - uses: cachix/install-nix-action@master 15 | with: 16 | nix_path: nixpkgs=channel:nixos-unstable 17 | install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.14.0pre20230127_ccaadc9/install 18 | extra_nix_config: | 19 | experimental-features = nix-command flakes 20 | substituters = https://attic.indexyz.me/indexyz https://indexyz.cachix.org https://cache.nixos.org/ 21 | trusted-public-keys = indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 22 | extra-platforms = aarch64-linux 23 | 24 | - name: Check Package 25 | run: | 26 | git config --global user.email github-actions[bot]@users.noreply.github.com 27 | git config --global user.name github-actions[bot] 28 | 29 | nix develop -c -- bash update_daily.bash 30 | git push 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .shake/ 2 | 3 | /result 4 | /result-* 5 | /_build/.shake.* 6 | /changelog.tmp 7 | 8 | .direnv/ 9 | /test.nix 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - test 3 | - build 4 | 5 | nixpkgs-fmt: 6 | stage: test 7 | image: nixery.dev/shell/nixpkgs-fmt 8 | script: 9 | - nixpkgs-fmt --check . 10 | 11 | .build: 12 | stage: build 13 | variables: 14 | CACHIX_AUTH_TOKEN: $CACHIX_TOKEN 15 | script: 16 | - | 17 | bash build-cache.bash 18 | 19 | .build docker: 20 | variables: 21 | USER: root 22 | before_script: 23 | - | 24 | mkdir -p /etc/nix 25 | echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf 26 | echo "substituters = https://indexyz.cachix.org https://cache.nixos.org/" >> /etc/nix/nix.conf 27 | echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ=" >> /etc/nix/nix.conf 28 | groupadd -r nixbld 29 | for n in $(seq 1 `nproc`); do useradd -c "Nix build user $n" -d /var/empty -g nixbld -G nixbld -M -N -r nixbld$n; done 30 | 31 | build linux: 32 | extends: 33 | - .build 34 | - .build docker 35 | image: nixery.dev/shell/nix/gnugrep/cachix/git/shadow/jq 36 | 37 | build linux aarch64: 38 | extends: 39 | - .build 40 | tags: 41 | # FIXME: using shell executor currently, switch to docker executor 42 | - aarch64-linux-shell 43 | 44 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: | 3 | direnv allow 4 | mkdir -p /home/gitpod/.config/nix && 5 | echo 'sandbox = false' >> /home/gitpod/.config/nix/nix.conf 6 | 7 | vscode: 8 | extensions: 9 | - EditorConfig.EditorConfig 10 | - bbenoist.nix 11 | - zhuangtongfa.material-theme 12 | - coenraads.bracket-pair-colorizer 13 | - donjayamanne.githistory 14 | - felipecaputo.git-project-manager 15 | - eamodio.gitlens 16 | - oderwat.indent-rainbow 17 | - wayou.vscode-todo-highlight 18 | - bungcip.better-toml 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.enableSmartCommit": true, 3 | "git.confirmSync": false, 4 | "git.autofetch": true, 5 | "editor.guides.indentation": true 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NixOS 2 | 3 | [![Build cache](https://github.com/X01A/nixos/actions/workflows/build.yaml/badge.svg)](https://github.com/X01A/nixos/actions/workflows/build.yaml) 4 | 5 | Personal nixos module and pkgs 6 | 7 | ## Setup 8 | 9 | Setup binary cache to speed up build 10 | 11 | ```nix 12 | nix.settings = { 13 | substituters = [ 14 | "https://attic.indexyz.me/indexyz" 15 | "https://indexyz.cachix.org" 16 | 17 | ]; 18 | trusted-public-keys = [ 19 | "indexyz:XxexOMK+bHXR2slT4A9wnJg00EZFXCUYqlUhlEEGQEc=" 20 | "indexyz.cachix.org-1:biBEnuZ4vTSsVMr8anZls+Lukq8w4zTHAK8/p+fdaJQ=" 21 | ]; 22 | }; 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /build-cache.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | nix --version 5 | 6 | # Upload and build cache 7 | PACKAGES_LIST=$(nix build --print-out-paths --no-link .#packageList) 8 | for PACKAGE in $(jq -r '.[]' < "$PACKAGES_LIST"); do 9 | echo "Build package: $PACKAGE" 10 | if nix build --no-link ".#""$PACKAGE"; then 11 | echo "Build Package Successfully"s 12 | PACKAGE_LOCATION=$(nix eval --raw ".#""$PACKAGE") 13 | echo "Package location: $PACKAGE_LOCATION" 14 | cachix push indexyz "$PACKAGE_LOCATION" 15 | PACKAGE_DRV_LOCATION=$(nix eval --raw ".#""$PACKAGE"".drvPath") 16 | echo "Package drv location: $PACKAGE_DRV_LOCATION" 17 | cachix push indexyz "$PACKAGE_DRV_LOCATION" 18 | else 19 | echo "::warning::Error occurred during building package ""$PACKAGE" 20 | fi 21 | done 22 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import 2 | ( 3 | let 4 | lock = builtins.fromJSON (builtins.readFile ./flake.lock); 5 | in 6 | fetchTarball { 7 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 8 | sha256 = lock.nodes.flake-compat.locked.narHash; 9 | } 10 | ) 11 | { 12 | src = ./.; 13 | }).defaultNix 14 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Personal nixos modules and packages"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:5aaee9/nixpkgs"; 6 | flake-compat = { 7 | url = "github:edolstra/flake-compat"; 8 | flake = false; 9 | }; 10 | 11 | flake-utils.url = "github:numtide/flake-utils"; 12 | 13 | disko = { 14 | url = "github:nix-community/disko"; 15 | inputs.nixpkgs.follows = "nixpkgs"; 16 | }; 17 | 18 | flake-parts = { 19 | url = "github:hercules-ci/flake-parts"; 20 | inputs.nixpkgs-lib.follows = "nixpkgs"; 21 | }; 22 | 23 | npmlock2nix = { 24 | url = "github:serokell/nix-npm-buildpackage"; 25 | flake = false; 26 | }; 27 | 28 | rust-overlay = { 29 | url = "github:oxalica/rust-overlay"; 30 | inputs.nixpkgs.follows = "nixpkgs"; 31 | }; 32 | }; 33 | 34 | outputs = inputs @ { flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } { 35 | systems = [ 36 | "aarch64-linux" 37 | "aarch64-darwin" 38 | "x86_64-darwin" 39 | "x86_64-linux" 40 | ]; 41 | 42 | 43 | imports = [ 44 | ./lib 45 | ./flake/modules.nix 46 | ./flake/packages.nix 47 | ./flake/dev.nix 48 | ]; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /flake/dev.nix: -------------------------------------------------------------------------------- 1 | { 2 | perSystem = { inputs, config, pkgs, self, ... }: { 3 | devShells.default = pkgs.mkShell { 4 | packages = with pkgs; [ 5 | nix-prefetch 6 | nixpkgs-fmt 7 | nix-update 8 | bash 9 | shellcheck 10 | ]; 11 | }; 12 | 13 | formatter = pkgs.nixpkgs-fmt; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /flake/modules.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | 3 | { 4 | flake.nixosModules = { 5 | indexyz = { ... }: { 6 | imports = [ ../modules/all-modules.nix ]; 7 | }; 8 | }; 9 | 10 | flake.homeModules.indexyz = { 11 | imports = [ ../home/all-modules.nix ]; 12 | }; 13 | 14 | 15 | flake.installer = (import "${toString inputs.nixpkgs}/nixos/lib/eval-config.nix" { 16 | system = "x86_64-linux"; 17 | 18 | modules = [ 19 | "${toString inputs.nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" 20 | ../modules/all-modules.nix 21 | ../modules/installer/iso.nix 22 | 23 | ({ ... }: { 24 | # Install disko 25 | environment.systemPackages = [ 26 | inputs.disko.packages."x86_64-linux".disko 27 | ]; 28 | }) 29 | ]; 30 | }).config.system.build.isoImage; 31 | } 32 | -------------------------------------------------------------------------------- /flake/packages.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | 3 | { 4 | imports = [ 5 | inputs.flake-parts.flakeModules.easyOverlay 6 | ]; 7 | 8 | perSystem = { inputs', config, pkgs, self', system, ... }: 9 | let 10 | os = pkgs.lib.last (pkgs.lib.strings.splitString "-" system); 11 | normalPkgs = import inputs.nixpkgs { inherit system; }; 12 | pkgs = import inputs.nixpkgs { 13 | inherit system; 14 | overlays = [ 15 | inputs.rust-overlay.overlays.default 16 | ]; 17 | }; 18 | in 19 | rec { 20 | packages = import ../packages { 21 | inherit os pkgs normalPkgs system; 22 | flakeInputs = inputs; 23 | 24 | npmlock2nix = pkgs.callPackage inputs.npmlock2nix { }; 25 | }; 26 | 27 | overlayAttrs = packages; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /home/all-modules.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | 3 | { 4 | imports = [ 5 | ./programs 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /home/programs/alacritty.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.alacritty; 6 | in 7 | { 8 | options = { 9 | indexyz.programs.alacritty.enable = mkOption { 10 | default = false; 11 | type = with types; bool; 12 | }; 13 | }; 14 | 15 | config = mkIf cfg.enable { 16 | programs.alacritty = { 17 | enable = true; 18 | settings = { 19 | window = { 20 | padding = { x = 10; y = 10; }; 21 | dimensions = { 22 | columns = 80; 23 | lines = 20; 24 | }; 25 | }; 26 | font = { 27 | size = 12; 28 | normal.family = "iosevka"; 29 | }; 30 | }; 31 | }; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /home/programs/default.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | 3 | { 4 | imports = [ 5 | ./git.nix 6 | ./nvim.nix 7 | ./direnv.nix 8 | ./alacritty.nix 9 | ./vscode.nix 10 | ./sway.nix 11 | ./waybar.nix 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /home/programs/direnv.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.direnv; 6 | in 7 | { 8 | options = { 9 | indexyz.programs.direnv.enable = mkOption { 10 | default = true; 11 | type = with types; bool; 12 | }; 13 | }; 14 | 15 | config = mkIf cfg.enable { 16 | programs.direnv = { 17 | enable = true; 18 | nix-direnv = { 19 | enable = true; 20 | }; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /home/programs/git.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.git; 6 | in 7 | { 8 | options = { 9 | indexyz.programs.git.enable = mkOption { 10 | default = true; 11 | type = with types; bool; 12 | }; 13 | }; 14 | 15 | config = mkIf cfg.enable { 16 | programs.git = { 17 | enable = true; 18 | userEmail = "7685264+5aaee9@users.noreply.github.com"; 19 | userName = "Indexyz"; 20 | 21 | extraConfig = { 22 | credential = { 23 | "https://github.com" = { 24 | helper = "${pkgs.gh}/bin/gh auth git-credential"; 25 | }; 26 | }; 27 | }; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /home/programs/nvim.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.nvim; 6 | in 7 | { 8 | options = { 9 | indexyz.programs.nvim.enable = mkOption { 10 | default = true; 11 | type = with types; bool; 12 | }; 13 | }; 14 | 15 | config = mkIf cfg.enable { 16 | xdg.configFile = { 17 | "nvim" = { 18 | source = ./nvim; 19 | recursive = true; 20 | }; 21 | }; 22 | 23 | programs = { 24 | neovim = { 25 | enable = true; 26 | viAlias = true; 27 | 28 | plugins = with pkgs.vimPlugins; [ 29 | # Nerd Tree 30 | nerdtree 31 | nerdtree-git-plugin 32 | 33 | # VIM Nix Auto fill 34 | vim-nix 35 | 36 | # Editor Config 37 | editorconfig-vim 38 | 39 | auto-pairs 40 | 41 | # Theme and color schema 42 | vim-airline 43 | vim-airline-clock 44 | dracula-vim 45 | 46 | # Indent with line 47 | indentLine 48 | vim-floaterm 49 | ]; 50 | 51 | extraConfig = '' 52 | call index#init() 53 | ''; 54 | }; 55 | }; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /home/programs/nvim/autoload/index.vim: -------------------------------------------------------------------------------- 1 | function! index#init() 2 | call index#base#init() 3 | call index#plugins#init() 4 | endfunction 5 | -------------------------------------------------------------------------------- /home/programs/nvim/autoload/index/base.vim: -------------------------------------------------------------------------------- 1 | map 2 | nnoremap w :w 3 | nnoremap W :w 4 | 5 | function! index#base#init() 6 | set encoding=utf8 7 | set tabstop=4 8 | set shiftwidth=4 9 | set expandtab 10 | set showcmd 11 | set nu 12 | set mouse=a 13 | endfunction 14 | -------------------------------------------------------------------------------- /home/programs/nvim/autoload/index/plugins.vim: -------------------------------------------------------------------------------- 1 | let g:index#plugins#load = [ 2 | \"nerdtree", 3 | \"term" 4 | \] 5 | 6 | function! index#plugins#init() 7 | for plugin in g:index#plugins#load 8 | exec 'call index#plugins#' . plugin . '#init()' 9 | endfor 10 | endfunction 11 | -------------------------------------------------------------------------------- /home/programs/nvim/autoload/index/plugins/nerdtree.vim: -------------------------------------------------------------------------------- 1 | 2 | 3 | function! index#plugins#nerdtree#init() 4 | let g:NERDTreeMinimalUI = 1 5 | let g:NERDTreeDirArrows = 1 6 | 7 | " Open Dir with TAB 8 | autocmd FileType nerdtree nmap 9 | 10 | autocmd VimEnter * NERDTree 11 | autocmd BufEnter * NERDTreeMirror 12 | 13 | autocmd VimEnter * wincmd w 14 | map :NERDTreeToggle 15 | endfunction 16 | -------------------------------------------------------------------------------- /home/programs/nvim/autoload/index/plugins/term.vim: -------------------------------------------------------------------------------- 1 | function! index#plugins#term#init() 2 | map :FloatermNew 3 | nmap :FloatermToggle 4 | tmap :FloatermToggle 5 | endfunction 6 | -------------------------------------------------------------------------------- /home/programs/vscode.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.vscode; 6 | 7 | mkOpenVSXExt = { publisher, name, version, sha256 }: { 8 | inherit name publisher version; 9 | vsix = builtins.fetchurl { 10 | inherit sha256; 11 | url = "https://open-vsx.org/api/${publisher}/${name}/${version}/file/${publisher}.${name}-${version}.vsix"; 12 | name = "${publisher}-${name}.zip"; 13 | }; 14 | }; 15 | 16 | extensions = (with pkgs.vscode-extensions; [ 17 | bbenoist.nix 18 | ms-python.python 19 | ms-azuretools.vscode-docker 20 | ms-vscode-remote.remote-ssh 21 | # Editorconfig 22 | editorconfig.editorconfig 23 | # Formatter 24 | hookyqr.beautify 25 | # Git Plugins 26 | donjayamanne.githistory 27 | eamodio.gitlens 28 | # Golang 29 | golang.go 30 | 31 | spywhere.guides 32 | pkief.material-icon-theme 33 | zhuangtongfa.material-theme 34 | ryu1kn.partial-diff 35 | ms-vsliveshare.vsliveshare 36 | rust-lang.rust-analyzer 37 | arrterian.nix-env-selector 38 | oderwat.indent-rainbow 39 | christian-kohler.path-intellisense 40 | mkhl.direnv 41 | jnoortheen.nix-ide 42 | vue.volar 43 | github.copilot 44 | github.copilot-chat 45 | ]) ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [ 46 | (mkOpenVSXExt { 47 | publisher = "jeanp413"; 48 | name = "open-remote-ssh"; 49 | version = "0.0.39"; 50 | sha256 = "1bps29zbs0xy7b2p3q5xmva1lh6ma3gz6wzvr96d9ihcpgcrnni5"; 51 | }) 52 | 53 | { 54 | name = "vscode-todo-highlight"; 55 | publisher = "wayou"; 56 | version = "1.0.5"; 57 | sha256 = "sha256-CQVtMdt/fZcNIbH/KybJixnLqCsz5iF1U0k+GfL65Ok="; 58 | } 59 | ]; 60 | in 61 | { 62 | options = { 63 | indexyz.programs.vscode = { 64 | enable = mkOption { 65 | default = false; 66 | type = with types; bool; 67 | }; 68 | }; 69 | }; 70 | 71 | config = mkIf cfg.enable { 72 | home.file.".vscode-oss/argv.json" = { 73 | force = true; 74 | text = builtins.toJSON { 75 | enable-crash-reporter = false; 76 | crash-reporter-id = "cde0befe-53e9-4442-9e17-8097c8d0e060"; 77 | enable-proposed-api = [ 78 | "jeanp413.open-remote-ssh" 79 | ]; 80 | }; 81 | }; 82 | 83 | programs.vscode = { 84 | enable = true; 85 | package = (pkgs.vscodium.override { 86 | commandLineArgs = builtins.concatStringsSep " " [ 87 | "--enable-wayland-ime" 88 | "--ozone-platform-hint=auto" 89 | ]; 90 | }); 91 | 92 | profiles.default = { 93 | inherit extensions; 94 | userSettings = { 95 | # Workbench style 96 | "workbench.colorTheme" = "One Dark Pro"; 97 | "workbench.iconTheme" = "material-icon-theme"; 98 | 99 | # Git settings 100 | "git.enableSmartCommit" = true; 101 | "git.confirmSync" = false; 102 | "git.autofetch" = true; 103 | "git.ignoreLegacyWarning" = true; 104 | 105 | # Font settings 106 | "terminal.integrated.fontFamily" = "CaskaydiaCove Nerd Font, Iosevka, Cascadia Code PL"; 107 | "editor.fontFamily" = "CaskaydiaCove Nerd Font, Iosevka, Cascadia Code PL"; 108 | "editor.fontLigatures" = true; 109 | "editor.fontSize" = 14; 110 | 111 | # Enable bracketPairColorization 112 | "editor.bracketPairColorization.enabled" = true; 113 | }; 114 | }; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /home/programs/waybar.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.programs.waybar; 6 | mainSettings = { 7 | layer = "top"; 8 | position = "top"; 9 | height = 30; 10 | 11 | modules-left = [ "sway/workspaces" "sway/mode" "sway/window" ]; 12 | modules-center = [ ]; 13 | modules-right = [ "idle_inhibitor" "pulseaudio" "network" "cpu" "memory" "temperature" "backlight" ] 14 | ++ [ "battery" "clock" "tray" ]; 15 | 16 | "sway/mode" = { 17 | format = "{}"; 18 | }; 19 | idle_inhibitor = { 20 | format = "{icon}"; 21 | format-icons = { 22 | activated = ""; 23 | deactivated = ""; 24 | }; 25 | }; 26 | tray = { 27 | # "icon-size" = 21; 28 | "spacing" = 10; 29 | }; 30 | clock = { 31 | tooltip-format = "{:%Y %B}\n{calendar}"; 32 | format-alt = "{:%Y-%m-%d}"; 33 | }; 34 | cpu = { 35 | "format" = "{usage}% "; 36 | "tooltip" = false; 37 | }; 38 | memory = { 39 | "format" = "{}% "; 40 | }; 41 | temperature = { 42 | # "thermal-zone" = 2; 43 | # hwmon-path = cfg.gui.waybar.hwmon-path; 44 | critical-threshold = 80; 45 | format-critical = "!{temperatureC}°C {icon}"; 46 | format = "{temperatureC}°C {icon}"; 47 | format-icons = [ "" "" "" ]; 48 | }; 49 | backlight = { 50 | format = "{percent}% {icon}"; 51 | format-icons = [ "" "" ]; 52 | }; 53 | battery = { 54 | states = { 55 | # "good" = 95; 56 | warning = 30; 57 | critical = 15; 58 | }; 59 | format = "{capacity}% {icon}"; 60 | format-charging = "{capacity}% "; 61 | format-plugged = "{capacity}% "; 62 | format-alt = "{time} {icon}"; 63 | # "format-good" = "" # An empty format will hide the module 64 | # "format-full" = ""; 65 | format-icons = [ "" "" "" "" "" ]; 66 | }; 67 | network = { 68 | # "interface" = "wlp2*" # (Optional) To force the use of this interface 69 | format-wifi = "{essid} ({signalStrength}%) "; 70 | format-ethernet = "{ifname} = {ipaddr}/{cidr} "; 71 | format-linked = "{ifname} (No IP) "; 72 | format-disconnected = "Disconnected ⚠"; 73 | format-alt = "{ifname} = {ipaddr}/{cidr}"; 74 | }; 75 | pulseaudio = { 76 | # "scroll-step" = 1 # % can be a float 77 | format = "{volume}% {icon} {format_source}"; 78 | format-bluetooth = "{volume}% {icon} {format_source}"; 79 | format-bluetooth-muted = " {icon} {format_source}"; 80 | format-muted = " {format_source}"; 81 | format-source = "{volume}% "; 82 | format-source-muted = ""; 83 | format-icons = { 84 | headphone = ""; 85 | hands-free = ""; 86 | headset = ""; 87 | phone = ""; 88 | portable = ""; 89 | car = ""; 90 | default = [ "" "" "" ]; 91 | }; 92 | on-click = "pavucontrol"; 93 | }; 94 | }; 95 | in 96 | { 97 | options = { 98 | indexyz.programs.waybar.enable = mkOption { 99 | default = false; 100 | type = with types; bool; 101 | }; 102 | }; 103 | 104 | config = mkIf cfg.enable { 105 | programs.waybar = { 106 | enable = true; 107 | systemd.enable = true; 108 | settings.main = mainSettings; 109 | }; 110 | 111 | systemd.user.services.waybar = { 112 | # Temporary "fix" until https://github.com/Alexays/Waybar/issues/1205 113 | # is resolved 114 | Service.Environment = [ "PATH=/run/current-system/sw/bin" ]; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /kexec.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./modules/all-modules.nix 6 | ]; 7 | 8 | indexyz.services.ssh.enable = true; 9 | indexyz.environment.base.enable = true; 10 | 11 | networking = { 12 | useDHCP = false; 13 | useNetworkd = true; 14 | }; 15 | 16 | systemd.network.networks.eth0 = { 17 | name = "eth0"; 18 | DHCP = "yes"; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /lib/attrs.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with builtins; 4 | with lib; 5 | 6 | rec { 7 | # attrsToList 8 | attrsToList = attrs: 9 | mapAttrsToList (name: value: { inherit name value; }) attrs; 10 | 11 | # mapFilterAttrs :: 12 | # (name -> value -> bool) 13 | # (name -> value -> { name = any; value = any; }) 14 | # attrs 15 | mapFilterAttrs = pred: f: attrs: filterAttrs pred (mapAttrs' f attrs); 16 | 17 | # Generate an attribute set by mapping a function over a list of values. 18 | genAttrs' = values: f: listToAttrs (map f values); 19 | 20 | # anyAttrs :: (name -> value -> bool) attrs 21 | anyAttrs = pred: attrs: 22 | any (attr: pred attr.name attr.value) (attrsToList attrs); 23 | 24 | # countAttrs :: (name -> value -> bool) attrs 25 | countAttrs = pred: attrs: 26 | count (attr: pred attr.name attr.value) (attrsToList attrs); 27 | } 28 | -------------------------------------------------------------------------------- /lib/default.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | inherit (inputs) nixpkgs; 4 | inherit (nixpkgs) lib; 5 | 6 | inherit (lib) makeExtensible attrValues foldr; 7 | 8 | modules = import ./modules.nix { 9 | inherit lib; 10 | self.attrs = import ./attrs.nix { inherit lib; self = { }; }; 11 | }; 12 | inherit (modules) mapModules; 13 | 14 | selfLib = makeExtensible (self: 15 | with self; mapModules ./. 16 | (file: import file { inherit self lib pkgs inputs; })); 17 | in 18 | { 19 | flake.lib = lib.extend (self: _super: { 20 | self = selfLib.extend 21 | (_self: super: 22 | foldr (a: b: a // b) { } (attrValues super)); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /lib/modules.nix: -------------------------------------------------------------------------------- 1 | { self, lib, ... }: 2 | 3 | let 4 | inherit (builtins) attrValues readDir pathExists concatLists; 5 | inherit (lib) id mapAttrsToList filterAttrs hasPrefix hasSuffix nameValuePair removeSuffix; 6 | inherit (self.attrs) mapFilterAttrs; 7 | in 8 | rec { 9 | mapModules = dir: fn: 10 | mapFilterAttrs 11 | (n: v: 12 | v != null && 13 | !(hasPrefix "_" n)) 14 | (n: v: 15 | let path = "${toString dir}/${n}"; in 16 | if v == "directory" && pathExists "${path}/default.nix" 17 | then nameValuePair n (fn path) 18 | else if v == "regular" && 19 | n != "default.nix" && 20 | hasSuffix ".nix" n 21 | then nameValuePair (removeSuffix ".nix" n) (fn path) 22 | else nameValuePair "" null) 23 | (readDir dir); 24 | 25 | mapModules' = dir: fn: 26 | attrValues (mapModules dir fn); 27 | 28 | mapModulesRec = dir: fn: 29 | mapFilterAttrs 30 | (n: v: 31 | v != null && 32 | !(hasPrefix "_" n)) 33 | (n: v: 34 | let path = "${toString dir}/${n}"; in 35 | if v == "directory" 36 | then nameValuePair n (mapModulesRec path fn) 37 | else if v == "regular" && n != "default.nix" && hasSuffix ".nix" n 38 | then nameValuePair (removeSuffix ".nix" n) (fn path) 39 | else nameValuePair "" null) 40 | (readDir dir); 41 | 42 | mapModulesRec' = dir: fn: 43 | let 44 | dirs = 45 | mapAttrsToList 46 | (k: _: "${dir}/${k}") 47 | (filterAttrs 48 | (n: v: v == "directory" && !(hasPrefix "_" n)) 49 | (readDir dir)); 50 | files = attrValues (mapModules dir id); 51 | paths = files ++ concatLists (map (d: mapModulesRec' d id) dirs); 52 | in 53 | map fn paths; 54 | } 55 | -------------------------------------------------------------------------------- /modules/all-modules.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | 3 | { 4 | imports = [ 5 | ./environment/base.nix 6 | ./environment/qemu.nix 7 | ./environment/efi.nix 8 | ./environment/shell.nix 9 | ./environment/acme 10 | ./services/ssh.nix 11 | ./services/clash 12 | ./services/teleport-agent.nix 13 | ./services/drone-web.nix 14 | ./services/drone-docker.nix 15 | ./services/frpc 16 | ./services/frps 17 | ./services/k3s.nix 18 | ./services/transmission.nix 19 | ./services/libvirt 20 | ./services/atftpd.nix 21 | ./services/novnc.nix 22 | ./services/leaf.nix 23 | ./services/dhcp 24 | ./services/dns 25 | ./services/forwarding 26 | ./services/hpool-miner.nix 27 | ./services/prometheus.nix 28 | ./services/vlmcsd.nix 29 | ./services/ksmbd.nix 30 | ./services/cloudreve.nix 31 | ./services/vouch.nix 32 | ./services/nginx.nix 33 | ./services/argo.nix 34 | ./services/drone-exec.nix 35 | ./services/vpncloud.nix 36 | ./services/reader.nix 37 | ./services/influxdb.nix 38 | ./devices/mlx4-mode.nix 39 | ./desktop/font.nix 40 | ./desktop/ime.nix 41 | ./desktop/sway.nix 42 | ./system/uboot 43 | ./services/wiretrustee-client.nix 44 | ./services/pufferpanel.nix 45 | ./network/nftables/default.nix 46 | ./network/tailscale 47 | ./network/netclient.nix 48 | ]; 49 | } 50 | -------------------------------------------------------------------------------- /modules/darwin/base.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.environment.base; 6 | in 7 | { 8 | options = { 9 | indexyz.environment.base = { 10 | enable = mkEnableOption "Enable base environment"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | nixpkgs.config.allowUnsupportedSystem = true; 16 | 17 | # Fish config 18 | programs.fish = { 19 | enable = true; 20 | shellInit = '' 21 | set -gx STARSHIP_CONFIG /etc/starship.toml 22 | 23 | ${pkgs.starship}/bin/starship init fish | source 24 | 25 | fish_add_path $HOME/go/bin 26 | ''; 27 | }; 28 | 29 | environment.etc."starship.toml".text = '' 30 | add_newline = false 31 | 32 | [gcloud] 33 | disabled = true 34 | ''; 35 | 36 | environment.shells = [ pkgs.fish ]; 37 | users.users.indexyz.shell = "/run/current-system/sw/bin/fish"; 38 | 39 | # Networking config 40 | networking.knownNetworkServices = [ "Wi-Fi" "Bluetooth PAN" "Thunderbolt Bridge" ]; 41 | 42 | # Nix config 43 | programs.nix-index.enable = true; 44 | services.nix-daemon.enable = true; 45 | 46 | nix = { 47 | package = pkgs.nixUnstable; 48 | useDaemon = true; 49 | settings.sandbox = true; 50 | 51 | extraOptions = '' 52 | experimental-features = nix-command flakes 53 | ''; 54 | }; 55 | 56 | environment.systemPackages = with pkgs; [ 57 | gh 58 | starship 59 | tmux 60 | wget 61 | sshpass 62 | ansible 63 | htop 64 | ripgrep 65 | coreutils 66 | p7zip 67 | sshfs 68 | mas 69 | bat 70 | nixpkgs-fmt 71 | iperf 72 | iperf2 73 | ffsend 74 | inxi 75 | tree 76 | ncdu 77 | smartmontools 78 | pv 79 | jq 80 | ]; 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /modules/darwin/default.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | 3 | { 4 | imports = [ 5 | ./base.nix 6 | ./homebrew.nix 7 | ./font.nix 8 | ]; 9 | } 10 | -------------------------------------------------------------------------------- /modules/darwin/font.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.environment.font; 6 | in 7 | { 8 | options = { 9 | indexyz.environment.font = { 10 | enable = mkEnableOption "Enable font environment"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | fonts = { 16 | fontDir.enable = true; 17 | fonts = with pkgs; [ 18 | cascadia-code 19 | iosevka-bin 20 | jetbrains-mono 21 | sarasa-gothic 22 | ]; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/darwin/homebrew.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.environment.homebrew; 6 | in 7 | { 8 | options = { 9 | indexyz.environment.homebrew = { 10 | enable = mkEnableOption "Enable homebrew environment"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | homebrew = { 16 | enable = true; 17 | onActivation = { 18 | cleanup = "zap"; 19 | autoUpdate = true; 20 | }; 21 | 22 | taps = [ 23 | "gromgit/fuse" 24 | "homebrew/cask-drivers" 25 | "homebrew/cask-fonts" 26 | "homebrew/cask" 27 | ]; 28 | casks = [ 29 | "yesplaymusic" 30 | "wine-stable" 31 | "vmware-fusion" 32 | "vivaldi" 33 | "visual-studio-code" 34 | "telegram-desktop" 35 | "telegram" 36 | "snipaste" 37 | "raspberry-pi-imager" 38 | "openinterminal" 39 | "obs" 40 | "mumble" 41 | "multimc" 42 | "motrix" 43 | "macfuse" 44 | "launchcontrol" 45 | "keyboardcleantool" 46 | "keka" 47 | "mattermost" 48 | "jetbrains-toolbox" 49 | "iterm2" 50 | "insomnia" 51 | "iina" 52 | "hiddenbar" 53 | "android-file-transfer" 54 | "android-platform-tools" 55 | "bitwarden" 56 | "chia" 57 | "clash-for-windows" 58 | "discord" 59 | "docker" 60 | "electronmail" 61 | "librewolf" 62 | "kicad" 63 | "steam" 64 | "parsec" 65 | ]; 66 | }; 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /modules/desktop/font.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.desktop.font; 6 | in 7 | { 8 | options = { 9 | indexyz.desktop.font = { 10 | enable = mkEnableOption "Enable desktop fonts"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | fonts = { 16 | enableDefaultFonts = true; 17 | enableGhostscriptFonts = true; 18 | 19 | fonts = with pkgs; [ 20 | roboto 21 | jetbrains-mono 22 | noto-fonts-cjk 23 | noto-fonts-extra 24 | noto-fonts-emoji 25 | noto-fonts-emoji-blob-bin 26 | noto-fonts 27 | noto-fonts-cjk-sans 28 | noto-fonts-cjk-serif 29 | wqy_microhei 30 | wqy_zenhei 31 | cascadia-code 32 | iosevka-bin 33 | 34 | (nerdfonts.override { fonts = [ "CascadiaCode" ]; }) 35 | ]; 36 | 37 | fontconfig = { 38 | enable = true; 39 | localConf = (builtins.readFile ./fontconfig.xml); 40 | }; 41 | }; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /modules/desktop/ime.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.desktop.ime; 6 | in 7 | { 8 | options = { 9 | indexyz.desktop.ime = { 10 | enable = mkEnableOption "Enable ime"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | i18n.inputMethod = { 16 | enabled = "fcitx5"; 17 | fcitx5.addons = with pkgs; [ 18 | fcitx5-rime 19 | fcitx5-material-color 20 | ]; 21 | }; 22 | 23 | # Run fcitx daemon in xserver session 24 | # systemd.user.services.fcitx5-daemon.enable = lib.mkForce false; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /modules/desktop/sway.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.desktop.sway; 6 | in 7 | { 8 | options = { 9 | indexyz.desktop.sway = { 10 | enable = mkEnableOption "Enable sway"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | programs.sway.enable = true; 16 | 17 | security.pam.services.swaylock = { 18 | text = '' 19 | auth include login 20 | ''; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/devices/mlx4-mode.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | 4 | with lib; 5 | let 6 | cfg = config.indexyz.devices.mlx4-mode; 7 | in 8 | { 9 | options = { 10 | indexyz.devices.mlx4-mode = { 11 | enable = mkEnableOption "Enable mlx4 mode switch"; 12 | 13 | mode = mkOption { 14 | type = types.enum [ "eth" "ib" "auto" ]; 15 | default = "eth"; 16 | description = "Network card mode"; 17 | }; 18 | }; 19 | }; 20 | 21 | config = mkIf cfg.enable { 22 | boot.initrd = { 23 | availableKernelModules = [ "mlx4_core" "mlx4_en" ]; 24 | postDeviceCommands = '' 25 | for pci_dev in /sys/bus/pci/devices/*/; do 26 | if [ -e $pci_dev/mlx4_port1 ]; then 27 | echo "${cfg.mode}" > $pci_dev/mlx4_port1; 28 | if [ -e $pci_dev/mlx4_port2 ]; then 29 | echo "${cfg.mode}" > $pci_dev/mlx4_port2 30 | fi 31 | fi 32 | done 33 | ''; 34 | }; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /modules/environment/acme/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.indexyz.environment.acme; 7 | in 8 | { 9 | options = { 10 | indexyz.environment.acme = { 11 | enable = mkOption { 12 | default = false; 13 | type = with types; bool; 14 | }; 15 | }; 16 | }; 17 | 18 | config = mkIf cfg.enable { 19 | security.acme = { 20 | acceptTerms = true; 21 | defaults.email = "acme@indexyz.me"; 22 | preliminarySelfsigned = true; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/environment/efi.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.environment.efi; 6 | in 7 | { 8 | options = { 9 | indexyz.environment.efi = { 10 | enable = mkEnableOption "Basic grub efi config"; 11 | }; 12 | }; 13 | config = mkIf cfg.enable { 14 | boot.loader = { 15 | grub = { 16 | enable = true; 17 | efiSupport = true; 18 | efiInstallAsRemovable = true; 19 | device = "nodev"; 20 | }; 21 | efi.canTouchEfiVariables = false; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /modules/environment/qemu.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.environment.qemu; 6 | in 7 | { 8 | options = { 9 | indexyz.environment.qemu = { 10 | enable = mkEnableOption "Qemu Environment"; 11 | }; 12 | }; 13 | config = mkIf cfg.enable { 14 | services.qemuGuest.enable = true; 15 | boot.growPartition = true; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /modules/installer/iso.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | { 4 | users.users.root.initialPassword = lib.mkDefault "toor"; 5 | 6 | networking = { 7 | wireless.enable = false; 8 | usePredictableInterfaceNames = false; 9 | networkmanager.enable = true; 10 | }; 11 | 12 | hardware.enableRedistributableFirmware = true; 13 | hardware.cpu.intel.updateMicrocode = true; 14 | 15 | boot.supportedFilesystems = lib.mkForce [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" "ext4" "vfat" ]; 16 | boot.kernelPackages = pkgs.linuxPackages_latest; 17 | hardware.enableAllFirmware = true; 18 | nixpkgs.config.allowUnfree = true; 19 | 20 | indexyz.services.ssh.enable = true; 21 | indexyz.environment.base.enable = true; 22 | 23 | documentation = { 24 | enable = true; 25 | man.enable = true; 26 | }; 27 | 28 | services.openssh.settings.PermitRootLogin = lib.mkForce "yes"; 29 | } 30 | -------------------------------------------------------------------------------- /modules/installer/qcow2.nix: -------------------------------------------------------------------------------- 1 | { modulesPath, config, pkgs, lib, ... }: 2 | 3 | { 4 | imports = [ 5 | (modulesPath + "/profiles/qemu-guest.nix") 6 | ]; 7 | 8 | users.users.root.initialPassword = lib.mkDefault "toor"; 9 | 10 | networking = { 11 | wireless.enable = false; 12 | useNetworkd = true; 13 | useDHCP = true; 14 | usePredictableInterfaceNames = false; 15 | }; 16 | 17 | boot.kernelPackages = pkgs.linuxPackages_latest; 18 | 19 | indexyz.services.ssh.enable = true; 20 | indexyz.environment.base.enable = true; 21 | indexyz.environment.efi.enable = true; 22 | services.qemuGuest.enable = true; 23 | 24 | fileSystems = { 25 | "/" = { 26 | device = "/dev/disk/by-label/nixos"; 27 | fsType = "ext4"; 28 | autoResize = true; 29 | }; 30 | 31 | "/boot" = { 32 | device = "/dev/disk/by-label/ESP"; 33 | fsType = "vfat"; 34 | }; 35 | }; 36 | 37 | boot.growPartition = true; 38 | 39 | system.build.qcow = import "${toString modulesPath}/../lib/make-disk-image.nix" { 40 | inherit lib config pkgs; 41 | diskSize = 4096; 42 | format = "qcow2"; 43 | partitionTableType = "efi"; 44 | copyChannel = false; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /modules/network/netclient.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.network.netclient; 6 | servicePath = with pkgs; [ 7 | iptables 8 | iproute2 9 | procps 10 | wireguard-tools 11 | ]; 12 | in 13 | { 14 | options = { 15 | indexyz.network.netclient = { 16 | enable = mkEnableOption "Enable netclient daemon"; 17 | }; 18 | }; 19 | 20 | config = mkIf cfg.enable { 21 | environment.systemPackages = with pkgs; [ 22 | netmaker 23 | ]; 24 | 25 | boot.kernel.sysctl = { 26 | "net.ipv4.ip_forward" = mkDefault 1; 27 | "net.ipv4.conf.all.src_valid_mark" = mkDefault 1; 28 | "net.ipv6.conf.all.forwarding" = mkDefault 1; 29 | }; 30 | 31 | systemd.services.netclient = { 32 | description = "Netmaker client"; 33 | after = [ "network.target" ]; 34 | wantedBy = [ "multi-user.target" ]; 35 | script = '' 36 | exec ${pkgs.netmaker}/bin/netclient daemon 37 | ''; 38 | path = servicePath; 39 | }; 40 | 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /modules/network/nftables/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.indexyz.network.firewall; 7 | networkCfg = config.networking.firewall; 8 | 9 | mapToPortRange = it: "${builtins.toString it.from}-${builtins.toString it.to}"; 10 | haveElement = it: (builtins.length it) > 0; 11 | 12 | buildElemet = it: optionalString (haveElement it) "elements = { ${builtins.concatStringsSep ", " it} }"; 13 | 14 | allowTcpPorts = (map builtins.toString networkCfg.allowedTCPPorts) ++ (map mapToPortRange networkCfg.allowedTCPPortRanges); 15 | allowUdpPorts = (map builtins.toString networkCfg.allowedUDPPorts) ++ (map mapToPortRange networkCfg.allowedUDPPortRanges); 16 | in 17 | { 18 | options = { 19 | indexyz.network.firewall = { 20 | enable = mkEnableOption "Enable custom nftables firewall"; 21 | 22 | blacklist = mkOption { 23 | # https://support.censys.io/hc/en-us/articles/360043177092-Opt-Out-of-Scanning 24 | default = [ "162.142.125.0/24" "167.94.138.0/24" "167.94.145.0/24" "167.94.146.0/24" "167.248.133.0/24" ]; 25 | type = with types; listOf str; 26 | }; 27 | 28 | extraInetRule = mkOption { 29 | default = ""; 30 | type = with types; str; 31 | }; 32 | 33 | extraInputRule = mkOption { 34 | default = ""; 35 | type = with types; str; 36 | }; 37 | }; 38 | }; 39 | 40 | config = mkIf cfg.enable { 41 | networking.firewall.enable = false; 42 | networking.nftables = { 43 | enable = true; 44 | checkRuleset = false; 45 | ruleset = '' 46 | table inet filter { 47 | set allow_tcp { 48 | type inet_service 49 | flags interval 50 | ${buildElemet allowTcpPorts} 51 | } 52 | 53 | set allow_udp { 54 | type inet_service 55 | flags interval 56 | ${buildElemet allowUdpPorts} 57 | } 58 | 59 | set blacklist { 60 | type ipv4_addr 61 | flags interval 62 | ${buildElemet cfg.blacklist} 63 | } 64 | 65 | chain input { 66 | type filter hook input priority 0; 67 | iifname lo accept 68 | ct state { established, related } accept 69 | ${optionalString networkCfg.allowPing "ip protocol icmp icmp type echo-request accept"} 70 | counter ip saddr @blacklist drop 71 | tcp dport @allow_tcp accept 72 | udp dport @allow_udp accept 73 | ${cfg.extraInputRule} 74 | counter drop 75 | } 76 | 77 | chain output { 78 | type filter hook output priority 0; 79 | accept 80 | } 81 | 82 | ${cfg.extraInetRule} 83 | } 84 | ''; 85 | }; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /modules/network/tailscale/cert.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.network.tailscale.cert; 6 | commonCfg = config.indexyz.network.tailscale; 7 | 8 | moduleEnable = commonCfg.enable && cfg.enable; 9 | in 10 | { 11 | options = { 12 | indexyz.network.tailscale.cert = { 13 | enable = mkEnableOption "Enable tailscale cert service"; 14 | traefikDefaultCert = mkEnableOption "Use tailscale cert as traefik default cert"; 15 | 16 | domain = mkOption { 17 | type = types.str; 18 | description = '' 19 | Tailscale cert base domain 20 | 21 | You can find it in https://login.tailscale.com/admin/dns 22 | ''; 23 | }; 24 | 25 | hostName = mkOption { 26 | type = types.str; 27 | default = config.networking.hostName; 28 | description = '' 29 | client node name in tailscale, usually is the hostName. 30 | ''; 31 | }; 32 | }; 33 | }; 34 | 35 | config = mkIf (moduleEnable) (mkMerge [ 36 | { 37 | systemd.services.tailscale-cert = { 38 | after = [ "network.target" "network-online.target" "tailscaled.service" ]; 39 | wants = [ "tailscaled.service" ]; 40 | wantedBy = [ "multi-user.target" ]; 41 | 42 | path = with pkgs; [ tailscale ]; 43 | 44 | serviceConfig = { 45 | Type = "oneshot"; 46 | UMask = 0022; 47 | StateDirectoryMode = 750; 48 | ProtectSystem = "strict"; 49 | ReadWritePaths = [ 50 | "/var/lib/tailscale-cert" 51 | ]; 52 | PrivateTmp = true; 53 | WorkingDirectory = "/var/lib/tailscale-cert"; 54 | NoNewPrivileges = true; 55 | PrivateDevices = true; 56 | ProtectClock = true; 57 | ProtectHome = true; 58 | ProtectHostname = true; 59 | StateDirectory = [ "tailscale-cert" ]; 60 | }; 61 | 62 | script = '' 63 | tailscale cert --cert-file cert.pem --key-file key.pem ${cfg.hostName}.${cfg.domain} 64 | ''; 65 | }; 66 | 67 | systemd.timers.tailscale-renew = { 68 | wantedBy = [ "timers.target" ]; 69 | description = "Renew tailscale server cert"; 70 | timerConfig = { 71 | OnCalendar = "weekly"; 72 | Unit = "tailscale-cert.service"; 73 | Persistent = "yes"; 74 | RandomizedDelaySec = "24h"; 75 | }; 76 | }; 77 | } 78 | 79 | (mkIf (config.services.traefik.enable && cfg.traefikDefaultCert) { 80 | 81 | systemd.services.traefik.serviceConfig.StateDirectory = [ "tailscale-cert" ]; 82 | services.traefik.dynamicConfigOptions = { 83 | tls.certificates = [ 84 | { 85 | certFile = "/var/lib/tailscale-cert/cert.pem"; 86 | keyFile = "/var/lib/tailscale-cert/key.pem"; 87 | } 88 | ]; 89 | }; 90 | }) 91 | ]); 92 | } 93 | -------------------------------------------------------------------------------- /modules/network/wireguard.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, nodes ? null, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.network.wireguard; 6 | getPublicKey = privateKey: (pkgs.readFile ( 7 | pkgs.runCommandLocal "wireguard-public-key" 8 | { 9 | path = with pkgs; [ wireguard coreutils ]; 10 | } '' 11 | echo ${privateKey} | wg pubkey | head -c 1 > $out 12 | '' 13 | )); 14 | 15 | publicKey = getPublicKey cfg.privateKey; 16 | in 17 | { 18 | options = { 19 | indexyz.network.wireguard = { 20 | enable = mkEnableOption "Enable mesh wireguard service"; 21 | 22 | port = mkOption { 23 | description = "WireGuard port that this server listening"; 24 | default = 54321; 25 | type = types.int; 26 | }; 27 | 28 | privateKey = mkOption { 29 | description = "WireGuard passkey"; 30 | type = types.str; 31 | }; 32 | 33 | name = mkOption { 34 | default = "wireguard"; 35 | description = "WireGuard interface name"; 36 | type = types.str; 37 | }; 38 | 39 | internal = mkOption { 40 | description = "WireGuard internal ip address"; 41 | type = types.str; 42 | }; 43 | 44 | targetAddress = mkOption 45 | { 46 | description = "WireGuard incoming connection address"; 47 | default = config.deployment.targetHost; 48 | defaultText = "1.1.1.1"; 49 | type = types.str; 50 | }; 51 | }; 52 | }; 53 | 54 | config = mkIf cfg.enable { 55 | assertions = singleton { 56 | assertion = (nodes != null); 57 | message = '' 58 | evalModules not provide nodes 59 | Please use colmena https://github.com/zhaofengli/colmena to deploy or disable wireguard module 60 | ''; 61 | }; 62 | 63 | 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /modules/services/argo.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.indexyz.services.argo; 7 | 8 | ruleOptions = types.submodule ({ 9 | options = { 10 | name = mkOption { 11 | type = types.str; 12 | description = "Cloudflare tunnel rule name"; 13 | }; 14 | 15 | targetHost = mkOption { 16 | type = types.str; 17 | example = "http://localhost:3000"; 18 | description = "The web host that should forward to cloudflare"; 19 | }; 20 | 21 | hostname = mkOption { 22 | type = types.str; 23 | example = "youknonw.indexyz.me"; 24 | description = "The hostname that cloudflare should use"; 25 | }; 26 | 27 | certFile = mkOption { 28 | type = types.str; 29 | example = "/run/secrets/CLOUDFLARE_CERT"; 30 | description = '' 31 | Cloudflare auth cert and origin cret file. 32 | You can create it by `cloudflared login` 33 | ''; 34 | }; 35 | 36 | after = mkOption { 37 | default = "network.target"; 38 | type = types.str; 39 | description = "Start cloudflared after"; 40 | example = "nginx.service"; 41 | }; 42 | }; 43 | }); 44 | in 45 | { 46 | 47 | options = { 48 | indexyz.services.argo = { 49 | enable = mkEnableOption "Cloudflare Argo Tunnel"; 50 | 51 | hosts = mkOption { 52 | type = with types; listOf ruleOptions; 53 | default = [ ]; 54 | }; 55 | }; 56 | }; 57 | 58 | config = mkIf cfg.enable { 59 | systemd.services = builtins.listToAttrs (map 60 | (item: { 61 | name = "argo-tunnel-${item.name}"; 62 | value = { 63 | wantedBy = [ "multi-user.target" ]; 64 | after = [ item.after ]; 65 | description = "${item.name} Argo Tunnel"; 66 | serviceConfig = { 67 | Restart = "always"; 68 | }; 69 | 70 | script = '' 71 | ${pkgs.cloudflared}/bin/cloudflared tunnel \ 72 | --origincert ${item.certFile} \ 73 | --hostname ${item.hostname} \ 74 | --url ${item.targetHost} 75 | ''; 76 | }; 77 | }) 78 | cfg.hosts); 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /modules/services/atftpd.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.atftpd; 6 | in 7 | { 8 | options = { 9 | indexyz.services.atftpd = { 10 | enable = mkOption { 11 | default = false; 12 | type = with types; bool; 13 | }; 14 | 15 | pkg = mkOption { 16 | default = pkgs.ipxe; 17 | type = types.package; 18 | defaultText = "pkgs.ipxe"; 19 | }; 20 | }; 21 | }; 22 | 23 | config = mkIf cfg.enable { 24 | services.atftpd = { 25 | enable = true; 26 | root = cfg.pkg; 27 | }; 28 | 29 | networking.firewall.allowedUDPPorts = [ 69 ]; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /modules/services/clash/subscribe-config.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | dataDir = "/var/lib/clash"; 7 | cfg = config.indexyz.services.clash; 8 | utils = import ./utils.nix { inherit pkgs config; }; 9 | inherit (utils) managePort manageAddr; 10 | in 11 | { 12 | config = mkIf cfg.enable { 13 | systemd.services = builtins.listToAttrs (map 14 | (item: { 15 | name = "clash-subscribe-${item.name}"; 16 | value = { 17 | serviceConfig = { 18 | Type = "oneshot"; 19 | WorkingDirectory = dataDir; 20 | StateDirectory = "clash"; 21 | }; 22 | wantedBy = [ "multi-user.target" ]; 23 | after = [ "network.target" ]; 24 | 25 | script = '' 26 | ${pkgs.curl}/bin/curl -SL '${item.url}' -o ${item.name}.yaml 27 | 28 | ${utils.updateConfigScript item.name true} 29 | ''; 30 | }; 31 | }) 32 | cfg.subscribe); 33 | 34 | systemd.timers = builtins.listToAttrs (map 35 | (item: { 36 | name = "clash-subscribe-${item.name}"; 37 | value = { 38 | wantedBy = [ "multi-user.target" ]; 39 | after = [ "network.target" ]; 40 | partOf = [ "clash-subscribe-${item.name}.service" ]; 41 | timerConfig.OnCalendar = item.calendar; 42 | }; 43 | }) 44 | cfg.subscribe); 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /modules/services/clash/subscribe.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | { 5 | options = { 6 | name = mkOption { 7 | type = types.str; 8 | }; 9 | 10 | url = mkOption { 11 | type = types.str; 12 | }; 13 | 14 | calendar = mkOption { 15 | type = types.str; 16 | default = "*-*-* 4:00:00"; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /modules/services/clash/utils.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config }: 2 | 3 | with pkgs.lib; 4 | let 5 | dataDir = "/var/lib/clash"; 6 | cfg = config.indexyz.services.clash; 7 | managePort = last (splitString ":" cfg.controller); 8 | manageAddr = "http://127.0.0.1:${managePort}"; 9 | in 10 | rec { 11 | inherit managePort manageAddr; 12 | updateConfigScript = name: enableUpdate: 13 | let 14 | fullName = "${dataDir}/${name}.yaml"; 15 | in 16 | '' 17 | # Replace ports 18 | ${pkgs.yq-go}/bin/yq eval "del(.socks-port)" -i ${fullName} 19 | ${pkgs.yq-go}/bin/yq eval "del(.port)" -i ${fullName} 20 | ${pkgs.yq-go}/bin/yq eval ".mixed-port = ${toString cfg.port}" -i ${fullName} 21 | 22 | ${optionalString cfg.allowLan '' 23 | ${pkgs.yq-go}/bin/yq eval ".allow-lan = true" -i ${fullName} 24 | ''} 25 | 26 | ${optionalString (cfg.dns != "") '' 27 | ${pkgs.yq-go}/bin/yq eval "del(.dns.nameserver)" -i ${fullName} 28 | ${pkgs.yq-go}/bin/yq eval ".dns.enable = true" -i ${fullName} 29 | ${pkgs.yq-go}/bin/yq eval ".dns.nameserver[0] = \"${cfg.dns}\"" -i ${fullName} 30 | ''} 31 | 32 | # Format document 33 | ${pkgs.yq-go}/bin/yq eval ${fullName} -I 4 --prettyPrint -i 34 | 35 | ${optionalString ((name == cfg.config) && enableUpdate) '' 36 | ${pkgs.curl}/bin/curl ${manageAddr}/configs -X PUT \ 37 | --data '{"path": "${fullName}"}' ${optionalString (cfg.secret != null) "-H 'Authorization: Bearer ${cfg.secret}'"} 38 | ''} 39 | ''; 40 | } 41 | -------------------------------------------------------------------------------- /modules/services/cloudreve.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, options, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.services.cloudreve; 6 | toml = pkgs.formats.toml { }; 7 | configFile = toml.generate "config.conf" cfg.settings; 8 | in 9 | { 10 | options = { 11 | services.cloudreve = { 12 | enable = mkEnableOption "Enable cloudreve"; 13 | 14 | settings = mkOption { 15 | default = 5212; 16 | type = types.attrs; 17 | }; 18 | 19 | package = mkOption { 20 | default = pkgs.cloudreve; 21 | type = types.package; 22 | defaultText = "pkgs.cloudreve"; 23 | }; 24 | }; 25 | }; 26 | 27 | 28 | config = mkIf cfg.enable { 29 | environment.systemPackages = [ cfg.package ]; 30 | 31 | systemd.services.cloudreve = { 32 | description = "Self-hosted file management and sharing system, supports multiple storage providers"; 33 | after = [ "network.target" ]; 34 | wantedBy = [ "multi-user.target" ]; 35 | 36 | serviceConfig = { 37 | PermissionsStartOnly = true; 38 | LimitNPROC = 512; 39 | LimitNOFILE = 1048576; 40 | ProtectHome = true; 41 | ProtectHostname = true; 42 | ProtectKernelLogs = true; 43 | RemoveIPC = true; 44 | RestrictNamespaces = true; 45 | RestrictRealtime = true; 46 | RestrictSUIDSGID = true; 47 | StateDirectory = "cloudreve"; 48 | RuntimeDirectory = "cloudreve"; 49 | RuntimeDirectoryPreserve = "cloudreve"; 50 | WorkingDirectory = "/var/lib/cloudreve"; 51 | StateDirectoryMode = "0700"; 52 | CapabilityBoundingSet = "cap_net_bind_service"; 53 | AmbientCapabilities = "cap_net_bind_service"; 54 | NoNewPrivileges = true; 55 | DynamicUser = true; 56 | Restart = "on-failure"; 57 | }; 58 | 59 | script = '' 60 | exec ${pkgs.cloudreve-pro}/bin/cloudreve -c ${configFile} 61 | ''; 62 | }; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /modules/services/dhcp/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | 4 | with lib; 5 | 6 | let 7 | cfg = config.indexyz.services.dhcp; 8 | subnetOptions = types.submodule (import ./subnet-options.nix { 9 | inherit lib; 10 | }); 11 | 12 | utils = import ./utils.nix { 13 | inherit lib; 14 | }; 15 | 16 | configText = utils.buildConfig cfg; 17 | in 18 | { 19 | options = { 20 | indexyz.services.dhcp = { 21 | enable = mkOption { 22 | default = false; 23 | type = with types; bool; 24 | }; 25 | 26 | subnets = mkOption { 27 | default = [ ]; 28 | type = with types; listOf subnetOptions; 29 | }; 30 | 31 | enableIpxe = mkOption { 32 | default = false; 33 | type = types.bool; 34 | }; 35 | 36 | interfaces = mkOption { 37 | default = [ ]; 38 | type = with types; listOf str; 39 | }; 40 | }; 41 | }; 42 | 43 | config = mkIf cfg.enable { 44 | services.dhcpd4 = { 45 | enable = true; 46 | interfaces = cfg.interfaces; 47 | extraConfig = configText; 48 | }; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /modules/services/dhcp/host-options.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | { 5 | options = { 6 | name = mkOption { 7 | type = types.str; 8 | }; 9 | 10 | mac = mkOption { 11 | type = types.str; 12 | }; 13 | 14 | address = mkOption { 15 | default = null; 16 | type = with types; nullOr str; 17 | }; 18 | 19 | router = mkOption { 20 | default = null; 21 | type = with types; nullOr str; 22 | }; 23 | 24 | dns = mkOption { 25 | default = null; 26 | type = with types; nullOr str; 27 | }; 28 | 29 | extraOptions = mkOption { 30 | default = null; 31 | type = with types; nullOr str; 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /modules/services/dhcp/subnet-options.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | let 5 | hostOptions = types.submodule (import ./host-options.nix { 6 | inherit lib; 7 | }); 8 | in 9 | { 10 | options = { 11 | ip = mkOption { 12 | type = types.str; 13 | }; 14 | 15 | netmask = mkOption { 16 | type = types.str; 17 | default = "255.255.255.0"; 18 | }; 19 | 20 | rangeBegin = mkOption { 21 | type = types.str; 22 | }; 23 | 24 | rangeEnd = mkOption { 25 | type = types.str; 26 | }; 27 | 28 | dns = mkOption { 29 | default = null; 30 | type = with types; nullOr str; 31 | }; 32 | 33 | router = mkOption { 34 | default = null; 35 | type = with types; nullOr str; 36 | }; 37 | 38 | ipxeFile = mkOption { 39 | default = null; 40 | type = with types; nullOr str; 41 | }; 42 | 43 | tftpServer = mkOption { 44 | default = null; 45 | type = with types; nullOr str; 46 | }; 47 | 48 | interface = mkOption { 49 | default = null; 50 | type = with types; nullOr str; 51 | }; 52 | 53 | hosts = mkOption { 54 | default = [ ]; 55 | type = types.listOf hostOptions; 56 | }; 57 | 58 | extraConfig = mkOption { 59 | default = ""; 60 | type = types.str; 61 | }; 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /modules/services/dns/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.dns; 6 | 7 | createProxyUpstream = server: "-u ${server}"; 8 | dnsProxy = concatStringsSep " " (map createProxyUpstream cfg.upstreams); 9 | in 10 | { 11 | options = { 12 | indexyz.services.dns = { 13 | enable = mkEnableOption "DNS Server"; 14 | 15 | openFirewall = mkOption { 16 | default = true; 17 | type = types.bool; 18 | }; 19 | 20 | upstreams = mkOption { 21 | default = [ ]; 22 | example = '' 23 | 8.8.8.8:53 24 | tls://dns.adguard.com 25 | https://dns.adguard.com/dns-query 26 | ''; 27 | type = with types; listOf str; 28 | }; 29 | 30 | proxyPort = mkOption { 31 | default = 5553; 32 | description = "DNS port for dnsproxy which forwarding upstream dns"; 33 | type = types.int; 34 | }; 35 | 36 | dnsPort = mkOption { 37 | default = 53; 38 | description = "Final dns expose port"; 39 | type = types.int; 40 | }; 41 | 42 | proxyArgs = mkOption { 43 | default = ""; 44 | description = "dnsproxy extra args"; 45 | type = types.str; 46 | }; 47 | 48 | extraConf = mkOption { 49 | default = ""; 50 | description = "Extra config for coredns zoon"; 51 | type = types.str; 52 | }; 53 | }; 54 | }; 55 | 56 | config = mkIf cfg.enable { 57 | assertions = singleton { 58 | assertion = (length cfg.upstreams) > 0; 59 | message = '' 60 | indexyz.services.dns should have upstream dns exist 61 | ''; 62 | }; 63 | 64 | systemd.services.dnsproxy = { 65 | description = "Dnsproxy dns server"; 66 | after = [ "network.target" ]; 67 | wantedBy = [ "multi-user.target" ]; 68 | 69 | serviceConfig = { 70 | PermissionsStartOnly = true; 71 | LimitNPROC = 512; 72 | LimitNOFILE = 1048576; 73 | CapabilityBoundingSet = "cap_net_bind_service"; 74 | AmbientCapabilities = "cap_net_bind_service"; 75 | NoNewPrivileges = true; 76 | DynamicUser = true; 77 | ExecStart = "${pkgs.dnsproxy}/bin/dnsproxy ${dnsProxy} -p ${toString cfg.proxyPort} ${cfg.proxyArgs}"; 78 | Restart = "on-failure"; 79 | }; 80 | }; 81 | 82 | networking.firewall = mkIf cfg.openFirewall { 83 | allowedTCPPorts = [ cfg.dnsPort ]; 84 | allowedUDPPorts = [ cfg.dnsPort ]; 85 | }; 86 | 87 | # TODO: add coredns rules 88 | services.coredns = { 89 | enable = true; 90 | config = '' 91 | .:${toString cfg.dnsPort} { 92 | errors 93 | log 94 | health 95 | ${cfg.extraConf} 96 | forward . 127.0.0.1:${toString cfg.proxyPort} 97 | cache { 98 | success 3600 99 | denial 0 100 | } 101 | } 102 | ''; 103 | }; 104 | }; 105 | } 106 | -------------------------------------------------------------------------------- /modules/services/drone-docker.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.drone-docker; 6 | ociCfg = config.virtualisation.oci-containers; 7 | 8 | configEnvFile = pkgs.writeText "drone.env" ('' 9 | DRONE_RPC_PROTO=${cfg.serverProto} 10 | DRONE_RPC_HOST=${cfg.serverHost} 11 | '' + (builtins.concatStringsSep "\n" (attrsets.mapAttrsToList 12 | (name: val: "${name}=${val}") 13 | cfg.extraSettings))); 14 | in 15 | { 16 | options = { 17 | indexyz.services.drone-docker = { 18 | enable = mkEnableOption "Enable drone docker backend"; 19 | 20 | rpcSecretFile = mkOption { 21 | type = types.str; 22 | example = "/run/drone/rpc_secret"; 23 | description = '' 24 | Secret to authenticate communication between runners and your central Drone server. 25 | You can use openssl to generate a shared secret: 26 | 27 | $ openssl rand -hex 16 28 | ''; 29 | }; 30 | 31 | serverProto = mkOption { 32 | default = "https"; 33 | type = types.enum [ "http" "https" ]; 34 | }; 35 | 36 | serverHost = mkOption { 37 | type = types.str; 38 | }; 39 | 40 | workDir = mkOption { 41 | type = types.str; 42 | default = "/var/lib/drone-runner-docker"; 43 | description = "Data store location"; 44 | }; 45 | 46 | extraSettings = mkOption { 47 | type = types.attrs; 48 | default = { }; 49 | description = '' 50 | Extra settings, see also: https://docs.drone.io/runner/docker/configuration/reference/ 51 | 52 | Example: 53 | { 54 | DRONE_RUNNER_LABELS = "os:nixos,arch:amd64"; 55 | } 56 | ''; 57 | }; 58 | 59 | secretEnvFile = mkOption { 60 | type = with types; nullOr str; 61 | default = null; 62 | description = '' 63 | Env file that load to drone every time boot 64 | ''; 65 | }; 66 | }; 67 | }; 68 | 69 | config = mkIf cfg.enable { 70 | systemd.services.drone-docker-runner = { 71 | description = "Drone pipeline runner that executes builds inside Docker containers"; 72 | after = [ "network.target" ]; 73 | wantedBy = [ "multi-user.target" ]; 74 | path = with pkgs; [ git bash ]; 75 | 76 | preStart = '' 77 | mkdir -p ${cfg.workDir} 78 | cat ${configEnvFile} > ${cfg.workDir}/conf.env 79 | echo "" >> ${cfg.workDir}/conf.env 80 | 81 | ${optionalString (cfg.secretEnvFile != null) '' 82 | cat ${cfg.secretEnvFile} > ${cfg.workDir}/conf.env 83 | echo "" >> ${cfg.workDir}/conf.env 84 | ''} 85 | 86 | ${optionalString (ociCfg.backend == "podman") '' 87 | echo "DOCKER_HOST=unix:///run/podman/podman.sock" >> ${cfg.workDir}/conf.env 88 | echo "DOCKER_API_VERSION=1.40" >> ${cfg.workDir}/conf.env 89 | ''} 90 | 91 | cat ${cfg.rpcSecretFile} | ${pkgs.gawk}/bin/gawk '{print "DRONE_RPC_SECRET="$0}' >> ${cfg.workDir}/conf.env 92 | ''; 93 | 94 | script = '' 95 | exec ${pkgs.drone-runner-docker}/bin/drone-runner-docker daemon ${cfg.workDir}/conf.env 96 | ''; 97 | }; 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /modules/services/drone-exec.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.drone-exec; 6 | 7 | configEnvFile = pkgs.writeText "drone.env" ('' 8 | DRONE_RPC_PROTO=${cfg.serverProto} 9 | DRONE_RPC_HOST=${cfg.serverHost} 10 | '' + (builtins.concatStringsSep "\n" (attrsets.mapAttrsToList 11 | (name: val: "${name}=${val}") 12 | cfg.extraSettings))); 13 | in 14 | { 15 | options = { 16 | indexyz.services.drone-exec = { 17 | enable = mkEnableOption "Enable drone exec backend"; 18 | 19 | rpcSecretFile = mkOption { 20 | type = types.str; 21 | example = "/run/drone/rpc_secret"; 22 | description = '' 23 | Secret to authenticate communication between runners and your central Drone server. 24 | You can use openssl to generate a shared secret: 25 | 26 | $ openssl rand -hex 16 27 | ''; 28 | }; 29 | 30 | serverProto = mkOption { 31 | default = "https"; 32 | type = types.enum [ "http" "https" ]; 33 | }; 34 | 35 | serverHost = mkOption { 36 | type = types.str; 37 | }; 38 | 39 | workDir = mkOption { 40 | type = types.str; 41 | default = "/var/lib/drone-runner-exec"; 42 | description = "Data store location"; 43 | }; 44 | 45 | extraSettings = mkOption { 46 | type = types.attrs; 47 | default = { }; 48 | description = '' 49 | Extra settings, see also: https://docs.drone.io/runner/docker/configuration/reference/ 50 | 51 | Example: 52 | { 53 | DRONE_RUNNER_LABELS = "os:nixos,arch:amd64"; 54 | } 55 | ''; 56 | }; 57 | 58 | secretEnvFile = mkOption { 59 | type = with types; nullOr str; 60 | default = null; 61 | description = '' 62 | Env file that load to drone every time boot 63 | ''; 64 | }; 65 | 66 | workerPkgs = mkOption { 67 | type = with types; listOf package; 68 | default = [ ]; 69 | description = "Extra package exist in runner path"; 70 | }; 71 | }; 72 | }; 73 | 74 | config = mkIf cfg.enable { 75 | systemd.services.drone-exec-runner = { 76 | description = "Drone pipeline runner that executes builds directly on the host machine"; 77 | after = [ "network.target" ]; 78 | wantedBy = [ "multi-user.target" ]; 79 | path = with pkgs; [ git bash ] ++ cfg.workerPkgs; 80 | 81 | preStart = '' 82 | mkdir -p ${cfg.workDir} 83 | cat ${configEnvFile} > ${cfg.workDir}/conf.env 84 | echo "" >> ${cfg.workDir}/conf.env 85 | 86 | ${optionalString (cfg.secretEnvFile != null) '' 87 | cat ${cfg.secretEnvFile} > ${cfg.workDir}/conf.env 88 | echo "" >> ${cfg.workDir}/conf.env 89 | ''} 90 | 91 | cat ${cfg.rpcSecretFile} | ${pkgs.gawk}/bin/gawk '{print "DRONE_RPC_SECRET="$0}' >> ${cfg.workDir}/conf.env 92 | ''; 93 | 94 | script = '' 95 | exec ${pkgs.drone-runner-exec}/bin/drone-runner-exec daemon ${cfg.workDir}/conf.env 96 | ''; 97 | }; 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /modules/services/drone-web.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.drone-web; 6 | envLoad = "/run/drone/env"; 7 | in 8 | { 9 | options = { 10 | indexyz.services.drone-web = { 11 | enable = mkEnableOption "Enable drone web"; 12 | 13 | port = mkOption { 14 | default = 5905; 15 | type = types.int; 16 | description = "Drone ci web interface location"; 17 | }; 18 | 19 | rpcSecretFile = mkOption { 20 | type = types.str; 21 | example = "/run/drone/rpc_secret"; 22 | description = '' 23 | Secret to authenticate communication between runners and your central Drone server. 24 | You can use openssl to generate a shared secret: 25 | 26 | $ openssl rand -hex 16 27 | ''; 28 | }; 29 | 30 | serverProto = mkOption { 31 | default = "https"; 32 | type = types.enum [ "http" "https" ]; 33 | }; 34 | 35 | serverHost = mkOption { 36 | default = "localhost"; 37 | type = types.str; 38 | }; 39 | 40 | extraSettings = mkOption { 41 | type = types.attrs; 42 | default = { }; 43 | description = '' 44 | Extra settings, see also: https://docs.drone.io/server/provider/ 45 | 46 | Example: 47 | { 48 | DRONE_GITHUB_CLIENT_ID = "GitHub Client"; 49 | DRONE_GITHUB_CLIENT_SECRET = "GitHub Secret"; 50 | } 51 | ''; 52 | }; 53 | 54 | secretEnvFile = mkOption { 55 | type = with types; nullOr str; 56 | default = null; 57 | description = '' 58 | Env file that load to drone every time boot 59 | ''; 60 | }; 61 | 62 | package = mkOption { 63 | default = pkgs.drone-oss; 64 | example = "pkgs.drone"; 65 | type = types.package; 66 | }; 67 | }; 68 | }; 69 | 70 | config = mkIf cfg.enable { 71 | systemd.services.drone = { 72 | description = "Drone is a Container-Native, Continuous Delivery Platform"; 73 | after = [ "network.target" ]; 74 | wantedBy = [ "multi-user.target" ]; 75 | 76 | script = '' 77 | rm -f ${envLoad} 78 | ${optionalString (cfg.secretEnvFile != null) '' 79 | cat $CREDENTIALS_DIRECTORY/envFile > ${envLoad} 80 | echo "" >> ${envLoad} 81 | ''} 82 | 83 | cat $CREDENTIALS_DIRECTORY/rpcSecret | ${pkgs.gawk}/bin/gawk '{print "DRONE_RPC_SECRET="$0}' >> ${envLoad} 84 | exec ${cfg.package}/bin/drone-server -env-file ${envLoad} 85 | ''; 86 | 87 | environment = { 88 | DRONE_SERVER_HOST = cfg.serverHost; 89 | DRONE_SERVER_PROTO = cfg.serverProto; 90 | DRONE_SERVER_PORT = ":${builtins.toString cfg.port}"; 91 | DRONE_DATADOG_ENABLED = "false"; 92 | } // cfg.extraSettings; 93 | 94 | serviceConfig = { 95 | NoNewPrivileges = true; 96 | DynamicUser = true; 97 | ProtectHome = true; 98 | ProtectHostname = true; 99 | ProtectKernelLogs = true; 100 | RemoveIPC = true; 101 | RestrictNamespaces = true; 102 | RestrictRealtime = true; 103 | RestrictSUIDSGID = true; 104 | StateDirectory = "drone"; 105 | RuntimeDirectory = "drone"; 106 | RuntimeDirectoryPreserve = "yes"; 107 | WorkingDirectory = "/var/lib/drone"; 108 | StateDirectoryMode = "0700"; 109 | LoadCredential = [ 110 | "rpcSecret:${cfg.rpcSecretFile}" 111 | ] ++ (if (cfg.secretEnvFile != null) then [ 112 | "envFile:${cfg.secretEnvFile}" 113 | ] else [ ]); 114 | }; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /modules/services/forwarding/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.forwarding; 6 | ruleOptions = types.submodule (import ./rule-options.nix { 7 | inherit lib; 8 | }); 9 | 10 | ifThenElse = cond: t: f: if cond then t else f; 11 | 12 | typeToAttr = type: ifThenElse (type == "all") 13 | { 14 | use_udp = true; 15 | } 16 | (ifThenElse (type == "tcp") 17 | { } 18 | { 19 | use_udp = true; 20 | no_tcp = true; 21 | }); 22 | 23 | generateConfig = conf: ({ 24 | listen = "${conf.listen}:${toString conf.port}"; 25 | remote = "${conf.target}:${toString conf.targetPort}"; 26 | } // (typeToAttr conf.type)); 27 | 28 | configData = { 29 | log = { level = cfg.logLevel; }; 30 | network = { use_udp = true; }; 31 | endpoints = map generateConfig cfg.rules; 32 | }; 33 | 34 | configFile = pkgs.writeText "config.json" (builtins.toJSON configData); 35 | in 36 | { 37 | options = { 38 | indexyz.services.forwarding = { 39 | enable = mkOption { 40 | default = false; 41 | type = with types; bool; 42 | }; 43 | 44 | logLevel = mkOption { 45 | default = "info"; 46 | type = types.enum [ "off" "error" "warn" "info" "debug" "trace" ]; 47 | }; 48 | 49 | rules = mkOption { 50 | default = [ ]; 51 | type = types.listOf ruleOptions; 52 | }; 53 | }; 54 | }; 55 | 56 | config = mkIf cfg.enable { 57 | 58 | systemd.services.realm = { 59 | after = [ "network.target" ]; 60 | wantedBy = [ "multi-user.target" ]; 61 | 62 | serviceConfig = { 63 | PermissionsStartOnly = true; 64 | LimitNPROC = 512; 65 | LimitNOFILE = 1048576; 66 | CapabilityBoundingSet = "cap_net_bind_service"; 67 | AmbientCapabilities = "cap_net_bind_service"; 68 | NoNewPrivileges = true; 69 | DynamicUser = true; 70 | ExecStart = "${pkgs.realm}/bin/realm -c ${configFile}"; 71 | Restart = "on-failure"; 72 | }; 73 | }; 74 | 75 | networking.firewall.allowedTCPPorts = ( 76 | map (item: item.port) 77 | (filter (it: ((it.type == "tcp") || (it.type == "all"))) cfg.rules) 78 | ); 79 | 80 | networking.firewall.allowedUDPPorts = ( 81 | map (item: item.port) 82 | (filter (it: ((it.type == "udp") || (it.type == "all"))) cfg.rules) 83 | ); 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /modules/services/forwarding/rule-options.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | { 5 | options = { 6 | listen = mkOption { 7 | default = "0.0.0.0"; 8 | type = types.str; 9 | }; 10 | 11 | port = mkOption { 12 | type = types.int; 13 | }; 14 | 15 | target = mkOption { 16 | type = types.str; 17 | }; 18 | 19 | targetPort = mkOption { 20 | type = types.int; 21 | }; 22 | 23 | type = mkOption { 24 | default = "all"; 25 | type = types.enum [ "tcp" "udp" "all" ]; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/services/frpc/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, utils, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.frpc; 6 | format = pkgs.formats.json { }; 7 | in 8 | { 9 | options = { 10 | indexyz.services.frpc = { 11 | enable = mkOption { 12 | default = false; 13 | type = with types; bool; 14 | }; 15 | 16 | settings = mkOption { 17 | type = format.type; 18 | default = { }; 19 | }; 20 | }; 21 | }; 22 | 23 | config = mkIf cfg.enable { 24 | systemd.services.frpc = { 25 | wantedBy = [ "multi-user.target" ]; 26 | after = [ "network.target" ]; 27 | 28 | startLimitIntervalSec = 0; 29 | serviceConfig = { 30 | Restart = "always"; 31 | RestartSec = "10s"; 32 | StateDirectory = "frpc"; 33 | RuntimeDirectory = "frpc"; 34 | RuntimeDirectoryPreserve = "frpc"; 35 | WorkingDirectory = "/var/lib/frpc"; 36 | }; 37 | 38 | script = '' 39 | ${utils.genJqSecretsReplacementSnippet cfg.settings "/var/lib/frpc/config.json"} 40 | exec ${pkgs.frp}/bin/frpc -c /var/lib/frpc/config.json 41 | ''; 42 | }; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /modules/services/frpc/rule-options.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | { 5 | options = { 6 | name = mkOption { 7 | type = types.str; 8 | }; 9 | 10 | port = mkOption { 11 | type = types.int; 12 | }; 13 | 14 | host = mkOption { 15 | type = types.str; 16 | default = "127.0.0.1"; 17 | }; 18 | 19 | domain = mkOption { 20 | type = types.str; 21 | }; 22 | 23 | remotePort = mkOption { 24 | type = types.int; 25 | }; 26 | 27 | type = mkOption { 28 | default = "tcp"; 29 | type = types.enum [ "tcp" "udp" "http" "https" ]; 30 | }; 31 | 32 | acme = mkOption { 33 | default = false; 34 | type = types.bool; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /modules/services/frpc/server-options.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | with lib; 4 | let 5 | ruleOptions = types.submodule (import ./rule-options.nix { 6 | inherit lib; 7 | }); 8 | in 9 | { 10 | options = { 11 | name = mkOption { 12 | type = types.str; 13 | default = "default"; 14 | }; 15 | 16 | server = mkOption { 17 | type = types.str; 18 | }; 19 | 20 | serverPort = mkOption { 21 | type = types.int; 22 | default = 7000; 23 | }; 24 | 25 | token = mkOption { 26 | description = '' 27 | Frp token verify, used to auth in server and client 28 | ''; 29 | type = types.str; 30 | }; 31 | 32 | rules = mkOption { 33 | default = [ ]; 34 | type = types.listOf ruleOptions; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /modules/services/frps/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, utils, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.frps; 6 | format = pkgs.formats.json { }; 7 | in 8 | { 9 | options = { 10 | indexyz.services.frps = { 11 | enable = mkOption { 12 | default = false; 13 | type = with types; bool; 14 | }; 15 | 16 | settings = mkOption { 17 | type = format.type; 18 | default = { }; 19 | }; 20 | }; 21 | }; 22 | 23 | config = mkIf cfg.enable { 24 | systemd.services.frps = { 25 | wantedBy = [ "multi-user.target" ]; 26 | after = [ "network.target" ]; 27 | serviceConfig = { 28 | Restart = "always"; 29 | RestartSec = 30; 30 | StateDirectory = "frps"; 31 | RuntimeDirectory = "frps"; 32 | RuntimeDirectoryPreserve = "frps"; 33 | WorkingDirectory = "/var/lib/frps"; 34 | }; 35 | 36 | script = '' 37 | ${utils.genJqSecretsReplacementSnippet cfg.settings "/var/lib/frps/config.json"} 38 | exec ${pkgs.frp}/bin/frps -c /var/lib/frps/config.json 39 | ''; 40 | }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /modules/services/hpool-miner.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.hpool-miner; 6 | minerConfig = { 7 | apiKey = cfg.token; 8 | deviceId = ""; 9 | cachePath = ""; 10 | debug = ""; 11 | log = { 12 | lv = "info"; 13 | path = "./log"; 14 | name = "miner.log"; 15 | }; 16 | scanPath = true; 17 | scanMinute = 1; 18 | token = ""; 19 | minerName = cfg.name; 20 | path = cfg.path; 21 | extraParams = { }; 22 | url = { 23 | info = ""; 24 | submit = ""; 25 | }; 26 | }; 27 | 28 | configData = pkgs.writeText "config.yaml" (builtins.toJSON minerConfig); 29 | in 30 | { 31 | options = { 32 | indexyz.services.hpool-miner = { 33 | enable = mkOption { 34 | default = false; 35 | type = types.bool; 36 | }; 37 | 38 | path = mkOption { 39 | type = with types; listOf str; 40 | }; 41 | 42 | name = mkOption { 43 | type = types.str; 44 | }; 45 | 46 | token = mkOption { 47 | type = types.str; 48 | }; 49 | 50 | dataDir = mkOption { 51 | default = "/var/lib/hpool-miner"; 52 | type = types.str; 53 | }; 54 | }; 55 | }; 56 | 57 | config = mkIf cfg.enable { 58 | systemd.services.hpool-miner = { 59 | wantedBy = [ "multi-user.target" ]; 60 | after = [ "network.target" ]; 61 | environment = { 62 | HOME = "${cfg.dataDir}"; 63 | }; 64 | serviceConfig = { 65 | Restart = "always"; 66 | RestartSec = "10s"; 67 | PrivateTmp = true; 68 | WorkingDirectory = "${cfg.dataDir}"; 69 | }; 70 | script = '' 71 | mkdir -p ${cfg.dataDir} 72 | cd ${cfg.dataDir} 73 | cp ${configData} config.yaml 74 | ${pkgs.hpool-chia-miner}/bin/hpool-miner-chia 75 | ''; 76 | }; 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /modules/services/influxdb.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.influxdb; 6 | in 7 | { 8 | options = { 9 | indexyz.services.influxdb = { 10 | enable = mkEnableOption "Enable influxdb version 2"; 11 | 12 | dataDir = mkOption { 13 | default = "/var/lib/influxdb"; 14 | type = types.str; 15 | }; 16 | 17 | bindAddress = mkOption { 18 | type = types.str; 19 | default = ":8086"; 20 | description = "Bind address for the REST HTTP API"; 21 | }; 22 | 23 | extraArgs = mkOption { 24 | type = types.str; 25 | default = ""; 26 | description = "Extra args to run influxd"; 27 | example = "--pprof-disabled"; 28 | }; 29 | }; 30 | }; 31 | 32 | config = mkIf cfg.enable { 33 | systemd.services.influxdb = { 34 | description = "Scalable datastore for metrics, events, and real-time analytics"; 35 | wantedBy = [ "multi-user.target" ]; 36 | after = [ "network.target" ]; 37 | 38 | script = '' 39 | mkdir -p ${cfg.dataDir} 40 | 41 | ${pkgs.influxdb2}/bin/influxd --reporting-disabled \ 42 | --bolt-path ${cfg.dataDir}/influxd.bolt --engine-path ${cfg.dataDir}/engine \ 43 | --http-bind-address ${cfg.bindAddress} ${cfg.extraArgs} 44 | ''; 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /modules/services/k3s.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.k3s; 6 | in 7 | { 8 | options = { 9 | indexyz.services.k3s = { 10 | enable = mkOption { 11 | default = false; 12 | type = with types; bool; 13 | }; 14 | }; 15 | }; 16 | 17 | config = mkIf cfg.enable { 18 | services.k3s = { 19 | enable = true; 20 | role = "server"; 21 | extraFlags = "--no-deploy traefik"; 22 | }; 23 | 24 | environment.variables.KUBECONFIG = "/etc/rancher/k3s/k3s.yaml"; 25 | 26 | # services.cgroups.enable = true; 27 | boot.kernelParams = [ 28 | "cgroup_memory=1" 29 | "cgroup_enable=memory" 30 | ]; 31 | 32 | environment.systemPackages = with pkgs; [ 33 | k3s 34 | kubectl 35 | kubernetes-helm 36 | ]; 37 | 38 | # https://github.com/NixOS/nixpkgs/issues/98766 39 | systemd.services.k3s.after = [ "network-online.service" "firewall.service" ]; 40 | systemd.services.k3s.serviceConfig.KillMode = lib.mkForce "control-group"; 41 | 42 | boot.kernelModules = [ "br_netfilter" "ip_conntrack" "ip_vs" "ip_vs_rr" "ip_vs_wrr" "ip_vs_sh" "overlay" ]; 43 | networking.firewall.extraCommands = '' 44 | iptables -A INPUT -i cni+ -j ACCEPT 45 | iptables -I INPUT 1 -i cni0 -s 10.42.0.0/16 -j ACCEPT 46 | iptables -I FORWARD 1 -s 10.42.0.0/15 -j ACCEPT 47 | ''; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /modules/services/ksmbd.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.ksmbd; 6 | 7 | user = types.submodule ({ 8 | options = { 9 | user = mkOption { 10 | type = types.str; 11 | }; 12 | pass = mkOption { 13 | type = types.str; 14 | }; 15 | }; 16 | }); 17 | 18 | userCommand = user: pass: '' 19 | ${pkgs.ksmbd-tools}/bin/ksmbd.adduser -i $out -a ${user} -p ${pass} 20 | ''; 21 | 22 | smbToString = x: 23 | if builtins.typeOf x == "bool" 24 | then boolToString x 25 | else toString x; 26 | 27 | shareConfig = name: 28 | let share = getAttr name cfg.shares; in 29 | "[${name}]\n " + (smbToString ( 30 | map 31 | (key: "${key} = ${smbToString (getAttr key share)}\n") 32 | (attrNames share) 33 | )); 34 | 35 | usersFile = pkgs.runCommand "ksmbd-users" { } (builtins.concatStringsSep "\n" (map (it: userCommand it.user it.pass) cfg.users)); 36 | configFile = pkgs.writeText "ksmbd.conf" '' 37 | [global] 38 | security = ${cfg.securityType} 39 | ${cfg.extraConfig} 40 | 41 | ${smbToString (map shareConfig (attrNames cfg.shares))} 42 | ''; 43 | in 44 | { 45 | options = { 46 | indexyz.services.ksmbd = { 47 | enable = mkEnableOption "Enable cifsd kernel server"; 48 | 49 | securityType = mkOption { 50 | type = types.str; 51 | default = "user"; 52 | description = "Samba security type"; 53 | }; 54 | 55 | extraConfig = mkOption { 56 | type = types.lines; 57 | default = ""; 58 | description = '' 59 | Additional global section and extra section lines go in here. 60 | ''; 61 | example = '' 62 | guest account = nobody 63 | map to guest = bad user 64 | ''; 65 | }; 66 | 67 | shares = mkOption { 68 | default = { }; 69 | description = '' 70 | A set describing shared resources. 71 | See man smb.conf for options. 72 | ''; 73 | type = types.attrsOf (types.attrsOf types.unspecified); 74 | example = literalExample '' 75 | { public = 76 | { path = "/srv/public"; 77 | "read only" = true; 78 | browseable = "yes"; 79 | "guest ok" = "yes"; 80 | comment = "Public samba share."; 81 | }; 82 | } 83 | ''; 84 | }; 85 | 86 | users = mkOption { 87 | default = [ ]; 88 | type = with types; listOf user; 89 | }; 90 | }; 91 | }; 92 | config = mkIf cfg.enable { 93 | boot = { 94 | extraModulePackages = [ pkgs.ksmbd-kernel ]; 95 | kernelModules = [ "ksmbd" ]; 96 | }; 97 | environment.systemPackages = [ pkgs.ksmbd-tools ]; 98 | 99 | systemd.services.ksmbd = { 100 | wantedBy = [ "multi-user.target" ]; 101 | after = [ "network.target" ]; 102 | preStart = '' 103 | mkdir -p /etc/ksmbd 104 | rm -f /etc/ksmbd/ksmbd.conf 105 | ln -s ${configFile} /etc/ksmbd/ksmbd.conf 106 | ''; 107 | serviceConfig = { 108 | Type = "forking"; 109 | ExecStart = "${pkgs.ksmbd-tools}/bin/ksmbd.mountd --users ${usersFile} --config /etc/ksmbd/ksmbd.conf -s"; 110 | Restart = "always"; 111 | PrivateTmp = true; 112 | }; 113 | }; 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/README.md: -------------------------------------------------------------------------------- 1 | # Devices 2 | 3 | Device renderers take device-specific configurations as input, and emit XML fragments to be included in the libvirt domain's `` section. 4 | They may also emit `provisionScript`s to be executed before the domain starts as well as other things (e.g., hints for the networking modules to configure DHCP). 5 | 6 | Here a custom NixOS-ish module system powered by `lib.evalModules` is used for type-checking and configuration merging. 7 | 8 | 9 | ## Network adapters 10 | 11 | Devices which act like network adapters should expose `network` in the rendered configurations, containing information on how the guest can be reached from the host. 12 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/basic-io.nix: -------------------------------------------------------------------------------- 1 | # Basic I/O devices 2 | 3 | { pkgs, ... }: 4 | with builtins; 5 | let 6 | lib = pkgs.lib; 7 | in 8 | { 9 | construct = 10 | { port ? null, password ? null }: { 11 | type = "basic-io"; 12 | config = { inherit port password; }; 13 | }; 14 | render = device: machineName: machine: 15 | let 16 | vncBase = "/run/hypervisor/vnc"; 17 | vncSocket = "${vncBase}/${machineName}"; 18 | in 19 | { 20 | deviceStanza = '' 21 | 22 | 25 | ${lib.optionalString (device.config.port == null) '' 26 | 27 | 28 | 29 | ''} 30 | 31 | ${lib.optionalString (device.config.port != null) '' 32 | 36 | ''} 37 | 38 | ''; 39 | 40 | provisionScript = toString (pkgs.writeScript "vm-basic-io" '' 41 | ${pkgs.coreutils}/bin/mkdir -p ${vncBase} 42 | ''); 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/block.nix: -------------------------------------------------------------------------------- 1 | # qcow2 provisioner 2 | 3 | { pkgs, config, ... }: 4 | with builtins; 5 | let 6 | lib = pkgs.lib; 7 | cfg = config.zhaofeng.services.hypervisor; 8 | tools = import ../tools { 9 | inherit pkgs config; 10 | }; 11 | in 12 | { 13 | # QEMU qcow2 disk image 14 | construct = 15 | { 16 | # Block device 17 | block ? null 18 | , # Target device 19 | # 20 | # Example: vda 21 | dev ? null 22 | , # Target bus 23 | # 24 | # Example: virtio 25 | bus ? "virtio" 26 | }: 27 | let 28 | compDev = 29 | if dev != null then dev 30 | else if bus == "virtio" then "vda" 31 | else throw "You must specify a target device (e.g., vda, sda) according to the target bus"; 32 | in 33 | { 34 | type = "block"; 35 | config = { 36 | inherit bus block; 37 | dev = compDev; 38 | }; 39 | }; 40 | 41 | render = device: machineName: machine: 42 | { 43 | deviceStanza = '' 44 | 45 | 46 | 47 | 48 | 49 | ''; 50 | 51 | provisionScript = ""; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/bridge.nix: -------------------------------------------------------------------------------- 1 | # Bridge 2 | 3 | { pkgs, config, ... }: 4 | with builtins; 5 | let 6 | lib = pkgs.lib; 7 | cfg = config.zhaofeng.services.hypervisor; 8 | 9 | tools = import ../tools { 10 | inherit pkgs config; 11 | }; 12 | in 13 | { 14 | # Host-side Bridge 15 | construct = 16 | { 17 | # Model 18 | model ? "virtio" 19 | , # Host-side bridge 20 | dev 21 | , # MAC address 22 | # 23 | # Leave null to generate deterministic name-based 24 | # MAC address 25 | mac ? null 26 | , # Network 27 | # 28 | # Hint for other modules to assign guest IPs on this 29 | # interface. 30 | # 31 | # If null, it's set to the name of the guest. 32 | network ? null 33 | , 34 | }: { 35 | type = "bridge"; 36 | config = { 37 | # null mac will be replaced in render 38 | inherit model dev mac network; 39 | }; 40 | }; 41 | 42 | render = device: machineName: machine: 43 | let 44 | interfaceId = "${machineName}-${device.config.model}-${device.config.dev}"; 45 | compMac = 46 | if device.config.mac != null then device.config.mac 47 | else tools.domainMac cfg.macNamespace interfaceId; 48 | compNetwork = 49 | if device.config.network != null then device.config.network 50 | else machineName; 51 | in 52 | { 53 | deviceStanza = '' 54 | 55 | 56 | 57 | 58 | 59 | ''; 60 | 61 | provisionScript = ""; 62 | 63 | network = { 64 | hostDev = device.config.dev; 65 | guestMac = compMac; 66 | network = compNetwork; 67 | }; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/custom.nix: -------------------------------------------------------------------------------- 1 | # A simple escape hatch to define arbitrary libvirt devices 2 | # 3 | # Configs contain two attributes: 4 | # - deviceStanza: XML stanza to be inserted into 5 | # - provisionScript: Optional provisionScript to be run before domain startup. Must be idempotent. 6 | { pkgs, ... }: 7 | { 8 | construct = { xml ? "" }: { 9 | config = { 10 | inherit xml; 11 | }; 12 | type = "custom"; 13 | }; 14 | render = device: machineName: machine: { 15 | deviceStanza = device.config.xml; 16 | provisionScript = ""; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, ... }: 2 | with builtins; 3 | let 4 | lib = pkgs.lib; 5 | 6 | supportedDevices = { 7 | basic-io = ./basic-io.nix; 8 | bridge = ./bridge.nix; 9 | custom = ./custom.nix; 10 | iso = ./iso.nix; 11 | qcow2 = ./qcow2.nix; 12 | veth-pair = ./veth-pair.nix; 13 | tpm = ./tpm.nix; 14 | block = ./block.nix; 15 | }; 16 | 17 | devices = lib.attrsets.mapAttrs (n: v: import v { inherit pkgs config; }) supportedDevices; 18 | in 19 | { 20 | render = device: machineName: machine: 21 | if hasAttr device.type devices then devices.${device.type}.render device machineName machine 22 | else throw "Unsupported device ${device.type}. Supported types: ${toString (attrNames supportedDevices)}"; 23 | } // (lib.attrsets.mapAttrs (n: v: v.construct) devices) 24 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/iso.nix: -------------------------------------------------------------------------------- 1 | # Attach an ISO 2 | 3 | { pkgs, ... }: 4 | with builtins; 5 | 6 | { 7 | # ISO 8 | construct = 9 | { 10 | # Path to ISO 11 | iso 12 | , # Target device 13 | # 14 | # Example: vdc 15 | dev ? null 16 | , # Target bus 17 | # 18 | # Example: virtio 19 | bus ? "scsi" 20 | , 21 | }: 22 | let 23 | compDev = 24 | if dev != null then dev 25 | else if bus == "scsi" then "sdc" 26 | else throw "You must specify a target device (e.g., sda, hda) according to the target bus"; 27 | 28 | compIso = toString iso; 29 | in 30 | { 31 | type = "iso"; 32 | config = { 33 | inherit bus; 34 | iso = compIso; 35 | dev = compDev; 36 | }; 37 | }; 38 | 39 | render = device: machineName: machine: { 40 | deviceStanza = '' 41 | 42 | 43 | 44 | 45 | 46 | 47 | ''; 48 | 49 | provisionScript = ""; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/qcow2.nix: -------------------------------------------------------------------------------- 1 | # qcow2 provisioner 2 | 3 | { pkgs, config, ... }: 4 | with builtins; 5 | let 6 | lib = pkgs.lib; 7 | cfg = config.zhaofeng.services.hypervisor; 8 | tools = import ../tools { 9 | inherit pkgs config; 10 | }; 11 | in 12 | { 13 | # QEMU qcow2 disk image 14 | construct = 15 | { 16 | # Name 17 | name ? "main" 18 | , # Path 19 | # 20 | # If null, determined from cfg.storagePath 21 | path ? null 22 | , # Capacity 23 | # 24 | # Has no effect (for now) if there's an 25 | # existing image 26 | capacity ? null 27 | , # Target device 28 | # 29 | # Example: vda 30 | dev ? null 31 | , # Target bus 32 | # 33 | # Example: virtio 34 | bus ? "virtio" 35 | , fromDisk ? null 36 | }: 37 | let 38 | compDev = 39 | if dev != null then dev 40 | else if bus == "virtio" then "vda" 41 | else throw "You must specify a target device (e.g., vda, sda) according to the target bus"; 42 | compPath = 43 | if path != null then path 44 | else "${cfg.storagePath}/%machineName%/${name}.qcow2"; 45 | in 46 | { 47 | type = "qcow2"; 48 | config = { 49 | inherit name capacity bus fromDisk; 50 | dev = compDev; 51 | path = compPath; 52 | }; 53 | }; 54 | 55 | render = device: machineName: machine: 56 | let 57 | deviceName = device.config.name; 58 | #diskPath = "/var/lib/hypervisor/${machineName}/${deviceName}.qcow2"; 59 | diskPath = replaceStrings [ "%machineName%" ] [ machineName ] device.config.path; 60 | capacity = tools.qemu-img.renderSize device.config.capacity; 61 | fromDisk = device.config.fromDisk; 62 | in 63 | { 64 | deviceStanza = '' 65 | 66 | 67 | 68 | 69 | 70 | ''; 71 | 72 | # FIXME: Better way than toString 73 | provisionScript = toString (pkgs.writeScript "vm-${machineName}-qcow2-${deviceName}" '' 74 | #!${pkgs.runtimeShell} -e 75 | dir=$(${pkgs.coreutils}/bin/dirname ${diskPath}) 76 | mkdir -p $dir 77 | 78 | if [ -f "${diskPath}" ]; then 79 | echo "Using existing qcow2 image at ${diskPath}" 80 | else 81 | ${lib.optionalString (fromDisk != null) '' 82 | echo "Copy disk image from ${fromDisk}" 83 | cp ${fromDisk} ${diskPath} 84 | ''} 85 | 86 | ${lib.optionalString (fromDisk == null) '' 87 | echo "Creating ${capacity} qcow2 image at ${diskPath}" 88 | ${pkgs.qemu}/bin/qemu-img create -f qcow2 ${diskPath} ${capacity} 89 | ''} 90 | fi 91 | ''); 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/tpm.nix: -------------------------------------------------------------------------------- 1 | # TPM devices 2 | 3 | { pkgs, ... }: 4 | with builtins; 5 | { 6 | construct = 7 | { version ? "2.0" }: { 8 | type = "tpm"; 9 | config = { inherit version; }; 10 | }; 11 | render = device: machineName: machine: 12 | { 13 | deviceStanza = '' 14 | 15 | 16 | 17 | ''; 18 | 19 | provisionScript = ""; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /modules/services/libvirt/devices/veth-pair.nix: -------------------------------------------------------------------------------- 1 | # Simple veth pair 2 | 3 | { pkgs, config, ... }: 4 | with builtins; 5 | let 6 | lib = pkgs.lib; 7 | cfg = config.zhaofeng.services.hypervisor; 8 | 9 | tools = import ../tools { 10 | inherit pkgs config; 11 | }; 12 | in 13 | { 14 | # Simple veth pair 15 | construct = 16 | { 17 | # Model 18 | model ? "virtio" 19 | , # Host-side device 20 | dev 21 | , # MAC address 22 | # 23 | # Leave null to generate deterministic name-based 24 | # MAC address 25 | mac ? null 26 | , # Network 27 | # 28 | # Hint for other modules to assign guest IPs on this 29 | # interface. 30 | # 31 | # If null, it's set to the name of the guest. 32 | network ? null 33 | , 34 | }: { 35 | type = "veth-pair"; 36 | config = { 37 | # null mac will be replaced in render 38 | inherit model dev mac network; 39 | }; 40 | }; 41 | 42 | render = device: machineName: machine: 43 | let 44 | interfaceId = "${machineName}-${device.config.model}-${device.config.dev}"; 45 | compMac = 46 | if device.config.mac != null then device.config.mac 47 | else tools.domainMac cfg.macNamespace interfaceId; 48 | compNetwork = 49 | if device.config.network != null then device.config.network 50 | else machineName; 51 | in 52 | { 53 | deviceStanza = '' 54 | 55 | 56 | 57 | 58 | 59 | ''; 60 | 61 | provisionScript = ""; 62 | 63 | network = { 64 | hostDev = device.config.dev; 65 | guestMac = compMac; 66 | network = compNetwork; 67 | }; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /modules/services/libvirt/fixes/remove-default-network.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | cfg = config.zhaofeng.services.hypervisor; 5 | in 6 | { 7 | config = lib.mkIf cfg.enable { 8 | systemd.services.libvirtd-config.script = lib.mkAfter '' 9 | rm /var/lib/libvirt/qemu/networks/default.xml 10 | ''; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/services/libvirt/models.nix: -------------------------------------------------------------------------------- 1 | # Definition of hypervisor resources 2 | # 3 | # Some of them map directly to libvirt XML elements, 4 | # and some are specific to this module. 5 | 6 | { lib, ... }: 7 | let 8 | types = lib.types; 9 | nullOrStr = description: default: lib.mkOption { 10 | inherit description default; 11 | type = types.nullOr types.str; 12 | }; 13 | str = description: lib.mkOption { 14 | inherit description; 15 | type = types.str; 16 | }; 17 | in 18 | rec { 19 | sizeType = types.submodule { 20 | options = { 21 | unit = lib.mkOption { 22 | description = "Unit"; 23 | type = types.enum [ 24 | # SI IEC 25 | "MB" 26 | "M" 27 | "MiB" 28 | "GB" 29 | "G" 30 | "GiB" 31 | "TB" 32 | "T" 33 | "TiB" 34 | ]; 35 | }; 36 | value = lib.mkOption { 37 | description = "Value"; 38 | type = types.ints.unsigned; 39 | }; 40 | }; 41 | }; 42 | 43 | deviceType = types.submodule { 44 | options = { 45 | type = lib.mkOption { 46 | description = "Type"; 47 | type = types.str; 48 | }; 49 | config = lib.mkOption { 50 | description = "Renderer-specific configurations"; 51 | type = types.attrs; 52 | }; 53 | }; 54 | }; 55 | 56 | # 57 | # 58 | # TODO: Generic interface declaration 59 | # 60 | # For my use-case, each VM has a veth pair to 61 | # the host that is not bridged. Routing is 62 | # configured elsewhere. 63 | ethernetInterfaceType = types.submodule { 64 | options = { 65 | model = lib.mkOption { 66 | description = "Model"; 67 | type = types.str; 68 | }; 69 | device = lib.mkOption { 70 | description = "Device name"; 71 | type = types.str; 72 | }; 73 | }; 74 | }; 75 | 76 | machineType = types.submodule { 77 | options = { 78 | title = nullOrStr "Human-readable name" null; 79 | description = nullOrStr "Description" null; 80 | 81 | arch = nullOrStr "Architecture" "x86_64"; 82 | machine = nullOrStr "Machine type" "pc-q35-5.2"; 83 | autoStart = lib.mkOption { 84 | description = "Auto-start domain"; 85 | default = true; 86 | type = types.bool; 87 | }; 88 | 89 | # FIXME: Not used right now 90 | firmware = lib.mkOption { 91 | description = "System firmware"; 92 | default = "bios"; 93 | type = types.enum [ "bios" "efi" ]; 94 | }; 95 | # TODO: Support more sophisticated topologies 96 | smp = lib.mkOption { 97 | description = "Number of vCores"; 98 | default = 1; 99 | type = types.ints.unsigned; 100 | }; 101 | memory = lib.mkOption { 102 | description = "Memory size"; 103 | type = sizeType; 104 | }; 105 | bootOrder = lib.mkOption { 106 | description = "Boot order"; 107 | type = types.listOf (types.enum [ 108 | "fd" 109 | "hd" 110 | "cdrom" 111 | "network" 112 | ]); 113 | default = [ "hd" "cdrom" ]; 114 | }; 115 | balloon = lib.mkOption { 116 | description = '' 117 | Enable machine mem balloon 118 | ''; 119 | default = true; 120 | type = types.bool; 121 | }; 122 | devices = lib.mkOption { 123 | description = '' 124 | Devices 125 | Use helper functions which emit renderer-specific 126 | values 127 | ''; 128 | default = [ ]; 129 | type = types.listOf deviceType; 130 | }; 131 | }; 132 | }; 133 | } 134 | -------------------------------------------------------------------------------- /modules/services/libvirt/tools/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, ... }: 2 | let 3 | lib = pkgs.lib; 4 | cfg = config.zhaofeng.services.hypervisor; 5 | in 6 | rec { 7 | devices = import ../devices { 8 | inherit pkgs config; 9 | }; 10 | renderedMachines = lib.attrsets.mapAttrs 11 | (name: val: 12 | val // { 13 | renderedDevices = builtins.map (d: devices.render d name val) val.devices; 14 | uuid = domainUuid cfg.domainNamespace name; 15 | } 16 | ) 17 | cfg.machines; 18 | 19 | qemu-img = import ./qemu-img.nix { inherit pkgs; }; 20 | zfs = import ./zfs.nix { inherit pkgs; }; 21 | 22 | domainUuid = namespace: name: builtins.readFile (pkgs.runCommandLocal "vm-${name}-uuid" { } '' 23 | ${pkgs.libossp_uuid}/bin/uuid -v5 ${namespace} ${lib.escapeShellArg name} | tr -d '\n' > $out 24 | ''); 25 | 26 | # FIXME: Extremely ugly abuse of UUID to generate hex strings... 27 | domainMac = namespace: identifier: builtins.readFile (pkgs.runCommandLocal "vm-${identifier}-mac" { } '' 28 | ${pkgs.libossp_uuid}/bin/uuid -v5 ${namespace} ${lib.escapeShellArg identifier} | tr -d '-' | sed -r 's/(.{2})/\1:/g' | cut -c1-17 | sed -r 's/./2/2' | tr -d '\n' > $out 29 | ''); 30 | 31 | units = 32 | let 33 | mkUnitFunction = unit: value: { 34 | inherit unit value; 35 | }; 36 | units = [ 37 | "MB" 38 | "M" 39 | "MiB" 40 | "GB" 41 | "G" 42 | "GiB" 43 | "TB" 44 | "T" 45 | "TiB" 46 | ]; 47 | in 48 | builtins.listToAttrs (map 49 | (unit: { 50 | name = unit; 51 | value = mkUnitFunction unit; 52 | }) 53 | units); 54 | } 55 | -------------------------------------------------------------------------------- /modules/services/libvirt/tools/qemu-img.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | with builtins; 3 | let 4 | supportedUnits = { 5 | K = "K"; 6 | KiB = "K"; 7 | M = "M"; 8 | MiB = "M"; 9 | G = "G"; 10 | GiB = "G"; 11 | T = "T"; 12 | TiB = "T"; 13 | }; 14 | in 15 | { 16 | renderSize = size: 17 | if hasAttr size.unit supportedUnits then 18 | "${toString size.value}${supportedUnits.${size.unit}}" 19 | else throw "Unit ${size.unit} is not supported by qemu-img. You may use: ${toString (attrNames supportedUnits)}"; 20 | } 21 | -------------------------------------------------------------------------------- /modules/services/libvirt/tools/zfs.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | with builtins; 3 | let 4 | supportedUnits = { 5 | K = "KB"; 6 | KiB = "KB"; 7 | M = "MB"; 8 | MiB = "MB"; 9 | G = "GB"; 10 | GiB = "GB"; 11 | T = "TB"; 12 | TiB = "TB"; 13 | }; 14 | in 15 | { 16 | renderSize = size: 17 | if hasAttr size.unit supportedUnits then 18 | "${toString size.value}${supportedUnits.${size.unit}}" 19 | else throw "Unit ${size.unit} is not supported by ZFS. You may use: ${toString (attrNames supportedUnits)}"; 20 | } 21 | -------------------------------------------------------------------------------- /modules/services/nginx.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.nginx; 6 | 7 | mkListenConfig = addr: { 8 | inherit addr; 9 | port = 443; 10 | ssl = true; 11 | extraParameters = [ "default" "fastopen=3" "reuseport" ]; 12 | }; 13 | in 14 | { 15 | options = { 16 | indexyz.services.nginx = { 17 | enable = mkEnableOption "Enable custom nginx conf"; 18 | openFirewall = mkOption { 19 | default = true; 20 | type = types.bool; 21 | }; 22 | 23 | fakeHost = mkOption { 24 | default = true; 25 | type = types.bool; 26 | }; 27 | }; 28 | }; 29 | 30 | config = mkIf cfg.enable { 31 | networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 80 443 ]; 32 | 33 | services.nginx = { 34 | enable = true; 35 | statusPage = true; 36 | recommendedGzipSettings = true; 37 | recommendedOptimisation = true; 38 | recommendedProxySettings = true; 39 | recommendedTlsSettings = true; 40 | 41 | eventsConfig = '' 42 | worker_connections 20000; 43 | ''; 44 | }; 45 | 46 | services.nginx.virtualHosts = mkIf cfg.fakeHost { 47 | "_" = { 48 | extraConfig = '' 49 | ssl_protocols TLSv1.2 TLSv1.3; 50 | ssl_session_timeout 10m; 51 | ssl_session_cache builtin:1000 shared:SSL:10m; 52 | ssl_reject_handshake on; 53 | 54 | return 444; 55 | ''; 56 | 57 | default = true; 58 | 59 | listen = [ 60 | (mkListenConfig "0.0.0.0") 61 | (mkListenConfig "[::]") 62 | ]; 63 | }; 64 | }; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /modules/services/novnc.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | with lib; 3 | let 4 | vmCfg = config.zhaofeng.services.hypervisor; 5 | cfg = config.indexyz.services.novnc; 6 | 7 | portList = (builtins.filter (config: config.port != null) 8 | (lib.attrsets.mapAttrsToList 9 | (name: machine: ( 10 | let 11 | basicio = (builtins.filter 12 | ( 13 | (device: device.type == "basic-io") 14 | ) 15 | machine.devices); 16 | in 17 | { 18 | name = name; 19 | port = 20 | if ((builtins.length basicio) > 0) then 21 | (builtins.head basicio).config.port 22 | else null; 23 | } 24 | )) 25 | vmCfg.machines)); 26 | in 27 | { 28 | options = { 29 | indexyz.services.novnc = { 30 | enable = mkEnableOption "Enable novnc for libvirt"; 31 | 32 | basicDomain = mkOption { 33 | type = types.str; 34 | example = "gaia.indexyz.me"; 35 | description = '' 36 | Basic domain for novnc 37 | ''; 38 | }; 39 | 40 | users = mkOption { 41 | type = types.attrs; 42 | description = '' 43 | Users that can access the noVNC backend. 44 | ''; 45 | }; 46 | 47 | tls = mkOption { 48 | type = types.bool; 49 | default = false; 50 | description = '' 51 | Enable TLS ACME encryption for novnc site 52 | ''; 53 | }; 54 | }; 55 | }; 56 | 57 | config = mkIf cfg.enable { 58 | systemd.services = builtins.listToAttrs (map 59 | (item: 60 | let 61 | vncBase = "/run/hypervisor/vnc"; 62 | vncSocket = "${vncBase}/${item.name}"; 63 | in 64 | { 65 | name = "websockify-${item.name}"; 66 | value = { 67 | description = "Websockify for machine ${item.name}"; 68 | wantedBy = [ "multi-user.target" ]; 69 | partOf = [ "vm-${item.name}-lifetime.service" ]; 70 | 71 | serviceConfig = { 72 | ExecStart = "${pkgs.python3Packages.websockify}/bin/websockify --unix ${vncSocket} 127.0.0.1:${toString item.port}"; 73 | Restart = "always"; 74 | }; 75 | }; 76 | }) 77 | portList); 78 | 79 | services.nginx.virtualHosts = builtins.listToAttrs (map 80 | (item: { 81 | name = "${item.name}.${cfg.basicDomain}"; 82 | value = { 83 | forceSSL = cfg.tls; 84 | enableACME = cfg.tls; 85 | root = pkgs.novnc; 86 | basicAuth = cfg.users; 87 | 88 | locations = { 89 | "/websockify" = { 90 | proxyWebsockets = true; 91 | proxyPass = "http://127.0.0.1:${toString item.port}"; 92 | extraConfig = '' 93 | proxy_read_timeout 61s; 94 | proxy_buffering off; 95 | ''; 96 | }; 97 | 98 | "/" = { 99 | index = "vnc.html"; 100 | }; 101 | }; 102 | }; 103 | }) 104 | portList); 105 | # environment.etc."io-port-list.json".text = (builtins.toJSON portList); 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /modules/services/prometheus.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.prometheus; 6 | in 7 | { 8 | options = { 9 | indexyz.services.prometheus = { 10 | enable = mkOption { 11 | default = false; 12 | type = with types; bool; 13 | }; 14 | 15 | nodeName = mkOption { 16 | type = types.str; 17 | }; 18 | 19 | remoteWrite = mkOption { 20 | type = types.str; 21 | description = "Url for protomethus remote write"; 22 | }; 23 | }; 24 | }; 25 | 26 | config = mkIf cfg.enable { 27 | services.prometheus.exporters.node = { 28 | enable = true; 29 | enabledCollectors = [ 30 | "logind" 31 | "systemd" 32 | ]; 33 | 34 | disabledCollectors = [ 35 | "textfile" 36 | ]; 37 | }; 38 | 39 | services.prometheus = { 40 | enable = true; 41 | scrapeConfigs = [{ 42 | job_name = "node"; 43 | scrape_interval = "10s"; 44 | static_configs = [{ 45 | targets = [ 46 | "localhost:9100" 47 | ]; 48 | labels = { 49 | alias = cfg.nodeName; 50 | }; 51 | }]; 52 | }]; 53 | 54 | remoteWrite = [{ 55 | url = cfg.remoteWrite; 56 | }]; 57 | }; 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /modules/services/pufferpanel.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | recursiveMergeAttrs = listOfAttrsets: fold (attrset: acc: recursiveUpdate attrset acc) { } listOfAttrsets; 7 | cfg = config.indexyz.services.pufferpanel; 8 | 9 | defaultConfig = { 10 | logs = "${cfg.dataDir}/logs"; 11 | panel = { 12 | database = { 13 | dialect = "sqlite3"; 14 | url = "file:${cfg.dataDir}/database.db?cache=shared"; 15 | }; 16 | 17 | web = { files = "${pkgs.pufferpanel}/assets/www"; }; 18 | daemon = { 19 | data = { 20 | cache = "${cfg.dataDir}/cache"; 21 | servers = "${cfg.dataDir}/servers"; 22 | }; 23 | }; 24 | }; 25 | }; 26 | 27 | configFile = pkgs.writeText "config.json" (builtins.toJSON (recursiveMergeAttrs [ defaultConfig cfg.extraConfig ])); 28 | in 29 | { 30 | options = { 31 | indexyz.services.pufferpanel = { 32 | enable = mkEnableOption "Enable pufferpanel"; 33 | 34 | dataDir = mkOption { 35 | type = types.str; 36 | default = "/var/lib/pufferpanel"; 37 | description = "Data store location"; 38 | }; 39 | 40 | openFirewall = mkOption { 41 | type = types.bool; 42 | default = false; 43 | }; 44 | 45 | withPkgs = mkOption { 46 | type = with types; listOf package; 47 | default = [ ]; 48 | description = "Extra package exist in runner path"; 49 | }; 50 | 51 | extraConfig = mkOption { 52 | type = (pkgs.formats.json { }).type; 53 | description = '' 54 | JSON config data needed for PufferPanel 55 | see also: https://github.com/PufferPanel/PufferPanel/blob/master/config/config.go 56 | ''; 57 | default = { }; 58 | }; 59 | }; 60 | }; 61 | 62 | config = mkIf cfg.enable { 63 | environment.systemPackages = with pkgs; [ 64 | pufferpanel 65 | ]; 66 | 67 | users.users.pufferpanel = { 68 | description = "PufferPanel service user"; 69 | home = cfg.dataDir; 70 | createHome = true; 71 | isSystemUser = true; 72 | group = "pufferpanel"; 73 | }; 74 | 75 | users.groups.pufferpanel = { }; 76 | 77 | systemd.services.pufferpanel = { 78 | wantedBy = [ "multi-user.target" ]; 79 | after = [ "network.target" ]; 80 | path = cfg.withPkgs; 81 | 82 | description = "PufferPanel is an open source game server management panel"; 83 | 84 | script = '' 85 | rm -rf ${cfg.dataDir}/email 86 | cp --no-preserve=mode,ownership -r ${pkgs.pufferpanel}/assets/email ${cfg.dataDir}/email 87 | cp -f ${configFile} ${cfg.dataDir}/config.json 88 | exec ${pkgs.pufferpanel}/bin/pufferpanel run 89 | ''; 90 | 91 | serviceConfig = { 92 | PermissionsStartOnly = true; 93 | Type = "simple"; 94 | User = "pufferpanel"; 95 | WorkingDirectory = cfg.dataDir; 96 | ExecPreStartPre = "mkdir -p ${cfg.dataDir}"; 97 | ExecStop = "${pkgs.pufferpanel}/bin/pufferpanel shutdown --pid $MAINPID"; 98 | TimeoutStopSec = "5m"; 99 | SendSIGKILL = "no"; 100 | }; 101 | }; 102 | 103 | networking.firewall = mkIf cfg.openFirewall { 104 | allowedTCPPorts = [ 8080 5657 ]; 105 | }; 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /modules/services/reader.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.reader; 6 | in 7 | { 8 | options = { 9 | indexyz.services.reader = { 10 | enable = mkEnableOption "Enable reader server"; 11 | 12 | java = mkOption { 13 | type = types.package; 14 | default = pkgs.jdk; 15 | }; 16 | 17 | port = mkOption { 18 | type = types.int; 19 | default = 8080; 20 | }; 21 | 22 | secure = mkOption { 23 | type = types.bool; 24 | default = false; 25 | }; 26 | 27 | inviteCode = mkOption { 28 | type = types.str; 29 | default = "inviteCode"; 30 | }; 31 | 32 | secureKey = mkOption { 33 | type = types.str; 34 | default = "secureKey"; 35 | }; 36 | }; 37 | }; 38 | 39 | config = mkIf cfg.enable { 40 | systemd.services.reader = { 41 | after = [ "network.target" ]; 42 | wantedBy = [ "multi-user.target" ]; 43 | 44 | serviceConfig = { 45 | PermissionsStartOnly = true; 46 | LimitNPROC = 512; 47 | LimitNOFILE = 1048576; 48 | ProtectHome = true; 49 | ProtectHostname = true; 50 | ProtectKernelLogs = true; 51 | RemoveIPC = true; 52 | RestrictNamespaces = true; 53 | RestrictRealtime = true; 54 | RestrictSUIDSGID = true; 55 | StateDirectory = "reader"; 56 | RuntimeDirectory = "reader"; 57 | RuntimeDirectoryPreserve = "reader"; 58 | WorkingDirectory = "/var/lib/reader"; 59 | StateDirectoryMode = "0700"; 60 | NoNewPrivileges = true; 61 | DynamicUser = true; 62 | Restart = "on-failure"; 63 | }; 64 | 65 | script = '' 66 | rm -f reader.jar 67 | cp ${pkgs.reader} reader.jar 68 | 69 | exec ${cfg.java}/bin/java -jar reader.jar --reader.app.secure=${trivial.boolToString cfg.secure} \ 70 | --reader.app.secureKey=${cfg.secureKey} --reader.app.inviteCode=${cfg.inviteCode} \ 71 | --reader.server.port=${toString cfg.port} 72 | ''; 73 | }; 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /modules/services/secrets/default.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.indexyz.secrets; 7 | secretsOptions = types.submodule ({ 8 | options = { 9 | name = mkOption { 10 | type = types.str; 11 | description = "Secrets name"; 12 | }; 13 | 14 | kv = mkOption { 15 | type = types.str; 16 | description = "Which kv that secrets storage"; 17 | }; 18 | 19 | field = mkOption { 20 | type = types.str; 21 | description = "Secrets in kv field"; 22 | }; 23 | 24 | user = mkOption { 25 | type = types.str; 26 | description = "Key owner user"; 27 | default = "root"; 28 | }; 29 | 30 | group = mkOption { 31 | type = types.str; 32 | description = "Key owner group"; 33 | default = "root"; 34 | }; 35 | 36 | labels = mkOption { 37 | type = with types; listOf str; 38 | default = [ ]; 39 | description = "Key label"; 40 | }; 41 | }; 42 | }); 43 | 44 | hasLabel = label: builtins.elem label cfg.hostLabels; 45 | deploymentKeys = filter (data: (any hasLabel data.labels)) cfg.availableSecrets; 46 | 47 | deplotmenyKeyToRealKey = data: { 48 | name = data.name; 49 | value = { 50 | inherit (data) user group; 51 | keyCommand = [ "vault" "kv" "get" "-field=${data.field}" data.kv ]; 52 | }; 53 | }; 54 | 55 | placeHolder = { 56 | name = "KEY_MANAGEMENT_PLACEHOLDER"; 57 | value = { 58 | keyCommand = [ "echo" "1" ]; 59 | }; 60 | }; 61 | in 62 | { 63 | options = { 64 | indexyz.secrets = { 65 | enable = mkEnableOption "Enable secrets management"; 66 | 67 | hostLabels = mkOption { 68 | type = with types; listOf str; 69 | default = [ "default" ]; 70 | }; 71 | 72 | availableSecrets = mkOption { 73 | type = with types; listOf secretsOptions; 74 | default = [ ]; 75 | }; 76 | }; 77 | }; 78 | 79 | config = mkIf (cfg.enable && (attrsets.hasAttrByPath [ "deployment" ] config)) { 80 | deployment.keys = builtins.listToAttrs ( 81 | lib.lists.flatten (map deplotmenyKeyToRealKey deploymentKeys) ++ [ placeHolder ] 82 | ); 83 | 84 | systemd.services.key-activate = { 85 | description = "Waiting for deploy keys"; 86 | wantedBy = [ "multi-user.target" ]; 87 | after = [ "network.target" ]; 88 | 89 | unitConfig.DefaultDependencies = false; 90 | serviceConfig = { 91 | Type = "oneshot"; 92 | RemainAfterExit = true; 93 | }; 94 | 95 | script = '' 96 | while ! [ -e /run/keys/KEY_MANAGEMENT_PLACEHOLDER ]; do 97 | sleep 0.1 98 | done 99 | 100 | systemctl start keys.target 101 | ''; 102 | }; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /modules/services/ssh.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.ssh; 6 | keys = [ 7 | # Main Key 8 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBuNngR3JgkjC7I7g8/v4YQNH8Pu13bZcCl9q7Ho8hYJ" 9 | # Yubi Key 10 | "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKGRHXiL9HrPg//VqVjS5bZXEODxrYIwBJu4hIcdlL+ZKBDiCWjUnfvP16s7GpDMuWtEExBWKUmlPeUPDkSsBLA=" 11 | ]; 12 | in 13 | { 14 | options = { 15 | indexyz.services.ssh = { 16 | enable = mkEnableOption "Enable ssh config override"; 17 | 18 | keys = mkOption { 19 | default = keys; 20 | type = with types; listOf str; 21 | }; 22 | }; 23 | }; 24 | 25 | config = mkIf cfg.enable { 26 | services.openssh = { 27 | enable = true; 28 | 29 | settings = { 30 | X11Forwarding = true; 31 | PermitRootLogin = lib.mkDefault "prohibit-password"; 32 | PasswordAuthentication = false; 33 | }; 34 | }; 35 | 36 | networking.firewall.allowedTCPPorts = [ 22 ]; 37 | 38 | users.users = { 39 | root.openssh.authorizedKeys.keys = cfg.keys; 40 | indexyz.openssh.authorizedKeys.keys = cfg.keys; 41 | }; 42 | }; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /modules/services/teleport-agent.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.indexyz.services.teleport-agent; 7 | in 8 | { 9 | options = { 10 | indexyz.services.teleport-agent = { 11 | enable = mkOption { 12 | type = types.bool; 13 | default = false; 14 | }; 15 | 16 | token = mkOption { 17 | type = types.str; 18 | }; 19 | 20 | authServer = mkOption { 21 | type = types.str; 22 | }; 23 | 24 | extraOptions = mkOption { 25 | type = types.str; 26 | default = ""; 27 | }; 28 | 29 | insecure = mkOption { 30 | type = types.bool; 31 | default = false; 32 | }; 33 | 34 | caPin = mkOption { 35 | type = with types; nullOr str; 36 | default = null; 37 | }; 38 | }; 39 | }; 40 | 41 | config = mkIf cfg.enable { 42 | systemd.services.teleport-join = { 43 | after = [ "network.target" ]; 44 | wantedBy = [ "multi-user.target" ]; 45 | 46 | script = '' 47 | ${pkgs.teleport}/bin/teleport start --roles=node \ 48 | --token=${cfg.token} ${optionalString cfg.insecure "--insecure"} \ 49 | --auth-server=${cfg.authServer} ${optionalString (cfg.caPin != null) "--ca-pin=${cfg.caPin}"} ${cfg.extraOptions} 50 | ''; 51 | }; 52 | networking.firewall.allowedTCPPorts = [ 3022 ]; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /modules/services/transmission.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | 4 | with lib; 5 | let 6 | cfg = config.indexyz.services.transmission; 7 | in 8 | { 9 | options = { 10 | indexyz.services.transmission = { 11 | enable = mkEnableOption "Enable transmission server"; 12 | 13 | downloadDir = mkOption { 14 | default = "/var/lib/transmission"; 15 | type = types.str; 16 | }; 17 | 18 | openPort = mkOption { 19 | default = false; 20 | type = types.bool; 21 | }; 22 | 23 | portNumber = mkOption { 24 | default = 9091; 25 | type = types.int; 26 | }; 27 | }; 28 | }; 29 | 30 | config = mkIf cfg.enable (lib.mkMerge [ 31 | ({ 32 | services.transmission = { 33 | enable = true; 34 | settings = { 35 | download-dir = cfg.downloadDir; 36 | rpc-enabled = true; 37 | rpc-whitelist = "127.0.0.1,192.168.*.*"; 38 | rpc-authentication-required = false; 39 | rpc-bind-address = "0.0.0.0"; 40 | rpc-host-whitelist-enabled = false; 41 | peer-port = 51413; 42 | incomplete-dir-enabled = false; 43 | preallocation = 0; 44 | rpc-port = cfg.portNumber; 45 | }; 46 | }; 47 | 48 | networking.firewall.allowedTCPPorts = [ 51413 ]; 49 | networking.firewall.allowedUDPPorts = [ 51413 ]; 50 | 51 | # Set webui home 52 | systemd.services.transmission.environment.TRANSMISSION_WEB_HOME = "${pkgs.transmission-web-control}/src"; 53 | }) 54 | 55 | (lib.mkIf (cfg.openPort) { 56 | networking.firewall.allowedTCPPorts = [ 9091 ]; 57 | }) 58 | ]); 59 | } 60 | -------------------------------------------------------------------------------- /modules/services/vlmcsd.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, options, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.vlmcsd; 6 | in 7 | { 8 | options = { 9 | indexyz.services.vlmcsd = { 10 | enable = mkEnableOption "Start vlmcsd kms server"; 11 | 12 | openFirewall = mkOption { 13 | default = true; 14 | type = types.bool; 15 | }; 16 | }; 17 | }; 18 | 19 | config = mkIf cfg.enable { 20 | systemd.services.vlmcsd = { 21 | wantedBy = [ "multi-user.target" ]; 22 | after = [ "network.target" ]; 23 | description = "Start vlmcsd server."; 24 | serviceConfig = { 25 | PermissionsStartOnly = true; 26 | Type = "simple"; 27 | ExecStart = ''${pkgs.vlmcsd}/bin/vlmcsd -D -d -t 3 -e -v''; 28 | }; 29 | }; 30 | 31 | networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 1688 ]; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /modules/services/vouch.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.vouch; 6 | 7 | resultJSON = pkgs.writeText "config.yml" (builtins.toJSON cfg.config); 8 | in 9 | { 10 | options = { 11 | indexyz.services.vouch = { 12 | enable = mkOption { 13 | default = false; 14 | type = with types; bool; 15 | }; 16 | 17 | port = mkOption { 18 | default = 9090; 19 | type = types.int; 20 | }; 21 | 22 | config = mkOption { 23 | default = { }; 24 | type = types.attrs; 25 | }; 26 | }; 27 | }; 28 | 29 | config = mkIf cfg.enable { 30 | systemd.services.vouch-proxy = { 31 | description = "an SSO and OAuth / OIDC login solution for Nginx using the auth_request module"; 32 | wantedBy = [ "multi-user.target" ]; 33 | after = [ "network.target" ]; 34 | 35 | script = '' 36 | ${pkgs.vouch-proxy}/bin/vouch-proxy -config ${resultJSON} -port ${toString cfg.port} 37 | ''; 38 | }; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /modules/services/vpncloud.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.vpncloud; 6 | 7 | peerStr = peer: "-c ${peer}"; 8 | claimStr = claim: "--claim ${claim}"; 9 | 10 | peers = concatStringsSep " " (map peerStr cfg.peers); 11 | claims = concatStringsSep " " (map claimStr cfg.claims); 12 | in 13 | { 14 | options = { 15 | indexyz.services.vpncloud = { 16 | enable = mkEnableOption "Enable vpncloud service"; 17 | 18 | port = mkOption { 19 | default = 20001; 20 | type = types.int; 21 | description = "VPNCloud listen port"; 22 | }; 23 | 24 | ip = mkOption { 25 | type = types.str; 26 | description = "VPNCloud interface ip"; 27 | example = "192.168.100.1/24"; 28 | }; 29 | 30 | passwordFile = mkOption { 31 | type = types.str; 32 | description = "VPNCloud password file"; 33 | example = "/run/keys/VPN_CLOUD_PASS"; 34 | }; 35 | 36 | mode = mkOption { 37 | default = "normal"; 38 | type = types.enum [ "normal" "router" "switch" "hub" ]; 39 | description = "The mode of the VPN"; 40 | }; 41 | 42 | device = mkOption { 43 | default = "vpncloud0"; 44 | type = types.str; 45 | description = "Name of the virtual device"; 46 | }; 47 | 48 | deviceType = mkOption { 49 | default = "tun"; 50 | type = types.enum [ "tun" "tap" ]; 51 | description = "Set the type of network"; 52 | }; 53 | 54 | peers = mkOption { 55 | default = [ ]; 56 | type = with types; listOf str; 57 | description = "Address of a peer to connect to"; 58 | }; 59 | 60 | claims = mkOption { 61 | default = [ ]; 62 | type = with types; listOf str; 63 | description = "The local subnets to claim"; 64 | }; 65 | }; 66 | }; 67 | 68 | config = mkIf cfg.enable { 69 | networking.firewall.allowedUDPPorts = [ cfg.port ]; 70 | # Allow forwarding 71 | boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; 72 | 73 | systemd.services.vpncloud = { 74 | wantedBy = [ "multi-user.target" ]; 75 | after = [ "network.target" ]; 76 | serviceConfig = { 77 | Restart = "always"; 78 | RestartSec = 30; 79 | }; 80 | 81 | script = '' 82 | ${pkgs.vpncloud}/bin/vpncloud \ 83 | -p $(cat ${cfg.passwordFile}) --ip ${cfg.ip} \ 84 | -l ${toString cfg.port} -m ${cfg.mode} -t ${cfg.deviceType} -d ${cfg.device} ${peers} ${claims} 85 | ''; 86 | }; 87 | }; 88 | } 89 | -------------------------------------------------------------------------------- /modules/services/wiretrustee-client.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, lib, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.indexyz.services.wiretrustee-client; 6 | in 7 | { 8 | options = { 9 | indexyz.services.wiretrustee-client = { 10 | enable = mkEnableOption "Enable wiretrustee client service"; 11 | }; 12 | }; 13 | 14 | config = mkIf cfg.enable { 15 | systemd.services.wiretrustee-client = { 16 | wantedBy = [ "multi-user.target" ]; 17 | after = [ "network.target" ]; 18 | serviceConfig = { 19 | Restart = "always"; 20 | RestartSec = 30; 21 | }; 22 | 23 | script = '' 24 | ${pkgs.wiretrustee}/bin/wiretrustee up 25 | ''; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/system/uboot/bootloader.sh: -------------------------------------------------------------------------------- 1 | #! @bash@/bin/sh -e 2 | 3 | shopt -s nullglob 4 | 5 | export PATH=/empty 6 | for i in @path@; do PATH=$PATH:$i/bin; done 7 | 8 | BASE_BOOT="/boot"; 9 | 10 | KERNEL_ADDR="0x14000000" 11 | INITRD_ADDR="0x15000000" 12 | DTB_ADDR="0x11800000" 13 | 14 | KERNEL_PARAMS=$(cat $1/kernel-params) 15 | 16 | cat > $BASE_BOOT"/boot.ini.input" <> $BASE_BOOT"/boot.ini.input" < $out 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /packages/clash-dsl/combinators.nix: -------------------------------------------------------------------------------- 1 | { formats, lib }: 2 | 3 | with lib; 4 | 5 | let 6 | clashTypes = import ./types { inherit lib formats; }; 7 | 8 | evalProfile = data: ( 9 | (evalModules { 10 | modules = [ 11 | { 12 | options = { 13 | profile = mkOption { 14 | type = clashTypes.profile; 15 | description = "Clash Profile"; 16 | }; 17 | }; 18 | } 19 | { 20 | profile = data; 21 | } 22 | ]; 23 | }).config.profile 24 | ); 25 | 26 | evalRule = ruleType: data: builtins.toString ( 27 | (evalModules { 28 | modules = [ 29 | { 30 | options = { 31 | rule = mkOption { 32 | type = ruleType; 33 | description = "Rule data"; 34 | }; 35 | }; 36 | } 37 | { 38 | rule = data; 39 | } 40 | ]; 41 | }).config.rule 42 | ); 43 | 44 | evalProxy = proxyType: data: ( 45 | (evalModules { 46 | modules = [ 47 | { 48 | options = { 49 | proxy = mkOption { 50 | type = proxyType; 51 | description = "Proxy data"; 52 | }; 53 | }; 54 | } 55 | { 56 | proxy = data; 57 | } 58 | ]; 59 | }).config.proxy 60 | ); 61 | in 62 | { 63 | inherit evalProfile; 64 | 65 | buildText = cfg: builtins.toString (evalProfile cfg); 66 | 67 | # Domain Based 68 | domain = domain: policy: evalRule clashTypes.rules.DOMAIN ({ inherit domain policy; }); 69 | domainSuffix = domainSuffix: policy: evalRule clashTypes.rules.DOMAIN-SUFFIX ({ inherit domainSuffix policy; }); 70 | domainKeyword = domainKeyword: policy: evalRule clashTypes.rules.DOMAIN-KEYWORD ({ inherit domainKeyword policy; }); 71 | 72 | # IP Based 73 | geoip = country: policy: evalRule clashTypes.rules.GEOIP ({ inherit country policy; }); 74 | ipCidr = cidr: policy: evalRule clashTypes.rules.IP-CIDR ({ inherit cidr policy; }); 75 | ipCidr6 = cidr: policy: evalRule clashTypes.rules.IP-CIDR6 ({ inherit cidr policy; }); 76 | srcCidr = cidr: policy: evalRule clashTypes.rules.SRC-IP-CIDR ({ inherit cidr policy; }); 77 | 78 | srcPort = port: policy: evalRule clashTypes.rules.SRC-PORT ({ inherit port policy; }); 79 | dstPort = port: policy: evalRule clashTypes.rules.DST-PORT ({ inherit port policy; }); 80 | 81 | processName = process: policy: evalRule clashTypes.rules.PROCESS-NAME ({ inherit process policy; }); 82 | 83 | match = policy: evalRule clashTypes.rules.MATCH ({ inherit policy; }); 84 | 85 | direct = "DIRECT"; 86 | reject = "REJECT"; 87 | 88 | wapperRules = rules: policy: (map (it: it policy) rules); 89 | } 90 | -------------------------------------------------------------------------------- /packages/clash-dsl/pkg.nix: -------------------------------------------------------------------------------- 1 | { formats, lib }: 2 | 3 | rec { 4 | types = import ./types { inherit lib formats; }; 5 | combinators = import ./combinators.nix { inherit lib formats; }; 6 | 7 | wapperRulesFile = rulesFile: (combinators.wapperRules (import rulesFile { inherit combinators; })); 8 | } 9 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/default.nix: -------------------------------------------------------------------------------- 1 | { formats, lib }: 2 | 3 | { 4 | inherit (import ./profile.nix { inherit lib formats; }) profile; 5 | inherit (import ./proxy.nix { inherit lib; }) proxyProvider buildProxyProvider proxyGroup buildProxyGroup; 6 | 7 | proxy = import ./proxy { inherit lib; }; 8 | rules = import ./rules { inherit lib; }; 9 | } 10 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/profile.nix: -------------------------------------------------------------------------------- 1 | { formats, lib }: 2 | 3 | with lib; 4 | 5 | let 6 | inherit (builtins) toJSON; 7 | proxy = import ./proxy.nix { inherit lib; }; 8 | recursiveMergeAttrs = listOfAttrsets: fold (attrset: acc: recursiveUpdate attrset acc) { } listOfAttrsets; 9 | 10 | profile = types.submodule { 11 | options = { 12 | port = mkOption { 13 | type = types.int; 14 | description = "Connect in port"; 15 | }; 16 | 17 | rules = mkOption { 18 | type = with types; listOf str; 19 | description = "Clash rules"; 20 | }; 21 | 22 | logLevel = mkOption { 23 | type = types.enum [ "silent" "info" "error" "warning" "debug" ]; 24 | default = "info"; 25 | }; 26 | 27 | mode = mkOption { 28 | type = types.enum [ "rule" "global" "direct" ]; 29 | default = "rule"; 30 | }; 31 | 32 | ipv6 = mkOption { 33 | type = types.bool; 34 | default = true; 35 | }; 36 | 37 | allowLan = mkOption { 38 | type = types.bool; 39 | default = true; 40 | }; 41 | 42 | bindAddress = mkOption { 43 | type = types.str; 44 | default = "*"; 45 | }; 46 | 47 | proxies = mkOption { 48 | type = with types; listOf attrs; 49 | default = [ ]; 50 | }; 51 | 52 | proxyProviders = mkOption { 53 | type = with types; listOf proxy.proxyProvider; 54 | default = [ ]; 55 | }; 56 | 57 | proxyGroups = mkOption { 58 | type = with types; listOf proxy.proxyGroup; 59 | default = [ ]; 60 | }; 61 | 62 | extraConfig = mkOption { 63 | type = (formats.json { }).type; 64 | default = { }; 65 | }; 66 | 67 | __toString = mkOption { 68 | readOnly = true; 69 | visible = false; 70 | }; 71 | }; 72 | 73 | config = { 74 | __toString = data: toJSON ({ 75 | mixin-port = data.port; 76 | log-level = data.logLevel; 77 | mode = data.mode; 78 | ipv6 = data.ipv6; 79 | allow-lan = data.allowLan; 80 | bind-address = data.bindAddress; 81 | proxy-providers = recursiveMergeAttrs (map proxy.buildProxyProvider data.proxyProviders); 82 | proxy-groups = map proxy.buildProxyGroup data.proxyGroups; 83 | 84 | proxies = data.proxies; 85 | 86 | rules = data.rules; 87 | } // data.extraConfig); 88 | }; 89 | }; 90 | in 91 | { 92 | inherit profile; 93 | } 94 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/proxy.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | let 5 | proxyProvider = types.submodule ({ 6 | options = { 7 | name = mkOption { 8 | type = types.str; 9 | }; 10 | 11 | url = mkOption { 12 | type = types.str; 13 | }; 14 | 15 | path = mkOption { 16 | type = types.str; 17 | }; 18 | 19 | type = mkOption { 20 | type = types.enum [ "http" ]; 21 | default = "http"; 22 | }; 23 | 24 | interval = mkOption { 25 | type = types.int; 26 | default = 86400; 27 | }; 28 | }; 29 | }); 30 | 31 | buildProxyProvider = provider: { 32 | "${provider.name}" = { 33 | inherit (provider) url type interval path; 34 | }; 35 | }; 36 | 37 | proxyGroup = types.submodule ({ 38 | options = { 39 | name = mkOption { 40 | type = types.str; 41 | }; 42 | 43 | type = mkOption { 44 | type = types.enum [ "select" "relay" "url-test" "fallback" "load-balance" ]; 45 | default = "select"; 46 | }; 47 | 48 | proxies = mkOption { 49 | type = with types; listOf str; 50 | default = [ ]; 51 | }; 52 | 53 | use = mkOption { 54 | type = with types; listOf str; 55 | default = [ ]; 56 | }; 57 | 58 | url = mkOption { 59 | type = with types; nullOr str; 60 | default = null; 61 | }; 62 | 63 | interval = mkOption { 64 | type = with types; nullOr int; 65 | default = null; 66 | }; 67 | 68 | interface-name = mkOption { 69 | type = types.str; 70 | default = ""; 71 | }; 72 | 73 | routing-mark = mkOption { 74 | type = types.int; 75 | default = 0; 76 | }; 77 | }; 78 | }); 79 | 80 | buildProxyGroup = group: { 81 | inherit (group) name type proxies use url interval interface-name routing-mark; 82 | }; 83 | in 84 | { 85 | inherit proxyProvider buildProxyProvider proxyGroup buildProxyGroup; 86 | } 87 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/proxy/default.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | let 5 | types = [ 6 | "http" 7 | ]; 8 | in 9 | genAttrs types (t: import (./. + "/${t}.nix") { inherit lib; }) 10 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/proxy/http.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | name = mkOption { 8 | type = types.str; 9 | example = "http"; 10 | description = " Name of proxy"; 11 | }; 12 | 13 | server = mkOption { 14 | type = types.str; 15 | example = "server"; 16 | description = "Http proxy server"; 17 | }; 18 | 19 | port = mkOption { 20 | type = types.int; 21 | example = "7890"; 22 | description = "Http proxy port"; 23 | }; 24 | 25 | username = mkOption { 26 | type = with types; nullOr str; 27 | default = null; 28 | }; 29 | 30 | password = mkOption { 31 | type = with types; nullOr str; 32 | default = null; 33 | }; 34 | 35 | tls = mkOption { 36 | type = with types; nullOr bool; 37 | default = null; 38 | }; 39 | 40 | skip-cert-verify = mkOption { 41 | type = with types; nullOr bool; 42 | default = null; 43 | }; 44 | 45 | sni = mkOption { 46 | type = with types; nullOr str; 47 | default = null; 48 | }; 49 | }; 50 | }) 51 | 52 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/DOMAIN-KEYWORD.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | domainKeyword = mkOption { 8 | type = types.str; 9 | example = "google"; 10 | description = " routes any FQDN that contains domain given"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "DOMAIN-KEYWORD,${data.domainKeyword},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/DOMAIN-SUFFIX.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | domainSuffix = mkOption { 8 | type = types.str; 9 | example = "youtube.com"; 10 | description = "routes any FQDN that ends with domain given"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "DOMAIN-SUFFIX,${data.domainSuffix},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/DOMAIN.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | domain = mkOption { 8 | type = types.str; 9 | example = "www.google.com"; 10 | description = "Route which domain to policy"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "DOMAIN,${data.domain},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/DST-PORT.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | port = mkOption { 8 | type = types.int; 9 | example = "80"; 10 | description = "routes any packets to the port 80 to policy"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "DST-PORT,${toString data.port},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/GEOIP.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | country = mkOption { 8 | type = types.str; 9 | example = "CN"; 10 | description = "routes any requests to a China IP address to policy"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "GEOIP,${data.country},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/IP-CIDR.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | cidr = mkOption { 8 | type = types.str; 9 | example = "127.0.0.0/8"; 10 | description = "routes any packets to 127.0.0.0/8 to the policy."; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "IP-CIDR,${data.cidr},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/IP-CIDR6.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | cidr = mkOption { 8 | type = types.str; 9 | example = "2620:0:2d0:200::7/32"; 10 | description = "routes any packets to 2620:0:2d0:200::7/32 to the policy."; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "IP-CIDR6,${data.cidr},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/MATCH.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | policy = mkOption { 8 | type = types.str; 9 | example = "DIRECT"; 10 | description = "The rest of the packets to policy"; 11 | }; 12 | 13 | __toString = mkOption { 14 | readOnly = true; 15 | visible = false; 16 | }; 17 | }; 18 | 19 | config = { 20 | __toString = data: "MATCH,${data.policy}"; 21 | }; 22 | }) 23 | 24 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/PROCESS-NAME.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | process = mkOption { 8 | type = types.str; 9 | example = "nc"; 10 | description = "routes the process nc to policy."; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "PROCESS-NAME,${data.process},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/SRC-IP-CIDR.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | cidr = mkOption { 8 | type = types.str; 9 | example = "192.168.1.201/32"; 10 | description = "routes any packets from 192.168.1.201/32 to the policy."; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "SRC-IP-CIDR,${data.cidr},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/SRC-PORT.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | 5 | types.submodule ({ 6 | options = { 7 | port = mkOption { 8 | type = types.int; 9 | example = "80"; 10 | description = "routes any packets from the port 80 to policy"; 11 | }; 12 | 13 | policy = mkOption { 14 | type = types.str; 15 | example = "DIRECT"; 16 | description = "Domain policy"; 17 | }; 18 | 19 | __toString = mkOption { 20 | readOnly = true; 21 | visible = false; 22 | }; 23 | }; 24 | 25 | config = { 26 | __toString = data: "SRC-PORT,${toString data.port},${data.policy}"; 27 | }; 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/clash-dsl/types/rules/default.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | with lib; 4 | let 5 | types = [ 6 | # Domain based 7 | "DOMAIN" 8 | "DOMAIN-SUFFIX" 9 | "DOMAIN-KEYWORD" 10 | 11 | # IP Based 12 | "GEOIP" 13 | "IP-CIDR" 14 | "IP-CIDR6" 15 | "SRC-IP-CIDR" 16 | 17 | "SRC-PORT" 18 | "DST-PORT" 19 | 20 | "PROCESS-NAME" 21 | 22 | "MATCH" 23 | ]; 24 | in 25 | genAttrs types (t: import (./. + "/${t}.nix") { inherit lib; }) 26 | -------------------------------------------------------------------------------- /packages/cloudreve/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, glibc, fetchurl }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "cloudreve"; 5 | version = "3.8.3"; 6 | src = fetchurl { 7 | url = "https://github.com/cloudreve/Cloudreve/releases/download/${version}/cloudreve_${version}_linux_amd64.tar.gz"; 8 | sha256 = "sha256-WTW2PonXW/8tdHVgRlGOjxQzDadEnoQPQprz9CAQGWQ="; 9 | }; 10 | 11 | phases = "installPhase"; 12 | 13 | installPhase = '' 14 | tar zxvf $src 15 | mkdir -p "$out"/bin/ 16 | install -m 755 cloudreve -t "$out"/bin/ 17 | ''; 18 | } 19 | -------------------------------------------------------------------------------- /packages/cockpit-machines/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenv, fetchzip, gettext }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "cockpit-machines"; 5 | version = "333"; 6 | 7 | src = fetchzip { 8 | url = "https://github.com/cockpit-project/cockpit-machines/releases/download/${version}/cockpit-machines-${version}.tar.xz"; 9 | sha256 = "sha256-VfT4ZJ905BxF8uIsxe27ahDD8+mPk6w/z1/FKjb9wbg="; 10 | }; 11 | 12 | nativeBuildInputs = [ 13 | gettext 14 | ]; 15 | 16 | makeFlags = [ "DESTDIR=$(out)" "PREFIX=" ]; 17 | 18 | postPatch = '' 19 | substituteInPlace Makefile \ 20 | --replace /usr/share $out/share 21 | touch pkg/lib/cockpit.js 22 | touch pkg/lib/cockpit-po-plugin.js 23 | touch dist/manifest.json 24 | ''; 25 | 26 | postFixup = '' 27 | gunzip $out/share/cockpit/machines/index.js.gz 28 | sed -i "s#/usr/bin/python3#/usr/bin/env python3#ig" $out/share/cockpit/machines/index.js 29 | sed -i "s#/usr/bin/pwscore#/usr/bin/env pwscore#ig" $out/share/cockpit/machines/index.js 30 | gzip -9 $out/share/cockpit/machines/index.js 31 | ''; 32 | 33 | dontBuild = true; 34 | 35 | meta = with lib; { 36 | description = "Cockpit UI for virtual machines"; 37 | license = licenses.lgpl21; 38 | homepage = "https://github.com/cockpit-project/cockpit-machines"; 39 | platforms = platforms.linux; 40 | maintainers = with maintainers; [ ]; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /packages/commit-notifier/pkg.nix: -------------------------------------------------------------------------------- 1 | { rustPlatform, pkg-config, openssl, sqlite, zlib, libgit2, fetchFromGitHub }: 2 | 3 | rustPlatform.buildRustPackage rec { 4 | pname = "commit-notifier"; 5 | version = "0-unstable-2025-05-31"; 6 | src = fetchFromGitHub ({ 7 | owner = "linyinfeng"; 8 | repo = "commit-notifier"; 9 | rev = "be8cb51bf4817f3b496760d2869e9ce79bdd344e"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-s4KYGVxxvpERmQjjtL+zWg5yAjr1VIhdwsCXkd1WtdI="; 12 | }); 13 | 14 | cargoHash = "sha256-888t71DEEwjXMo2gt+Yov16x+H4JWlmrLjdXNlpzfAI="; 15 | 16 | RUSTC_BOOTSTRAP = 1; 17 | 18 | buildInputs = [ 19 | openssl 20 | sqlite 21 | libgit2 22 | zlib 23 | ]; 24 | 25 | # TODO libssh2-sys failed to pass test 26 | doCheck = false; 27 | nativeBuildInputs = [ pkg-config ]; 28 | } 29 | -------------------------------------------------------------------------------- /packages/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, normalPkgs, os, npmlock2nix, flakeInputs, system }: 2 | 3 | with normalPkgs.lib; 4 | let 5 | build-electron-appimage = normalPkgs.callPackage ./build-electron-appimage { }; 6 | osPkgPath = ./. + "/os-specific/${os}"; 7 | systemPackages = if builtins.pathExists osPkgPath then normalPkgs.callPackage osPkgPath { inherit pkgs normalPkgs; } else { }; 8 | 9 | dirOnly = it: if it.value == "directory" then true else false; 10 | hasPkgFile = dir: it: 11 | let 12 | itDir = builtins.readDir ("${dir}/${it.name}"); 13 | in 14 | attrsets.hasAttrByPath [ "pkg.nix" ] itDir && itDir."pkg.nix" == "regular"; 15 | 16 | packages = scanPackages "${flakeInputs.self.outPath}/packages"; 17 | 18 | buildPackage = dir: name: 19 | (pkgs.callPackage "${dir}/${name}/pkg.nix" { }); 20 | 21 | scanPackages = dir: 22 | builtins.listToAttrs ( 23 | map 24 | (it: { 25 | name = it.name; 26 | value = buildPackage dir it.name; 27 | }) 28 | (filter (hasPkgFile dir) 29 | (filter dirOnly 30 | (attrsets.mapAttrsToList (name: value: { inherit name value; }) (builtins.readDir dir))))); 31 | 32 | isDerivation = package: normalPkgs.lib.attrsets.hasAttrByPath [ "drvPath" ] package; 33 | 34 | resultPackages = rec { 35 | inherit build-electron-appimage; 36 | 37 | # tools need to read global config 38 | libvirt-tools = import ../modules/services/libvirt/tools; 39 | libvirt-iso-library = pkgs.callPackage ../modules/services/libvirt/library.nix { }; 40 | build-vm-qcow = pkgs.callPackage ./build-vm-qcow { }; 41 | 42 | } // systemPackages // packages; 43 | 44 | buildPacakges = (builtins.filter (it: isDerivation it.value) (pkgs.lib.attrsets.mapAttrsToList 45 | (name: value: { 46 | inherit name value; 47 | }) 48 | resultPackages)); 49 | 50 | buildPacakgesList = builtins.filter 51 | (item: 52 | let 53 | meta = pkgs.lib.attrsets.attrByPath [ "meta" "platforms" ] [ system ] item.value; 54 | in 55 | (pkgs.lib.lists.any (item: item == system) meta)) 56 | buildPacakges; 57 | 58 | packageList = pkgs.writeText "packages.json" (builtins.toJSON (map (it: it.name) buildPacakgesList)); 59 | in 60 | resultPackages // { inherit packageList; } 61 | -------------------------------------------------------------------------------- /packages/derper/pkg.nix: -------------------------------------------------------------------------------- 1 | { tailscale }: 2 | 3 | tailscale.overrideAttrs (oldAttrs: rec { 4 | pname = "derper"; 5 | subPackages = [ "cmd/derper" ]; 6 | 7 | patchPhase = '' 8 | # Disable ServerHello check 9 | substituteInPlace cmd/derper/cert.go --replace 'hi.ServerName != m.hostname' 'false' 10 | substituteInPlace cmd/derper/cert.go --replace 'err := x509Cert.VerifyHostname(hostname); err != nil' 'false' 11 | substituteInPlace cmd/derper/cert.go --replace 'x509Cert, err := x509.ParseCertificate(cert.Certificate[0])' "" 12 | substituteInPlace cmd/derper/cert.go --replace '"crypto/x509"' "" 13 | ''; 14 | 15 | postInstall = ":"; 16 | }) 17 | -------------------------------------------------------------------------------- /packages/dnslookup/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib, buildGoModule, fetchFromGitHub }: 2 | 3 | buildGoModule rec { 4 | pname = "dnslookup"; 5 | version = "1.10.0"; 6 | src = fetchFromGitHub ({ 7 | owner = "ameshkov"; 8 | repo = "dnslookup"; 9 | rev = "v${version}"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-T3KvaNAPS4WEALttMaZx+zOc3Iu9aSujH0WNfHa2baM="; 12 | }); 13 | 14 | vendorHash = "sha256-pLgXsasWD4Wb1dW0+1fl5M+CM2hr7zohXiHLsDj73h0="; 15 | 16 | modSha256 = lib.fakeSha256; 17 | subPackages = [ "." ]; 18 | 19 | doCheck = false; 20 | } 21 | -------------------------------------------------------------------------------- /packages/dnsmasq-china-list/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenvNoCC 2 | , fetchFromGitHub 3 | , defaultResolver ? "https://1.1.1.1/dns-query" 4 | , chinaDns ? "114.114.114.114" 5 | , ... 6 | }: 7 | 8 | stdenvNoCC.mkDerivation { 9 | pname = "dnsmasq-china-list"; 10 | version = "0-unstable-2025-05-25"; 11 | src = fetchFromGitHub ({ 12 | owner = "felixonmars"; 13 | repo = "dnsmasq-china-list"; 14 | rev = "54fdadf38bac16650d3be9d6bc4b075d814e2091"; 15 | fetchSubmodules = true; 16 | sha256 = "sha256-f3/L4m/rulctFtOvZ6vi9Wm8LBQquY/4KdQNh0k+yPc="; 17 | }); 18 | 19 | phases = "installPhase"; 20 | installPhase = '' 21 | mkdir $out 22 | echo "${defaultResolver}" > $out/adguard.upstream 23 | cat $src/accelerated-domains.china.conf | sed -E "s#server=(\/.+\/)114\.114\.114\.114#[\1]${chinaDns}#g" >> $out/adguard.upstream 24 | 25 | cp $src/accelerated-domains.china.conf $out/ 26 | ''; 27 | } 28 | -------------------------------------------------------------------------------- /packages/fcitx5-material-color/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, lib, fetchFromGitHub }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "fcitx5-material-color"; 5 | version = "0.2.1"; 6 | src = fetchFromGitHub ({ 7 | owner = "hosxy"; 8 | repo = "Fcitx5-Material-Color"; 9 | rev = "0.2.1"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-i9JHIJ+cHLTBZUNzj9Ujl3LIdkCllTWpO1Ta4OT1LTc="; 12 | }); 13 | 14 | dontBuild = true; 15 | dontConfigure = true; 16 | 17 | installPhase = '' 18 | install -Dm644 arrow.png radio.png -t $out/share/${pname}/ 19 | for _variant in black blue brown deepPurple indigo orange pink red sakuraPink teal; do 20 | _variant_name=Material-Color-''${_variant^} 21 | mkdir -p $out/share/fcitx5/themes/$_variant_name/ 22 | ln -s $out/share/${pname}/arrow.png $out/share/fcitx5/themes/$_variant_name/ 23 | ln -s $out/share/${pname}/radio.png $out/share/fcitx5/themes/$_variant_name/ 24 | install -Dm644 theme-$_variant.conf $out/share/fcitx5/themes/$_variant_name/theme.conf 25 | sed -i "s/^Name=.*/Name=$_variant_name/" $out/share/fcitx5/themes/$_variant_name/theme.conf 26 | done 27 | ''; 28 | 29 | meta = with lib; { 30 | homepage = "https://github.com/hosxy/Fcitx5-Material-Color"; 31 | description = "Material color theme for fcitx5"; 32 | license = licenses.asl20; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /packages/hev-socks5-tproxy/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchFromGitHub, stdenv }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "hev-socks5-tproxy"; 5 | version = "2.8.0"; 6 | src = fetchFromGitHub ({ 7 | owner = "heiher"; 8 | repo = "hev-socks5-tproxy"; 9 | rev = "2.6.0"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-vunuMpQInB390rUJ4C1pLvLTtEJozU9Mtk9cUr0gJ3k="; 12 | }); 13 | 14 | makeFlags = [ 15 | "INSTDIR=${placeholder "out"}" 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/index-firefox/pkg.nix: -------------------------------------------------------------------------------- 1 | { wrapFirefox, firefox-unwrapped }: 2 | 3 | wrapFirefox firefox-unwrapped { 4 | extraPolicies = { 5 | PasswordManagerEnabled = false; 6 | DisableFirefoxAccounts = true; 7 | DisablePocket = true; 8 | EnableTrackingProtection = { 9 | Value = true; 10 | Locked = true; 11 | Cryptomining = true; 12 | Fingerprinting = true; 13 | }; 14 | Preferences = { 15 | "browser.newtabpage.activity-stream.feeds.topsites" = false; 16 | "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; 17 | "network.trr.mode" = 3; 18 | "network.dns.echconfig.enabled" = true; 19 | "network.dns.http3_echconfig.enabled" = true; 20 | "network.dns.use_https_rr_as_altsvc" = true; 21 | 22 | # Mode to use when receiving pan gesture input. 23 | # Fix wired left / right swipe on touchpad 24 | # https://hg.mozilla.org/mozilla-central/file/tip/modules/libpref/init/StaticPrefList.yaml#l562 25 | "apz.gtk.pangesture.delta_mode" = 2; 26 | }; 27 | 28 | ExtensionSettings = { 29 | # Adguard 30 | "adguardadblocker@adguard.com" = { 31 | installation_mode = "force_installed"; 32 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/adguard-adblocker/latest.xpi"; 33 | }; 34 | 35 | # Switchy Omega 36 | "switchyomega@feliscatus.addons.mozilla.org" = { 37 | installation_mode = "force_installed"; 38 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/switchyomega/latest.xpi"; 39 | }; 40 | 41 | # SponsorBlock 42 | "sponsorBlocker@ajay.app" = { 43 | installation_mode = "force_installed"; 44 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/sponsorblock/latest.xpi"; 45 | }; 46 | 47 | # Privacy Badger 48 | "jid1-MnnxcxisBPnSXQ@jetpack" = { 49 | installation_mode = "force_installed"; 50 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/privacy-badger17/latest.xpi"; 51 | }; 52 | 53 | # User-Agent Switcher and Manager 54 | "{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}" = { 55 | installation_mode = "force_installed"; 56 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/user-agent-string-switcher/latest.xpi"; 57 | }; 58 | 59 | # HTTPS Everywhere 60 | "https-everywhere@eff.org" = { 61 | installation_mode = "force_installed"; 62 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/https-everywhere/latest.xpi"; 63 | }; 64 | 65 | # Tabby 66 | "tabby@whatsyouridea.com" = { 67 | installation_mode = "force_installed"; 68 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/tabby-window-tab-manager/latest.xpi"; 69 | }; 70 | 71 | # 1Password 72 | "{d634138d-c276-4fc8-924b-40a0ea21d284}" = { 73 | installation_mode = "force_installed"; 74 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/1password-x-password-manager/latest.xpi"; 75 | }; 76 | 77 | # Immersive Translate 78 | "{5efceaa7-f3a2-4e59-a54b-85319448e305}" = { 79 | installation_mode = "force_installed"; 80 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/immersive-translate/latest.xpi"; 81 | }; 82 | 83 | # SafePal 84 | "{3fd93479-b7c6-4fce-b31b-5dcfbe843f61}" = { 85 | installation_mode = "force_installed"; 86 | install_url = "https://addons.mozilla.org/firefox/downloads/latest/safepal-extension-wallet/latest.xpi"; 87 | }; 88 | }; 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /packages/kcptun/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenv, fetchFromGitHub, buildGoModule }: 2 | 3 | buildGoModule rec { 4 | pname = "kcptun"; 5 | version = "20230811"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "xtaci"; 9 | repo = "kcptun"; 10 | rev = "v${version}"; 11 | sha256 = "sha256-ZuZ0JR5KIdMfzTKk88EFDMhXsE4zpVi8FnmvTTqlwuE="; 12 | }; 13 | 14 | vendorHash = null; 15 | 16 | postInstall = '' 17 | mv $out/bin/client $out/bin/kcptun-client 18 | mv $out/bin/server $out/bin/kcptun-server 19 | ''; 20 | 21 | meta = with lib; { 22 | description = "Stable and secure tunnel with multiplexing and FEC"; 23 | homepage = "https://github.com/xtaci/kcptun"; 24 | license = licenses.mit; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/landrop/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, lib, libsForQt5, libsodium }: 2 | 3 | let 4 | pname = "landrop"; 5 | version = "0.4.0"; 6 | landrop = fetchFromGitHub ({ 7 | owner = "LANDrop"; 8 | repo = "LANDrop"; 9 | rev = "v${version}"; 10 | fetchSubmodules = false; 11 | sha256 = "sha256-IwtphjMSa0e2mO5C4zHId48SUpT99sXziZzApnSmvrU="; 12 | }); 13 | in 14 | stdenv.mkDerivation rec { 15 | inherit pname version; 16 | src = "${landrop}/LANDrop"; 17 | 18 | buildInputs = with libsForQt5; [ qtbase libsodium ]; 19 | nativeBuildInputs = with libsForQt5; [ 20 | wrapQtAppsHook 21 | qmake 22 | ]; 23 | 24 | postPatch = '' 25 | substituteInPlace LANDrop.pro \ 26 | --replace "PREFIX = /usr/local" "PREFIX = $out" \ 27 | --replace "\$\$PWD/.." "${landrop}" 28 | ''; 29 | } 30 | -------------------------------------------------------------------------------- /packages/leaf/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "leaf"; 5 | version = "0.3.1"; 6 | 7 | src = fetchurl { 8 | url = "https://github.com/eycorsican/leaf/releases/download/v${version}/leaf-x86_64-unknown-linux-musl.gz"; 9 | sha256 = "UOW7fleDz40idmDKk4J/7B1fj9l2FXsREW3QGtTgLes="; 10 | }; 11 | 12 | phases = [ "installPhase" ]; 13 | 14 | installPhase = '' 15 | mkdir -p "$out"/bin/ 16 | cp $src $out/leaf.gz 17 | gunzip $out/leaf.gz 18 | install -m 755 $out/leaf -t "$out"/bin/ 19 | rm -f $out/leaf 20 | ''; 21 | } 22 | -------------------------------------------------------------------------------- /packages/libcron/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, cmake }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "libcron"; 5 | version = "1.3.1-unstable-2025-06-01"; 6 | 7 | src = fetchFromGitHub ({ 8 | owner = "PerMalmberg"; 9 | repo = "libcron"; 10 | rev = "de143e8b8eea0615e8c660c7408a3fd075b5b45c"; 11 | fetchSubmodules = true; 12 | sha256 = "sha256-X59U+VrqFU1r45R+FzV/AkywOyxLX2oXzoIuS8EsuVc="; 13 | }); 14 | 15 | cmakeFlags = [ 16 | "-DCMAKE_BUILD_TYPE=Release" 17 | ]; 18 | 19 | nativeBuildInputs = [ cmake ]; 20 | } 21 | -------------------------------------------------------------------------------- /packages/libvirt-dbus/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , fetchFromGitLab 4 | , meson 5 | , pkg-config 6 | , glib 7 | , libvirt 8 | , libvirt-glib 9 | , docutils 10 | , ninja 11 | }: 12 | 13 | stdenv.mkDerivation rec { 14 | pname = "libvirt-dbus"; 15 | version = "1.4.1"; 16 | 17 | src = fetchFromGitLab { 18 | owner = "libvirt"; 19 | repo = "libvirt-dbus"; 20 | rev = "v${version}"; 21 | sha256 = "sha256:112jbkp2b0pk6dpb0p68zg1ba196f4i0y57s1jzjn5vl4f11fv3g"; 22 | }; 23 | 24 | mesonFlags = [ 25 | "-Dsystem_user=root" 26 | ]; 27 | 28 | nativeBuildInputs = [ 29 | meson 30 | pkg-config 31 | docutils 32 | ninja 33 | ]; 34 | buildInputs = [ 35 | glib 36 | libvirt 37 | libvirt-glib 38 | ]; 39 | 40 | meta = with lib; { 41 | description = "DBus protocol binding for libvirt native C API"; 42 | license = licenses.lgpl2Plus; 43 | homepage = src.meta.homepage; 44 | platforms = platforms.linux; 45 | maintainers = with maintainers; [ ]; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /packages/mainsail/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenvNoCC 3 | , fetchzip 4 | }: 5 | 6 | stdenvNoCC.mkDerivation rec { 7 | pname = "mainsail"; 8 | version = "2.14.0"; 9 | 10 | src = fetchzip { 11 | url = "https://github.com/mainsail-crew/mainsail/releases/download/v${version}/mainsail.zip"; 12 | sha256 = "sha256-SSI5L4GJ8+09CHRB2+qy93PksWH2FMgD++1qKh217aU="; 13 | stripRoot = false; 14 | }; 15 | 16 | dontConfigure = true; 17 | dontBuild = true; 18 | 19 | installPhase = '' 20 | runHook preInstall 21 | mkdir -p $out/share/mainsail 22 | cp -r ./* $out/share/mainsail 23 | runHook postInstall 24 | ''; 25 | 26 | meta = with lib; { 27 | description = "Web interface for managing and controlling 3D printers with Klipper"; 28 | homepage = "https://docs.mainsail.xyz"; 29 | changelog = "https://github.com/mainsail-crew/mainsail/releases/tag/v${version}"; 30 | license = licenses.gpl3Plus; 31 | platforms = platforms.linux; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /packages/mattermost-ent/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, autoPatchelfHook, buildPhase ? "", ... }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "mattermost-ent"; 5 | version = "10.8.1"; 6 | src = fetchurl { 7 | url = "https://releases.mattermost.com/${version}/mattermost-${version}-linux-amd64.tar.gz"; 8 | sha256 = "sha256-8TLwyBX025/705IHiFxaYBEXki65oI9aKH/sZcQN9CY="; 9 | }; 10 | 11 | inherit buildPhase; 12 | 13 | nativeBuildInputs = [ 14 | autoPatchelfHook 15 | stdenv.cc.cc.lib 16 | ]; 17 | 18 | installPhase = '' 19 | cp -R . $out 20 | ''; 21 | } 22 | -------------------------------------------------------------------------------- /packages/mcsmanager/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenvNoCC, nodejs_20, fetchzip, makeWrapper, buildNpmPackage, ... }: 2 | let 3 | version = "10.4.3"; 4 | src = fetchzip { 5 | url = "https://github.com/MCSManager/MCSManager/releases/download/v${version}/mcsmanager_linux_release.tar.gz"; 6 | sha256 = "sha256-vXiHbXNhM2DegRq592fHbQK3jFddMKlCi1zl6JbZddw="; 7 | }; 8 | 9 | pname = "mcsmanager"; 10 | 11 | makeNodeModules = name: hash: buildNpmPackage { 12 | name = "mcsmanager-daemon-node-modules-${version}"; 13 | inherit pname version; 14 | 15 | src = "${src}/${name}"; 16 | 17 | npmDepsHash = hash; 18 | 19 | dontBuild = true; 20 | installPhase = '' 21 | cp -r node_modules $out/ 22 | ''; 23 | }; 24 | 25 | daemonNodeModules = makeNodeModules "daemon" "sha256-MCbnOe1/ykojAj9hX82FAogWALqHzyzuwbienARvVKQ="; 26 | webNodeModuels = makeNodeModules "web" "sha256-O2NjRlK8n6oEN7YB9MaJHKKvwsjzOA7dAsp3LmdV4ds="; 27 | in 28 | stdenvNoCC.mkDerivation rec { 29 | inherit pname version src; 30 | 31 | dontConfigure = true; 32 | nativeBuildInputs = [ makeWrapper ]; 33 | 34 | buildPhase = '' 35 | substituteInPlace daemon/app.js \ 36 | --replace-fail 'process.cwd(), "lib"' "\"$out/mcsmanager/daemon\", \"lib\"" 37 | 38 | substituteInPlace daemon/app.js \ 39 | --replace-fail 'const PACKAGE_JSON = "package.json";' "const PACKAGE_JSON = \"$out/mcsmanager/daemon/package.json\";" 40 | 41 | substituteInPlace web/app.js \ 42 | --replace-fail 'process.cwd(), "public"' "\"$out/mcsmanager/web\", \"public\"" 43 | 44 | substituteInPlace web/app.js \ 45 | --replace-fail 'const PACKAGE_JSON = "package.json";' "const PACKAGE_JSON = \"$out/mcsmanager/web/package.json\";" 46 | 47 | substituteInPlace daemon/app.js \ 48 | --replace-fail 'fs_extra_1.default.chmodSync(const_2.' "// fs_extra_1.default.chmodSync(const_2." 49 | 50 | chmod -R 755 daemon/lib/ 51 | ''; 52 | dontCheckForBrokenSymlinks = true; 53 | installPhase = '' 54 | runHook preInstall 55 | mkdir -p $out/mcsmanager 56 | 57 | rm -rf daemon/node_modules 58 | rm -rf web/node_modules 59 | cp -r ./* $out/mcsmanager 60 | cp -r ${daemonNodeModules} $out/mcsmanager/daemon/node_modules 61 | cp -r ${webNodeModuels} $out/mcsmanager/web/node_modules 62 | 63 | makeWrapper ${nodejs_20}/bin/node "$out/bin/mcsmanager-daemon" \ 64 | --add-flags "$out/mcsmanager/daemon/app.js" 65 | 66 | 67 | makeWrapper ${nodejs_20}/bin/node "$out/bin/mcsmanager-web" \ 68 | --add-flags "$out/mcsmanager/web/app.js" 69 | runHook postInstall 70 | ''; 71 | } 72 | -------------------------------------------------------------------------------- /packages/microsocks/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "microsocks"; 5 | version = "1.0.5"; 6 | src = fetchFromGitHub ({ 7 | owner = "rofl0r"; 8 | repo = "microsocks"; 9 | rev = "v${version}"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-5NR2gtm+uMkjmkV/dv3DzSedfNvYpHZgFHVSrybl0Tk="; 12 | }); 13 | 14 | installPhase = '' 15 | mkdir -p $out/bin/ 16 | install -m 755 microsocks -t $out/bin/ 17 | ''; 18 | } 19 | -------------------------------------------------------------------------------- /packages/miui-auto-tasks/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, makeWrapper, python3, python3Packages }: 2 | 3 | let 4 | onepush = import ../onepush/pkg.nix { 5 | inherit python3Packages fetchFromGitHub; 6 | }; 7 | 8 | python3WithPackages = python3.withPackages (python-packages: with python-packages; [ 9 | requests 10 | python-dotenv 11 | pyyaml 12 | onepush 13 | ]); 14 | in 15 | stdenv.mkDerivation { 16 | pname = "miui-auto-tasks"; 17 | version = "1.8.2-hotfix4-unstable-2025-04-16"; 18 | src = fetchFromGitHub { 19 | owner = "0-8-4"; 20 | repo = "miui-auto-tasks"; 21 | rev = "0e452de92605a897c5b3dd614f205fd0b7d2bbeb"; 22 | sha256 = "sha256-jh7iW25rLDjeaLtY1dsyzRdt6PKcPHb6E2HRfU6bs8k="; 23 | fetchSubmodules = true; 24 | }; 25 | 26 | phases = "installPhase"; 27 | nativeBuildInputs = [ makeWrapper ]; 28 | installPhase = '' 29 | mkdir -p $out/python $out/bin 30 | cp -r $src/* $out/python/ 31 | rm -f $out/python/config.yaml 32 | substituteInPlace "$out/python/utils/utils.py" \ 33 | --replace "dotenv.find_dotenv(filename='config.yaml')" "dotenv.find_dotenv(filename='config.yaml', usecwd=True)" 34 | makeWrapper ${python3WithPackages}/bin/python "$out/bin/miuitask" \ 35 | --add-flags "$out/python/miuitask.py" 36 | ''; 37 | } 38 | -------------------------------------------------------------------------------- /packages/mmdb-ipip/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchgit }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "mmdb-ipip"; 5 | version = "202506020312-unstable-2025-06-03"; 6 | src = fetchgit { 7 | url = "https://github.com/alecthw/mmdb_china_ip_list.git"; 8 | rev = "74678762e5335f644d47f7bb40d392fc755ab8a7"; 9 | fetchSubmodules = true; 10 | deepClone = false; 11 | leaveDotGit = false; 12 | sha256 = "sha256-SQOazNvFf/TAoSFvQlf5u4WonePV9MS3w7Ir8tpu310="; 13 | }; 14 | installPhase = '' 15 | install -m 755 Country.mmdb $out 16 | ''; 17 | } 18 | -------------------------------------------------------------------------------- /packages/mumble-discord-bridge/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchFromGitHub, buildGoModule, lib, pkg-config, libopus }: 2 | 3 | buildGoModule rec { 4 | pname = "mumble-discord-bridge"; 5 | 6 | version = "0.5.3"; 7 | 8 | src = fetchFromGitHub ({ 9 | owner = "Stieneee"; 10 | repo = pname; 11 | rev = "v${version}"; 12 | fetchSubmodules = true; 13 | sha256 = "sha256-Rr1g3gdmbmMcXN9KFpktKhB2sedplrFcT2GMfUY9b7g="; 14 | }); 15 | 16 | vendorHash = "sha256-U3RLLXGirZsh5nTlt8tgLsCmNIa3x1SacTFgHhG4OoI="; 17 | nativeBuildInputs = [ pkg-config ]; 18 | buildInputs = [ libopus ]; 19 | 20 | # Testing is taking more then 10 minute 21 | doCheck = false; 22 | 23 | meta = with lib; { 24 | homepage = "https://github.com/Stieneee/mumble-discord-bridge"; 25 | description = "A simple voice bridge between Mumble and Discord"; 26 | changelog = "https://github.com/Stieneee/mumble-discord-bridge/releases/tag/v${version}"; 27 | license = licenses.mit; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/nettrace/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, clang, clang-tools, zlib, glibc, llvm, fetchFromGitHub, pkg-config, python3, libelf, libbpf, bpftools, ... }: 2 | 3 | let 4 | python3WithPackages = python3.withPackages (python-packages: with python-packages; [ 5 | pyyaml 6 | ]); 7 | in 8 | stdenv.mkDerivation rec { 9 | pname = "nettrace"; 10 | version = "1.2.11"; 11 | 12 | src = fetchFromGitHub { 13 | owner = "OpenCloudOS"; 14 | repo = pname; 15 | rev = "v${version}"; 16 | sha256 = "sha256-mcshgNOsRpNXcoYfT0I+mbZlLu/sW38vRBSrK4lDXms="; 17 | }; 18 | 19 | hardeningDisable = [ 20 | "stackprotector" 21 | "zerocallusedregs" 22 | ]; 23 | 24 | nativeBuildInputs = [ 25 | pkg-config 26 | python3WithPackages 27 | ]; 28 | 29 | buildInputs = [ 30 | libelf 31 | libbpf 32 | bpftools 33 | llvm 34 | clang-tools 35 | clang 36 | zlib.static 37 | glibc.static 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /packages/novnc/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, jre8, unzip }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "novnc"; 5 | version = "1.6.0"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "novnc"; 9 | repo = "noVNC"; 10 | rev = "60c7518f8c32704615b4953bae28783786817cdc"; 11 | sha256 = "0llag553aw0marb9p59rb14prjqwknvyrjwqvgakf4mxsk0l2nqy"; 12 | }; 13 | 14 | phases = "installPhase"; 15 | installPhase = '' 16 | mkdir -p $out 17 | cp -rv $src/* $out 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /packages/onepush/pkg.nix: -------------------------------------------------------------------------------- 1 | { python3Packages, fetchFromGitHub }: 2 | 3 | python3Packages.buildPythonPackage { 4 | pname = "onepush"; 5 | version = "1.1.0-unstable-2025-06-03"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "y1ndan"; 9 | repo = "onepush"; 10 | rev = "cd5f4c3dcc0ed63c4f82f4bb9893c7a90eec6446"; 11 | sha256 = "sha256-NCkfL+JS6z8reQ1et2d2dBADxzsLLjl5OZAb1x1GdqU="; 12 | }; 13 | 14 | propagatedBuildInputs = with python3Packages; [ 15 | requests 16 | pytest 17 | pycryptodome 18 | ]; 19 | 20 | doCheck = false; # Test fails 21 | } 22 | -------------------------------------------------------------------------------- /packages/os-specific/linux/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, normalPkgs, kernelPatches, ... }: 2 | 3 | with normalPkgs; 4 | { 5 | ksmbd-tools = callPackage ./ksmbd/tools.nix { }; 6 | 7 | ksmbd-kernel = callPackage ./ksmbd/kernel.nix { }; 8 | } 9 | -------------------------------------------------------------------------------- /packages/os-specific/linux/ksmbd/kernel.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenv, fetchFromGitHub, linuxPackages }: 2 | 3 | with linuxPackages; 4 | assert lib.versionAtLeast kernel.version "5.4"; 5 | 6 | stdenv.mkDerivation { 7 | pname = "ksmbd"; 8 | version = "3.2.1-unstable-2025-05-12"; 9 | src = fetchFromGitHub ({ 10 | owner = "namjaejeon"; 11 | repo = "ksmbd"; 12 | rev = "63bd67769512d4addce6261df11c777a50730752"; 13 | fetchSubmodules = true; 14 | sha256 = "sha256-S1dRfNL6ux+/PQncbeiJ/11EkeSlAb6iLecfIIwPqL8="; 15 | }); 16 | 17 | nativeBuildInputs = kernel.moduleBuildDependencies; 18 | 19 | makeFlags = [ 20 | "KVERSION=${kernel.modDirVersion}" 21 | "KDIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" 22 | "MDIR=${placeholder "out"}/lib/modules/${kernel.modDirVersion}" 23 | ]; 24 | 25 | preConfigure = '' 26 | sed -i 's|depmod|#depmod|' Makefile 27 | ''; 28 | 29 | meta.platforms = [ "x86_64-linux" ]; 30 | } 31 | -------------------------------------------------------------------------------- /packages/os-specific/linux/ksmbd/tools.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenv, fetchFromGitHub, autoreconfHook, glib, pkg-config, libnl }: 2 | 3 | stdenv.mkDerivation { 4 | pname = "ksmbd-tools"; 5 | version = "0-unstable-2025-01-20"; 6 | src = fetchFromGitHub ({ 7 | owner = "namjaejeon"; 8 | repo = "ksmbd-tools"; 9 | rev = "1025a9846a99c8e50d73a3fff4bf958fa0a8a852"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-Mw8neMAEeZCBdHv/B3Vvu0MKpdgK6Tq3+INeJDH5oNM="; 12 | }); 13 | 14 | nativeBuildInputs = [ autoreconfHook glib pkg-config libnl ]; 15 | } 16 | -------------------------------------------------------------------------------- /packages/ping-exporter/pkg.nix: -------------------------------------------------------------------------------- 1 | { lib, buildGoModule, fetchFromGitHub }: 2 | 3 | buildGoModule rec { 4 | pname = "ping-exporter"; 5 | version = "1.1.3"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "czerwonk"; 9 | repo = "ping_exporter"; 10 | rev = version; 11 | hash = "sha256-Jdo+6/e9gES8q4wTGRuy5HSj7VimOMZ9q3guKDcKJxg="; 12 | }; 13 | 14 | vendorHash = "sha256-1oNbg6lu9xLJKeYOzK23HOTLJc3KWri7z4/2AZ7Hzms="; 15 | 16 | meta = with lib; { 17 | description = "Prometheus exporter for ICMP echo requests"; 18 | homepage = "https://github.com/czerwonk/ping_exporter"; 19 | license = licenses.mit; 20 | maintainers = with maintainers; [ nudelsalat ]; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/pufferpanel/default.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenvNoCC, fetchFromGitHub, buildGoModule, npmlock2nix, jq }: 2 | 3 | let 4 | pname = "pufferpanel"; 5 | version = "v2.6.2"; 6 | src = fetchFromGitHub ({ 7 | owner = "PufferPanel"; 8 | repo = "PufferPanel"; 9 | rev = "v2.6.2"; 10 | fetchSubmodules = true; 11 | sha256 = "sha256-Mwg4wKhbF1ohXGk2VwZrG5Xc5kdhrg5+Wnf0phv53qU="; 12 | }); 13 | 14 | webSrc = stdenvNoCC.mkDerivation { 15 | name = "${pname}-web-src"; 16 | 17 | inherit version src; 18 | phases = [ "buildPhase" ]; 19 | # set missing version 20 | buildPhase = '' 21 | cp --no-preserve=mode,ownership -r $src/client $out 22 | ${jq}/bin/jq ".version = \"${version}\"" $out/package-lock.json > test.json 23 | rm -f $out/package-lock.json 24 | mv test.json $out/package-lock.json 25 | ''; 26 | }; 27 | 28 | web = npmlock2nix.buildNpmPackage { 29 | src = webSrc; 30 | 31 | npmBuild = "npm run build"; 32 | installPhase = "cp -r dist $out"; 33 | 34 | }; 35 | in 36 | buildGoModule { 37 | inherit pname version src; 38 | vendorHash = "sha256-w3PExVOUQQLyjBvRUVqFfNc131ys4UpH6q/eFVCVye8="; 39 | 40 | # modSha256 = lib.fakeSha256; 41 | subPackages = [ "cmd" ]; 42 | 43 | fixupPhase = '' 44 | mkdir -p $out/assets 45 | cp -r ${web} $out/assets/www 46 | cp -r $src/assets/email $out/assets 47 | cd $out/bin 48 | mv cmd pufferpanel 49 | ''; 50 | 51 | doCheck = false; 52 | } 53 | -------------------------------------------------------------------------------- /packages/quickjspp/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, cmake }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "quickjspp"; 5 | version = "20191027-unstable-2023-12-21"; 6 | 7 | src = fetchFromGitHub ({ 8 | owner = "ftk"; 9 | repo = "quickjspp"; 10 | rev = "0c00c48895919fc02da3f191a2da06addeb07f09"; 11 | fetchSubmodules = true; 12 | sha256 = "sha256-YdDSs5KkjnX2tjI4wDsEqDSPYahKSocnxtnBgiv6xcA="; 13 | }); 14 | 15 | nativeBuildInputs = [ cmake ]; 16 | } 17 | -------------------------------------------------------------------------------- /packages/rapidjson/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchFromGitHub, cmake }: 2 | 3 | stdenv.mkDerivation rec { 4 | pname = "rapidjson"; 5 | version = "1.1.0-unstable-2025-02-05"; 6 | 7 | src = fetchFromGitHub ({ 8 | owner = "tencent"; 9 | repo = "rapidjson"; 10 | rev = "24b5e7a8b27f42fa16b96fc70aade9106cf7102f"; 11 | fetchSubmodules = true; 12 | sha256 = "sha256-fCiPqNrC1dB7f3InIMHMbHhapB9cSyMCaH9qoO3FPAk="; 13 | }); 14 | 15 | nativeBuildInputs = [ cmake ]; 16 | } 17 | -------------------------------------------------------------------------------- /packages/reader/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenvNoCC, fetchurl, lib }: 2 | 3 | stdenvNoCC.mkDerivation rec { 4 | name = "reader-pro"; 5 | version = "3.2.14"; 6 | 7 | src = fetchurl { 8 | url = "https://github.com/hectorqin/reader/releases/download/v${version}/reader-pro-${version}.jar"; 9 | sha256 = "sha256-sm+0dp1onZj/JkCM55onXXGfNgkGyErPUv9ATpgDDIw="; 10 | }; 11 | 12 | phases = [ "buildPhase" ]; 13 | 14 | buildPhase = '' 15 | cp $src $out 16 | ''; 17 | } 18 | -------------------------------------------------------------------------------- /packages/realm/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchFromGitHub, rust-bin, makeRustPlatform, lib, pkg-config, openssl, ... }: 2 | 3 | let 4 | rust = rust-bin.selectLatestNightlyWith (toolchain: toolchain.default); 5 | rustPlatform = makeRustPlatform { 6 | rustc = rust; 7 | cargo = rust; 8 | }; 9 | in 10 | rustPlatform.buildRustPackage rec { 11 | pname = "realm"; 12 | version = "2.7.0"; 13 | src = fetchFromGitHub ({ 14 | owner = "zhboner"; 15 | repo = "realm"; 16 | rev = "v${version}"; 17 | fetchSubmodules = true; 18 | sha256 = "sha256-vkLGfSDRYqvoqyVM/CWGJjpvXXPisEZxUSjLZGjNzno="; 19 | }); 20 | 21 | cargoHash = "sha256-Oe64l16uYdU6NvTl7XrEm6dAtRFngI9yHC4fe4hpTNA="; 22 | 23 | # transport feature broken 24 | buildNoDefaultFeatures = true; 25 | buildFeatures = [ "multi-thread" "brutal-shutdown" "jemalloc" "proxy" "balance" ]; 26 | 27 | buildInputs = [ 28 | openssl 29 | ]; 30 | 31 | nativeBuildInputs = [ pkg-config ]; 32 | } 33 | -------------------------------------------------------------------------------- /packages/safenet-driver/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchzip, stdenv, dpkg, pcsclite, autoPatchelfHook, glib, pango, gtk3 }: 2 | 3 | stdenv.mkDerivation { 4 | name = "safenet-driver"; 5 | version = "10.8"; 6 | 7 | src = fetchzip { 8 | url = "https://www.globalsign.com/en/safenet-drivers/USB/10.8/GlobalSign-SAC-Ubuntu-2004.zip"; 9 | sha256 = "sha256-Z8vjrgtrg+yRHwuls4TUlmff9rjW96/QyQGtZN+hoVQ="; 10 | }; 11 | 12 | buildInputs = [ dpkg pcsclite ]; 13 | 14 | nativeBuildInputs = [ 15 | autoPatchelfHook 16 | stdenv.cc.cc.lib 17 | glib 18 | pango 19 | gtk3 20 | ]; 21 | 22 | buildPhase = '' 23 | dpkg -x safenetauthenticationclient_10.8.1050_amd64.deb . 24 | ''; 25 | 26 | installPhase = '' 27 | mkdir -p $out 28 | cp -r usr/lib $out/lib 29 | cp -r usr/bin $out/bin 30 | cp -r usr/share $out/share 31 | ''; 32 | } 33 | -------------------------------------------------------------------------------- /packages/simple-obfs/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchgit, lib, stdenv, autoconf, automake, libtool, libev, autoreconfHook }: 2 | 3 | with lib; 4 | stdenv.mkDerivation rec { 5 | pname = "simple-obfs"; 6 | version = "0.0.5-unstable-2019-08-17"; 7 | src = fetchgit { 8 | url = "https://github.com/shadowsocks/simple-obfs.git"; 9 | rev = "486bebd9208539058e57e23a12f23103016e09b4"; 10 | sha256 = "sha256-eyVRec9V2qM/9XL+SZCuTXkD3qbbGMjTL/kDsAzwl9c="; 11 | fetchSubmodules = true; 12 | deepClone = false; 13 | leaveDotGit = false; 14 | }; 15 | 16 | configureFlags = [ "--disable-documentation" ]; 17 | 18 | nativeBuildInputs = [ autoconf automake autoreconfHook ]; 19 | buildInputs = [ libtool libev ]; 20 | 21 | # MacOS support is broken 22 | meta.platforms = platforms.linux; 23 | } 24 | -------------------------------------------------------------------------------- /packages/speedtest/pkg.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl }: 2 | 3 | let 4 | version = "1.1.1"; 5 | 6 | fetchSrc = { 7 | x86_64-linux = { 8 | url = "https://install.speedtest.net/app/cli/ookla-speedtest-${version}-linux-x86_64.tgz"; 9 | sha256 = "0304lfqpxq2xzf7vhgri0jzcflcvixjaz3q8bzkl3mz4zvypf14p"; 10 | }; 11 | aarch64-linux = { 12 | url = "https://install.speedtest.net/app/cli/ookla-speedtest-${version}-linux-aarch64.tgz"; 13 | sha256 = "1n8z8f6kml0k383vcvgwiwsyv4mackyc500ml8jcmhz17y3l0si7"; 14 | }; 15 | }."${stdenv.system}" or (throw "Unsupported system"); 16 | in 17 | stdenv.mkDerivation rec { 18 | pname = "speedtest-cli"; 19 | inherit version; 20 | 21 | src = fetchurl { 22 | inherit (fetchSrc) url sha256; 23 | name = "${pname}-${version}.tar.gz"; 24 | }; 25 | 26 | setSourceRoot = "sourceRoot=`pwd`"; 27 | 28 | meta.description = "CLI for SpeedTest"; 29 | 30 | buildPhase = '' 31 | tar zxvf $src 32 | ''; 33 | 34 | installPhase = '' 35 | mkdir -p "$out"/bin/ 36 | install -m 755 speedtest -t "$out"/bin/ 37 | ''; 38 | } 39 | -------------------------------------------------------------------------------- /packages/stickerpicker/pkg.nix: -------------------------------------------------------------------------------- 1 | { python3Packages, fetchFromGitHub }: 2 | 3 | python3Packages.buildPythonPackage rec { 4 | pname = "stickerpicker"; 5 | version = "0-unstable-2025-03-25"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "maunium"; 9 | repo = pname; 10 | rev = "4b96d236212b1212976f4c3c60479e7aaed866cb"; 11 | sha256 = "sha256-PQ6Qv7VSumLa05Mrnylh1i8maWAHptd4vKwdElE4Tns="; 12 | }; 13 | 14 | propagatedBuildInputs = with python3Packages; [ 15 | aiohttp 16 | yarl 17 | pillow 18 | telethon 19 | cryptg 20 | python-magic 21 | pkgs.cacert 22 | ]; 23 | 24 | doCheck = false; 25 | } 26 | -------------------------------------------------------------------------------- /packages/teleport-ent/pkg.nix: -------------------------------------------------------------------------------- 1 | { fetchurl, stdenv, autoPatchelfHook, buildPhase ? "", ... }: 2 | 3 | let 4 | info = import ./version.nix; 5 | inherit (info) version hash; 6 | 7 | fetchSrc = { 8 | x86_64-linux = { 9 | url = "https://cdn.teleport.dev/teleport-ent-v${version}-linux-amd64-bin.tar.gz"; 10 | sha256 = hash.x86_64-linux; 11 | }; 12 | aarch64-linux = { 13 | url = "https://cdn.teleport.dev/teleport-ent-v${version}-linux-arm64-bin.tar.gz"; 14 | sha256 = hash.aarch64-linux; 15 | }; 16 | }."${stdenv.system}" or (throw "Unsupported system"); 17 | in 18 | stdenv.mkDerivation { 19 | pname = "teleport-ent"; 20 | inherit version; 21 | 22 | src = fetchurl fetchSrc; 23 | 24 | inherit buildPhase; 25 | 26 | nativeBuildInputs = [ 27 | autoPatchelfHook 28 | stdenv.cc.cc.lib 29 | ]; 30 | 31 | installPhase = '' 32 | mkdir -p $out/bin 33 | cp {tctl,teleport,tsh} $out/bin 34 | ''; 35 | 36 | passthru.updateScript = ./update.sh; 37 | meta = { 38 | homepage = "https://github.com/gravitational/teleport"; 39 | description = "Protect access to all of your infrastructure."; 40 | changelog = "https://github.com/gravitational/teleport/releases/tag/v${version}"; 41 | mainProgram = "teleport"; 42 | platforms = [ "x86_64-linux" "aarch64-linux" ]; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /packages/teleport-ent/update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nix-shell 2 | #!nix-shell -i bash -p coreutils curl jq common-updater-scripts 3 | set -euo pipefail 4 | 5 | tag_name=$(curl https://api.github.com/repos/gravitational/teleport/releases/latest | jq -r ".tag_name") 6 | prefix="v" 7 | 8 | version=${tag_name#"$prefix"} 9 | 10 | amd64_pkg_hash=$(nix-prefetch-url "https://cdn.teleport.dev/teleport-ent-v$version-linux-amd64-bin.tar.gz") 11 | amd64_pkg_hash=$(nix hash to-sri "sha256:$amd64_pkg_hash") 12 | 13 | arm64_pkg_hash=$(nix-prefetch-url "https://cdn.teleport.dev/teleport-ent-v$version-linux-arm64-bin.tar.gz") 14 | arm64_pkg_hash=$(nix hash to-sri "sha256:$arm64_pkg_hash") 15 | 16 | cat > version.nix < \K([0-9\\.]*)(?=

)")" --flake mattermost-ent 37 | 38 | for package in "teleport-ent"; do 39 | current_version=$(nix eval --raw .#packages.x86_64-linux."$package".version) 40 | pushd packages/$package/ 41 | bash update.sh 42 | popd 43 | git add . 44 | new_version=$(nix eval --raw .#packages.x86_64-linux."$package".version) 45 | 46 | if [ "$current_version" != "$new_version" ]; then 47 | git commit -m "$package: $current_version -> $new_version" 48 | fi 49 | done 50 | -------------------------------------------------------------------------------- /update_daily.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | nix-update --commit --version branch --flake simple-obfs 4 | nix-update --commit --version branch --flake commit-notifier 5 | nix-update --commit --version branch=release --flake mmdb-ipip 6 | nix-update --commit --version branch --flake ksmbd-kernel 7 | nix-update --commit --version branch --flake ksmbd-tools 8 | nix-update --commit --version branch=gh-pages --flake yacd-meta 9 | nix-update --commit --version branch --flake quickjspp 10 | nix-update --commit --version branch --flake rapidjson 11 | nix-update --commit --version branch --flake libcron 12 | nix-update --commit --version branch --flake dnsmasq-china-list 13 | nix-update --commit --version branch --flake chnroutes 14 | nix-update --commit --version branch --flake stickerpicker 15 | nix-update --commit --version branch=master --flake miui-auto-tasks 16 | nix-update --commit --version branch --flake onepush 17 | --------------------------------------------------------------------------------