geschätzte Lesezeit: 4 min

NixOS on the Framework

NixOS 21.11 with GNOME running on the Framework laptop.

What a treat it is to review the Framework laptop a few months before I’ll be buying my own.

The Framework promises to be an powerful, high-end ultra thin laptop with the stand-out feature of easy repairs and upgrades. I think they’ve done it.

Let’s install NixOS.

Live Media

You’ll need an install image with Linux 5.13 or newer to have a working Wi-Fi card.

This presents a challenge: the ISOs provided by https://nixos.org today use Linux 5.10.

If you’re comfortable installing NixOS without a GUI, you can fetch a minimal 21.05 ISO with the latest kernel from Hydra.

Optionally, Building Our Own Live Media

Building your own customized install media is straightforward. You’ll need a Linux machine with Nix.

First, write the following in to a file named custom-media.nix:

{ pkgs, modulesPath, ... }: {
    imports = [
        "${modulesPath}/installer/cd-dvd/installation-cd-graphical-gnome.nix"
    ];
    boot.kernelPackages = pkgs.linuxPackages_latest;
}

Then enter a nix-shell with nixos-generators and build the media:

$nix-shell -p nixos-generators
nix-shell$nixos-generate -I nixpkgs=channel:nixos-unstable --format iso --configuration ./custom-media.nix 
unpacking 'https://nixos.org/channels/nixos-unstable/nixexprs.tar.xz'...
these derivations will be built:
  ...snip...
/nix/store/gnnbjvd916yh1f4svbgrssq94550pbxl-nixos-21.11pre304626.8ecc61c91a5-x86_64-linux.iso/iso/nixos-21.11pre304626.8ecc61c91a5-x86_64-linux.iso

Then copy the ISO to my USB disk, which is called /dev/sda.

Note: the sync at the end is critical.

$ sudo cp /nix/store/gnnbjvd916yh1f4svbgrssq94550pbxl-nixos-21.11pre304626.8ecc61c91a5-x86_64-linux.iso/iso/nixos-21.11pre304626.8ecc61c91a5-x86_64-linux.iso /dev/sda
$ sudo sync

Disabling Secure Boot

  1. Reboot
  2. Enter the Firmware Configuration (Fn + F2)
  3. Navigate to the Security tab
  4. Select Secure Boot
  5. Select Enforce Secure Boot
  6. Select Disabled
  7. Save and reboot with Fn + F10

Note: Secure Boot will prevent unsigned software from running. NixOS does not support Secure Boot today.

Booting Your Media

It appears the machine can boot from any USB port.

  1. Reboot
  2. Enter the Boot Manager (Fn + F12)
  3. Select your USB disk

Installing NixOS

Follow the standard NixOS installation instructions.

After running nixos-generate-config, edit /mnt/etc/nixos/configuration.nix and add a few lines:

  • boot.kernelPackages = pkgs.linuxPackages_latest; - for WiFi support
  • services.fprintd.enable = true; for fingerprint support

Continue the installation procedure.

Seriously. That’s it.

The review unit they shipped me is pre-release hardware, but well specced out and lovely:

  • 11th Gen Intel i7-1185G7, up to 4.8GHz
  • 16G of RAM
  • Intel(R) Wi-Fi 6 AX210 160MHz, REV=0x420
  • 2 USB-C ports, a mini-display port, and a Micro SD slot

Its performance seems quite good, easily good enough for my day to day work. It has no problems driving my 38” ultrawide display.

The machine is silent except when I’m compiling, and it has never felt hot. After a long compilation some areas near the hinge are noticably warm, but the hand rests are still cool.

The keyboard and trackpad feel, to me, perfect. The keys feel crisp but not heavy. The trackpad feels large and precise. That said, click is a bit too clicky.

Hardware switches for the audio and camera are nice, but a bit hard to toggle. The switches are very small and smooth, making it difficult to move. The switches are part of the replacable bezel, and this may be easily fixed.

The power brick is UL Energy Verified and just slightly larger than the Dell XPS 9300 brick.

The Intel Wi-Fi 6 AX210 has integration issues with Linux. Sometimes the wifi firmware crashes on startup, but it seems to be no more frequent than 50/50. Once it is booted, the wifi is rock solid.

QR Codes on Everything

The inside of the laptop, with dozens of QR codes.

Everything has a QR code as a link to instructions. And I mean everything: down to the cable connecting the wall to the power brick.

However, many of them don’t actually lead anywhere. I wasn’t too surprised to see the power cable’s QR code was 404ing, but a bit surprised to see the link for RAM replacement 404ing. I am sure this is a work in progress and these QR codes will all work.

Relative to the XPS 9300

I want the smallest, lightest laptop I can buy, and the Framework is a strong contender here.

This laptop is essentially the same width and thickness: within a milimeter or two. The framework comes in at just 60 grams heavier than the XPS (1330g vs. 1270g.)

One major improvement over the 9300: The fingerprint sensor is supported by recent versions of fprintd out of the box, and no TOD patches are required. The sensor is fast and reliable, whereas the Dell XPS 9300’s TOD Goodix drivers are nearly worthless on Linux.

Some aspects of the Framework are a bit more “industrial” feeling:

  • The cable from the brick to the wall looks like a desktop PC’s cable. Thick, shiny plastic. compared to the more polished, polished, on-brand look of the Dell cable.
  • The rubber feet are chunky, and not super sticky.
  • Opening the lid is not super easy like on the XPS.

Overall, I am extremely satisfied by Framework. The team seems great, and their values appear to match my own. I’ll be pulling out my wallet later this year when my current laptop isn’t so new. I think they’ve fulfilled their promise, and have created a refreshing machine: an ultralight which is servicable.

Yes, please.

geschätzte Lesezeit: 16 min

grahamc’s “Erase your darlings” blog post is an amazing example of what a snapshotting filesystems (zfs) combined with an immutable, infrastructue-as-code OS (NixOS) can achieve. To summarize the post, grahamc demonstrates how to erase the root partition at boot while opting in to state by getting NixOS to symlink stuff to a dedicated partition. This restores the machine to a clean state on every boot, preserving the “new computer smell”.

I believe the main selling point of this concept of opt-in state is that it makes it dead simple to keep track of ephemeral machine state (everything not explicitly specified by your NixOS configuration) and enforces elimination of Configuration Drift. While the benefits of this are clear for servers, this also works pretty well with workstations and laptops, where you gradually accumulate junk in /etc and /var which you never can be completely confident in deleting.1

Here are some notes on how to reproduce the setup with an encrypted2 btrfs root, along with a few tips for a nicer laptop experience. The instructions for encrypted btrfs root are heavily based on this blog post.

Making a Live USB

The laptop I’m currently using is a Dell XPS-13 2-in-1 (7390) with a fair number of issues running on Linux, some of which interferes with boot. Fortunately, most of these have been fixed in newer kernels, but the default installation ISO ships an older kernel version, so we need a custom ISO. Building an ISO with a custom configuration for NixOS is shockingly simple; following the instructions on the wiki:

# iso.nix
{ config, pkgs, ... }:
{
  imports = [
    # installation-cd-graphical-plasma5-new-kernel.nix uses pkgs.linuxPackages_latest
    # instead of the default kernel.
    <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-plasma5-new-kernel.nix>
    <nixpkgs/nixos/modules/installer/cd-dvd/channel.nix>
  ];
  hardware.enableAllFirmware = true;
  nixpkgs.config.allowUnfree = true;
  environment.systemPackages = with pkgs; [
    wget
    vim
    git
    tmux
    gparted
    nix-prefetch-scripts
  ];
}

The image can be built with

nix-build '<nixpkgs/nixos>' -A config.system.build.isoImage -I nixos-config=iso.nix

Then, we write the ISO to a USB stick like so:

sudo dd if=./result/iso/nixos-20.03....-x86_64-linux.iso of=/dev/<usb device> bs=1M status=progress

NixOS Installation

Once we’ve booted into a graphical session, we need to partition the disk. We’ll refer to the whole disk as $DISK (/dev/nvme0n1 in my case), and we need three partitions. The EFI partition, swap3, and the rest of the disk for btrfs to use, which we’ll respecively refer to as "$DISK"p1, "$DISK"p2, and "$DISK"p3.

Btrfs doesn’t natively support encryption, so we’ll be using dm-crypt to transparently encrypt the partition, which would be available at /dev/mapper/enc after running these commands:

cryptsetup --verify-passphrase -v luksFormat "$DISK"p3
cryptsetup open "$DISK"p3 enc

We can then format each partition as needed:

mkfs.vfat -n boot "$DISK"p1
mkswap "$DISK"p2
swapon "$DISK"p2
mkfs.btrfs /dev/mapper/enc

Now we have a btrfs volume, we need to decide on how to structure our subvolumes. We want to split our data into a number of subvolumes to keep track of a few things:

  • root: The subvolume for /, which will be cleared on every boot.
  • home: The subvolume for /home, which should be backed up.
  • nix: The subvolume for /nix, which needs to be persistent but is not worth backing up, as it’s trivial to reconstruct.
  • persist: The subvolume for /persist, containing system state which should be persistent across reboots and possibly backed up.
  • log: The subvolume for /var/log. I’m not so interested in backing up logs but I want them to be preserved across reboots, so I’m dedicating a subvolume to logs rather than using the persist subvolume.

Somewhat arbitrarily, we’ll go with the “Flat” layout as described in the btrfs wiki, and create our subvolumes accordingly.

mount -t btrfs /dev/mapper/enc /mnt
# We first create the subvolumes outlined above:
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
btrfs subvolume create /mnt/nix
btrfs subvolume create /mnt/persist
btrfs subvolume create /mnt/log
# We then take an empty *readonly* snapshot of the root subvolume,
# which we'll eventually rollback to on every boot.
btrfs subvolume snapshot -r /mnt/root /mnt/root-blank
umount /mnt

Once we’ve created the subvolumes, we mount them with the options that we want. Here, we’re using Zstandard compression along with the noatime option.

mount -o subvol=root,compress=zstd,noatime /dev/mapper/enc /mnt
mkdir /mnt/home
mount -o subvol=home,compress=zstd,noatime /dev/mapper/enc /mnt/home
mkdir /mnt/nix
mount -o subvol=nix,compress=zstd,noatime /dev/mapper/enc /mnt/nix
mkdir /mnt/persist
mount -o subvol=persist,compress=zstd,noatime /dev/mapper/enc /mnt/persist
mkdir -p /mnt/var/log
mount -o subvol=log,compress=zstd,noatime /dev/mapper/enc /mnt/var/log
# don't forget this!
mkdir /mnt/boot
mount "$DISK"p1 /mnt/boot

Then, let NixOS figure out the config.

nixos-generate-config --root /mnt

This should result with /mnt/etc/nixos/hardware-configuration.nix looking something like this:

# 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, ... }:
{
  imports =
    [ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
    ];
  boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];
  fileSystems."/" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=root" "compress=zstd" "noatime" ];
    };
  boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/050db9bf-0741-4150-8cf8-d6ec12735d4c";
  fileSystems."/home" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=home" "compress=zstd" "noatime" ];
    };
  fileSystems."/nix" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=nix" "compress=zstd" "noatime" ];
    };
  fileSystems."/var/log" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=log" "compress=zstd" "noatime" ];
    };
  fileSystems."/persist" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=persist" "compress=zstd" "noatime" ];
    };
  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/8CE7-3C76";
      fsType = "vfat";
    };
  swapDevices =
    [ { device = "/dev/disk/by-uuid/5b1b6659-14ab-497f-a788-5518c25e7ec8"; }
    ];
  nix.maxJobs = lib.mkDefault 8;
  powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
  # High-DPI console
  console.font = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz";
}

Make sure that this is what you want, and adjust options as necessary. Note that in order to correctly persist /var/log, the log subvolume needs to be mounted early enough in the boot process. To do this, we need to add neededForBoot = true; so the entry will look like this:

  fileSystems."/var/log" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=log" "compress=zstd" "noatime" ];
      neededForBoot = true;
    };

