diff --git a/affine/affine-server.nix b/affine/affine-server.nix new file mode 100644 index 0000000..1f20c56 --- /dev/null +++ b/affine/affine-server.nix @@ -0,0 +1,43 @@ +{ pkgs, lib, config, ... }: + +let + affine-static = "/var/lib/affine"; + affine-config = config.services.affine; +in { + config = lib.mkIf affine-config.enable { + virtualisation.oci-containers.containers."affine_server" = { + image = "ghcr.io/toeverything/affine:stable"; + environment = with affine-config.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" ]; + }; + }; +} \ No newline at end of file diff --git a/affine/affine.nix b/affine/affine.nix index aa27f83..a8ffbc8 100644 --- a/affine/affine.nix +++ b/affine/affine.nix @@ -1,215 +1,40 @@ -# Auto-generated using compose2nix v0.3.1. { pkgs, lib, config, ... }: -let affine-static = "/var/lib/affine"; - +let + affine-static = "/var/lib/affine"; + affine-config = config.services.affine; in { + config = lib.mkIf affine-config.enable { + system.activationScripts.affine-dir = '' + mkdir -p ${affine-static}/{config,db,storage} + ''; - system.activationScripts.affine-dir = '' - mkdir -p ${affine-static}/{config,db,storage} - ''; + virtualisation.docker = { + enable = true; + autoPrune.enable = true; + }; - # Runtime - virtualisation.docker = { - enable = true; - autoPrune.enable = true; - }; + networking.firewall.interfaces."docker+".allowedUDPPorts = [ 53 ]; - # 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"; - virtualisation.oci-containers.backend = "docker"; + 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" ]; + }; - # 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" ]; - }; -} + systemd.targets."docker-compose-affine-root" = { + unitConfig.Description = "Root target generated by compose2nix."; + wantedBy = [ "multi-user.target" ]; + }; + }; +} \ No newline at end of file diff --git a/affine/main.nix b/affine/main.nix index 1c26018..40105bd 100644 --- a/affine/main.nix +++ b/affine/main.nix @@ -3,6 +3,10 @@ { imports = [ ./affine.nix + ./affine-server.nix + ./redis.nix + ./postgres.nix + ./migration.nix ./options.nix ]; } diff --git a/affine/migration.nix b/affine/migration.nix new file mode 100644 index 0000000..e0e9714 --- /dev/null +++ b/affine/migration.nix @@ -0,0 +1,40 @@ +{ pkgs, lib, config, ... }: + +let + affine-static = "/var/lib/affine"; + affine-config = config.services.affine; +in { + config = lib.mkIf affine-config.enable { + virtualisation.oci-containers.containers."affine_migration_job" = { + image = "ghcr.io/toeverything/affine:stable"; + environment = with affine-config.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" ]; + }; + }; +} \ No newline at end of file diff --git a/affine/options.nix b/affine/options.nix index ffd68fa..9dbb1f3 100644 --- a/affine/options.nix +++ b/affine/options.nix @@ -2,7 +2,9 @@ { options = with lib; with types; { - affine = { + services.affine = { + enable = mkEnableOption "AFFINE collaborative tool"; + env = { PORT = mkOption { type = int; default = 3010; }; DB_USERNAME = mkOption { type = str; default = "affine"; }; diff --git a/affine/postgres.nix b/affine/postgres.nix new file mode 100644 index 0000000..a70f482 --- /dev/null +++ b/affine/postgres.nix @@ -0,0 +1,36 @@ +{ pkgs, lib, config, ... }: + +let + affine-static = "/var/lib/affine"; + affine-config = config.services.affine; +in { + config = lib.mkIf affine-config.enable { + virtualisation.oci-containers.containers."affine_postgres" = { + image = "pgvector/pgvector:pg16"; + environment = with affine-config.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 affine-config.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" ]; + }; + }; +} \ No newline at end of file diff --git a/affine/redis.nix b/affine/redis.nix new file mode 100644 index 0000000..56e1d3c --- /dev/null +++ b/affine/redis.nix @@ -0,0 +1,27 @@ +{ pkgs, lib, config, ... }: + +let + affine-config = config.services.affine; +in { + config = lib.mkIf affine-config.enable { + 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" ]; + }; + }; +} \ No newline at end of file diff --git a/debug.sh b/debug.sh new file mode 100644 index 0000000..f0afaba --- /dev/null +++ b/debug.sh @@ -0,0 +1 @@ +nix repl --extra-experimental-features 'flakes' . \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..425f2dd --- /dev/null +++ b/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1758791193, + "narHash": "sha256-F8WmEwFoHsnix7rt290R0rFXNJiMbClMZyIC/e+HYf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "25e53aa156d47bad5082ff7618f5feb1f5e02d01", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-25.05", + "type": "indirect" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1758690382, + "narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "e643668fd71b949c53f8626614b21ff71a07379d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 98f6f72..decd8d2 100644 --- a/flake.nix +++ b/flake.nix @@ -7,7 +7,9 @@ }; outputs = { self, nixpkgs, nixpkgs-unstable, ... }: { - marzban = import ./marzban/main.nix; - affine = import ./affine/main.nix; - }; -} + nixosModules = { + affine = import ./affine/main.nix; + marzban = import ./marzban/main.nix; + }; + }; +} \ No newline at end of file