When running NixOS on AWS EC2, and populating /etc/nixos/configuration.nix via user data, there are times when you need to refer to the instance’s IP address (private, not EIP or something complicated).
How does one lookup and provide the IP as a value, to be used for parameters defined in configuration.nix?
I guess what I’m not understanding is how you would integrate that into configuration.nix such that you could use that value, pass it as a variable to a module, etc. Are you suggesting we can embed shell straight into configuration.nix?
Trying to get my nixOS local IP in my configuration too.
With this I could get it to run a script that should get the IP address, but it would just give the localhost address
let
ipDerivation = pkgs.runCommand "${pkgs.busybox}/bin/ip" {} ''
${pkgs.busybox}/bin/ip a | grep "scope" | grep -Po '(?<=inet )[\d.]+' | head -n 2 | tail -n 1 > "$out";
echo "$out";
'';
ipAddress = builtins.readFile ipDerivation;
in
it seems like the environment it runs that script doesn’t have access to the internet, so it can’t get the local IP. This code just gives NETWOR UNREACHABLE:
let
ipDerivation = pkgs.runCommand "${pkgs.busybox}/bin/ip" {} ''
${pkgs.busybox}/bin/ip -4 route get 8.8.8.8 | awk '{print $7}' > "$out";
echo "$out";
'';
ipAddress = builtins.readFile ipDerivation;
in
You can’t get your machines DHCP assigned IP address within the configuration. That is considered impure.
You can either hardcode your network configuration and re use the configuration values where ever else you need them, or you need to find ways to cope with not knowing the address.
Perhaps you can describe the actual problem you want to solve?
In my case my configuration already needs --impure because of this line in a module I made and am using: frida = (builtins.getFlake "github:itstarsun/frida-nix").packages.x86_64-linux.frida-tools;.
But still, I’d prefer to do it the right way.
The problem is also in that module, I’m running this docker program that communicates with a VM running on my PC, and it needs my IP in the environoment:
virtualisation.oci-containers.containers = {
fastapi-dls = {
image = "collinwebdesigns/fastapi-dls:latest";
volumes = [
"${cfg.fastapi-dls.docker-directory}/fastapi-dls/cert:/app/cert:rw"
"dls-db:/app/database"
];
# Set environment variables
environment = {
TZ = "${cfg.fastapi-dls.timezone}";
DLS_URL = "${cfg.fastapi-dls.local_ipv4}"; # this should grab your hostname or your IP!
DLS_PORT = "443";
LEASE_EXPIRE_DAYS="90";
DATABASE = "sqlite:////app/database/db.sqlite";
DEBUG = "true";
};
extraOptions = [
];
# Publish the container's port to the host
ports = [ "443:443" ];
# Automatically start the container
autoStart = true;
};
};
My ideas are, making my configuration have a static IP and hardcoding it as suggested (tho it’s a laptop, and I’m not sure if I change networks or change to a wired connection if the IP stays the same), Not use docker and compile the program, or finding a way to do it with the --impure argument
Either way, you’ve answered the question in the post, so I guess the only thing left to answer here would be maybe some way to do this with the --impure argument
Maybe you can use the virtualisation.oci-containers.containers.<name>.environmentFiles option for that. At boot (or in a systemd timer if your ip address changes a lot, or even better, whenever you detect that it changes) run a script that writes your ip address to some file, e.g. /my-ip, and then set environmentFiles = ["/my-ip"]; in your container configuration.
You should instead define the itstarsun/frida-nix input in your flake.nix and then pass it into default.nix to make this pure, for example:
Wow, thank you so much for that flake input solution! I had tried it before but didn’t know how to pass it to the default.nix file!
(unfortunately, it looks like it still needs impure because of docker 🤦 error: access to absolute path '/opt/docker' is forbidden in pure eval mode (use '--impure' to override))
As for the IP, I’m content with hardcoding the IP and setting a static IP for now:
But if applying your suggestion, I had trouble making systemd services interact with files on my system before, because they also seemed to be restricted in a “sandboxed” environment, much like pkgs.runCommand seemed to be. But I just tried it again with this code and managed to create a /my-ip file successfully so all’s good:
systemd.services.my-awesome-service = {
description = "writes a file to /my-ip";
serviceConfig.PassEnvironment = "DISPLAY";
script = ''
${pkgs.busybox}/bin/ip a | grep "scope" | grep -Po '(?<=inet )[\d.]+' | head -n 2 | tail -n 1 > /my-ip;
echo "success!"
'';
wantedBy = [ "multi-user.target" ]; # starts after login
};
You’re welcome So how import works is that you can basically replace import <path> with (<content of path>) where path can be a .nix file or a directory containing a default.nix. So in this case, the
import ./default.nix frida
would turn into
(fridaFlake: { pkgs, lib, ... }: { ... }) frida
so an anonymous function that gets called with the frida argument. Hope this helps
Maybe ProtectSystem was enabled on those services? Could of course be a lot of things…