Although it’s possible to customize /etc/nixos/configuration.nix at this point to set up all the things you need in one fell swoop, I recommend starting out with a reletively minimal config to make sure everything works ok. I went with something like this, with a user called delta:

{ config, pkgs, ... }:
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];
  boot.kernelPackages = pkgs.linuxPackages_latest;
  boot.supportedFilesystems = [ "btrfs" ];
  hardware.enableAllFirmware = true;
  nixpkgs.config.allowUnfree = true;
  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;
  networking.hostName = "apollo"; # Define your hostname.
  networking.networkmanager.enable = true;
  # Enable the X11 windowing system.
  services.xserver.enable = true;
  # Enable the KDE Desktop Environment.
  services.xserver.displayManager.sddm.enable = true;
  services.xserver.desktopManager.plasma5.enable = true;
  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.delta = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
  };
  system.stateVersion = "20.03";
}

Take a deep breath.

nixos-install
reboot

If all goes well, we’ll be prompted for the passphrase for $DISK entered earlier, then we’ll see the greeter for the KDE Desktop Environment. Swith to another tty with Ctrl+Alt+F1, login as root, passwd delta to set your password, and switch back to KDE with Ctrl+Alt+F7. Once you’re logged in, you can continue to tweak your NixOS configuration as you want. However, I generally recommend keeping enabled services at a minimum, and setting up opt-in state first.

Now that we’re comfortable in our desktop environment of choice (mine is XMonad), we can move onto the opt-in state setup. First, we need to find out what state exists in the first place. Seeing what has changed since we took the blank snapshot seems like a good way to do this.

Taking a diff between the root subvolume and the root-blank subvolume (in btrfs, snapshots are just subvolumes) can be done with a script based off of the answers to this serverfault question.

#!/usr/bin/env bash
# fs-diff.sh
set -euo pipefail
OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999)
OLD_TRANSID=${OLD_TRANSID#transid marker was }
sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" |
sed '$d' |
cut -f17- -d' ' |
sort |
uniq |
while read path; do
  path="/$path"
  if [ -L "$path" ]; then
    : # The path is a symbolic link, so is probably handled by NixOS already
  elif [ -d "$path" ]; then
    : # The path is a directory, ignore
  else
    echo "$path"
  fi
done

Then, all it takes to find out which files now exist in the root subvolume is:

sudo mkdir /mnt
sudo mount -o subvol=/ /dev/mapper/enc /mnt
./fs-diff.sh

This may show a surprisingly small list of files, or possible something fairly lengthy, depending on your configuration. We’ll first tackle NetworkManager, so we don’t have to re-type passwords to Wi-Fi access points after every reboot. While grahamc’s original blog post suggests that simply persisting /etc/NetworkManager/system-connections by moving it to somewhere in /persist and creating a symlink is enough, this was not enough to get it to work on my XMonad setup. I ended up with something like this, symlinking a few files in /var/lib/NetworkManager as well.

  environment.etc = {
    "NetworkManager/system-connections".source = "/persist/etc/NetworkManager/system-connections";
  };
  systemd.tmpfiles.rules = [
    "L /var/lib/NetworkManager/secret_key - - - - /persist/var/lib/NetworkManager/secret_key"
    "L /var/lib/NetworkManager/seen-bssids - - - - /persist/var/lib/NetworkManager/seen-bssids"
    "L /var/lib/NetworkManager/timestamps - - - - /persist/var/lib/NetworkManager/timestamps"
  ];

Now you might have noticed that the NixOS configuration itself lives in /etc/nixos/, which will be deleted if left there. After adding a few things, I ended up with a configuration like this.

 environment.etc = {
    nixos.source = "/persist/etc/nixos";
    "NetworkManager/system-connections".source = "/persist/etc/NetworkManager/system-connections";
    adjtime.source = "/persist/etc/adjtime";
    NIXOS.source = "/persist/etc/NIXOS";
    machine-id.source = "/persist/etc/machine-id";
  };
  systemd.tmpfiles.rules = [
    "L /var/lib/NetworkManager/secret_key - - - - /persist/var/lib/NetworkManager/secret_key"
    "L /var/lib/NetworkManager/seen-bssids - - - - /persist/var/lib/NetworkManager/seen-bssids"
    "L /var/lib/NetworkManager/timestamps - - - - /persist/var/lib/NetworkManager/timestamps"
  ];
  security.sudo.extraConfig = ''
    # rollback results in sudo lectures after each reboot
    Defaults lecture = never
  '';

Rolling back the root subvolume is a little bit involved when compared to zfs, but can be achieved with this config.

  # Note `lib.mkBefore` is used instead of `lib.mkAfter` here.
  boot.initrd.postDeviceCommands = pkgs.lib.mkBefore ''
    mkdir -p /mnt
    # We first mount the btrfs root to /mnt
    # so we can manipulate btrfs subvolumes.
    mount -o subvol=/ /dev/mapper/enc /mnt
    # While we're tempted to just delete /root and create
    # a new snapshot from /root-blank, /root is already
    # populated at this point with a number of subvolumes,
    # which makes `btrfs subvolume delete` fail.
    # So, we remove them first.
    #
    # /root contains subvolumes:
    # - /root/var/lib/portables
    # - /root/var/lib/machines
    #
    # I suspect these are related to systemd-nspawn, but
    # since I don't use it I'm not 100% sure.
    # Anyhow, deleting these subvolumes hasn't resulted
    # in any issues so far, except for fairly
    # benign-looking errors from systemd-tmpfiles.
    btrfs subvolume list -o /mnt/root |
    cut -f9 -d' ' |
    while read subvolume; do
      echo "deleting /$subvolume subvolume..."
      btrfs subvolume delete "/mnt/$subvolume"
    done &&
    echo "deleting /root subvolume..." &&
    btrfs subvolume delete /mnt/root
    echo "restoring blank /root subvolume..."
    btrfs subvolume snapshot /mnt/root-blank /mnt/root
    # Once we're done rolling back to a blank snapshot,
    # we can unmount /mnt and continue on the boot process.
    umount /mnt
  '';

While NixOS will take care of creating the specified symlinks, we need to move the relevant file and directories to where the symlinks are pointing at after running sudo nixos-rebuild boot and before rebooting.

sudo nixos-rebuild boot
sudo mkdir -p /persist/etc/NetworkManager
sudo cp -r {,/persist}/etc/NetworkManager/system-connections
sudo mkdir -p /persist/var/lib/NetworkManager
sudo cp /var/lib/NetworkManager/{secret_key,seen-bssids,timestamps} /persist/var/lib/NetworkManager/
sudo cp {,/persist}/etc/nixos
sudo cp {,/persist}/etc/adjtime
sudo cp {,/persist}/etc/NIXOS

Before rebooting, make sure that your user credentials are appropriately handled. Be especially careful4 when setting users.mutableUsers to false and using users.extraUsers.<name?>.passwordFile, as these settings are some of the few in NixOS which can lock you out across NixOS configurations and require non-trivial recovery work or a reinstall. If you want declerative user management, I recommend using users.extraUsers.<name?>.hashedPasswords, but this has it’s own downsides as well.5

Take another deep breath.

reboot

If something goes wrong and /mnt/root isn’t deleted, btrfs subvolume snapshot /mnt/root-blank /mnt/root will just create a snapshot under /mnt/root, so a quick hack to check if rolling back failed without consulting journalctl -b is to see if /mnt/root/root-blank exists.6

As much as Nix and NixOS are attractive for everyday use, sometimes the time it takes to get some language or package running on NixOS just doesn’t seem worth it. That’s when container runtimes like Docker and LXD can help. These tools can act as an escape hatch to get some software working quickly on your machine.

Here, we’ll go through the workflow for getting NixOS services to work with opt-in state, with Docker and LXD as examples.

First, let’s get Docker and LXD running to inspect what kind of state they have. Thanks to NixOS, this is a just a few lines of configuration.

  virtualisation = {
     docker.enable = true;
    lxd = {
      enable = true;
      recommendedSysctlSettings = true;
    };
  };
sudo nixos-rebuild switch

This will install, set up, and start both Docker and LXD on our machine. With fs-diff.sh we can see a few relevant files and directories show up.

/etc/docker/key.json
...
/var/lib/docker/...
/var/lib/lxd/...

Some quick googling tells us that /etc/docker/key.json is generated on every boot, so it seems like we don’t need to keep this around. On the other hand, /var/lib/docker and /var/lib/lxd seem important, so let’s adjust our config accordingly.

  systemd.tmpfiles.rules = [
    "L /var/lib/NetworkManager/secret_key - - - - /persist/var/lib/NetworkManager/secret_key"
    "L /var/lib/NetworkManager/seen-bssids - - - - /persist/var/lib/NetworkManager/seen-bssids"
    "L /var/lib/NetworkManager/timestamps - - - - /persist/var/lib/NetworkManager/timestamps"
    "L /var/lib/lxd - - - - /persist/var/lib/lxd"
    "L /var/lib/docker - - - - /persist/var/lib/docker"
  ];

Now, stop the two services and copy over the directories.

sudo mkdir -p /persist/var/lib/
sudo systemctl stop lxd
sudo cp -r {,/persist}/var/lib/lxd
sudo systemctl stop docker
sudo cp -r {,/persist}/var/lib/docker
sudo nixos-rebuild boot
reboot

If all goes well, running the fs-diff.sh after reboot shouldn’t show persisted directories /var/lib/lxd and /var/lib/docker since they should be symlinks which are created during the boot process.

Docker should work without any problems at this point, but we LXD needs some additional configuration. LXD requires a storage pool to operate, so we create a subvolume for LXD, and mount it in /persist.

sudo mount -o subvol=/ /mnt
sudo btrfs subvolume create /mnt/lxd
sudo umount /mnt
sudo mkdir /persist/lxd
sudo mount -o subvol=lxd /dev/mapper/enc /persist/lxd

Once the subvolume is ready, we run lxd init and answer the questions in the following manner.

$ lxd init
Would you like to use LXD clustering? (yes/no) [default=no]: no
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm) [default=btrfs]:
Would you like to create a new btrfs subvolume under /var/lib/lxd? (yes/no) [default=yes]: no
Create a new BTRFS pool? (yes/no) [default=yes]: no
Name of the existing BTRFS pool or dataset: /persist/lxd
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

Remember to add the relevant information to /etc/nixos/hardware-configuration.nix so NixOS will mount the subvolume where LXD expects (i.e. /persist/lxd).

  fileSystems."/persist/lxd" =
    { device = "/dev/disk/by-uuid/f73c53b7-ae6c-4240-89c3-511ad918edcc";
      fsType = "btrfs";
      options = [ "subvol=lxd" "compress=zstd" "noatime" ];
    };

EDIT 2020-01-26: Added persistence for /etc/machine-id, which fixes an issue where journalctl fails to find logs from past boots, among various others. Thanks j-hui for pointing this out!

Thanks to cannorin and __pandaman64__ for comments and suggestions.

  1. When using a Windows or macOS laptop, I find myself reinstalling the OS every so often to restore the machine to a clean state. Why go through this trouble if you can get your OS to do this on every boot?↩︎

  2. Sadly, we stop short of FDE and settle for only encrypting the btrfs volume, as encrypting /boot seems much more complicated than I’m willing to experiment with. It’s unfortunate that desktop Linux security severely lags behind smartphones, where FDE is the norm rather than the exception, for example.↩︎

  3. Note that I’m creating a swap partition despite having 32GB of RAM. Contrary to popular belief, you should still create swap partitions on systems with “enough RAM”. See this blog post for details: In defence of swap: common misconceptions↩︎

  4. You may need to add neededForBoot = true; to /persist, but I haven’t verified this first-hand.↩︎

  5. Using hashedPasswords has two drawbacks off the top of my head:

    • Since your configuration is kept in the Nix store, other users can read your hashed password and attempt to crack it. Note this does not happen when users.mutableUsers = false; since /etc/shadow is only root-readable.
    • Putting your configuration.nix in a public repository has similar problems. I feel this is a bigger problem, since you can no longer just git clone https://github.com/user/dotfiles-repo which may somewhat complicate your initial setup process.
    ↩︎
  6. Something like [ -d /root-blank ] && notify-send -u critical "opt-in state" "rollback failed" would be nice to run after logging in.↩︎

