Skip to content

Instantly share code, notes, and snippets.

@mattdenner
Last active July 30, 2025 07:25
Show Gist options
  • Select an option

  • Save mattdenner/befcf099f5cfcc06ea04dcdd4969a221 to your computer and use it in GitHub Desktop.

Select an option

Save mattdenner/befcf099f5cfcc06ea04dcdd4969a221 to your computer and use it in GitHub Desktop.
Suspend and then hibernate after 60 minutes

I found a post about suspending and then going into hibernate that included a really clever script. Turns out that with NixOS this is even esaier to coordinate as you have systemd so can have a before and after service. I just include this in my /etc/nixos/configuration.nix file and nixos-rebuild; then a systemctl suspend or a close of the lid will cause the hibernate timer to be set.

{ config, pkgs, ... }: let
hibernateEnvironment = {
HIBERNATE_SECONDS = "3600";
HIBERNATE_LOCK = "/var/run/autohibernate.lock";
};
in {
systemd.services."awake-after-suspend-for-a-time" = {
description = "Sets up the suspend so that it'll wake for hibernation";
wantedBy = [ "suspend.target" ];
before = [ "systemd-suspend.service" ];
environment = hibernateEnvironment;
script = ''
curtime=$(date +%s)
echo "$curtime $1" >> /tmp/autohibernate.log
echo "$curtime" > $HIBERNATE_LOCK
${pkgs.utillinux}/bin/rtcwake -m no -s $HIBERNATE_SECONDS
'';
serviceConfig.Type = "simple";
};
systemd.services."hibernate-after-recovery" = {
description = "Hibernates after a suspend recovery due to timeout";
wantedBy = [ "suspend.target" ];
after = [ "systemd-suspend.service" ];
environment = hibernateEnvironment;
script = ''
curtime=$(date +%s)
sustime=$(cat $HIBERNATE_LOCK)
rm $HIBERNATE_LOCK
if [ $(($curtime - $sustime)) -ge $HIBERNATE_SECONDS ] ; then
systemctl hibernate
else
${pkgs.utillinux}/bin/rtcwake -m no -s 1
fi
'';
serviceConfig.Type = "simple";
};
}
@jyap808
Copy link

jyap808 commented Nov 21, 2024

Has anyone figured out how to get this to work without that awesome before an after script? Its so weird that setting a simple 'suspend-then-hibernate' still won't work on NixOS.

Read my 2 replies above. Suspend-then-hibernate works.

@HuzaifaTP
Copy link

@jyap808 thanks a lot for the details :)

@frostytopper
Copy link

I get the feeling that having some basic hardware-configuration updates helps make this tool work efficiently.

I'm having great success with the suspend-then-hibernate in my config:

services.logind.lidSwitch = "suspend-then-hibernate";
I also have zramSwap going:
zramSwap.enable = true; zramSwap.memoryPercent = 50;
A swap partition designated in my hardware-config:
swapDevices = [ { device = "/dev/disk/by-uuid/c4a01f3b-299c-4871-a728-6d19f8106e7b"; } ];
This seems to be allowing my system to function properly. Also, if you haven't updated your hwconfig to opengl, and you happen to have an amd system, check out my full hardware-config:
`# Do not modify this file! It was generated by ‘nixos-generate-config’

and may be overwritten by future invocations. Please make changes

to /etc/nixos/configuration.nix instead.

{ config, lib, pkgs, modulesPath, ... }:

{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];

boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ "amdgpu" ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];

fileSystems."/" =
{ device = "/dev/disk/by-uuid/a64bb1dc-cf69-4d41-89db-98a22ea3cabe";
fsType = "ext4";
};

fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/1284-4374";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};

fileSystems."/efi" =
{ device = "/dev/disk/by-uuid/ACD2-C2B7";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};

swapDevices =
[ { device = "/dev/disk/by-uuid/c4a01f3b-299c-4871-a728-6d19f8106e7b"; }
];

General AMD GPU/OpenGL support settings, for the 24.11 instructions:

hardware.graphics =
{ enable = true;
enable32Bit = true;
extraPackages = with pkgs; [
libvdpau-va-gl
libva-vdpau-driver
amdvlk
rocmPackages.clr
rocmPackages.clr.icd
libva

  ];
  extraPackages32 = with pkgs; [
    driversi686Linux.amdvlk
  ];
};

Enables DHCP on each ethernet and wireless interface. In case of scripted networking

(the default) this is the recommended approach. When using systemd-networkd it's

still possible to use this option, but it's recommended to use it in conjunction

with explicit per-interface declarations with networking.interfaces.<interface>.useDHCP.

networking.useDHCP = lib.mkDefault true;

networking.interfaces.eno1.useDHCP = lib.mkDefault true;

networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true;

nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment