How to deploy custom NixOS module configuration with a flake using nixos-rebuild and keep the relative path of a custom script file?

hello, I use nixos-rebuild to deploy my remote nixos like this:

nixos-rebuild switch --fast --flake '.#router' --target-host root@192.168.123.176 --build-host root@nixbuilder

but i have a custom module config like this:

{ lib, config, pkgs, ... }:
with lib;
let
  cfg = config.services.ad-upstream;
in
{
  
  options.services.ad-upstream = {
    enable = mkOption {
      default = false;
      description = "Enable AdguardHome upstream service";
    };
    path = mkOption {
      default = null;
      type = types.nullOr types.path;
      description = "Path to upstream.sh";
    };
  };


  config = mkIf cfg.enable {
    systemd.services.ad-upstream = {
      description = "AdguardHome upstream service";
      after = ["network-online.target"];
      serviceConfig = {
        ExecStart = cfg.path;
      };
    };
    systemd.timers.ad-upstream = {
      description = "AdguardHome upstream timer";
      after = ["network-online.target"];
      wantedBy = ["multi-user.target"];
      timerConfig = {
        OnCalendar = "*-*-* 5:00";
        Unit = "ad-upstream.service";
      };
    };
  };
}

and module config defined in the configuration.nix :

 services.ad-upstream.enable = true;
 services.ad-upstream.path = ./upstream.sh;

the ./upstream.sh and the upstream.nix (module) under my configuration.nix directory.

we know that when nixos-rebuild with flake, it will copy the current directory to the /nix/store/xxxx-source, but after i run “nixos-rebuild” to deploy remote machine, the nix/store/xxxx-source not on the target machine. so the services.ad-upstream.path = ./upstream.shconfig will broken because of ./upstream.sh not exist.

any one have idea about this case?

the ad-upstream.service content, and the ExecStart path not exist.

[root@router:/etc/systemd/system]# cat ad-upstream.service
[Unit]
After=network-online.target
Description=AdguardHome upstream service

[Service]
Environment="LOCALE_ARCHIVE=/nix/store/md3q61177ag9r74xp74lv0ka7l5dsf7g-glibc-locales-2.35-224/lib/locale/locale-archive"
Environment="PATH=/nix/store/z2k31yvarhcnlc98a76wm07q7a6ryla5-coreutils-9.1/bin:/nix/store/5pm0j70fz1b2jj6krvxbaamq3v0p5b69-findutils-4.9.0/bin:/nix/store/a1s15jpz7fad571j2cyyczjpnxfnag0k-gnugrep-3.7/bin:/nix/store/sfiyijw1gp063ymv2m4zl58imkrfidsv-gnused-4.9/bin:/nix/store/hhp5rgz71srhcpfh9l3kxal5yh0k4bd4-systemd-252.5/bin:/nix/store/z2k31yvarhcnlc98a76wm07q7a6ryla5-coreutils-9.1/sbin:/nix/store/5pm0j70fz1b2jj6krvxbaamq3v0p5b69-findutils-4.9.0/sbin:/nix/store/a1s15jpz7fad571j2cyyczjpnxfnag0k-gnugrep-3.7/sbin:/nix/store/sfiyijw1gp063ymv2m4zl58imkrfidsv-gnused-4.9/sbin:/nix/store/hhp5rgz71srhcpfh9l3kxal5yh0k4bd4-systemd-252.5/sbin"
Environment="TZDIR=/nix/store/9kk1ji1gr4094f2w99w2y6ip2gnwjwn0-tzdata-2022g/share/zoneinfo"



ExecStart=/nix/store/lw0fml9skb0q4w2fqxmxasss413z3z61-source/hosts/router/upstream.sh


[root@router:/etc/systemd/system]# ls /nix/store/lw0fml9skb0q4w2fqxmxasss413z3z61-source/hosts/router/upstream.sh
ls: cannot access '/nix/store/lw0fml9skb0q4w2fqxmxasss413z3z61-source/hosts/router/upstream.sh': No such file or directory

[root@router:/etc/systemd/system]#

my flake dir:

[nix-shell:~/workspace/nixos]$ tree
.
├── builder
├── common
│   ├── default.nix
│   └── users
│       └── default.nix
├── flake.lock
├── flake.nix
├── home
│   ├── custom.fish
│   ├── default.nix
│   └── neovim.nix
├── hosts
│   ├── gitea
│   │   ├── configuration.nix
│   │   └── default.nix
│   ├── homedog
│   │   ├── configuration.nix
│   │   ├── default.nix
│   │   └── hardware-configuration.nix
│   └── router
│       ├── configuration.nix
│       ├── default.nix
│       ├── upstream.nix
│       └── upstream.sh
├── keys
│   ├── builder_ed25519
│   └── builder_ed25519.pub
├── nixos.qcow2
└── ops

default.nix:

{ ... }:
{
  imports = [
    ./configuration.nix
    ./upstream.nix
  ];
}

  1. You should prefer script over ServiceConfig.ExecStart
  2. The path is used in a way that it looses its context, try "${cfg.path}" instead.

thanks, Nobbz.
but the “script” option, auto-generate a /nix/store/xxx-unit-script-ad-upstream-start/bin/ad-upstream-start that content is:

#!/nix/store/k32c6vzr9g1nln6v0gypz6ar6lqjb63l-bash-5.2-p15/bin/bash
set -e
/nix/store/0wkxrnm2bk5dh727x5zqm1rv65yvl8pn-upstream.sh

but the /nix/store/0wkxrnm2bk5dh727x5zqm1rv65yvl8pn-upstream.sh has wrong Permission:

-r--r--r-- 2 root root 1577 Jan  1  1970 /nix/store/0wkxrnm2bk5dh727x5zqm1rv65yvl8pn-upstream.sh

systemctl start ad-upstream will log error:

ad-upstream-start: line 3: /nix/store/j48rbpyrg0jc3f3gqzpkxadh22lazzfx-upstream.sh: Permission denied

workaround:

 path = [pkgs.unixtools.ping pkgs.curl] ;
 script = "${pkgs.bash}/bin/bash ${cfg.path}";

The file in the store should be executable, if the file in the repo is executable.