index

geschätzte Lesezeit: 8 min

Erase your darlings

immutable infrastructure for mutable systems

I erase my systems at every boot.

Over time, a system collects state on its root partition. This state lives in assorted directories like /etc and /var, and represents every under-documented or out-of-order step in bringing up the services.

“Right, run myapp-init.”

These small, inconsequential “oh, oops” steps are the pieces that get lost and don’t appear in your runbooks.

“Just download ca-certificates to … to fix …”

Each of these quick fixes leaves you doomed to repeat history in three years when you’re finally doing that dreaded RHEL 7 to RHEL 8 upgrade.

“Oh, touch /etc/ipsec.secrets or the l2tp tunnel won’t work.”

Immutable infrastructure gets us so close

Immutable infrastructure is a wonderfully effective method of eliminating so many of these forgotten steps. Leaning in to the pain by deleting and replacing your servers on a weekly or monthly basis means you are constantly testing and exercising your automation and runbooks.

The nugget here is the regular and indiscriminate removal of system state. Destroying the whole server doesn’t leave you much room to forget the little tweaks you made along the way.

These techniques work great when you meet two requirements:

  • you can provision and destroy servers with an API call
  • the servers aren’t inherently stateful

Long running servers

There are lots of cases in which immutable infrastructure doesn’t work, and the dirty secret is those servers need good tools the most.

Long-running servers cause long outages. Their runbooks are outdated and incomplete. They accrete tweaks and turn in to an ossified, brittle snowflake — except its arms are load-bearing.

Let’s bring the ideas of immutable infrastructure to these systems too. Whether this system is embedded in a stadium’s jumbotron, in a datacenter, or under your desk, we can keep the state under control.

FHS isn’t enough

The hard part about applying immutable techniques to long running servers is knowing exactly where your application state ends and the operating system, software, and configuration begin.

This is hard because legacy operating systems and the Filesystem Hierarchy Standard poorly separate these areas of concern. For example, /var/lib is for state information, but how much of this do you actually care about tracking? What did you configure in /etc on purpose?

The answer is probably not a lot.

You may not care, but all of this accumulation of junk is a tarpit. Everything becomes harder: replicating production, testing changes, undoing mistakes.

New computer smell

Getting a new computer is this moment of cleanliness. The keycaps don’t have oils on them, the screen is perfect, and the hard drive is fresh and unspoiled — for about an hour or so.

Let’s get back to that.

How is this possible?

NixOS can boot with only two directories: /boot, and /nix.

/nix contains read-only system configurations, which are specified by your configuration.nix and are built and tracked as system generations. These never change. Once the files are created in /nix, the only way to change the config’s contents is to build a new system configuration with the contents you want.

Any configuration or files created on the drive outside of /nix is state and cruft. We can lose everything outside of /nix and /boot and have a healthy system. My technique is to explicitly opt in and choose which state is important, and only keep that.

How this is possible comes down to the boot sequence.

For NixOS, the bootloader follows the same basic steps as a standard Linux distribution: the kernel starts with an initial ramdisk, and the initial ramdisk mounts the system disks.

And here is where the similarities end.

NixOS’s early startup

NixOS configures the bootloader to pass some extra information: a specific system configuration. This is the secret to NixOS’s bootloader rollbacks, and also the key to erasing our disk on each boot. The parameter is named systemConfig.

On every startup the very early boot stage knows what the system’s configuration should be: the entire system configuration is stored in the read-only /nix/store, and the directory passed through systemConfig has a reference to the config. Early boot then manipulates /etc and /run to match the chosen setup. Usually this involves swapping out a few symlinks.

If /etc simply doesn’t exist, however, early boot creates /etc and moves on like it were any other boot. It also creates /var, /dev, /home, and any other core directories that must be present.

Simply speaking, an empty / is not surprising to NixOS. In fact, the NixOS netboot, EC2, and installation media all start out this way.

Opting out

Before we can opt in to saving data, we must opt out of saving data by default. I do this by setting up my filesystem in a way that lets me easily and safely erase the unwanted data, while preserving the data I do want to keep.

My preferred method for this is using a ZFS dataset and rolling it back to a blank snapshot before it is mounted. A partition of any other filesystem would work just as well too, running mkfs at boot, or something similar. If you have a lot of RAM, you could skip the erase step and make / a tmpfs.

Opting out with ZFS

When installing NixOS, I partition my disk with two partitions, one for the boot partition, and another for a ZFS pool. Then I create and mount a few datasets.

My root dataset:

# zfs create -p -o mountpoint=legacy rpool/local/root

Before I even mount it, I create a snapshot while it is totally blank:

# zfs snapshot rpool/local/root@blank

And then mount it:

# mount -t zfs rpool/local/root /mnt

Then I mount the partition I created for the /boot:

# mkdir /mnt/boot
# mount /dev/the-boot-partition /mnt/boot

Create and mount a dataset for /nix:

# zfs create -p -o mountpoint=legacy rpool/local/nix
# mkdir /mnt/nix
# mount -t zfs rpool/local/nix /mnt/nix

And a dataset for /home:

# zfs create -p -o mountpoint=legacy rpool/safe/home
# mkdir /mnt/home
# mount -t zfs rpool/safe/home /mnt/home

And finally, a dataset explicitly for state I want to persist between boots:

# zfs create -p -o mountpoint=legacy rpool/safe/persist
# mkdir /mnt/persist
# mount -t zfs rpool/safe/persist /mnt/persist

Note: in my systems, datasets under rpool/local are never backed up, and datasets under rpool/safe are.

And now safely erasing the root dataset on each boot is very easy: after devices are made available, roll back to the blank snapshot:

{
  boot.initrd.postDeviceCommands = lib.mkAfter ''    zfs rollback -r rpool/local/root@blank  '';
}

I then finish the installation as normal. If all goes well, your next boot will start with an empty root partition but otherwise be configured exactly as you specified.

Opting in

Now that I’m keeping no state, it is time to specify what I do want to keep. My choices here are different based on the role of the system: a laptop has different state than a server.

Here are some different pieces of state and how I preserve them. These examples largely use reconfiguration or symlinks, but using ZFS datasets and mount points would work too.

Wireguard private keys

Create a directory under /persist for the key:

# mkdir -p /persist/etc/wireguard/

And use Nix’s wireguard module to generate the key there:

{
  networking.wireguard.interfaces.wg0 = {
    generatePrivateKeyFile = true;
    privateKeyFile = "/persist/etc/wireguard/wg0";
  };
}

NetworkManager connections

Create a directory under /persist, mirroring the /etc structure:

# mkdir -p /persist/etc/NetworkManager/system-connections

And use Nix’s etc module to set up the symlink:

{
  etc."NetworkManager/system-connections" = {
    source = "/persist/etc/NetworkManager/system-connections/";
  };
}

Bluetooth devices

Create a directory under /persist, mirroring the /var structure:

# mkdir -p /persist/var/lib/bluetooth

And then use systemd’s tmpfiles.d rules to create a symlink from /var/lib/bluetooth to my persisted directory:

{
  systemd.tmpfiles.rules = [
    "L /var/lib/bluetooth - - - - /persist/var/lib/bluetooth"
  ];
}

SSH host keys

Create a directory under /persist, mirroring the /etc structure:

# mkdir -p /persist/etc/ssh

And use Nix’s openssh module to create and use the keys in that directory:

{
  services.openssh = {
    enable = true;
    hostKeys = [
      {
        path = "/persist/ssh/ssh_host_ed25519_key";
        type = "ed25519";
      }
      {
        path = "/persist/ssh/ssh_host_rsa_key";
        type = "rsa";
        bits = 4096;
      }
    ];
  };
}

ACME certificates

Create a directory under /persist, mirroring the /var structure:

# mkdir -p /persist/var/lib/acme

And then use systemd’s tmpfiles.d rules to create a symlink from /var/lib/acme to my persisted directory:

{
  systemd.tmpfiles.rules = [
    "L /var/lib/acme - - - - /persist/var/lib/acme"
  ];
}

I found this process a bit scary for the first few weeks: was I losing important data each reboot? No, I wasn’t.

If you’re worried and want to know what state you’ll lose on the next boot, you can list the files on your root filesystem and see if you’re missing something important:

# tree -x /
├── bin
│   └── sh -> /nix/store/97zzcs494vn5k2yw-dash-0.5.10.2/bin/dash
├── boot
├── dev
├── etc
│   ├── asound.conf -> /etc/static/asound.conf
... snip ...

ZFS can give you a similar answer:

# zfs diff rpool/local/root@blank
M       /
+       /nix
+       /etc
+       /root
+       /var/lib/is-nix-channel-up-to-date
+       /etc/pki/fwupd
+       /etc/pki/fwupd-metadata
... snip ...

You may bump in to new state you meant to be preserving. When I’m adding new services, I think about the state it is writing and whether I care about it or not. If I care, I find a way to redirect its state to /persist.

Take care to reboot these machines on a somewhat regular basis. It will keep things agile, proving your system state is tracked correctly.

This technique has given me the “new computer smell” on every boot without the datacenter full of hardware, and even on systems that do carry important state. I have deployed this strategy to systems in the large and small: build farm servers, database servers, my NAS and home server, my raspberry pi garage door opener, and laptops.

NixOS enables powerful new deployment models in so many ways, allowing for systems of all shapes and sizes to be managed properly and consistently. I think this model of ephemeral roots is yet another example of this flexibility and power. I would like to see this partitioning scheme become a reference architecture and take us out of this eternal tarpit of legacy.

geschätzte Lesezeit: 36 min

Mit Steckersolar-Geräten können Sie auch als Mieter:in oder Wohnungseigentümer:in eigenen Sonnenstrom erzeugen. Wir sagen Ihnen, worauf Sie dabei achten sollten.

Außen an dem Geländer eines Balkons sind zwei Solarmodule montiert.

On

Bald einfachere Regeln für Steckersolar-Geräte?

Der Verband der Elektrotechnik Elektronik Informationstechnik e.V. (VDE) hat am 11. Januar 2023 ein Positionspapier veröffentlicht, in dem er einfachere Regeln für Steckersolar-Geräte fordert. Die Verbraucherzentralen begrüßen die geplanten Vereinfachungen. Derzeit sind diese  Vereinfachungen, darunter die Freigabe des Schukosteckers, der Wegfall der Anmeldung beim Netzbetreiber und die Anhebung der Leistungsgrenze von 600 auf 800 Watt (AC) nur ein Vorschlag im Positionspapier des VDE. Sie sind daher noch nicht gültig und anwendbar.

Auch der Verbraucherzentrale Bundesverband (vzbv) befürwortet, dass Schuko-Stecker eingesetzt werden.

Wichtig zu wissen: Seit dem 1. Januar 2023 sind Photovoltaikanlagen und Batteriespeicher mit einem Umsatzsteuersatz von 0 Prozent versehen. Diese 0 Prozent gelten auch für Steckersolar-Geräte.

1. Was ist ein Steckersolar-Gerät und wie funktioniert es?

Sie haben einen Balkon oder eine Terrasse? Dann können Sie dort eigenen Solarstrom gewinnen und aktiver Teil der Energiewende werden - mit einem Steckersolar-Gerät. Diese kleinen Photovoltaiksysteme werden oft auch Mini-Solaranlagen, Plug & Play-Solaranlage oder Balkonkraftwerke genannt, weil sie sich beispielsweise an die Balkonbrüstung montieren lassen. Um eine "Anlage" im technischen Sinn handelt es sich dabei aber nicht, sondern eher um ein stromerzeugendes Haushaltsgerät.

