From 17f65ed65f51e936922e32f5354f06b8685ae06e Mon Sep 17 00:00:00 2001 From: emptyynes Date: Wed, 17 Sep 2025 16:33:24 +0700 Subject: [PATCH] first commit --- affine/.options.nix.kate-swp | Bin 0 -> 78 bytes affine/affine.nix | 215 +++++++++++++++++++++++++++++++++++ affine/main.nix | 8 ++ affine/options.nix | 15 +++ affine/volume.nix | 21 ++++ flake.nix | 13 +++ marzban/main.nix | 8 ++ marzban/marzban.nix | 89 +++++++++++++++ marzban/options.nix | 25 ++++ 9 files changed, 394 insertions(+) create mode 100644 affine/.options.nix.kate-swp create mode 100644 affine/affine.nix create mode 100644 affine/main.nix create mode 100644 affine/options.nix create mode 100644 affine/volume.nix create mode 100644 flake.nix create mode 100644 marzban/main.nix create mode 100644 marzban/marzban.nix create mode 100644 marzban/options.nix diff --git a/affine/.options.nix.kate-swp b/affine/.options.nix.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..7ce6500a17bd2466ca8465c2877c0729b8c92115 GIT binary patch literal 78 zcmZQzU=Z?7EJ;-eE>A2_aLdd|RWQ;sU|?Vn`G2i{`TLn09&?-W&8%;cF>qXP?pLrU Z0|Nsu0|Nsy0|Nu2f-9WQ0^%pR0sw!X6C(fs literal 0 HcmV?d00001 diff --git a/affine/affine.nix b/affine/affine.nix new file mode 100644 index 0000000..aa27f83 --- /dev/null +++ b/affine/affine.nix @@ -0,0 +1,215 @@ +# Auto-generated using compose2nix v0.3.1. +{ pkgs, lib, config, ... }: + +let affine-static = "/var/lib/affine"; + +in { + + system.activationScripts.affine-dir = '' + mkdir -p ${affine-static}/{config,db,storage} + ''; + + # Runtime + virtualisation.docker = { + enable = true; + autoPrune.enable = true; + }; + + # Enable container name DNS for non-default Podman networks. + # https://github.com/NixOS/nixpkgs/issues/226365 + networking.firewall.interfaces."docker+".allowedUDPPorts = [ 53 ]; + + virtualisation.oci-containers.backend = "docker"; + + # Containers + virtualisation.oci-containers.containers."affine_migration_job" = { + image = "ghcr.io/toeverything/affine:stable"; + environment = with config.affine.env; { + "AFFINE_INDEXER_ENABLED" = "false"; + "AFFINE_REVISION" = config.affine.revision; + "CONFIG_LOCATION" = "${affine-static}/config"; + "DATABASE_URL" = "postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE}"; + "DB_DATABASE" = DB_DATABASE; + "DB_DATA_LOCATION" = "${affine-static}/db"; + "DB_PASSWORD" = DB_PASSWORD; + "DB_USERNAME" = DB_USERNAME; + "PORT" = toString PORT; + "REDIS_SERVER_HOST" = "redis"; + "UPLOAD_LOCATION" = "${affine-static}/storage"; + }; + volumes = [ + "${affine-static}/config:/root/.affine/config:rw" + "${affine-static}/storage:/root/.affine/storage:rw" + ]; + cmd = [ "sh" "-c" "node ./scripts/self-host-predeploy.js" ]; + dependsOn = [ + "affine_postgres" + "affine_redis" + ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=affine_migration" + "--network=affine_default" + ]; + }; + systemd.services."docker-affine_migration_job" = { + serviceConfig = { + Restart = lib.mkOverride 90 "no"; + }; + after = [ + "docker-network-affine_default.service" + ]; + requires = [ + "docker-network-affine_default.service" + ]; + partOf = [ + "docker-compose-affine-root.target" + ]; + wantedBy = [ + "docker-compose-affine-root.target" + ]; + }; + virtualisation.oci-containers.containers."affine_postgres" = { + image = "pgvector/pgvector:pg16"; + environment = with config.affine.env; { + "POSTGRES_DB" = DB_DATABASE; + "POSTGRES_HOST_AUTH_METHOD" = "trust"; + "POSTGRES_INITDB_ARGS" = "--data-checksums"; + "POSTGRES_PASSWORD" = DB_PASSWORD; + "POSTGRES_USER" = DB_USERNAME; + }; + volumes = [ + "${affine-static}/db:/var/lib/postgresql/data:rw" + ]; + log-driver = "journald"; + extraOptions = with config.affine.env; [ + "--health-cmd=[\"pg_isready\", \"-U\", \"${DB_USERNAME}\", \"-d\", \"${DB_DATABASE}\"]" + "--health-interval=10s" + "--health-retries=5" + "--health-timeout=5s" + "--network-alias=postgres" + "--network=affine_default" + ]; + }; + systemd.services."docker-affine_postgres" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + }; + after = [ + "docker-network-affine_default.service" + ]; + requires = [ + "docker-network-affine_default.service" + ]; + partOf = [ + "docker-compose-affine-root.target" + ]; + wantedBy = [ + "docker-compose-affine-root.target" + ]; + }; + virtualisation.oci-containers.containers."affine_redis" = { + image = "redis"; + log-driver = "journald"; + extraOptions = [ + "--health-cmd=[\"redis-cli\", \"--raw\", \"incr\", \"ping\"]" + "--health-interval=10s" + "--health-retries=5" + "--health-timeout=5s" + "--network-alias=redis" + "--network=affine_default" + ]; + }; + systemd.services."docker-affine_redis" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + }; + after = [ + "docker-network-affine_default.service" + ]; + requires = [ + "docker-network-affine_default.service" + ]; + partOf = [ + "docker-compose-affine-root.target" + ]; + wantedBy = [ + "docker-compose-affine-root.target" + ]; + }; + virtualisation.oci-containers.containers."affine_server" = { + image = "ghcr.io/toeverything/affine:stable"; + environment = with config.affine.env; { + "AFFINE_INDEXER_ENABLED" = "false"; + "AFFINE_REVISION" = config.affine.revision; + "CONFIG_LOCATION" = "${affine-static}/config"; + "DATABASE_URL" = "postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE}"; + "DB_DATABASE" = DB_DATABASE; + "DB_DATA_LOCATION" = "${affine-static}/db"; + "DB_PASSWORD" = DB_PASSWORD; + "DB_USERNAME" = DB_USERNAME; + "PORT" = toString PORT; + "REDIS_SERVER_HOST" = "redis"; + "UPLOAD_LOCATION" = "${affine-static}/storage"; + }; + volumes = [ + "${affine-static}/config:/root/.affine/config:rw" + "${affine-static}/storage:/root/.affine/storage:rw" + ]; + ports = [ + "${ toString config.affine.env.PORT}:3010/tcp" + ]; + dependsOn = [ + "affine_migration_job" + "affine_postgres" + "affine_redis" + ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=affine" + "--network=affine_default" + ]; + }; + systemd.services."docker-affine_server" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + }; + after = [ + "docker-network-affine_default.service" + ]; + requires = [ + "docker-network-affine_default.service" + ]; + partOf = [ + "docker-compose-affine-root.target" + ]; + wantedBy = [ + "docker-compose-affine-root.target" + ]; + }; + + # Networks + systemd.services."docker-network-affine_default" = { + path = [ pkgs.docker ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStop = "docker network rm -f affine_default"; + }; + script = '' + docker network inspect affine_default || docker network create affine_default + ''; + partOf = [ "docker-compose-affine-root.target" ]; + wantedBy = [ "docker-compose-affine-root.target" ]; + }; + + # Root service + # When started, this will automatically create all resources and start + # the containers. When stopped, this will teardown all resources. + systemd.targets."docker-compose-affine-root" = { + unitConfig = { + Description = "Root target generated by compose2nix."; + }; + wantedBy = [ "multi-user.target" ]; + }; +} diff --git a/affine/main.nix b/affine/main.nix new file mode 100644 index 0000000..1c26018 --- /dev/null +++ b/affine/main.nix @@ -0,0 +1,8 @@ +{ config, pkgs, ... }: + +{ + imports = [ + ./affine.nix + ./options.nix + ]; +} diff --git a/affine/options.nix b/affine/options.nix new file mode 100644 index 0000000..ffd68fa --- /dev/null +++ b/affine/options.nix @@ -0,0 +1,15 @@ +{ lib, ... }: + +{ + options = with lib; with types; { + affine = { + env = { + PORT = mkOption { type = int; default = 3010; }; + DB_USERNAME = mkOption { type = str; default = "affine"; }; + DB_PASSWORD = mkOption { type = str; default = "affine"; }; + DB_DATABASE = mkOption { type = str; default = "affine"; }; + }; + revision = mkOption { type = str; default = "stable"; }; + }; + }; +} diff --git a/affine/volume.nix b/affine/volume.nix new file mode 100644 index 0000000..5bbc961 --- /dev/null +++ b/affine/volume.nix @@ -0,0 +1,21 @@ +{ pkgs, lib, config, ... }: + + +pkgs.stdenv.mkDerivation { + name = "affine-volume"; + phases = ["buildPhase" "installPhase" ]; + + buildPhase = '' + mkdir -p $out + touch $out/.env + echo "" > $out/.env + ''; + + installPhase = '' + echo "AFFINE_REVISION="${config.affine.revision}" >> $out/.env + echo "PORT=${config.affine.env.PORT}" >> $out/.env + echo "DB_USERNAME=${config.affine.env.DB_USERNAME}" >> $out/.env + echo "DB_PASSWORD=${config.affine.env.DB_PASSWORD}" >> $out/.env + echo "DB_DATABASE=${config.affine.env.DB_DATABASE}" >> $out/.env + ''; +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..98f6f72 --- /dev/null +++ b/flake.nix @@ -0,0 +1,13 @@ +{ + description = "Project-A Software Flake!"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + }; + + outputs = { self, nixpkgs, nixpkgs-unstable, ... }: { + marzban = import ./marzban/main.nix; + affine = import ./affine/main.nix; + }; +} diff --git a/marzban/main.nix b/marzban/main.nix new file mode 100644 index 0000000..85c2f36 --- /dev/null +++ b/marzban/main.nix @@ -0,0 +1,8 @@ +{pkgs, lib, stdenv, config, ...}: + +{ + imports = [ + ./options.nix + ./marzban.nix + ]; +} \ No newline at end of file diff --git a/marzban/marzban.nix b/marzban/marzban.nix new file mode 100644 index 0000000..cbf7dc7 --- /dev/null +++ b/marzban/marzban.nix @@ -0,0 +1,89 @@ +{ pkgs, lib, config, ... }: # compose2nix + +let + marzban-volume = pkgs.stdenv.mkDerivation { + name = "marzban-volume"; + phases = [ "buildPhase" "installPhase" ]; + + buildInputs = with pkgs; [ + openssl + ]; + + buildPhase = '' + mkdir -p $out + mkdir -p $out/certs + touch $out/.env + touch $out/xray-config.json + echo "" > $out/.env + ''; + + installPhase = + (if config.marzban.cert then '' + ${pkgs.openssl}/bin/openssl req -newkey rsa:4096 -x509 -sha512 -days 730 -nodes -out $out/certs/certificate.pem -keyout $out/certs/privatekey.pem -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=${config.marzban.domain}" + echo 'UVICORN_SSL_CERTFILE="/code/certs/certificate.pem"' >> $out/.env + echo 'UVICORN_SSL_KEYFILE="/code/certs/privatekey.pem"' >> $out/.env + echo 'UVICORN_SSL_CA_TYPE="private"' >> $out/.env + '' else '''') + + + '' + echo 'UVICORN_HOST="${config.marzban.env.UVICORN_HOST}"' >> $out/.env + echo 'UVICORN_PORT=${toString config.marzban.env.UVICORN_PORT}' >> $out/.env + echo 'SUDO_USERNAME="${config.marzban.env.SUDO_USERNAME}"' >> $out/.env + echo 'SUDO_PASSWORD="${config.marzban.env.SUDO_PASSWORD}"' >> $out/.env + echo 'DOCS=${if config.marzban.env.DOCS then "True" else "False"}' >> $out/.env + '' + + + '' + cat > $out/xray_config.json <