Was kann ein Steckersolar-Gerät?

Das Solarmodul erzeugt aus Sonnenlicht elektrischen Strom, den ein Wechselrichter in "Haushaltsstrom" umwandelt. Dieser wird direkt mit einem in der Wohnung vorhandenen Stromkreis verbunden. Im einfachsten Fall stecken Sie dazu einen Stecker in eine vorhandene Steckdose.

Der Strom aus dem Steckersolar-Gerät fließt beispielsweise in die Steckdose am Balkon und von dort zu Fernseher, Kühlschrank und Waschmaschine, die an anderen Steckdosen in der Wohnung eingestöpselt sind. Dann zählt der Stromzähler langsamer, es wird weniger Strom aus dem öffentlichen Netz bezogen. Reicht der Strom vom Balkon nicht für den Betrieb der Haushaltsgeräte aus, fließt einfach Strom vom Versorger aus dem Netz dazu.

Ohne Netzanschluss produzieren die Solargeräte keinen Strom. Beim Camping oder im Schrebergarten können Sie stattdessen sogenannte "Inselsysteme" mit einer Batterie und einer anderen Art von Wechselrichter nutzen.

Steckersolar-Geräte bestehen meist aus 1 oder 2 Standard-Solarmodulen und einem Wechselrichter. Je nach Ausstattung kommen noch weitere Bauteile hinzu.

Klicken Sie in unserer Grafik einfach die markierten Punkte an - dann erhalten Sie weitere Information dazu:

';TinyTooltip.POPOVER_TEMPLATE='';TinyTooltip.CLEARFIX='';TinyTooltip.DEFAULTS={animation:true,action:'popover',placement:'top',selector:false,template:TinyTooltip.DEFAULT_TEMPLATE,skin:'default',trigger:'hover focus',delay:{show:0,hide:0},responsive:true,title:'',content:'',html:false,container:'body',viewport:{selector:'body',padding:0},ajax:false,ajaxUrl:'',params:{},method:'GET',loading:'loading...',error:'error occurred',cache:true,shadow:true,opacity:0.9,radius:4,border:true,padding:8,width:0,maxwidth:TinyTooltip.MAXWIDTH,textalign:'center',backcolor:'#000000',textcolor:'#ffffff',bordercolor:'#ffffff',titleBackcolor:'#f7f7f7',titleBordercolor:'#ebebeb',titleTextcolor:'#444444',contentBackcolor:'#ffffff',contentTextcolor:'#444444',menuLinkcolor:'#ffffff',menuHoverLinkcolor:'#000000',menuHoverBackcolor:'#ffffff',menuItemDividercolor:'#ffffff',arrowcolor:'#ffffff'};TinyTooltip.prototype.init=function(type,element,options){this.enabled=true;this.type=type;this.$element=$(element);this.options=this.getOptions(options);this.$viewport=this.options.viewport&&$($.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):(this.options.viewport.selector||this.options.viewport));this.inState={click:false,hover:false,focus:false};if(this.$element[0]instanceof document.constructor&&!this.options.selector){throw new Error('`selector` option must be specified when initializing '+this.type+' on the window.document object!');} var triggers=this.options.trigger.split(' ');for(var i=triggers.length;i--;){var trigger=triggers[i];if(trigger=='click'){this.$element.on('click.'+this.type,this.options.selector,$.proxy(this.toggle,this));}else if(trigger=='hoverable'){var $tip=this.tip();var that=this;this.$element.on('mouseenter.'+this.type,this.options.selector,$.proxy(this.enter,this));$tip.on('mouseleave.'+this.type,this.options.selector,$.proxy(this.leave,this));this.$element.on('mouseleave.'+this.type,this.options.selector,function(){var leave_timer=setTimeout(function(){$tip.trigger('mouseleave.'+that.type);},that.options.delay.hide);$tip.on('mouseenter.'+that.type,that.options.selector,function(){clearTimeout(leave_timer);});});}else if(trigger!='manual'){var eventIn=trigger=='hover'?'mouseenter':'focusin';var eventOut=trigger=='hover'?'mouseleave':'focusout';this.$element.on(eventIn+'.'+this.type,this.options.selector,$.proxy(this.enter,this));this.$element.on(eventOut+'.'+this.type,this.options.selector,$.proxy(this.leave,this));}} this.options.selector?(this._options=$.extend({},this.options,{trigger:'manual',selector:''})):this.fixTitle();};TinyTooltip.prototype.getDefaults=function(){return TinyTooltip.DEFAULTS;};TinyTooltip.prototype.getOptions=function(options){options=$.extend({},this.getDefaults(),this.$element.data(),options);if(options.delay&&typeof options.delay=='number'){options.delay={show:options.delay,hide:options.delay};}else{options.delay={show:options.delayShow,hide:options.delayHide};} if(options.responsive){options.placement=options.placement.replace(/auto/ig,'').trim();if(options.placement==''){options.placement='auto';}else{options.placement+=' auto';}}else{options.placement=options.placement.replace(/auto/ig,'').trim();} options.action=(options.action==null||options.action=='tooltip')?'tooltip':'popover';if(options.skin==''||options.skin==null||options.skin==undefined){options.skin='default';} if(options.skin=='default'){options.textalign=options.action=='popover'?'left':options.textalign;options.bordercolor=options.action=='popover'?'#cccccc':options.bordercolor;} if(options.skin=='custom'){if(options.action=='popover'){if(this.$element.data('bordercolor')==null){options.bordercolor='#bbbbbb';}}} options.template=(options.action==null||options.action=='tooltip')?TinyTooltip.DEFAULT_TEMPLATE:TinyTooltip.POPOVER_TEMPLATE;return options;};TinyTooltip.prototype.getDelegateOptions=function(){var options={};var defaults=this.getDefaults();this._options&&$.each(this._options,function(key,value){if(defaults[key]!=value)options[key]=value;});return options;};TinyTooltip.prototype.enter=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('gg.'+this.type);if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions());$(obj.currentTarget).data('gg.'+this.type,self);} if(obj instanceof $.Event){self.inState[obj.type=='focusin'?'focus':'hover']=true;} if(self.tip().hasClass('in')||self.hoverState=='in'){self.hoverState='in';return;} clearTimeout(self.timeout);self.hoverState='in';if(!self.options.delay||!self.options.delay.show)return self.show();self.timeout=setTimeout(function(){if(self.hoverState=='in')self.show();},self.options.delay.show);};TinyTooltip.prototype.isInStateTrue=function(){for(var key in this.inState){if(this.inState[key])return true;} return false;};TinyTooltip.prototype.leave=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('gg.'+this.type);if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions());$(obj.currentTarget).data('gg.'+this.type,self);} if(obj instanceof $.Event){self.inState[obj.type=='focusout'?'focus':'hover']=false;} self.ajaxState=null;if(self.isInStateTrue())return;clearTimeout(self.timeout);self.hoverState='out';if(!self.options.delay||!self.options.delay.hide)return self.hide();self.timeout=setTimeout(function(){if(self.hoverState=='out')self.hide();},self.options.delay.hide);};TinyTooltip.prototype.show=function(){TinyToolTipController.removeAll();var e=$.Event('show.gg.'+this.type);if(this.options.action=='tooltip'){if(!this.ajaxState&&this.options.ajax){if(this.options.cache){if(this.$element.attr('data-original-title')==''){this.$element.attr('data-original-title',this.options.loading);}}else{this.$element.attr('data-original-title',this.options.loading);}}}else if(this.options.action=='popover'){if(!this.ajaxState&&this.options.ajax){if(this.options.cache){if(this.$element.attr('data-content')==null){this.$element.attr('data-content',this.options.loading);}}else{this.$element.attr('data-content',this.options.loading);}}} if(this.hasContent()&&this.enabled){this.$element.trigger(e);var inDom=$.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!inDom)return;var that=this;var $tip=this.tip();TinyTooltipController.add(that);var tipId=this.getUID(this.type);this.setContent();$tip.attr('id',tipId);TinyTooltipController.add(this);this.$element.attr('aria-describedby',tipId);if(this.options.animation)$tip.addClass('fade');var placement=typeof this.options.placement=='function'?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement;var autoToken=/\s?auto?\s?/i;var autoPlace=autoToken.test(placement);if(autoPlace)placement=placement.replace(autoToken,'')||'top';$tip.detach().css({top:0,left:0,display:'block'}).addClass(placement).data('gg.'+this.type,this);this.options.container?$tip.appendTo(this.options.container):$tip.insertAfter(this.$element);this.$element.trigger('inserted.gg.'+this.type);var windowWidth=$(document).width();var scrollerWidth=this.scrollbarWidth();var widthDifference=$(document).width()-$(window).width();var tooltipWidth=this.options.maxwidth;if(widthDifference>0){windowWidth=windowWidth-scrollerWidth;} if(windowWidth>$(window).width()){windowWidth=$(window).width()-scrollerWidth;} var windowHeight=$(document).height();if(widthDifference>scrollerWidth){windowHeight=windowHeight-scrollerWidth;} if(tooltipWidth!=0){if(tooltipWidth*2>windowWidth){tooltipWidth=Math.floor((windowWidth / 2)-5);} else{tooltipWidth-=30;} if(tooltipWidth*1.5>windowWidth / 2){tooltipWidth=Math.floor((windowWidth / 2)-5);}} else{if(340*2>windowWidth){tooltipWidth=Math.floor((windowWidth / 2)-5);} else{tooltipWidth=340;}} if(this.options.action=='tooltip'){$tip.find('.tinytooltip-inner').css({'min-width':this.options.width>tooltipWidth?tooltipWidth:this.options.width+'px','max-width':tooltipWidth+'px'});}else if(this.options.action=='popover'){$tip.css({'min-width':this.options.width>tooltipWidth?tooltipWidth:this.options.width+'px','max-width':(tooltipWidth+18)+'px'});$tip.find('.tinypopover-inner').css({'min-width':this.options.width>tooltipWidth?tooltipWidth:this.options.width+'px','max-width':(tooltipWidth+18)+'px'});} var pos=this.getPosition();var actualWidth=$tip[0].offsetWidth;var actualHeight=$tip[0].offsetHeight;if(autoPlace){var orgPlacement=placement;var viewportDim=this.getPosition(this.$viewport);switch(placement){case'top-left':placement=placement=='top-left'&&pos.top-actualHeightviewportDim.width?'top-right':placement;placement=placement=='bottom-left'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;break;case'top':placement=placement=='top'&&pos.top-actualHeightviewportDim.width?'bottom-right':placement;placement=placement=='top'&&pos.left-actualWidthviewportDim.width?'top-right':placement;break;case'top-right':placement=placement=='top-right'&&pos.top-actualHeightviewportDim.width?'top-right':placement;placement=placement=='right-bottom'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;break;case'right-top':placement=placement=='right-top'&&pos.top-actualHeightviewportDim.width?'left-top':placement;placement=placement=='right-bottom'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;placement=placement=='left-top'&&pos.left-actualWidthviewportDim.width?'top-right':placement;placement=placement=='bottom-left'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;break;case'right':placement=placement=='right'&&pos.right+actualWidth>viewportDim.width?'top-right':placement;placement=placement=='top-right'&&pos.top-actualHeightviewportDim.bottom?'left-top':placement;placement=placement=='left-top'&&pos.left-actualWidthviewportDim.width?'top-right':placement;placement=placement=='right-bottom'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;break;case'right-bottom':placement=placement=='right-bottom'&&pos.bottom+actualHeight>viewportDim.bottom?'right-top':placement;placement=placement=='right-top'&&pos.right+actualWidth>viewportDim.width?'left-top':placement;placement=placement=='right-bottom'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;placement=placement=='left-top'&&pos.left-actualWidthviewportDim.bottom?'top-left':placement;placement=placement=='bottom-left'&&pos.right+actualWidth>viewportDim.width?'bottom-right':placement;placement=placement=='top-left'&&pos.right+actualWidth>viewportDim.width?'top-right':placement;break;case'bottom':placement=placement=='bottom'&&pos.bottom+actualHeight>viewportDim.bottom?'top':placement;placement=placement=='bottom'&&pos.left-actualWidthviewportDim.width?'bottom-right':placement;placement=placement=='top'&&pos.left-actualWidthviewportDim.width?'top-right':placement;break;case'bottom-right':placement=placement=='bottom-right'&&pos.bottom+actualHeight>viewportDim.bottom?'top-right':placement;placement=placement=='bottom-right'&&pos.left-actualWidth0){this.arrow().css(isVertical?verticalOffsetPosition:'top',50*(1-delta / dimension)+'%').css(isVertical?'top':'left','');}};TinyTooltip.prototype.setContent=function(){if(this.options.action=='tooltip'){this.setTinyTooltipContent();}else{this.setPopoverContent();}};TinyTooltip.prototype.setTinyTooltipContent=function(){var $tip=this.tip();var title=this.getTitle();$tip.find('.tinytooltip-inner')[this.options.html?'html':'text'](title);$tip.find('.tinytooltip-inner').append(TinyTooltip.CLEARFIX);$tip.removeClass('fade in top top-left top-right bottom bottom-left bottom-right left left-top left-bottom right right-top right-bottom');$tip.find('.tinytooltip-inner').css({'padding':this.options.padding+'px','min-width':0,'max-width':this.options.maxwidth+'px'});var resetWidth=false;if(this.ajaxState!=null||!this.options.ajax){resetWidth=true;}else{if(this.cacheState){resetWidth=true;}} if(resetWidth){$tip.find('.tinytooltip-inner').css({'padding':this.options.padding+'px','min-width':this.options.width+'px','max-width':(this.options.width==0?this.options.maxwidth:this.options.width)+'px'});}};TinyTooltip.prototype.setPopoverContent=function(){var $tip=this.tip();var title=this.getTitle();var content=this.getContent();$tip.find('.tinypopover-title')[this.options.html?'html':'text'](title);$tip.find('.tinypopover-content').children().detach().end()[this.options.html?(typeof content=='string'?'html':'append'):'text'](content);$tip.find('.tinypopover-inner').append(TinyTooltip.CLEARFIX);$tip.find('.tinypopover-content').append(TinyTooltip.CLEARFIX);$tip.removeClass('fade in top top-left top-right bottom bottom-left bottom-right left left-top left-bottom right right-top right-bottom') if(!$tip.find('.tinypopover-title').html())$tip.find('.tinypopover-title').hide();$tip.css({'min-width':0,'max-width':this.options.maxwidth+'px'});$tip.find('.tinypopover-content').css({'padding':this.options.padding+'px'});var resetWidth=false;if(this.ajaxState!=null||!this.options.ajax){resetWidth=true;}else{if(this.cacheState){resetWidth=true;}} if(resetWidth){$tip.css({'min-width':this.options.width+'px','max-width':(this.options.width==0?this.options.maxwidth:this.options.width)+'px'});}};TinyTooltip.prototype.setRemoteContent=function(){if(this.options.action=='tooltip'){this.setTinyTooltipRemoteContent();}else{this.setPopoverRemoteContent();}};TinyTooltip.prototype.setTinyTooltipRemoteContent=function(){if(this.options.ajax){var $tip=this.tip();var that=this;that.ajaxState=true;if(that.cacheState==null||!that.cacheState){var xhr=null;xhr=$.ajax({method:that.options.method,url:that.options.ajaxUrl,data:that.options.params,dataType:'json',cache:that.options.cache});xhr.fail(function(){that.$element.attr('data-original-title',that.options.error);that.show();that.cacheState=false;that.$element.attr('data-original-title',that.options.loading);});xhr.done(function(result){var title=result.data;that.$element.attr('data-original-title',title);that.show();that.cacheState=that.options.cache;if(!that.options.cache){that.$element.attr('data-original-title',that.options.loading);}});}}};TinyTooltip.prototype.setPopoverRemoteContent=function(){if(this.options.ajax){var $tip=this.tip();var that=this;that.ajaxState=true;if(that.cacheState==null||!that.cacheState){var xhr=null;xhr=$.ajax({method:that.options.method,url:that.options.ajaxUrl,data:that.options.params,dataType:'json',cache:that.options.cache});xhr.fail(function(){that.$element.attr('data-content',that.options.error);that.show();that.cacheState=false;that.$element.attr('data-content',that.options.loading);});xhr.done(function(result){var title=result.data;that.$element.attr('data-content',title);that.show();that.cacheState=that.options.cache;if(!that.options.cache){that.$element.attr('data-content',that.options.loading);}});}}};TinyTooltip.prototype.setStyles=function(placement){if(this.options.action=='tooltip'){this.setTinyTooltipStyles(placement);}else{this.setPopoverStyles(placement);}};TinyTooltip.prototype.setTinyTooltipStyles=function(placement){var $tip=this.tip();if(this.options.skin!='custom'){$tip.addClass(this.options.skin);if(!this.options.border){$tip.addClass('no-border');}} if(this.options.skin!='custom'){$tip.find('.tinytooltip-inner').css({'border-radius':this.options.radius+'px','text-align':this.options.textalign});}else{$tip.find('.tinytooltip-inner').css({'background':this.options.backcolor,'color':this.options.textcolor,'border-width':this.options.border?'1px':0,'border-color':this.options.bordercolor,'border-radius':this.options.radius+'px','text-align':this.options.textalign});} if(!this.options.shadow){$tip.find('.tinytooltip-inner').css({'box-shadow':'none'});} placement=placement=='bottom-left'||placement=='bottom-right'?'bottom':placement=='top-left'||placement=='top-right'?'top':placement=='left-bottom'||placement=='left-top'?'left':placement=='right-bottom'||placement=='right-top'?'right':placement;$tip.find('.tinytooltip-inner > .video-wrapper').css({"width":($tip.width()-(this.options.padding*2))+"px"});if(this.options.skin=='custom'){$tip.find('.tinytooltip-arrow').css('border-'+placement+'-color',this.options.backcolor);$tip.find('.tinytooltip-arrow-border').css('border-'+placement+'-color',this.options.border?this.options.bordercolor:this.options.backcolor);var that=this;$tip.find('.tinytooltip-inner > .tinytooltip-menu li a').each(function(){$(this).parent().css({'border-bottom-color':that.options.menuItemDividercolor});$(this).css({'color':that.options.menuLinkcolor});$(this).on('mouseenter',function(){$(this).css({'color':that.options.menuHoverLinkcolor,'background':that.options.menuHoverBackcolor});});$(this).on('mouseleave',function(){$(this).css({'color':that.options.menuLinkcolor,'background':'none'});});});}};TinyTooltip.prototype.setPopoverStyles=function(placement){var $tip=this.tip();var title=this.getTitle();if(this.options.skin!='custom'){$tip.addClass(this.options.skin);if(!this.options.border){$tip.addClass('no-border');}} if(!this.options.shadow){$tip.find('.tinypopover-inner').css({'box-shadow':'none'});} if(this.options.skin!='custom'){$tip.find('.tinypopover-title').css({'border-radius':this.options.radius+'px '+this.options.radius+'px 0 0'});$tip.find('.tinypopover-content').css({'border-radius':'0 0 '+this.options.radius+'px '+this.options.radius+'px'});}else{$tip.find('.tinypopover-title').css({'background-color':this.options.titleBackcolor,'color':this.options.titleTextcolor,'border-color':this.options.titleBackcolor,'border-bottom-color':this.options.titleBordercolor,'border-radius':this.options.radius+'px '+this.options.radius+'px 0 0'});$tip.find('.tinypopover-content').css({'background-color':this.options.contentBackcolor,'color':this.options.contentTextcolor,'border-radius':'0 0 '+this.options.radius+'px '+this.options.radius+'px'});} placement=placement=='bottom-left'||placement=='bottom-right'?'bottom':placement=='top-left'||placement=='top-right'?'top':placement=='left-bottom'||placement=='left-top'?'left':placement=='right-bottom'||placement=='right-top'?'right':placement;$tip.find('.tinypopover-inner .video-wrapper').css({"width":($tip.width()-(this.options.padding*2))+"px"});if(this.options.skin!='custom'){$tip.find('.tinypopover-inner').css({'border-radius':this.options.radius+'px','text-align':this.options.textalign});}else{$tip.find('.tinypopover-arrow-border').css('border-'+placement+'-color',this.options.border?this.options.bordercolor:this.options.titleBackcolor);if(/bottom|bottom-left|bottom-right|left-bottom|right-bottom/.test(placement)){$tip.find('.tinypopover-arrow-border > .tinypopover-arrow').css('border-'+placement+'-color',this.options.titleBackcolor);}else{$tip.find('.tinypopover-arrow-border > .tinypopover-arrow').css('border-'+placement+'-color',this.options.contentBackcolor);} if($tip.find('.tinypopover-title').html()==''){$tip.find('.tinypopover-arrow-border > .tinypopover-arrow').css('border-'+placement+'-color',this.options.contentBackcolor);$tip.find('.tinypopover-arrow-border').css('border-'+placement+'-color',this.options.border?this.options.bordercolor:this.options.contentBackcolor);} $tip.find('.tinypopover-inner').css({'color':this.options.textcolor,'border-color':this.options.bordercolor,'border-width':this.options.border?'1px':0,'border-radius':this.options.radius+'px','text-align':this.options.textalign});}};TinyTooltip.prototype.fixTitle=function(){var $e=this.$element;if($e.attr('title')||typeof $e.attr('data-original-title')!='string'){$e.attr('data-original-title',$e.attr('title')||'').attr('title','');}};TinyTooltip.prototype.hasContent=function(){return this.getTitle()||this.getContent();};TinyTooltip.prototype.getContent=function(){var $e=this.$element;var o=this.options;return $e.attr('data-content')||(typeof o.content=='function'?o.content.call($e[0]):o.content);};TinyTooltip.prototype.getPosition=function($element){$element=$element||this.$element;var el=$element[0];var isBody=el.tagName=='BODY';var elRect=el.selector!=''?el.getBoundingClientRect():{width:$(window).width(),height:$(window).height()};if(elRect.width==null){elRect=$.extend({},elRect,{width:elRect.right-elRect.left,height:elRect.bottom-elRect.top});} var isSvg=window.SVGElement&&el instanceof window.SVGElement;var elOffset=isBody?{top:0,left:0}:(isSvg?null:$element.offset());var scroll={scroll:isBody?document.documentElement.scrollTop||document.body.scrollTop:$element.scrollTop()};var outerDims=isBody?{width:$(window).width(),height:$(window).height()}:null;if(el.tagName=='AREA'){var areaName=el.parentElement.getAttribute('name');var imgTop=$("img[usemap='#"+areaName+"']").offset().top;var imgLeft=$("img[usemap='#"+areaName+"']").offset().left;var areaShape=el.getAttribute('shape').toLowerCase();var areaX=parseInt(el.getAttribute('coords').split(',')[0]);var areaY=parseInt(el.getAttribute('coords').split(',')[1]);var areaWidth=parseInt(el.getAttribute('coords').split(',')[2]);var areaHeight=parseInt(el.getAttribute('coords').split(',')[3]||areaWidth);if(areaShape=='rect'){elOffset={top:parseInt(imgTop+areaY),left:parseInt(imgLeft+areaX)};elRect={width:areaWidth-areaX,height:areaHeight-areaY};} if(areaShape=='circle'){elOffset={top:parseInt(imgTop+areaY-areaWidth),left:parseInt(imgLeft+areaX-areaWidth)};elRect={width:areaWidth*2,height:areaWidth*2};} if(areaShape=='poly'){var coords=new Array();var splitCoords=el.getAttribute('coords').split(',');for(var index=0;indexx2?1:-1;});var minX=coords[0].x;coords.sort(function(a,b){var y1=a.y,y2=b.y;if(y1==y2)return 0;return y1>y2?1:-1;});var minY=coords[0].y;elOffset={top:parseInt(imgTop+minY),left:parseInt(imgLeft+minX)};elRect={width:maxX-minX,height:maxY-minY};}} return $.extend({},elRect,scroll,outerDims,elOffset);};TinyTooltip.prototype.getCalculatedOffset=function(placement,pos,actualWidth,actualHeight){return placement=='bottom'?{top:pos.top+pos.height,left:pos.left+pos.width / 2-actualWidth / 2}:placement=='top'?{top:pos.top-actualHeight,left:pos.left+pos.width / 2-actualWidth / 2}:placement=='left'?{top:(this.options.action=='popover'?-8:0)+pos.top+pos.height / 2-actualHeight / 2,left:pos.left-actualWidth}:placement=='right'?{top:(this.options.action=='popover'?-8:0)+pos.top+pos.height / 2-actualHeight / 2,left:pos.left+pos.width}:placement=='right-top'?{top:pos.top-actualHeight+pos.height+6,left:pos.left+pos.width}:placement=='right-bottom'?{top:pos.top-4,left:pos.left+pos.width}:placement=='left-top'?{top:pos.top-actualHeight+pos.height+6,left:pos.left-actualWidth}:placement=='left-bottom'?{top:pos.top-4,left:pos.left-actualWidth}:placement=='bottom-left'?{top:pos.top+pos.height,left:pos.left}:placement=='bottom-right'?{top:pos.top+pos.height,left:pos.left+pos.width-actualWidth}:placement=='top-left'?{top:pos.top-actualHeight,left:pos.left}:placement=='top-right'?{top:pos.top-actualHeight,left:pos.left+pos.width-actualWidth}:'';};TinyTooltip.prototype.getViewportAdjustedDelta=function(placement,pos,actualWidth,actualHeight){var delta={top:0,left:0};if(!this.$viewport)return delta;var viewportPadding=this.options.viewport&&this.options.viewport.padding||0;var viewportDimensions=this.getPosition(this.$viewport);if(/right|left/.test(placement)){var topEdgeOffset=pos.top-viewportPadding-viewportDimensions.scroll;var bottomEdgeOffset=pos.top+viewportPadding-viewportDimensions.scroll+actualHeight;if(topEdgeOffsetviewportDimensions.top+viewportDimensions.height){delta.top=viewportDimensions.top+viewportDimensions.height-bottomEdgeOffset;}}else{var leftEdgeOffset=pos.left-viewportPadding;var rightEdgeOffset=pos.left+viewportPadding+actualWidth;if(leftEdgeOffsetviewportDimensions.right){delta.left=viewportDimensions.left+viewportDimensions.width-rightEdgeOffset;}} return delta;};TinyTooltip.prototype.getTitle=function(){var title;var $e=this.$element;var o=this.options;title=$e.attr('data-original-title')||(typeof o.title=='function'?o.title.call($e[0]):o.title);return title;};TinyTooltip.prototype.getUID=function(prefix){do prefix+=~~(Math.random()*1000000);while(document.getElementById(prefix));return prefix;};TinyTooltip.prototype.tip=function(){if(!this.$tip){this.$tip=$(this.options.template);if(this.$tip.length!=1){throw new Error(this.type+' `template` option must consist of exactly 1 top-level element!');}} return this.$tip;};TinyTooltip.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find('.'+this.options.action+'-arrow'));};TinyTooltip.prototype.enable=function(){this.enabled=true;};TinyTooltip.prototype.disable=function(){this.enabled=false;};TinyTooltip.prototype.toggleEnabled=function(){this.enabled=!this.enabled;};TinyTooltip.prototype.toggle=function(e){var self=this;if(e){self=$(e.currentTarget).data('gg.'+this.type);if(!self){self=new this.constructor(e.currentTarget,this.getDelegateOptions());$(e.currentTarget).data('gg.'+this.type,self);}} if(e){self.inState.click=!self.inState.click;if(self.isInStateTrue())self.enter(self);else self.leave(self);}else{self.tip().hasClass('in')?self.leave(self):self.enter(self);}};TinyTooltip.prototype.destroy=function(){var that=this;clearTimeout(this.timeout);this.hide(function(){that.$element.off('gg.'+that.type).removeData('gg.'+that.type);if(that.$tip){that.$tip.detach();} that.$tip=null;that.$arrow=null;that.$viewport=null;that.$element=null;});};TinyTooltip.prototype.scrollbarWidth=function(){var div=$('

');$('body').append(div);var w1=$('div',div).innerWidth();div.css('overflow','scroll');var w2=$('div',div).innerWidth();$(div).remove();return(w1-w2);};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data('gg.tooltip');var options=typeof option=='object'&&option;if(!data&&/destroy|hide/.test(option))return;if(!data)$this.data('gg.tooltip',(data=new TinyTooltip(this,options)));if(typeof option=='string')data[option]();});} var old=$.fn.tooltip;$.fn.tooltip=Plugin;$.fn.tooltip.Constructor=TinyTooltip;$.fn.tooltip.noConflict=function(){$.fn.tooltip=old;return this;};old=$.fn.tinytooltip;$.fn.tinytooltip=Plugin;$.fn.tinytooltip.Constructor=TinyTooltip;$.fn.tinytooltip.noConflict=function(){$.fn.tinytooltip=old;return this;};$('.thc-hotspot-wrapper .thc-hotspot').each(function(){if($(this).attr('data-action')=='popover'){$(this).tinytooltip({title:function(){return $(this).data('title');},content:function(){return $(this).find('.data-template-container').html();},container:"#vbz-info-graphic-container"});}else{$(this).tinytooltip({title:function(){return $(this).find('.data-template-container').html();},container:"#vbz-info-graphic-container"});}});}); ]]>

Solarmodule

Die Standard-Module sind etwa 1 Meter mal 1,7 Meter groß, wiegen etwa 20 Kilogramm und liefern eine Nennleistung von 350 bis über 400 Watt. Daneben werden auch Solarmodule ohne Glasfront oder kleinformatigere Solarmodule angeboten, die sich für eine einfachere Montage, beispielsweise am Balkon, besonders gut eignen.

Wechselrichter

Der Wechselrichter enthält die Elektronik, die den Gleichstrom, den das Solarmodul aus dem Sonnenlicht erzeugt, so in Wechselstrom umwandelt, dass der erzeugte Strom direkt ins Stromnetz des Hauses fließen und von den vorhandenen Haushaltsgeräten genutzt werden kann. Dieser Modulwechselrichter erfüllt alle technischen und Sicherheitsanforderungen, die auch größere Geräte einhalten müssen. Er ist üblicherweise zur Verwendung im Freien geeignet.

Anschluss ans Stromnetz

Die Verbindung mit dem Stromnetz erfolgt über ein Kabel mit einer Steckverbindung. Ein fester Anschluss ist in der Regel nicht vorgesehen, damit sich das Steckersolar-Gerät jederzeit ein- oder ausstecken lässt und Sie es an einem anderen Ort nutzen können, ohne einen Elektroinstallationsbetrieb beauftragen zu müssen. Welcher Steckverbinder für den Anschluss vorgesehen ist, sollten Sie den Angaben des Herstellerbetriebs entnehmen können. Grundsätzlich gibt es zwei Möglichkeiten, den Spezialstecker Typ "Wieland" oder die in Haushalten üblichen Schukostecker. An welche der drei Phasen des Stromnetzes ein Steckersolar-Gerät angeschlossen wird, ist übrigens gleichgültig, der Strom wird auch von Geräten auf den anderen beiden Phasen genutzt.

Solarmodul-Befestigung

Besondere Sorgfalt ist geboten bei der Montage des Solarmoduls. Der Montageort und das Befestigungsmaterial müssen dafür geeignet sein. Auch dazu sollten Sie in den Angaben des Herstellerbetriebs (Bedienungsanleitung) Hinweise finden. Die meisten Unternehmen verkaufen auch fertige Montagesets. Wichtig ist hier vor allem, dass das Solarmodul nicht durch Wind beschädigt oder durch das eigene Gewicht herabfallen kann.

Monitoring

Um zu sehen, ob das Steckersolar-Gerät so funktioniert wie es soll und wie viel Energie es liefert, ist eine passende Messeinrichtung zu empfehlen. Für manche Wechselrichter gibt es Zusatzgeräte, die diese Funktion übernehmen. Ansonsten können Sie auch Steckdosen-Messgeräte oder per WLAN oder Bluetooth abrufbare Mess-Sensoren nutzen.

Batteriespeicher

Der Solarstrom wird im Steckersolar-Gerät nicht gespeichert, sondern ins Wohnungs-Stromnetz eingespeist und direkt verbraucht. Einzelne Herstellerbetriebe haben immer wieder mal kleine Batteriespeicher im Programm. Bisher gibt es aber noch keine Produkte, die finanziell attraktiv sind. Deshalb raten wir von Batteriespeichern für Steckersolar-Geräte ab.

2. Was ist der Unterschied zu einer Photovoltaikanlage?

Im Gegensatz zu Photovoltaikanlagen sind die wesentlich kleineren Steckersolar-Geräte dafür gedacht, dass Privatpersonen sie selbst anbringen, anschließen und direkt nutzen. Auch die Anmeldung beim Netzbetreiber und beim Marktstammdatenregister dürfen Sie selbst vornehmen. Die Mini-Solaranlagen lassen sich auch einfach entfernen und woanders weiterbetreiben, zum Beispiel bei einem Umzug. Sie haben eine Leistung von bis zu 600 Watt (Wechselrichterleistung).

Photovoltaikanlagen auf Privathäusern haben dagegen eine Leistung zwischen 3 und 20 Kilowatt (kWp). Sie bestehen aus mehreren Komponenten, deren Installation und Wartung von einem Fachbetrieb durchgeführt werden muss, der auch die nötigen technischen Anfragen und Anmeldungen beim örtlichen Netzbetreiber erledigt. Die PV-Anlage ist für den dauerhaften Betrieb fest installiert und kann nur mit erheblichem Aufwand entfernt und an ein anderes Gebäude versetzt werden.

Wie ein Steckersolar-Gerät im Einsatz aussieht und Erfahrungen von Balkonkraftwerk-Besitzer:innen sehen Sie in diesem Video:

3. Eignet sich ein Steckersolar-Gerät für meine Wohnung?

Grundsätzlich ist ein Steckersolar-Gerät geeignet für Wohnungen mit

  • einem Balkon oder
  • einer Terrasse oder
  • einer Dachfläche über der Wohnung bzw. vor dem Fenster, ein Garagendach oder
  • einer zur Sonne ausgerichteten Außenwandfläche.

Ein Steckersolar-Gerät ist deutlich günstiger als eine Photovoltaikanlage und daher auch für Geringverdienende finanzierbar.

Ein Steckersolar-Gerät können Sie auch auf die Terrasse oder in den Garten stellen. Beim Umzug können Sie das Gerät einfach mitnehmen.

Für Miet- und Eigentumswohnungen gilt: Wenn Sie das Solarmodul an der Balkonbrüstung oder der Hauswand anbringen wollen, müssen Vermieter:in oder Eigentumsgemeinschaft in der Regel zustimmen. Seit 2020 das Wohneigentumsgesetz (WEG) geändert wurde, ist hierfür keine Einstimmigkeit mehr nötig, sondern nur noch eine mehrheitliche Erlaubnis.

Beachten Sie, dass in besonderen Fällen Vorschriften des Denkmalschutzes dem Vorhaben entgegenstehen können:

  • Etwa wenn denkmalgeschützte Objekte in unmittelbarer Nähe sind oder
  • im denkmalgeschützten Ortskern oder
  • wenn bauaufsichtliche Vorschriften dem Vorhaben entgegenstehen. Stichwort: Überkopfverglasung.

4. Sind Steckersolar-Geräte sicher?

Die Geräte sind grundsätzlich sehr sicher. Ende 2021 waren bereits über 190.000 solcher Systeme in Deutschland in Betrieb. Bisher ist kein einziger Fall von Sachschäden oder verletzten Personen bekannt geworden. Das liegt daran, dass die verwendete Technik ausgereift ist und die gleichen Komponenten in professionell installierten Photovoltaikanlagen eingesetzt werden. Es dürfen nur normgemäß hergestellte und geprüfte Bauteile verwendet werden.

Sicher sind Steckersolar-Geräte dann, wenn die verwendeten Modulwechselrichter die Anforderungen erfüllen, die auch an Wechselrichter für normale Photovoltaikanlagen gestellt werden. Die Installationsnorm sieht zudem vor, dass eine Elektrofachkraft die Eignung des Stromkreises für die Einspeisung von Solarstrom prüft.

Vor allem sollten Sie an eine Steckdose bzw. an einen Stromkreis immer nur ein einziges Steckersolar-Gerät (einen Wechselrichter) anschließen. Gefährlich wäre die Kopplung mehrerer Geräte über eine Mehrfachsteckdose.

Eine Produktnorm, nach der die Geräte geprüft und zertifiziert werden können, wird derzeit  entwickelt. Daran sind auch der DIN-Verbraucherrat und die Verbraucherzentrale beteiligt, eine Veröffentlichung wurde bereits 2022 erwartet und steht nun für 2024 an. Bis diese Produktnorm veröffentlicht wird, können Sie sich beim Kauf zum Beispiel am Sicherheitsstandard orientieren, den die Deutsche Gesellschaft für Sonnenenergie (DGS) veröffentlicht hat.

Außerdem sollten Sie die Hinweise zum Anschluss und zur Benutzung beachten, die Herstellerfirmen mit dem Gerät liefern. Von ihnen sollten Sie auch erfahren, wie Sie das Solarmodul und den Wechselrichter am vorgesehenen Montageort sicher befestigen.

5. Wie groß sind Steckersolar-Geräte und welche Größe passt zu mir?

Wir verstehen unter Steckersolar-Geräten 1 bis 2 Solarmodule mit einem Wechselrichter, die an einen Stromkreis im Haushalt angeschlossen werden.

Das können 1 bis 2 Standard-Solarmodule (im Format von rund 1 x 1,70 Meter) aktueller Bauart sein, die typischerweise jeweils zwischen 350 und 420 Watt Nennleistung haben. In den nächsten Jahren wird die elektrische Leistung der Standardmodule immer besser werden.

Die genannten 600 Watt beziehen sich auf die Anschlussleistung des Wechselrichters auf der Stromnetz-Seite (AC). Es dürfen auch 2 Module mit je 340 Watt oder auch 2 Module mit jeweils 420 Watt betrieben werden, sofern die Anschlussleistung des Wechselrichters 600 Watt nicht überschreitet.

Alternativ bieten sich auch kleinformatigere, leichtere Solarmodule an, die sich beispielsweise an Balkonbrüstungen einfacher befestigen lassen. Diese haben 50 bis 150 Watt Leistung, und 2 bis 4 davon können an einen Modulwechselrichter angeschlossen werden.

Tipp: Wenn Sie möglichst viel Solarstrom selbst nutzen und eine Netzeinspeisung vermeiden möchten, empfehlen wir eine Leistung von 200 bis 400 Watt, im Regelfall ist das ein Standard-Solarmodul. Falls Sie mehr Solarstrom erzeugen möchten, kommen für Sie auch 2 Standard-Solarmodule in Frage.

Prinzipiell könnten auch Stecker-PV-Systeme mit höherer Leistung aufgebaut werden. Es werden inzwischen auch Steckersolar-Geräte mit zum Beispiel 2.400 Watt angeboten, deren Wechselrichter aber auch maximal 600 Watt abgeben dürfen. Davon raten die Verbraucherzentralen ab, da hier hohe Kosten entstehen, durch eine Abregelung aber nur wenig Strom genutzt werden kann.

Höhere Modulleistungen ohne Begrenzung des Wechselrichters sollten aus unserer Sicht als "richtige" PV-Anlage ausgeführt werden. Spätestens dann ist aber eine Elektrofachkraft notwendig, die alle technischen Voraussetzungen des Stromanschlusses prüft und das Gerät beim Netzbetreiber anmeldet.

Der bei einer großen Photovoltaikanlage höhere Installationsaufwand lohnt sich finanziell aber meist erst bei deutlich größeren Anlagenleistungen von mehr als 3 Kilowatt.

6. Was bringt ein Steckersolar-Gerät? Lohnt es sich für mich?

undefined

Ein Jahresertrag von ca. 260 kWh ist realistisch.

Der Jahresertrag sollte ca. 200 kWh erreichen, wenn das Modul senkrecht an der Balkonbrüstung angebracht ist. Er steigt auf bis zu 250 kWh, je nachdem, in welchem Winkel das Modul ausgerichtet ist.

Der Jahresertrag kann zwischen 130 bis 200 kWh liegen. Er hängt stark davon ab, wie sehr Objekte in unmittelbarer Nähe, z.B. Häuser, Bäume oder Büsche, Schatten auf das Modul werfen.

Der Jahresertrag bringt ca. 150 kWh. Eine Schrägstellung des Moduls kann den Ertrag erhöhen.

Der Ertrag liegt hier deutlich unter 100 kWh. Deshalb lohnt sich ein Modul an dieser Stelle kaum.

Mit einem Steckersolar-Gerät leisten Sie Ihren eigenen persönlichen Beitrag zur Energiewende. Die Mini-Solarsysteme produzieren in der Regel genug Strom, um an sonnigen Tagen einen wesentlichen Teil der Grundlast und der Mittagsspitze eines Haushaltes zu decken.

Ein Standardsolarmodul mit 380 Watt Leistung, das verschattungsfrei an einem Südbalkon montiert wurde, liefert etwa 280 Kilowattstunden Strom pro Jahr. Ihr Strombezug reduziert sich dadurch etwa um die gleiche Menge, wenn Sie den Strom im Haushalt direkt verbrauchen können.

Diese Strommenge entspricht etwa dem jährlichen Verbrauch eines Kühlschranks und einer Waschmaschine in einem Haushalt mit 2 Personen. Bei einem durchschnittlichen Strompreis von 33 Cent bringt das eine jährliche Ersparnis von rund 66 Euro.

Ein Steckersolar-Gerät mit Standard-Modul kostet normalerweise zwischen 350 und 600 Euro. Da derzeit die Nachfrage sehr hoch ist und sich die Lieferung von Bauteilen verzögert, sind die Preise aktuell teilweise deutlich höher. Im Gegenzug sind aber auch die Stromkosten in den Haushalten in den vergangenen Monaten deutlich gestiegen.

Der Ertrag des Gerätes und somit seine Wirtschaftlichkeit sind von verschiedenen Faktoren abhängig. Dazu gehören die Anschaffungskosten, die Ausrichtung des Moduls bei möglichst wenig Verschattung und natürlich der aktuelle Strompreis des Stromversorgers. Besonders sinnvoll ist die senkrechte Montage an der Außenseite einer Balkonbrüstung, die verschattungsfrei nach Südwest bis Südost ausgerichtet ist. Die senkrechte Anordnung reduziert im Sommer die nicht nutzbaren Erzeugungsspitzen und erhöht dafür im Winterhalbjahr die nutzbaren Erträge.

Für einen Standort mit durchschnittlicher Sonnenscheindauer in Deutschland können Sie die Wirtschaftlichkeit eines Steckersolar-Gerätes mit dem Stecker-Solar-Simulator der HTW Berlin abschätzen.

Sie reduzieren aber nicht nur Ihre Stromrechnung, sondern tun auch der Umwelt etwas Gutes: Etwa 2,5 Tonnen CO2-Ausstoß spart das Mini-Solarsystem in 20 Jahren. 

Ungeeignete Montageorte sind:

  • hinter der Balkonbrüstung in der Balkonnische,
  • an der Wand unter dem Balkon des darüber liegenden Stockwerks,
  • Plätze mit Verschattung, beispielsweise durch Bäume, Laternenmasten oder Nachbargebäude.

Durch eine dauerhafte, auch nur teilweise Verschattung oder Verschmutzung der Module kann es zu Ertragsminderungen kommen, die sich deutlich stärker auswirken als bei einer Photovoltaikanlage. Daher sollten Sie Ihr Modul regelmäßig überprüfen und von Schmutz befreien.

Wir haben die wichtigsten Infos zu diesem Thema für Sie auch als Podcast aufbereitet. In der Episode "Solarstrom vom Balkon" spricht Marie Hartmann u.a. mit Thomas Seltmann, Photovoltaikexperte der Verbraucherzentrale NRW. Hören Sie doch mal rein!

7. Gibt es eine Förderung für Steckersolar-Geräte?

Immer mehr Kommunen, einzelne Bundesländer und Regionalverbände fördern Steckersolar-Geräte durch Zuschüsse. Außerdem unterstützen Netzbetreiber und Stromversorger diese Anwendung zunehmend, indem sie die Anmeldung vereinfachen und die Nutzung nicht behindern oder solche Systeme sogar aktiv bewerben. Doch Vorsicht: Oftmals werden in den Förderbedingungen auch Anforderungen festgelegt, etwa der Einsatz einer speziellen Einspeisesteckdose, die Überprüfung der Elektroinstallation durch einen Elektriker oder die Übernahme von Installationskosten für das Setzen eines neuen Zählers. Um keine Probleme mit der Förderung zu bekommen, müssen diese Punkte dann auch zwingend umgesetzt werden. 

Bei Steckersolar-Geräten wird üblicherweise auch auf die EEG-Einspeisevergütung verzichtet. Wenn ein Steckersolar-Gerät beispielsweise jährlich 500 Kilowattstunden Strom erzeugt und davon 150 Kilowattstunden ins Netz fließen, würde das eine Einspeisevergütung von rund 12 Euro im Jahr bedeuten. Dem stünde dann ein regelmäßiger, aber unverhältnismäßig hoher Ablese- und Abrechnungsaufwand gegenüber.

8. Wo muss ich ein Steckersolar-Gerät anmelden?

Die Europäische Union hat in ihrer EU-Verordnung 2016/631 kleine Erzeuger unter 800 Watt als "nicht signifikat" eingestuft, weil sie "nicht systemrelevant" seien. Trotzdem wollen die deutschen Netzbetreiber, dass alle Erzeugungsanlagen, unabhängig von ihrer Leistung, bei ihnen gemeldet werden. Von einer Genehmigung ist der Betrieb aber nicht abhängig. Diese Forderung haben sie in die entsprechende Vorschrift (Anwendungsregel VDE-AR-N 4105) hineingeschrieben. Vorgesehen ist dabei für Erzeuger bis 600 Watt AC-Leistung, wozu auch Steckersolar-Geräte nach unserer Definition zählen, ein vereinfachtes Formular. Immerhin muss nicht zwingend eine Elektrofachkraft dieses Formular ausfüllen, das können Sie auch selbst tun, wenn Sie ein Steckersolar-Gerät nutzen.

Viele Netzbetreiber stellen die vereinfachten Formulare auf ihrer Internetseite zur Verfügung, manche versenden sie auf Anfrage. Einige bieten sogar eine besonders komfortable Online-Anmeldung an. Der Anmeldung müssen Sie ein Datenblatt des verwendeten Wechselrichters beifügen, aus dem hervorgeht, dass das Gerät die Voraussetzungen zum Netzanschluss erfüllt (Konformitätserklärung).

Hilfestellung bei der Anmeldung gibt es bei manchen Herstellerfirmen von Balkon-Modulen.

Obwohl strittig ist, ob es sich bei Steckersolar-Geräten überhaupt um "Anlagen" handelt, zumindest wenn diese Systeme nicht fest angeschlossen, sondern wie Haushaltsgeräte über einen Stecker mit dem Stromkreis verbunden sind, fordert auch die Bundesnetzagentur eine Anmeldung im Marktstammdatenregister.

Es sind derzeit also 2 Anmeldungen notwendig: Beim lokalen Stromnetzbetreiber und bei der Bundesnetzagentur. Wichtig ist bei diesen Anmeldungen, dass beide Male die gleichen technischen Daten, etwa die Leistung oder das Inbetriebnahmedatum, eingetragen werden, da die Daten im Hintergrund miteinander abgeglichen werden.

Für Verbraucher:innen haben die Anmeldungen keine Vorteile, sie schaffen nur bürokratischen Aufwand. Da auch ein Steckersolar-Gerät formal eine netzgekoppelte PV-Anlage ist, sind die Anmeldungen gefordert. Ohne Anmeldung im Marktstammdatenregister kann ein Bußgeld drohen.

Hinweis: Haben Sie schon eine PV-Anlage auf dem Dach, die älter ist als 12 Monate und deren Strom teilweise im Haushalt verbraucht wird, ist das Steckersolar-Gerät als zusätzliche neue Anlage zu sehen. Wenn Sie nicht auf dem gleichen Dach (mit gleicher Ausrichtung und Neigung) installiert wird, wird der Netzbetreiber vermutlich einen zusätzlichen Zähler verlangen. Unter diesen Umständen wird der Betrieb des Steckersolar-Geräts unrentabel. Nur wenn die Dachanlage jünger als 12 Monate ist (es gilt das Inbetriebnahmedatum), kann das Steckersolar-Gerät als Erweiterung der bestehenden Anlage beim Netzbetreiber und im Marktstammdatenregister nachgemeldet werden.

9. Brauche ich einen neuen Zähler?

Auch wenn Steckersolar-Geräte für den Eigenverbrauch gedacht sind und nicht für die Netzeinspeisung, kann Strom ins Netz fließen. Technisch ist das kein Problem, und es ist auch erlaubt, wenn Sie Wechselrichter verwenden, die der Norm entsprechen.

Durch das Steckersolar-Gerät könnte es vorkommen, dass herkömmliche Stromzähler mit mechanischen Drehscheiben („Ferraris-Zähler“) rückwärts laufen, denn diese Zähler sind nicht mit einer Rücklaufsperre ausgestattet. Deshalb tauscht der Netzbetreiber als grundzuständiger Messstellenbetreiber in diesem Fall den herkömmlichen Zähler in einen modernen elektronischen Zähler um, der auch moderne Messeinrichtung (mME) genannt wird.

Diese Zähler gibt es in zwei Ausführungen: Einrichtungszähler messen weiterhin nur den Strombezug und zählen nicht rückwärts, wenn Strom ins Netz fließt. Die (geringe) Überschusseinspeisung wird bei dieser Zählervariante nicht gemessen.

Die zweite Möglichkeit ist ein Zweirichtungszähler. Technisch handelt es sich um die gleichen Zähler, allerdings sind sie so programmiert, dass sie beide Zählrichtungen – den Strombezug aus dem Netz und die Rückspeisung ins Netz – getrennt erfassen und anzeigen. Solche Zähler werden auch bei Photovoltaikanlagen mit Überschusseinspeisung eingesetzt.

Im Lauf der nächsten Jahre sieht der Gesetzgeber vor, dass alle Stromzähler in Deutschland im Rahmen des so genannten Smart-Meter-Rollouts durch solche modernen Messeinrichtungen ersetzt werden. 

Baut Ihr Netzbetreiber den alten Zähler aus und stattdessen eine moderne Messeinrichtung ein, darf er dafür keine Kosten in Rechnung stellen. Denn das Messstellenbetriebsgesetz schreibt vor, dass die Kosten für den Ein- und Ausbau von Zählern im jährlichen Messpreis bereits enthalten sein müssen. Viele Netzbetreiber erklären sich schon bei der Anmeldung eines Steckersolar-Geräts bereit, auf eine Rechnung für den Zähler zu verzichten.

Wird eine moderne Messeinrichtung eingebaut, können die jährlichen Messkosten bis auf den dafür gesetzlichen Höchstwert von 20 Euro pro Jahr steigen.

Achten Sie darauf, dass Ihr gewählter Stromlieferant oder der Grundversorger die Messkosten im Rahmen des Grundpreises für den Strombezug nicht doppelt abrechnet.

10. Was sollte ich beim Kauf beachten?

Sie sollten nur steckfertige Geräte kaufen.

Ganz wichtig ist technisch, dass der enthaltene Wechselrichter eine Konformitätserklärung gemäß VDE AR 4105 enthält, nur dann darf er am Stromnetz betrieben werden. Achten Sie auch darauf, dass der Wechselrichter auf eine Ausgangsleistung (AC-Leistung) von maximal 600 Watt (AC) begrenzt ist. Die Solarmodule dürfen mehr Leistung haben.

In einzelnen Fällen verkaufen Firmen Geräte beispielsweise mit offenen Kabelenden ohne Anschlussstecker. Kund:innen sollen hier den Stecker offenbar selbst montieren.

Dadurch übertragen Herstellerfirmen die Verantwortung für die Fertigstellung des Produkts auf die Käufer:innen. Diese darf rechtlich aber nur eine Elektrofachkraft vornehmen, nicht jedoch jemand ohne Fachkenntnisse. Gleiches gilt auch für den Tausch einer Steckdose: Auch das ist formal von einer Elektrofachkraft vorzunehmen.

Die Verbraucherzentralen empfehlen beim Kauf darauf zu achten, dass Herstellerfirmen für das Steckersolar-Gerät den DGS-Sicherheitsstandard (DGS 0001:2019-10) einhalten. Voraussichtlich 2024 wird eine Produktnorm für Steckersolar-Geräte vorliegen. Sie wird  derzeit erarbeitet.

Mini-Solarsysteme, auch Balkonkraftwerke genannt, können Sie teilweise beim örtlichen Photovoltaik-Fachhandel erwerben. Die meisten Angebote gibt es aber im spezialisierten Onlinehandel. Marktübersichten dazu finden Sie derzeit auf diesen Internetseiten:

  • PV-Magazine (Photovoltaik-Fachzeitschrift)
  • Pvplug.de (Deutsche Gesellschaft für Sonnenenergie e.V.)

Inzwischen finden sich auch Angebote bei Discountern oder Elektronikmärkten. Diese sind jedoch meistens deutlich teurer als die Fachhandelsangebote, und die Beratung und Auswahl sind dort eher begrenzt. Achten Sie darauf, dass die Angebote technisch vollständig sind und zum Beispiel auch die Unterkonstruktion enthalten ist.

Sind alle Voraussetzungen gegeben, können Sie das Gerät selbst einstöpseln. Mancherorts helfen auch Selbstbauworkshops, die beispielsweise von regionalen Energiegenossenschaften oder anderen Initiativen durchgeführt werden und Menschen aus der Nachbarschaft, die bereits eigene Erfahrungen mit Steckersolar-Gerät gesammelt haben.

11. Wie erkenne ich, ob es funktioniert und wie viel es leistet?

Solarmodule oder Modulwechselrichter selbst zeigen die Funktionstüchtigkeit oder aktuelle Leistung nicht direkt an. Manchmal haben die Wechselrichter eine LED, die durch Blinken oder Leuchten bestimmte Betriebszustände signalisiert. Das reicht aber nicht aus, um zu erkennen, ob das Gerät ordnungsgemäß läuft und welche Leistung es bringt.

Einige Wechselrichter beinhalten eine Leistungsmessung, die Sie mit Hilfe eines externen Zusatzgerätes auslesen und speichern können. Das funktioniert unter Umständen auch mit einer Onlineanbindung an ein Internetportal, ähnlich wie bei Photovoltaikanlagen (Monitoring). Dann kann die Stromerzeugung teilweise auch auf dem Handy abgelesen werden.

Bei einem Anschluss über einen Schukostecker in der Steckdose - sofern dieser für das gekaufte Gerät zulässig ist - können Sie ein handelsübliches Strommessgerät verwenden, wie es auch zwischen Steckdose und Kühlschrank gesteckt werden kann, um den Stromverbrauch zu ermitteln. Viele dieser Geräte können auch in die umgekehrte Richtung messen und eignen sich so auch als Erzeugungszähler bei einem Steckersolar-Gerät.

Nach dem gleichen Prinzip funktionieren sogenannte "intelligente Steckdosen", die sich per WLAN vom Router oder von Smart-Home-Steuerungen schalten lassen und oft auch eine Energiemessung beinhalten.

Sowohl Strommessgeräte wie auch intelligente Steckdosen sind für den Anschluss über den so genannten "Wieland"-Spezialstecker bisher nicht verfügbar. In diesem Fall können Sie eine kleine Elektronik in die Steckdose einbauen lassen, um die Daten zu erfassen. Diese Elektronik misst ebenfalls den Stromfluss und schickt ihn über Bluetooth oder WLAN an den Internetrouter oder das Smartphone.

Wenn Solarmodule und Wechselrichter ausgedient haben, können Sie diese zur Entsorgung und Wiederverwertung beim örtlichen Recyclinghof oder bei der Verkaufsstelle abgeben.

Checkliste: Schritt für Schritt zum Steckersolar-Gerät

  1. Eignen sich die örtlichen Gegebenheiten für den Anschluss eines Steckersolar-Gerätes? Ist dort möglichst viel Sonne?
  2. Sind der Montageort, die Steckdose und der Stromkreis auf dem aktuellen Stand?
  3. Sind Vermieter:in oder Eigentümergemeinschaft einverstanden?
  4. Gibt es gegebenenfalls bau- oder satzungsrechtliche Einschränkungen, etwa durch Denkmalschutzvorschriften bei altem Ortskern oder Überkopfverglasung?
  5. Welche Anforderungen stellt der Netzbetreiber und der eventuelle Fördergeber?
  6. Haben Sie das passende Angebot gefunden, das alle Anforderungen erfüllt? (Technik, Preis/Leistung, Lieferung, Montage und Anschluss, DGS-Sicherheitsstandard/künftig Gerätenorm)
  7. Haben Sie ans Monitoring gedacht, um die Leistung zu checken?
  8. Haben Sie Fachleute oder eine örtliche Selbstbaugruppe an der Hand, die Sie im Zweifel fragen können?
  9. Ist alles klar mit der Anmeldung und einem eventuell nötigen Zählertausch?

geschätzte Lesezeit: 1 min

You probably want to have some more persistent files than the two bind mounts we already have created during the setup.

Adding persistent files from etc:

{
  # …
  # machine-id is used by systemd for the journal, if you don't
  # persist this file you won't be able to easily use journalctl to
  # look at journals for previous boots.
  environment.etc."machine-id".source
    = "/nix/persist/etc/machine-id";
  # if you want to run an openssh daemon, you may want to store the
  # host keys across reboots.
  #
  # For this to work you will need to create the directory yourself:
  # $ mkdir /nix/persist/etc/ssh
  environment.etc."ssh/ssh_host_rsa_key".source
    = "/nix/persist/etc/ssh/ssh_host_rsa_key";
  environment.etc."ssh/ssh_host_rsa_key.pub".source
    = "/nix/persist/etc/ssh/ssh_host_rsa_key.pub";
  environment.etc."ssh/ssh_host_ed25519_key".source
    = "/nix/persist/etc/ssh/ssh_host_ed25519_key";
  environment.etc."ssh/ssh_host_ed25519_key.pub".source
    = "/nix/persist/etc/ssh/ssh_host_ed25519_key.pub";
  # …
}

From here you can probably figure out how to do more bind-mounts and symbolic links in /etc for the files you want to live across reboots.

A useful tool to discovering files in your tmpfs is ncdu, I tend to run sudo ncdu -x / to walk around the directory tree to see if there's something I want to make persistent.

You may want to make your /home persistent, that can be done by a mount or bind-mount. I have that as tmpfs as well, but that is probably enough content for it's own post.

Update: Now there's a follow-up post for putting tmpfs on /home as well, it's located here: NixOS ❄: tmpfs as home.